feat: get user by username

pull/4338/head
johnnyjoy 5 months ago
parent 45c16f9d52
commit 57014e392f

@ -18,15 +18,16 @@ service UserService {
rpc ListUsers(ListUsersRequest) returns (ListUsersResponse) { rpc ListUsers(ListUsersRequest) returns (ListUsersResponse) {
option (google.api.http) = {get: "/api/v1/users"}; option (google.api.http) = {get: "/api/v1/users"};
} }
// SearchUsers searches users by filter.
rpc SearchUsers(SearchUsersRequest) returns (SearchUsersResponse) {
option (google.api.http) = {get: "/api/v1/users:search"};
}
// GetUser gets a user by name. // GetUser gets a user by name.
rpc GetUser(GetUserRequest) returns (User) { rpc GetUser(GetUserRequest) returns (User) {
option (google.api.http) = {get: "/api/v1/{name=users/*}"}; option (google.api.http) = {get: "/api/v1/{name=users/*}"};
option (google.api.method_signature) = "name"; 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. // GetUserAvatarBinary gets the avatar of a user.
rpc GetUserAvatarBinary(GetUserAvatarBinaryRequest) returns (google.api.HttpBody) { rpc GetUserAvatarBinary(GetUserAvatarBinaryRequest) returns (google.api.HttpBody) {
option (google.api.http) = {get: "/file/{name=users/*}/avatar"}; option (google.api.http) = {get: "/file/{name=users/*}/avatar"};
@ -133,21 +134,16 @@ message ListUsersResponse {
repeated User users = 1; repeated User users = 1;
} }
message SearchUsersRequest {
// Filter is used to filter users returned in the list.
// Format: "username == 'frank'"
string filter = 1;
}
message SearchUsersResponse {
repeated User users = 1;
}
message GetUserRequest { message GetUserRequest {
// The name of the user. // The name of the user.
string name = 1; string name = 1;
} }
message GetUserByUsernameRequest {
// The username of the user.
string username = 1;
}
message GetUserAvatarBinaryRequest { message GetUserAvatarBinaryRequest {
// The name of the user. // The name of the user.
string name = 1; string name = 1;

File diff suppressed because it is too large Load Diff

@ -53,38 +53,6 @@ func local_request_UserService_ListUsers_0(ctx context.Context, marshaler runtim
return msg, metadata, err return msg, metadata, err
} }
var filter_UserService_SearchUsers_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
func request_UserService_SearchUsers_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq SearchUsersRequest
metadata runtime.ServerMetadata
)
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_UserService_SearchUsers_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.SearchUsers(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_UserService_SearchUsers_0(ctx context.Context, marshaler runtime.Marshaler, server UserServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq SearchUsersRequest
metadata runtime.ServerMetadata
)
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_UserService_SearchUsers_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.SearchUsers(ctx, &protoReq)
return msg, metadata, err
}
func request_UserService_GetUser_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { func request_UserService_GetUser_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var ( var (
protoReq GetUserRequest protoReq GetUserRequest
@ -121,6 +89,38 @@ func local_request_UserService_GetUser_0(ctx context.Context, marshaler runtime.
return msg, metadata, err return msg, metadata, err
} }
var filter_UserService_GetUserByUsername_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
func request_UserService_GetUserByUsername_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq GetUserByUsernameRequest
metadata runtime.ServerMetadata
)
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_UserService_GetUserByUsername_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.GetUserByUsername(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_UserService_GetUserByUsername_0(ctx context.Context, marshaler runtime.Marshaler, server UserServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq GetUserByUsernameRequest
metadata runtime.ServerMetadata
)
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_UserService_GetUserByUsername_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.GetUserByUsername(ctx, &protoReq)
return msg, metadata, err
}
var filter_UserService_GetUserAvatarBinary_0 = &utilities.DoubleArray{Encoding: map[string]int{"name": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} var filter_UserService_GetUserAvatarBinary_0 = &utilities.DoubleArray{Encoding: map[string]int{"name": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
func request_UserService_GetUserAvatarBinary_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { func request_UserService_GetUserAvatarBinary_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
@ -633,45 +633,45 @@ func RegisterUserServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux
} }
forward_UserService_ListUsers_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) forward_UserService_ListUsers_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
}) })
mux.Handle(http.MethodGet, pattern_UserService_SearchUsers_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { mux.Handle(http.MethodGet, pattern_UserService_GetUser_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context()) ctx, cancel := context.WithCancel(req.Context())
defer cancel() defer cancel()
var stream runtime.ServerTransportStream var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.UserService/SearchUsers", runtime.WithHTTPPathPattern("/api/v1/users:search")) annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.UserService/GetUser", runtime.WithHTTPPathPattern("/api/v1/{name=users/*}"))
if err != nil { if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return return
} }
resp, md, err := local_request_UserService_SearchUsers_0(annotatedContext, inboundMarshaler, server, req, pathParams) resp, md, err := local_request_UserService_GetUser_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil { if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return return
} }
forward_UserService_SearchUsers_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) forward_UserService_GetUser_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
}) })
mux.Handle(http.MethodGet, pattern_UserService_GetUser_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { mux.Handle(http.MethodGet, pattern_UserService_GetUserByUsername_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context()) ctx, cancel := context.WithCancel(req.Context())
defer cancel() defer cancel()
var stream runtime.ServerTransportStream var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.UserService/GetUser", runtime.WithHTTPPathPattern("/api/v1/{name=users/*}")) annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v1.UserService/GetUserByUsername", runtime.WithHTTPPathPattern("/api/v1/users:username"))
if err != nil { if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return return
} }
resp, md, err := local_request_UserService_GetUser_0(annotatedContext, inboundMarshaler, server, req, pathParams) resp, md, err := local_request_UserService_GetUserByUsername_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil { if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return return
} }
forward_UserService_GetUser_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) forward_UserService_GetUserByUsername_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
}) })
mux.Handle(http.MethodGet, pattern_UserService_GetUserAvatarBinary_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { mux.Handle(http.MethodGet, pattern_UserService_GetUserAvatarBinary_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context()) ctx, cancel := context.WithCancel(req.Context())
@ -950,39 +950,39 @@ func RegisterUserServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux
} }
forward_UserService_ListUsers_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) forward_UserService_ListUsers_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
}) })
mux.Handle(http.MethodGet, pattern_UserService_SearchUsers_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { mux.Handle(http.MethodGet, pattern_UserService_GetUser_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context()) ctx, cancel := context.WithCancel(req.Context())
defer cancel() defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.UserService/SearchUsers", runtime.WithHTTPPathPattern("/api/v1/users:search")) annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.UserService/GetUser", runtime.WithHTTPPathPattern("/api/v1/{name=users/*}"))
if err != nil { if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return return
} }
resp, md, err := request_UserService_SearchUsers_0(annotatedContext, inboundMarshaler, client, req, pathParams) resp, md, err := request_UserService_GetUser_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil { if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return return
} }
forward_UserService_SearchUsers_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) forward_UserService_GetUser_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
}) })
mux.Handle(http.MethodGet, pattern_UserService_GetUser_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { mux.Handle(http.MethodGet, pattern_UserService_GetUserByUsername_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context()) ctx, cancel := context.WithCancel(req.Context())
defer cancel() defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.UserService/GetUser", runtime.WithHTTPPathPattern("/api/v1/{name=users/*}")) annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/memos.api.v1.UserService/GetUserByUsername", runtime.WithHTTPPathPattern("/api/v1/users:username"))
if err != nil { if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return return
} }
resp, md, err := request_UserService_GetUser_0(annotatedContext, inboundMarshaler, client, req, pathParams) resp, md, err := request_UserService_GetUserByUsername_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil { if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return return
} }
forward_UserService_GetUser_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) forward_UserService_GetUserByUsername_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
}) })
mux.Handle(http.MethodGet, pattern_UserService_GetUserAvatarBinary_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { mux.Handle(http.MethodGet, pattern_UserService_GetUserAvatarBinary_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context()) ctx, cancel := context.WithCancel(req.Context())
@ -1176,8 +1176,8 @@ func RegisterUserServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux
var ( var (
pattern_UserService_ListUsers_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "users"}, "")) pattern_UserService_ListUsers_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "users"}, ""))
pattern_UserService_SearchUsers_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "users"}, "search"))
pattern_UserService_GetUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3}, []string{"api", "v1", "users", "name"}, "")) pattern_UserService_GetUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3}, []string{"api", "v1", "users", "name"}, ""))
pattern_UserService_GetUserByUsername_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "users"}, "username"))
pattern_UserService_GetUserAvatarBinary_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 2, 5, 2, 2, 3}, []string{"file", "users", "name", "avatar"}, "")) pattern_UserService_GetUserAvatarBinary_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 2, 5, 2, 2, 3}, []string{"file", "users", "name", "avatar"}, ""))
pattern_UserService_CreateUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "users"}, "")) pattern_UserService_CreateUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "users"}, ""))
pattern_UserService_UpdateUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3}, []string{"api", "v1", "users", "user.name"}, "")) pattern_UserService_UpdateUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3}, []string{"api", "v1", "users", "user.name"}, ""))
@ -1193,8 +1193,8 @@ var (
var ( var (
forward_UserService_ListUsers_0 = runtime.ForwardResponseMessage forward_UserService_ListUsers_0 = runtime.ForwardResponseMessage
forward_UserService_SearchUsers_0 = runtime.ForwardResponseMessage
forward_UserService_GetUser_0 = runtime.ForwardResponseMessage forward_UserService_GetUser_0 = runtime.ForwardResponseMessage
forward_UserService_GetUserByUsername_0 = runtime.ForwardResponseMessage
forward_UserService_GetUserAvatarBinary_0 = runtime.ForwardResponseMessage forward_UserService_GetUserAvatarBinary_0 = runtime.ForwardResponseMessage
forward_UserService_CreateUser_0 = runtime.ForwardResponseMessage forward_UserService_CreateUser_0 = runtime.ForwardResponseMessage
forward_UserService_UpdateUser_0 = runtime.ForwardResponseMessage forward_UserService_UpdateUser_0 = runtime.ForwardResponseMessage

@ -22,8 +22,8 @@ const _ = grpc.SupportPackageIsVersion9
const ( const (
UserService_ListUsers_FullMethodName = "/memos.api.v1.UserService/ListUsers" UserService_ListUsers_FullMethodName = "/memos.api.v1.UserService/ListUsers"
UserService_SearchUsers_FullMethodName = "/memos.api.v1.UserService/SearchUsers"
UserService_GetUser_FullMethodName = "/memos.api.v1.UserService/GetUser" UserService_GetUser_FullMethodName = "/memos.api.v1.UserService/GetUser"
UserService_GetUserByUsername_FullMethodName = "/memos.api.v1.UserService/GetUserByUsername"
UserService_GetUserAvatarBinary_FullMethodName = "/memos.api.v1.UserService/GetUserAvatarBinary" UserService_GetUserAvatarBinary_FullMethodName = "/memos.api.v1.UserService/GetUserAvatarBinary"
UserService_CreateUser_FullMethodName = "/memos.api.v1.UserService/CreateUser" UserService_CreateUser_FullMethodName = "/memos.api.v1.UserService/CreateUser"
UserService_UpdateUser_FullMethodName = "/memos.api.v1.UserService/UpdateUser" UserService_UpdateUser_FullMethodName = "/memos.api.v1.UserService/UpdateUser"
@ -43,10 +43,10 @@ const (
type UserServiceClient interface { type UserServiceClient interface {
// ListUsers returns a list of users. // ListUsers returns a list of users.
ListUsers(ctx context.Context, in *ListUsersRequest, opts ...grpc.CallOption) (*ListUsersResponse, error) ListUsers(ctx context.Context, in *ListUsersRequest, opts ...grpc.CallOption) (*ListUsersResponse, error)
// SearchUsers searches users by filter.
SearchUsers(ctx context.Context, in *SearchUsersRequest, opts ...grpc.CallOption) (*SearchUsersResponse, error)
// GetUser gets a user by name. // GetUser gets a user by name.
GetUser(ctx context.Context, in *GetUserRequest, opts ...grpc.CallOption) (*User, error) GetUser(ctx context.Context, in *GetUserRequest, opts ...grpc.CallOption) (*User, error)
// GetUserByUsername gets a user by username.
GetUserByUsername(ctx context.Context, in *GetUserByUsernameRequest, opts ...grpc.CallOption) (*User, error)
// GetUserAvatarBinary gets the avatar of a user. // GetUserAvatarBinary gets the avatar of a user.
GetUserAvatarBinary(ctx context.Context, in *GetUserAvatarBinaryRequest, opts ...grpc.CallOption) (*httpbody.HttpBody, error) GetUserAvatarBinary(ctx context.Context, in *GetUserAvatarBinaryRequest, opts ...grpc.CallOption) (*httpbody.HttpBody, error)
// CreateUser creates a new user. // CreateUser creates a new user.
@ -89,20 +89,20 @@ func (c *userServiceClient) ListUsers(ctx context.Context, in *ListUsersRequest,
return out, nil return out, nil
} }
func (c *userServiceClient) SearchUsers(ctx context.Context, in *SearchUsersRequest, opts ...grpc.CallOption) (*SearchUsersResponse, error) { func (c *userServiceClient) GetUser(ctx context.Context, in *GetUserRequest, opts ...grpc.CallOption) (*User, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(SearchUsersResponse) out := new(User)
err := c.cc.Invoke(ctx, UserService_SearchUsers_FullMethodName, in, out, cOpts...) err := c.cc.Invoke(ctx, UserService_GetUser_FullMethodName, in, out, cOpts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return out, nil return out, nil
} }
func (c *userServiceClient) GetUser(ctx context.Context, in *GetUserRequest, opts ...grpc.CallOption) (*User, error) { func (c *userServiceClient) GetUserByUsername(ctx context.Context, in *GetUserByUsernameRequest, opts ...grpc.CallOption) (*User, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(User) out := new(User)
err := c.cc.Invoke(ctx, UserService_GetUser_FullMethodName, in, out, cOpts...) err := c.cc.Invoke(ctx, UserService_GetUserByUsername_FullMethodName, in, out, cOpts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -225,10 +225,10 @@ func (c *userServiceClient) DeleteUserAccessToken(ctx context.Context, in *Delet
type UserServiceServer interface { type UserServiceServer interface {
// ListUsers returns a list of users. // ListUsers returns a list of users.
ListUsers(context.Context, *ListUsersRequest) (*ListUsersResponse, error) ListUsers(context.Context, *ListUsersRequest) (*ListUsersResponse, error)
// SearchUsers searches users by filter.
SearchUsers(context.Context, *SearchUsersRequest) (*SearchUsersResponse, error)
// GetUser gets a user by name. // GetUser gets a user by name.
GetUser(context.Context, *GetUserRequest) (*User, error) GetUser(context.Context, *GetUserRequest) (*User, error)
// GetUserByUsername gets a user by username.
GetUserByUsername(context.Context, *GetUserByUsernameRequest) (*User, error)
// GetUserAvatarBinary gets the avatar of a user. // GetUserAvatarBinary gets the avatar of a user.
GetUserAvatarBinary(context.Context, *GetUserAvatarBinaryRequest) (*httpbody.HttpBody, error) GetUserAvatarBinary(context.Context, *GetUserAvatarBinaryRequest) (*httpbody.HttpBody, error)
// CreateUser creates a new user. // CreateUser creates a new user.
@ -264,12 +264,12 @@ type UnimplementedUserServiceServer struct{}
func (UnimplementedUserServiceServer) ListUsers(context.Context, *ListUsersRequest) (*ListUsersResponse, error) { func (UnimplementedUserServiceServer) ListUsers(context.Context, *ListUsersRequest) (*ListUsersResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListUsers not implemented") return nil, status.Errorf(codes.Unimplemented, "method ListUsers not implemented")
} }
func (UnimplementedUserServiceServer) SearchUsers(context.Context, *SearchUsersRequest) (*SearchUsersResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method SearchUsers not implemented")
}
func (UnimplementedUserServiceServer) GetUser(context.Context, *GetUserRequest) (*User, error) { func (UnimplementedUserServiceServer) GetUser(context.Context, *GetUserRequest) (*User, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetUser not implemented") return nil, status.Errorf(codes.Unimplemented, "method GetUser not implemented")
} }
func (UnimplementedUserServiceServer) GetUserByUsername(context.Context, *GetUserByUsernameRequest) (*User, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetUserByUsername not implemented")
}
func (UnimplementedUserServiceServer) GetUserAvatarBinary(context.Context, *GetUserAvatarBinaryRequest) (*httpbody.HttpBody, error) { func (UnimplementedUserServiceServer) GetUserAvatarBinary(context.Context, *GetUserAvatarBinaryRequest) (*httpbody.HttpBody, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetUserAvatarBinary not implemented") return nil, status.Errorf(codes.Unimplemented, "method GetUserAvatarBinary not implemented")
} }
@ -342,38 +342,38 @@ func _UserService_ListUsers_Handler(srv interface{}, ctx context.Context, dec fu
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _UserService_SearchUsers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { func _UserService_GetUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SearchUsersRequest) in := new(GetUserRequest)
if err := dec(in); err != nil { if err := dec(in); err != nil {
return nil, err return nil, err
} }
if interceptor == nil { if interceptor == nil {
return srv.(UserServiceServer).SearchUsers(ctx, in) return srv.(UserServiceServer).GetUser(ctx, in)
} }
info := &grpc.UnaryServerInfo{ info := &grpc.UnaryServerInfo{
Server: srv, Server: srv,
FullMethod: UserService_SearchUsers_FullMethodName, FullMethod: UserService_GetUser_FullMethodName,
} }
handler := func(ctx context.Context, req interface{}) (interface{}, error) { handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(UserServiceServer).SearchUsers(ctx, req.(*SearchUsersRequest)) return srv.(UserServiceServer).GetUser(ctx, req.(*GetUserRequest))
} }
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _UserService_GetUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { func _UserService_GetUserByUsername_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetUserRequest) in := new(GetUserByUsernameRequest)
if err := dec(in); err != nil { if err := dec(in); err != nil {
return nil, err return nil, err
} }
if interceptor == nil { if interceptor == nil {
return srv.(UserServiceServer).GetUser(ctx, in) return srv.(UserServiceServer).GetUserByUsername(ctx, in)
} }
info := &grpc.UnaryServerInfo{ info := &grpc.UnaryServerInfo{
Server: srv, Server: srv,
FullMethod: UserService_GetUser_FullMethodName, FullMethod: UserService_GetUserByUsername_FullMethodName,
} }
handler := func(ctx context.Context, req interface{}) (interface{}, error) { handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(UserServiceServer).GetUser(ctx, req.(*GetUserRequest)) return srv.(UserServiceServer).GetUserByUsername(ctx, req.(*GetUserByUsernameRequest))
} }
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
@ -587,14 +587,14 @@ var UserService_ServiceDesc = grpc.ServiceDesc{
MethodName: "ListUsers", MethodName: "ListUsers",
Handler: _UserService_ListUsers_Handler, Handler: _UserService_ListUsers_Handler,
}, },
{
MethodName: "SearchUsers",
Handler: _UserService_SearchUsers_Handler,
},
{ {
MethodName: "GetUser", MethodName: "GetUser",
Handler: _UserService_GetUser_Handler, Handler: _UserService_GetUser_Handler,
}, },
{
MethodName: "GetUserByUsername",
Handler: _UserService_GetUserByUsername_Handler,
},
{ {
MethodName: "GetUserAvatarBinary", MethodName: "GetUserAvatarBinary",
Handler: _UserService_GetUserAvatarBinary_Handler, Handler: _UserService_GetUserAvatarBinary_Handler,

@ -459,24 +459,22 @@ paths:
$ref: '#/definitions/googlerpcStatus' $ref: '#/definitions/googlerpcStatus'
tags: tags:
- UserService - UserService
/api/v1/users:search: /api/v1/users:username:
get: get:
summary: SearchUsers searches users by filter. summary: GetUserByUsername gets a user by username.
operationId: UserService_SearchUsers operationId: UserService_GetUserByUsername
responses: responses:
"200": "200":
description: A successful response. description: A successful response.
schema: schema:
$ref: '#/definitions/v1SearchUsersResponse' $ref: '#/definitions/v1User'
default: default:
description: An unexpected error response. description: An unexpected error response.
schema: schema:
$ref: '#/definitions/googlerpcStatus' $ref: '#/definitions/googlerpcStatus'
parameters: parameters:
- name: filter - name: username
description: |- description: The username of the user.
Filter is used to filter users returned in the list.
Format: "username == 'frank'"
in: query in: query
required: false required: false
type: string type: string
@ -2848,14 +2846,6 @@ definitions:
properties: properties:
markdown: markdown:
type: string type: string
v1SearchUsersResponse:
type: object
properties:
users:
type: array
items:
type: object
$ref: '#/definitions/v1User'
v1SpoilerNode: v1SpoilerNode:
type: object type: object
properties: properties:

@ -15,7 +15,6 @@ const (
MemoNamePrefix = "memos/" MemoNamePrefix = "memos/"
ResourceNamePrefix = "resources/" ResourceNamePrefix = "resources/"
InboxNamePrefix = "inboxes/" InboxNamePrefix = "inboxes/"
StorageNamePrefix = "storages/"
IdentityProviderNamePrefix = "identityProviders/" IdentityProviderNamePrefix = "identityProviders/"
ActivityNamePrefix = "activities/" ActivityNamePrefix = "activities/"
) )
@ -95,19 +94,6 @@ func ExtractInboxIDFromName(name string) (int32, error) {
return id, nil return id, nil
} }
// ExtractStorageIDFromName returns the storage ID from a resource name.
func ExtractStorageIDFromName(name string) (int32, error) {
tokens, err := GetNameParentTokens(name, StorageNamePrefix)
if err != nil {
return 0, err
}
id, err := util.ConvertStringToInt32(tokens[0])
if err != nil {
return 0, errors.Errorf("invalid storage ID %q", tokens[0])
}
return id, nil
}
func ExtractIdentityProviderIDFromName(name string) (int32, error) { func ExtractIdentityProviderIDFromName(name string) (int32, error) {
tokens, err := GetNameParentTokens(name, IdentityProviderNamePrefix) tokens, err := GetNameParentTokens(name, IdentityProviderNamePrefix)
if err != nil { if err != nil {

@ -11,11 +11,9 @@ import (
"time" "time"
"github.com/golang-jwt/jwt/v5" "github.com/golang-jwt/jwt/v5"
"github.com/google/cel-go/cel"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"github.com/pkg/errors" "github.com/pkg/errors"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
expr "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
"google.golang.org/genproto/googleapis/api/httpbody" "google.golang.org/genproto/googleapis/api/httpbody"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
@ -51,46 +49,27 @@ func (s *APIV1Service) ListUsers(ctx context.Context, _ *v1pb.ListUsersRequest)
return response, nil return response, nil
} }
func (s *APIV1Service) SearchUsers(ctx context.Context, request *v1pb.SearchUsersRequest) (*v1pb.SearchUsersResponse, error) { func (s *APIV1Service) GetUser(ctx context.Context, request *v1pb.GetUserRequest) (*v1pb.User, error) {
if request.Filter == "" { userID, err := ExtractUserIDFromName(request.Name)
return nil, status.Errorf(codes.InvalidArgument, "filter is empty")
}
filter, err := parseSearchUsersFilter(request.Filter)
if err != nil { if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "failed to parse filter: %v", err) return nil, status.Errorf(codes.InvalidArgument, "invalid user name: %v", err)
}
userFind := &store.FindUser{}
if filter.Username != nil {
userFind.Username = filter.Username
}
if filter.Random {
userFind.Random = true
}
if filter.Limit != nil {
userFind.Limit = filter.Limit
} }
user, err := s.Store.GetUser(ctx, &store.FindUser{
users, err := s.Store.ListUsers(ctx, userFind) ID: &userID,
})
if err != nil { if err != nil {
return nil, status.Errorf(codes.Internal, "failed to search users: %v", err) return nil, status.Errorf(codes.Internal, "failed to get user: %v", err)
}
response := &v1pb.SearchUsersResponse{
Users: []*v1pb.User{},
}
for _, user := range users {
response.Users = append(response.Users, convertUserFromStore(user))
} }
return response, nil if user == nil {
return nil, status.Errorf(codes.NotFound, "user not found")
} }
func (s *APIV1Service) GetUser(ctx context.Context, request *v1pb.GetUserRequest) (*v1pb.User, error) { return convertUserFromStore(user), nil
userID, err := ExtractUserIDFromName(request.Name)
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "invalid user name: %v", err)
} }
func (s *APIV1Service) GetUserByUsername(ctx context.Context, request *v1pb.GetUserByUsernameRequest) (*v1pb.User, error) {
user, err := s.Store.GetUser(ctx, &store.FindUser{ user, err := s.Store.GetUser(ctx, &store.FindUser{
ID: &userID, Username: &request.Username,
}) })
if err != nil { if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get user: %v", err) return nil, status.Errorf(codes.Internal, "failed to get user: %v", err)
@ -599,63 +578,6 @@ func convertUserRoleToStore(role v1pb.User_Role) store.Role {
} }
} }
// SearchUsersFilterCELAttributes are the CEL attributes for SearchUsersFilter.
var SearchUsersFilterCELAttributes = []cel.EnvOption{
cel.Variable("username", cel.StringType),
cel.Variable("random", cel.BoolType),
cel.Variable("limit", cel.IntType),
}
type SearchUsersFilter struct {
Username *string
Random bool
Limit *int
}
func parseSearchUsersFilter(expression string) (*SearchUsersFilter, error) {
e, err := cel.NewEnv(SearchUsersFilterCELAttributes...)
if err != nil {
return nil, err
}
ast, issues := e.Compile(expression)
if issues != nil {
return nil, errors.Errorf("found issue %v", issues)
}
filter := &SearchUsersFilter{}
expr, err := cel.AstToParsedExpr(ast)
if err != nil {
return nil, err
}
callExpr := expr.GetExpr().GetCallExpr()
findSearchUsersField(callExpr, filter)
return filter, nil
}
func findSearchUsersField(callExpr *expr.Expr_Call, filter *SearchUsersFilter) {
if len(callExpr.Args) == 2 {
idExpr := callExpr.Args[0].GetIdentExpr()
if idExpr != nil {
if idExpr.Name == "username" {
username := callExpr.Args[1].GetConstExpr().GetStringValue()
filter.Username = &username
} else if idExpr.Name == "random" {
random := callExpr.Args[1].GetConstExpr().GetBoolValue()
filter.Random = random
} else if idExpr.Name == "limit" {
limit := int(callExpr.Args[1].GetConstExpr().GetInt64Value())
filter.Limit = &limit
}
return
}
}
for _, arg := range callExpr.Args {
callExpr := arg.GetCallExpr()
if callExpr != nil {
findSearchUsersField(callExpr, filter)
}
}
}
func extractImageInfo(dataURI string) (string, string, error) { func extractImageInfo(dataURI string) (string, string, error) {
dataURIRegex := regexp.MustCompile(`^data:(?P<type>.+);base64,(?P<base64>.+)`) dataURIRegex := regexp.MustCompile(`^data:(?P<type>.+);base64,(?P<base64>.+)`)
matches := dataURIRegex.FindStringSubmatch(dataURI) matches := dataURIRegex.FindStringSubmatch(dataURI)

@ -32,12 +32,8 @@ const UserProfile = () => {
} }
userStore userStore
.searchUsers(`username == "${username}"`) .fetchUserByUsername(username)
.then((users) => { .then((user) => {
if (users.length !== 1) {
throw new Error("User not found");
}
const user = users[0];
setUser(user); setUser(user);
loadingState.setFinish(); loadingState.setFinish();
}) })

@ -63,19 +63,15 @@ export const useUserStore = create(
set({ userMapByName: userMap }); set({ userMapByName: userMap });
return user; return user;
}, },
listUsers: async () => { fetchUserByUsername: async (username: string) => {
const { users } = await userServiceClient.listUsers({}); const user = await userServiceClient.getUserByUsername({ username });
const userMap = get().userMapByName; const userMap = get().userMapByName;
for (const user of users) {
userMap[user.name] = user; userMap[user.name] = user;
}
set({ userMapByName: userMap }); set({ userMapByName: userMap });
return users; return user;
}, },
searchUsers: async (filter: string) => { listUsers: async () => {
const { users } = await userServiceClient.searchUsers({ const { users } = await userServiceClient.listUsers({});
filter,
});
const userMap = get().userMapByName; const userMap = get().userMapByName;
for (const user of users) { for (const user of users) {
userMap[user.name] = user; userMap[user.name] = user;

Loading…
Cancel
Save