Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
canifa_note
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Vũ Hoàng Anh
canifa_note
Commits
506b477d
Commit
506b477d
authored
Aug 04, 2025
by
johnnyjoy
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: get user by username
parent
fa2fa8a5
Changes
15
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
515 additions
and
1239 deletions
+515
-1239
filter.go
plugin/filter/filter.go
+5
-0
user_service.proto
proto/api/v1/user_service.proto
+1
-33
user_service.pb.go
proto/gen/api/v1/user_service.pb.go
+219
-372
user_service.pb.gw.go
proto/gen/api/v1/user_service.pb.gw.go
+0
-74
user_service_grpc.pb.go
proto/gen/api/v1/user_service_grpc.pb.go
+0
-40
openapi.yaml
proto/gen/openapi.yaml
+84
-336
user_filter_test.go
server/router/api/v1/user_filter_test.go
+68
-0
user_service.go
server/router/api/v1/user_service.go
+48
-44
user.go
store/db/mysql/user.go
+21
-0
user.go
store/db/postgres/user.go
+21
-0
user.go
store/db/sqlite/user.go
+21
-0
user.go
store/user.go
+3
-0
user.ts
web/src/store/user.ts
+2
-2
user_service.ts
web/src/types/proto/api/v1/user_service.ts
+3
-218
descriptor.ts
web/src/types/proto/google/protobuf/descriptor.ts
+19
-120
No files found.
plugin/filter/filter.go
View file @
506b477d
...
@@ -36,6 +36,11 @@ var MemoFilterCELAttributes = []cel.EnvOption{
...
@@ -36,6 +36,11 @@ var MemoFilterCELAttributes = []cel.EnvOption{
),
),
}
}
// UserFilterCELAttributes are the CEL attributes for user.
var
UserFilterCELAttributes
=
[]
cel
.
EnvOption
{
cel
.
Variable
(
"username"
,
cel
.
StringType
),
}
// Parse parses the filter string and returns the parsed expression.
// Parse parses the filter string and returns the parsed expression.
// The filter string should be a CEL expression.
// The filter string should be a CEL expression.
func
Parse
(
filter
string
,
opts
...
cel
.
EnvOption
)
(
expr
*
exprv1
.
ParsedExpr
,
err
error
)
{
func
Parse
(
filter
string
,
opts
...
cel
.
EnvOption
)
(
expr
*
exprv1
.
ParsedExpr
,
err
error
)
{
...
...
proto/api/v1/user_service.proto
View file @
506b477d
...
@@ -50,12 +50,6 @@ service UserService {
...
@@ -50,12 +50,6 @@ service UserService {
option
(
google.api.method_signature
)
=
"name"
;
option
(
google.api.method_signature
)
=
"name"
;
}
}
// SearchUsers searches for users based on query.
rpc
SearchUsers
(
SearchUsersRequest
)
returns
(
SearchUsersResponse
)
{
option
(
google.api.http
)
=
{
get
:
"/api/v1/users:search"
};
option
(
google.api.method_signature
)
=
"query"
;
}
// GetUserAvatar gets the avatar of a user.
// GetUserAvatar gets the avatar of a user.
rpc
GetUserAvatar
(
GetUserAvatarRequest
)
returns
(
google.api.HttpBody
)
{
rpc
GetUserAvatar
(
GetUserAvatarRequest
)
returns
(
google.api.HttpBody
)
{
option
(
google.api.http
)
=
{
get
:
"/api/v1/{name=users/*}/avatar"
};
option
(
google.api.http
)
=
{
get
:
"/api/v1/{name=users/*}/avatar"
};
...
@@ -231,12 +225,8 @@ message ListUsersRequest {
...
@@ -231,12 +225,8 @@ message ListUsersRequest {
// Supported fields: username, email, role, state, create_time, update_time
// Supported fields: username, email, role, state, create_time, update_time
string
filter
=
3
[(
google.api.field_behavior
)
=
OPTIONAL
];
string
filter
=
3
[(
google.api.field_behavior
)
=
OPTIONAL
];
// Optional. The order to sort results by.
// Example: "create_time desc" or "username asc"
string
order_by
=
4
[(
google.api.field_behavior
)
=
OPTIONAL
];
// Optional. If true, show deleted users in the response.
// Optional. If true, show deleted users in the response.
bool
show_deleted
=
5
[(
google.api.field_behavior
)
=
OPTIONAL
];
bool
show_deleted
=
4
[(
google.api.field_behavior
)
=
OPTIONAL
];
}
}
message
ListUsersResponse
{
message
ListUsersResponse
{
...
@@ -307,28 +297,6 @@ message DeleteUserRequest {
...
@@ -307,28 +297,6 @@ message DeleteUserRequest {
bool
force
=
2
[(
google.api.field_behavior
)
=
OPTIONAL
];
bool
force
=
2
[(
google.api.field_behavior
)
=
OPTIONAL
];
}
}
message
SearchUsersRequest
{
// Required. The search query.
string
query
=
1
[(
google.api.field_behavior
)
=
REQUIRED
];
// Optional. The maximum number of users to return.
int32
page_size
=
2
[(
google.api.field_behavior
)
=
OPTIONAL
];
// Optional. A page token for pagination.
string
page_token
=
3
[(
google.api.field_behavior
)
=
OPTIONAL
];
}
message
SearchUsersResponse
{
// The list of users matching the search query.
repeated
User
users
=
1
;
// A token for the next page of results.
string
next_page_token
=
2
;
// The total count of matching users.
int32
total_size
=
3
;
}
message
GetUserAvatarRequest
{
message
GetUserAvatarRequest
{
// Required. The resource name of the user.
// Required. The resource name of the user.
// Format: users/{user}
// Format: users/{user}
...
...
proto/gen/api/v1/user_service.pb.go
View file @
506b477d
This diff is collapsed.
Click to expand it.
proto/gen/api/v1/user_service.pb.gw.go
View file @
506b477d
...
@@ -298,41 +298,6 @@ func local_request_UserService_DeleteUser_0(ctx context.Context, marshaler runti
...
@@ -298,41 +298,6 @@ func local_request_UserService_DeleteUser_0(ctx context.Context, marshaler runti
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
req
.
Body
!=
nil
{
_
,
_
=
io
.
Copy
(
io
.
Discard
,
req
.
Body
)
}
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_GetUserAvatar_0
(
ctx
context
.
Context
,
marshaler
runtime
.
Marshaler
,
client
UserServiceClient
,
req
*
http
.
Request
,
pathParams
map
[
string
]
string
)
(
proto
.
Message
,
runtime
.
ServerMetadata
,
error
)
{
func
request_UserService_GetUserAvatar_0
(
ctx
context
.
Context
,
marshaler
runtime
.
Marshaler
,
client
UserServiceClient
,
req
*
http
.
Request
,
pathParams
map
[
string
]
string
)
(
proto
.
Message
,
runtime
.
ServerMetadata
,
error
)
{
var
(
var
(
protoReq
GetUserAvatarRequest
protoReq
GetUserAvatarRequest
...
@@ -1144,26 +1109,6 @@ func RegisterUserServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux
...
@@ -1144,26 +1109,6 @@ func RegisterUserServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux
}
}
forward_UserService_DeleteUser_0
(
annotatedContext
,
mux
,
outboundMarshaler
,
w
,
req
,
resp
,
mux
.
GetForwardResponseOptions
()
...
)
forward_UserService_DeleteUser_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
)
{
ctx
,
cancel
:=
context
.
WithCancel
(
req
.
Context
())
defer
cancel
()
var
stream
runtime
.
ServerTransportStream
ctx
=
grpc
.
NewContextWithServerTransportStream
(
ctx
,
&
stream
)
inboundMarshaler
,
outboundMarshaler
:=
runtime
.
MarshalerForRequest
(
mux
,
req
)
annotatedContext
,
err
:=
runtime
.
AnnotateIncomingContext
(
ctx
,
mux
,
req
,
"/memos.api.v1.UserService/SearchUsers"
,
runtime
.
WithHTTPPathPattern
(
"/api/v1/users:search"
))
if
err
!=
nil
{
runtime
.
HTTPError
(
ctx
,
mux
,
outboundMarshaler
,
w
,
req
,
err
)
return
}
resp
,
md
,
err
:=
local_request_UserService_SearchUsers_0
(
annotatedContext
,
inboundMarshaler
,
server
,
req
,
pathParams
)
md
.
HeaderMD
,
md
.
TrailerMD
=
metadata
.
Join
(
md
.
HeaderMD
,
stream
.
Header
()),
metadata
.
Join
(
md
.
TrailerMD
,
stream
.
Trailer
())
annotatedContext
=
runtime
.
NewServerMetadataContext
(
annotatedContext
,
md
)
if
err
!=
nil
{
runtime
.
HTTPError
(
annotatedContext
,
mux
,
outboundMarshaler
,
w
,
req
,
err
)
return
}
forward_UserService_SearchUsers_0
(
annotatedContext
,
mux
,
outboundMarshaler
,
w
,
req
,
resp
,
mux
.
GetForwardResponseOptions
()
...
)
})
mux
.
Handle
(
http
.
MethodGet
,
pattern_UserService_GetUserAvatar_0
,
func
(
w
http
.
ResponseWriter
,
req
*
http
.
Request
,
pathParams
map
[
string
]
string
)
{
mux
.
Handle
(
http
.
MethodGet
,
pattern_UserService_GetUserAvatar_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
()
...
@@ -1589,23 +1534,6 @@ func RegisterUserServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux
...
@@ -1589,23 +1534,6 @@ func RegisterUserServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux
}
}
forward_UserService_DeleteUser_0
(
annotatedContext
,
mux
,
outboundMarshaler
,
w
,
req
,
resp
,
mux
.
GetForwardResponseOptions
()
...
)
forward_UserService_DeleteUser_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
)
{
ctx
,
cancel
:=
context
.
WithCancel
(
req
.
Context
())
defer
cancel
()
inboundMarshaler
,
outboundMarshaler
:=
runtime
.
MarshalerForRequest
(
mux
,
req
)
annotatedContext
,
err
:=
runtime
.
AnnotateContext
(
ctx
,
mux
,
req
,
"/memos.api.v1.UserService/SearchUsers"
,
runtime
.
WithHTTPPathPattern
(
"/api/v1/users:search"
))
if
err
!=
nil
{
runtime
.
HTTPError
(
ctx
,
mux
,
outboundMarshaler
,
w
,
req
,
err
)
return
}
resp
,
md
,
err
:=
request_UserService_SearchUsers_0
(
annotatedContext
,
inboundMarshaler
,
client
,
req
,
pathParams
)
annotatedContext
=
runtime
.
NewServerMetadataContext
(
annotatedContext
,
md
)
if
err
!=
nil
{
runtime
.
HTTPError
(
annotatedContext
,
mux
,
outboundMarshaler
,
w
,
req
,
err
)
return
}
forward_UserService_SearchUsers_0
(
annotatedContext
,
mux
,
outboundMarshaler
,
w
,
req
,
resp
,
mux
.
GetForwardResponseOptions
()
...
)
})
mux
.
Handle
(
http
.
MethodGet
,
pattern_UserService_GetUserAvatar_0
,
func
(
w
http
.
ResponseWriter
,
req
*
http
.
Request
,
pathParams
map
[
string
]
string
)
{
mux
.
Handle
(
http
.
MethodGet
,
pattern_UserService_GetUserAvatar_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
()
...
@@ -1870,7 +1798,6 @@ var (
...
@@ -1870,7 +1798,6 @@ var (
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"
},
""
))
pattern_UserService_DeleteUser_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_DeleteUser_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_SearchUsers_0
=
runtime
.
MustPattern
(
runtime
.
NewPattern
(
1
,
[]
int
{
2
,
0
,
2
,
1
,
2
,
2
},
[]
string
{
"api"
,
"v1"
,
"users"
},
"search"
))
pattern_UserService_GetUserAvatar_0
=
runtime
.
MustPattern
(
runtime
.
NewPattern
(
1
,
[]
int
{
2
,
0
,
2
,
1
,
2
,
2
,
1
,
0
,
4
,
2
,
5
,
3
,
2
,
4
},
[]
string
{
"api"
,
"v1"
,
"users"
,
"name"
,
"avatar"
},
""
))
pattern_UserService_GetUserAvatar_0
=
runtime
.
MustPattern
(
runtime
.
NewPattern
(
1
,
[]
int
{
2
,
0
,
2
,
1
,
2
,
2
,
1
,
0
,
4
,
2
,
5
,
3
,
2
,
4
},
[]
string
{
"api"
,
"v1"
,
"users"
,
"name"
,
"avatar"
},
""
))
pattern_UserService_ListAllUserStats_0
=
runtime
.
MustPattern
(
runtime
.
NewPattern
(
1
,
[]
int
{
2
,
0
,
2
,
1
,
2
,
2
},
[]
string
{
"api"
,
"v1"
,
"users"
},
"stats"
))
pattern_UserService_ListAllUserStats_0
=
runtime
.
MustPattern
(
runtime
.
NewPattern
(
1
,
[]
int
{
2
,
0
,
2
,
1
,
2
,
2
},
[]
string
{
"api"
,
"v1"
,
"users"
},
"stats"
))
pattern_UserService_GetUserStats_0
=
runtime
.
MustPattern
(
runtime
.
NewPattern
(
1
,
[]
int
{
2
,
0
,
2
,
1
,
2
,
2
,
1
,
0
,
4
,
2
,
5
,
3
},
[]
string
{
"api"
,
"v1"
,
"users"
,
"name"
},
"getStats"
))
pattern_UserService_GetUserStats_0
=
runtime
.
MustPattern
(
runtime
.
NewPattern
(
1
,
[]
int
{
2
,
0
,
2
,
1
,
2
,
2
,
1
,
0
,
4
,
2
,
5
,
3
},
[]
string
{
"api"
,
"v1"
,
"users"
,
"name"
},
"getStats"
))
...
@@ -1894,7 +1821,6 @@ var (
...
@@ -1894,7 +1821,6 @@ var (
forward_UserService_CreateUser_0
=
runtime
.
ForwardResponseMessage
forward_UserService_CreateUser_0
=
runtime
.
ForwardResponseMessage
forward_UserService_UpdateUser_0
=
runtime
.
ForwardResponseMessage
forward_UserService_UpdateUser_0
=
runtime
.
ForwardResponseMessage
forward_UserService_DeleteUser_0
=
runtime
.
ForwardResponseMessage
forward_UserService_DeleteUser_0
=
runtime
.
ForwardResponseMessage
forward_UserService_SearchUsers_0
=
runtime
.
ForwardResponseMessage
forward_UserService_GetUserAvatar_0
=
runtime
.
ForwardResponseMessage
forward_UserService_GetUserAvatar_0
=
runtime
.
ForwardResponseMessage
forward_UserService_ListAllUserStats_0
=
runtime
.
ForwardResponseMessage
forward_UserService_ListAllUserStats_0
=
runtime
.
ForwardResponseMessage
forward_UserService_GetUserStats_0
=
runtime
.
ForwardResponseMessage
forward_UserService_GetUserStats_0
=
runtime
.
ForwardResponseMessage
...
...
proto/gen/api/v1/user_service_grpc.pb.go
View file @
506b477d
...
@@ -26,7 +26,6 @@ const (
...
@@ -26,7 +26,6 @@ const (
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"
UserService_DeleteUser_FullMethodName
=
"/memos.api.v1.UserService/DeleteUser"
UserService_DeleteUser_FullMethodName
=
"/memos.api.v1.UserService/DeleteUser"
UserService_SearchUsers_FullMethodName
=
"/memos.api.v1.UserService/SearchUsers"
UserService_GetUserAvatar_FullMethodName
=
"/memos.api.v1.UserService/GetUserAvatar"
UserService_GetUserAvatar_FullMethodName
=
"/memos.api.v1.UserService/GetUserAvatar"
UserService_ListAllUserStats_FullMethodName
=
"/memos.api.v1.UserService/ListAllUserStats"
UserService_ListAllUserStats_FullMethodName
=
"/memos.api.v1.UserService/ListAllUserStats"
UserService_GetUserStats_FullMethodName
=
"/memos.api.v1.UserService/GetUserStats"
UserService_GetUserStats_FullMethodName
=
"/memos.api.v1.UserService/GetUserStats"
...
@@ -58,8 +57,6 @@ type UserServiceClient interface {
...
@@ -58,8 +57,6 @@ type UserServiceClient interface {
UpdateUser
(
ctx
context
.
Context
,
in
*
UpdateUserRequest
,
opts
...
grpc
.
CallOption
)
(
*
User
,
error
)
UpdateUser
(
ctx
context
.
Context
,
in
*
UpdateUserRequest
,
opts
...
grpc
.
CallOption
)
(
*
User
,
error
)
// DeleteUser deletes a user.
// DeleteUser deletes a user.
DeleteUser
(
ctx
context
.
Context
,
in
*
DeleteUserRequest
,
opts
...
grpc
.
CallOption
)
(
*
emptypb
.
Empty
,
error
)
DeleteUser
(
ctx
context
.
Context
,
in
*
DeleteUserRequest
,
opts
...
grpc
.
CallOption
)
(
*
emptypb
.
Empty
,
error
)
// SearchUsers searches for users based on query.
SearchUsers
(
ctx
context
.
Context
,
in
*
SearchUsersRequest
,
opts
...
grpc
.
CallOption
)
(
*
SearchUsersResponse
,
error
)
// GetUserAvatar gets the avatar of a user.
// GetUserAvatar gets the avatar of a user.
GetUserAvatar
(
ctx
context
.
Context
,
in
*
GetUserAvatarRequest
,
opts
...
grpc
.
CallOption
)
(
*
httpbody
.
HttpBody
,
error
)
GetUserAvatar
(
ctx
context
.
Context
,
in
*
GetUserAvatarRequest
,
opts
...
grpc
.
CallOption
)
(
*
httpbody
.
HttpBody
,
error
)
// ListAllUserStats returns statistics for all users.
// ListAllUserStats returns statistics for all users.
...
@@ -150,16 +147,6 @@ func (c *userServiceClient) DeleteUser(ctx context.Context, in *DeleteUserReques
...
@@ -150,16 +147,6 @@ func (c *userServiceClient) DeleteUser(ctx context.Context, in *DeleteUserReques
return
out
,
nil
return
out
,
nil
}
}
func
(
c
*
userServiceClient
)
SearchUsers
(
ctx
context
.
Context
,
in
*
SearchUsersRequest
,
opts
...
grpc
.
CallOption
)
(
*
SearchUsersResponse
,
error
)
{
cOpts
:=
append
([]
grpc
.
CallOption
{
grpc
.
StaticMethod
()},
opts
...
)
out
:=
new
(
SearchUsersResponse
)
err
:=
c
.
cc
.
Invoke
(
ctx
,
UserService_SearchUsers_FullMethodName
,
in
,
out
,
cOpts
...
)
if
err
!=
nil
{
return
nil
,
err
}
return
out
,
nil
}
func
(
c
*
userServiceClient
)
GetUserAvatar
(
ctx
context
.
Context
,
in
*
GetUserAvatarRequest
,
opts
...
grpc
.
CallOption
)
(
*
httpbody
.
HttpBody
,
error
)
{
func
(
c
*
userServiceClient
)
GetUserAvatar
(
ctx
context
.
Context
,
in
*
GetUserAvatarRequest
,
opts
...
grpc
.
CallOption
)
(
*
httpbody
.
HttpBody
,
error
)
{
cOpts
:=
append
([]
grpc
.
CallOption
{
grpc
.
StaticMethod
()},
opts
...
)
cOpts
:=
append
([]
grpc
.
CallOption
{
grpc
.
StaticMethod
()},
opts
...
)
out
:=
new
(
httpbody
.
HttpBody
)
out
:=
new
(
httpbody
.
HttpBody
)
...
@@ -324,8 +311,6 @@ type UserServiceServer interface {
...
@@ -324,8 +311,6 @@ type UserServiceServer interface {
UpdateUser
(
context
.
Context
,
*
UpdateUserRequest
)
(
*
User
,
error
)
UpdateUser
(
context
.
Context
,
*
UpdateUserRequest
)
(
*
User
,
error
)
// DeleteUser deletes a user.
// DeleteUser deletes a user.
DeleteUser
(
context
.
Context
,
*
DeleteUserRequest
)
(
*
emptypb
.
Empty
,
error
)
DeleteUser
(
context
.
Context
,
*
DeleteUserRequest
)
(
*
emptypb
.
Empty
,
error
)
// SearchUsers searches for users based on query.
SearchUsers
(
context
.
Context
,
*
SearchUsersRequest
)
(
*
SearchUsersResponse
,
error
)
// GetUserAvatar gets the avatar of a user.
// GetUserAvatar gets the avatar of a user.
GetUserAvatar
(
context
.
Context
,
*
GetUserAvatarRequest
)
(
*
httpbody
.
HttpBody
,
error
)
GetUserAvatar
(
context
.
Context
,
*
GetUserAvatarRequest
)
(
*
httpbody
.
HttpBody
,
error
)
// ListAllUserStats returns statistics for all users.
// ListAllUserStats returns statistics for all users.
...
@@ -381,9 +366,6 @@ func (UnimplementedUserServiceServer) UpdateUser(context.Context, *UpdateUserReq
...
@@ -381,9 +366,6 @@ func (UnimplementedUserServiceServer) UpdateUser(context.Context, *UpdateUserReq
func
(
UnimplementedUserServiceServer
)
DeleteUser
(
context
.
Context
,
*
DeleteUserRequest
)
(
*
emptypb
.
Empty
,
error
)
{
func
(
UnimplementedUserServiceServer
)
DeleteUser
(
context
.
Context
,
*
DeleteUserRequest
)
(
*
emptypb
.
Empty
,
error
)
{
return
nil
,
status
.
Errorf
(
codes
.
Unimplemented
,
"method DeleteUser not implemented"
)
return
nil
,
status
.
Errorf
(
codes
.
Unimplemented
,
"method DeleteUser not implemented"
)
}
}
func
(
UnimplementedUserServiceServer
)
SearchUsers
(
context
.
Context
,
*
SearchUsersRequest
)
(
*
SearchUsersResponse
,
error
)
{
return
nil
,
status
.
Errorf
(
codes
.
Unimplemented
,
"method SearchUsers not implemented"
)
}
func
(
UnimplementedUserServiceServer
)
GetUserAvatar
(
context
.
Context
,
*
GetUserAvatarRequest
)
(
*
httpbody
.
HttpBody
,
error
)
{
func
(
UnimplementedUserServiceServer
)
GetUserAvatar
(
context
.
Context
,
*
GetUserAvatarRequest
)
(
*
httpbody
.
HttpBody
,
error
)
{
return
nil
,
status
.
Errorf
(
codes
.
Unimplemented
,
"method GetUserAvatar not implemented"
)
return
nil
,
status
.
Errorf
(
codes
.
Unimplemented
,
"method GetUserAvatar not implemented"
)
}
}
...
@@ -540,24 +522,6 @@ func _UserService_DeleteUser_Handler(srv interface{}, ctx context.Context, dec f
...
@@ -540,24 +522,6 @@ func _UserService_DeleteUser_Handler(srv interface{}, ctx context.Context, dec f
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
)
{
in
:=
new
(
SearchUsersRequest
)
if
err
:=
dec
(
in
);
err
!=
nil
{
return
nil
,
err
}
if
interceptor
==
nil
{
return
srv
.
(
UserServiceServer
)
.
SearchUsers
(
ctx
,
in
)
}
info
:=
&
grpc
.
UnaryServerInfo
{
Server
:
srv
,
FullMethod
:
UserService_SearchUsers_FullMethodName
,
}
handler
:=
func
(
ctx
context
.
Context
,
req
interface
{})
(
interface
{},
error
)
{
return
srv
.
(
UserServiceServer
)
.
SearchUsers
(
ctx
,
req
.
(
*
SearchUsersRequest
))
}
return
interceptor
(
ctx
,
in
,
info
,
handler
)
}
func
_UserService_GetUserAvatar_Handler
(
srv
interface
{},
ctx
context
.
Context
,
dec
func
(
interface
{})
error
,
interceptor
grpc
.
UnaryServerInterceptor
)
(
interface
{},
error
)
{
func
_UserService_GetUserAvatar_Handler
(
srv
interface
{},
ctx
context
.
Context
,
dec
func
(
interface
{})
error
,
interceptor
grpc
.
UnaryServerInterceptor
)
(
interface
{},
error
)
{
in
:=
new
(
GetUserAvatarRequest
)
in
:=
new
(
GetUserAvatarRequest
)
if
err
:=
dec
(
in
);
err
!=
nil
{
if
err
:=
dec
(
in
);
err
!=
nil
{
...
@@ -855,10 +819,6 @@ var UserService_ServiceDesc = grpc.ServiceDesc{
...
@@ -855,10 +819,6 @@ var UserService_ServiceDesc = grpc.ServiceDesc{
MethodName
:
"DeleteUser"
,
MethodName
:
"DeleteUser"
,
Handler
:
_UserService_DeleteUser_Handler
,
Handler
:
_UserService_DeleteUser_Handler
,
},
},
{
MethodName
:
"SearchUsers"
,
Handler
:
_UserService_SearchUsers_Handler
,
},
{
{
MethodName
:
"GetUserAvatar"
,
MethodName
:
"GetUserAvatar"
,
Handler
:
_UserService_GetUserAvatar_Handler
,
Handler
:
_UserService_GetUserAvatar_Handler
,
...
...
proto/gen/openapi.yaml
View file @
506b477d
This diff is collapsed.
Click to expand it.
server/router/api/v1/user_filter_test.go
0 → 100644
View file @
506b477d
package
v1
import
(
"testing"
"github.com/usememos/memos/plugin/filter"
)
func
TestUserFilterValidation
(
t
*
testing
.
T
)
{
testCases
:=
[]
struct
{
name
string
filter
string
expectErr
bool
}{
{
name
:
"valid username filter with equals"
,
filter
:
`username == "testuser"`
,
expectErr
:
false
,
},
{
name
:
"valid username filter with contains"
,
filter
:
`username.contains("admin")`
,
expectErr
:
false
,
},
{
name
:
"invalid filter - unknown field"
,
filter
:
`invalid_field == "test"`
,
expectErr
:
true
,
},
{
name
:
"empty filter"
,
filter
:
""
,
expectErr
:
true
,
},
{
name
:
"invalid syntax"
,
filter
:
`username ==`
,
expectErr
:
true
,
},
}
for
_
,
tc
:=
range
testCases
{
t
.
Run
(
tc
.
name
,
func
(
t
*
testing
.
T
)
{
// Test the filter parsing directly
_
,
err
:=
filter
.
Parse
(
tc
.
filter
,
filter
.
UserFilterCELAttributes
...
)
if
tc
.
expectErr
&&
err
==
nil
{
t
.
Errorf
(
"Expected error for filter %q, but got none"
,
tc
.
filter
)
}
if
!
tc
.
expectErr
&&
err
!=
nil
{
t
.
Errorf
(
"Expected no error for filter %q, but got: %v"
,
tc
.
filter
,
err
)
}
})
}
}
func
TestUserFilterCELAttributes
(
t
*
testing
.
T
)
{
// Test that our UserFilterCELAttributes contains the username variable
expectedAttributes
:=
map
[
string
]
bool
{
"username"
:
true
,
}
// This is a basic test to ensure the attributes are defined
// In a real test, you would create a CEL environment and verify the attributes
for
attrName
:=
range
expectedAttributes
{
t
.
Logf
(
"Expected attribute %s should be available in UserFilterCELAttributes"
,
attrName
)
}
}
server/router/api/v1/user_service.go
View file @
506b477d
...
@@ -25,12 +25,13 @@ import (
...
@@ -25,12 +25,13 @@ import (
"github.com/usememos/memos/internal/base"
"github.com/usememos/memos/internal/base"
"github.com/usememos/memos/internal/util"
"github.com/usememos/memos/internal/util"
"github.com/usememos/memos/plugin/filter"
v1pb
"github.com/usememos/memos/proto/gen/api/v1"
v1pb
"github.com/usememos/memos/proto/gen/api/v1"
storepb
"github.com/usememos/memos/proto/gen/store"
storepb
"github.com/usememos/memos/proto/gen/store"
"github.com/usememos/memos/store"
"github.com/usememos/memos/store"
)
)
func
(
s
*
APIV1Service
)
ListUsers
(
ctx
context
.
Context
,
_
*
v1pb
.
ListUsersRequest
)
(
*
v1pb
.
ListUsersResponse
,
error
)
{
func
(
s
*
APIV1Service
)
ListUsers
(
ctx
context
.
Context
,
request
*
v1pb
.
ListUsersRequest
)
(
*
v1pb
.
ListUsersResponse
,
error
)
{
currentUser
,
err
:=
s
.
GetCurrentUser
(
ctx
)
currentUser
,
err
:=
s
.
GetCurrentUser
(
ctx
)
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
)
...
@@ -39,12 +40,21 @@ func (s *APIV1Service) ListUsers(ctx context.Context, _ *v1pb.ListUsersRequest)
...
@@ -39,12 +40,21 @@ func (s *APIV1Service) ListUsers(ctx context.Context, _ *v1pb.ListUsersRequest)
return
nil
,
status
.
Errorf
(
codes
.
PermissionDenied
,
"permission denied"
)
return
nil
,
status
.
Errorf
(
codes
.
PermissionDenied
,
"permission denied"
)
}
}
users
,
err
:=
s
.
Store
.
ListUsers
(
ctx
,
&
store
.
FindUser
{})
userFind
:=
&
store
.
FindUser
{}
if
request
.
Filter
!=
""
{
if
err
:=
s
.
validateUserFilter
(
ctx
,
request
.
Filter
);
err
!=
nil
{
return
nil
,
status
.
Errorf
(
codes
.
InvalidArgument
,
"invalid filter: %v"
,
err
)
}
userFind
.
Filters
=
append
(
userFind
.
Filters
,
request
.
Filter
)
}
users
,
err
:=
s
.
Store
.
ListUsers
(
ctx
,
userFind
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
status
.
Errorf
(
codes
.
Internal
,
"failed to list users: %v"
,
err
)
return
nil
,
status
.
Errorf
(
codes
.
Internal
,
"failed to list users: %v"
,
err
)
}
}
// TODO: Implement proper
filtering,
ordering, and pagination
// TODO: Implement proper ordering, and pagination
// For now, return all users with basic structure
// For now, return all users with basic structure
response
:=
&
v1pb
.
ListUsersResponse
{
response
:=
&
v1pb
.
ListUsersResponse
{
Users
:
[]
*
v1pb
.
User
{},
Users
:
[]
*
v1pb
.
User
{},
...
@@ -70,47 +80,7 @@ func (s *APIV1Service) GetUser(ctx context.Context, request *v1pb.GetUserRequest
...
@@ -70,47 +80,7 @@ func (s *APIV1Service) GetUser(ctx context.Context, request *v1pb.GetUserRequest
if
user
==
nil
{
if
user
==
nil
{
return
nil
,
status
.
Errorf
(
codes
.
NotFound
,
"user not found"
)
return
nil
,
status
.
Errorf
(
codes
.
NotFound
,
"user not found"
)
}
}
userPb
:=
convertUserFromStore
(
user
)
return
convertUserFromStore
(
user
),
nil
// TODO: Implement read_mask field filtering
// For now, return all fields
return
userPb
,
nil
}
func
(
s
*
APIV1Service
)
SearchUsers
(
ctx
context
.
Context
,
request
*
v1pb
.
SearchUsersRequest
)
(
*
v1pb
.
SearchUsersResponse
,
error
)
{
currentUser
,
err
:=
s
.
GetCurrentUser
(
ctx
)
if
err
!=
nil
{
return
nil
,
status
.
Errorf
(
codes
.
Internal
,
"failed to get user: %v"
,
err
)
}
if
currentUser
.
Role
!=
store
.
RoleHost
&&
currentUser
.
Role
!=
store
.
RoleAdmin
{
return
nil
,
status
.
Errorf
(
codes
.
PermissionDenied
,
"permission denied"
)
}
// Search users by username, email, or display name
users
,
err
:=
s
.
Store
.
ListUsers
(
ctx
,
&
store
.
FindUser
{})
if
err
!=
nil
{
return
nil
,
status
.
Errorf
(
codes
.
Internal
,
"failed to list users: %v"
,
err
)
}
var
filteredUsers
[]
*
store
.
User
query
:=
strings
.
ToLower
(
request
.
Query
)
for
_
,
user
:=
range
users
{
if
strings
.
Contains
(
strings
.
ToLower
(
user
.
Username
),
query
)
||
strings
.
Contains
(
strings
.
ToLower
(
user
.
Email
),
query
)
||
strings
.
Contains
(
strings
.
ToLower
(
user
.
Nickname
),
query
)
{
filteredUsers
=
append
(
filteredUsers
,
user
)
}
}
response
:=
&
v1pb
.
SearchUsersResponse
{
Users
:
[]
*
v1pb
.
User
{},
TotalSize
:
int32
(
len
(
filteredUsers
)),
}
for
_
,
user
:=
range
filteredUsers
{
response
.
Users
=
append
(
response
.
Users
,
convertUserFromStore
(
user
))
}
return
response
,
nil
}
}
func
(
s
*
APIV1Service
)
GetUserAvatar
(
ctx
context
.
Context
,
request
*
v1pb
.
GetUserAvatarRequest
)
(
*
httpbody
.
HttpBody
,
error
)
{
func
(
s
*
APIV1Service
)
GetUserAvatar
(
ctx
context
.
Context
,
request
*
v1pb
.
GetUserAvatarRequest
)
(
*
httpbody
.
HttpBody
,
error
)
{
...
@@ -1316,3 +1286,37 @@ func extractWebhookIDFromName(name string) string {
...
@@ -1316,3 +1286,37 @@ func extractWebhookIDFromName(name string) string {
}
}
return
""
return
""
}
}
// validateUserFilter validates the user filter string.
func
(
s
*
APIV1Service
)
validateUserFilter
(
_
context
.
Context
,
filterStr
string
)
error
{
if
filterStr
==
""
{
return
errors
.
New
(
"filter cannot be empty"
)
}
// Validate the filter.
parsedExpr
,
err
:=
filter
.
Parse
(
filterStr
,
filter
.
UserFilterCELAttributes
...
)
if
err
!=
nil
{
return
errors
.
Wrap
(
err
,
"failed to parse filter"
)
}
convertCtx
:=
filter
.
NewConvertContext
()
// Determine the dialect based on the actual database driver
var
dialect
filter
.
SQLDialect
switch
s
.
Profile
.
Driver
{
case
"sqlite"
:
dialect
=
&
filter
.
SQLiteDialect
{}
case
"mysql"
:
dialect
=
&
filter
.
MySQLDialect
{}
case
"postgres"
:
dialect
=
&
filter
.
PostgreSQLDialect
{}
default
:
// Default to SQLite for unknown drivers
dialect
=
&
filter
.
SQLiteDialect
{}
}
converter
:=
filter
.
NewCommonSQLConverter
(
dialect
)
err
=
converter
.
ConvertExprToSQL
(
convertCtx
,
parsedExpr
.
GetExpr
())
if
err
!=
nil
{
return
errors
.
Wrap
(
err
,
"failed to convert filter to SQL"
)
}
return
nil
}
store/db/mysql/user.go
View file @
506b477d
...
@@ -7,6 +7,7 @@ import (
...
@@ -7,6 +7,7 @@ import (
"github.com/pkg/errors"
"github.com/pkg/errors"
"github.com/usememos/memos/plugin/filter"
"github.com/usememos/memos/store"
"github.com/usememos/memos/store"
)
)
...
@@ -84,6 +85,26 @@ func (d *DB) UpdateUser(ctx context.Context, update *store.UpdateUser) (*store.U
...
@@ -84,6 +85,26 @@ func (d *DB) UpdateUser(ctx context.Context, update *store.UpdateUser) (*store.U
func
(
d
*
DB
)
ListUsers
(
ctx
context
.
Context
,
find
*
store
.
FindUser
)
([]
*
store
.
User
,
error
)
{
func
(
d
*
DB
)
ListUsers
(
ctx
context
.
Context
,
find
*
store
.
FindUser
)
([]
*
store
.
User
,
error
)
{
where
,
args
:=
[]
string
{
"1 = 1"
},
[]
any
{}
where
,
args
:=
[]
string
{
"1 = 1"
},
[]
any
{}
for
_
,
filterStr
:=
range
find
.
Filters
{
// Parse filter string and return the parsed expression.
// The filter string should be a CEL expression.
parsedExpr
,
err
:=
filter
.
Parse
(
filterStr
,
filter
.
UserFilterCELAttributes
...
)
if
err
!=
nil
{
return
nil
,
err
}
convertCtx
:=
filter
.
NewConvertContext
()
// ConvertExprToSQL converts the parsed expression to a SQL condition string.
converter
:=
filter
.
NewCommonSQLConverter
(
&
filter
.
MySQLDialect
{})
if
err
:=
converter
.
ConvertExprToSQL
(
convertCtx
,
parsedExpr
.
GetExpr
());
err
!=
nil
{
return
nil
,
err
}
condition
:=
convertCtx
.
Buffer
.
String
()
if
condition
!=
""
{
where
=
append
(
where
,
fmt
.
Sprintf
(
"(%s)"
,
condition
))
args
=
append
(
args
,
convertCtx
.
Args
...
)
}
}
if
v
:=
find
.
ID
;
v
!=
nil
{
if
v
:=
find
.
ID
;
v
!=
nil
{
where
,
args
=
append
(
where
,
"`id` = ?"
),
append
(
args
,
*
v
)
where
,
args
=
append
(
where
,
"`id` = ?"
),
append
(
args
,
*
v
)
}
}
...
...
store/db/postgres/user.go
View file @
506b477d
...
@@ -5,6 +5,7 @@ import (
...
@@ -5,6 +5,7 @@ import (
"fmt"
"fmt"
"strings"
"strings"
"github.com/usememos/memos/plugin/filter"
"github.com/usememos/memos/store"
"github.com/usememos/memos/store"
)
)
...
@@ -85,6 +86,26 @@ func (d *DB) UpdateUser(ctx context.Context, update *store.UpdateUser) (*store.U
...
@@ -85,6 +86,26 @@ func (d *DB) UpdateUser(ctx context.Context, update *store.UpdateUser) (*store.U
func
(
d
*
DB
)
ListUsers
(
ctx
context
.
Context
,
find
*
store
.
FindUser
)
([]
*
store
.
User
,
error
)
{
func
(
d
*
DB
)
ListUsers
(
ctx
context
.
Context
,
find
*
store
.
FindUser
)
([]
*
store
.
User
,
error
)
{
where
,
args
:=
[]
string
{
"1 = 1"
},
[]
any
{}
where
,
args
:=
[]
string
{
"1 = 1"
},
[]
any
{}
for
_
,
filterStr
:=
range
find
.
Filters
{
// Parse filter string and return the parsed expression.
// The filter string should be a CEL expression.
parsedExpr
,
err
:=
filter
.
Parse
(
filterStr
,
filter
.
UserFilterCELAttributes
...
)
if
err
!=
nil
{
return
nil
,
err
}
convertCtx
:=
filter
.
NewConvertContext
()
// ConvertExprToSQL converts the parsed expression to a SQL condition string.
converter
:=
filter
.
NewCommonSQLConverter
(
&
filter
.
PostgreSQLDialect
{})
if
err
:=
converter
.
ConvertExprToSQL
(
convertCtx
,
parsedExpr
.
GetExpr
());
err
!=
nil
{
return
nil
,
err
}
condition
:=
convertCtx
.
Buffer
.
String
()
if
condition
!=
""
{
where
=
append
(
where
,
fmt
.
Sprintf
(
"(%s)"
,
condition
))
args
=
append
(
args
,
convertCtx
.
Args
...
)
}
}
if
v
:=
find
.
ID
;
v
!=
nil
{
if
v
:=
find
.
ID
;
v
!=
nil
{
where
,
args
=
append
(
where
,
"id = "
+
placeholder
(
len
(
args
)
+
1
)),
append
(
args
,
*
v
)
where
,
args
=
append
(
where
,
"id = "
+
placeholder
(
len
(
args
)
+
1
)),
append
(
args
,
*
v
)
}
}
...
...
store/db/sqlite/user.go
View file @
506b477d
...
@@ -5,6 +5,7 @@ import (
...
@@ -5,6 +5,7 @@ import (
"fmt"
"fmt"
"strings"
"strings"
"github.com/usememos/memos/plugin/filter"
"github.com/usememos/memos/store"
"github.com/usememos/memos/store"
)
)
...
@@ -86,6 +87,26 @@ func (d *DB) UpdateUser(ctx context.Context, update *store.UpdateUser) (*store.U
...
@@ -86,6 +87,26 @@ func (d *DB) UpdateUser(ctx context.Context, update *store.UpdateUser) (*store.U
func
(
d
*
DB
)
ListUsers
(
ctx
context
.
Context
,
find
*
store
.
FindUser
)
([]
*
store
.
User
,
error
)
{
func
(
d
*
DB
)
ListUsers
(
ctx
context
.
Context
,
find
*
store
.
FindUser
)
([]
*
store
.
User
,
error
)
{
where
,
args
:=
[]
string
{
"1 = 1"
},
[]
any
{}
where
,
args
:=
[]
string
{
"1 = 1"
},
[]
any
{}
for
_
,
filterStr
:=
range
find
.
Filters
{
// Parse filter string and return the parsed expression.
// The filter string should be a CEL expression.
parsedExpr
,
err
:=
filter
.
Parse
(
filterStr
,
filter
.
UserFilterCELAttributes
...
)
if
err
!=
nil
{
return
nil
,
err
}
convertCtx
:=
filter
.
NewConvertContext
()
// ConvertExprToSQL converts the parsed expression to a SQL condition string.
converter
:=
filter
.
NewCommonSQLConverter
(
&
filter
.
SQLiteDialect
{})
if
err
:=
converter
.
ConvertExprToSQL
(
convertCtx
,
parsedExpr
.
GetExpr
());
err
!=
nil
{
return
nil
,
err
}
condition
:=
convertCtx
.
Buffer
.
String
()
if
condition
!=
""
{
where
=
append
(
where
,
fmt
.
Sprintf
(
"(%s)"
,
condition
))
args
=
append
(
args
,
convertCtx
.
Args
...
)
}
}
if
v
:=
find
.
ID
;
v
!=
nil
{
if
v
:=
find
.
ID
;
v
!=
nil
{
where
,
args
=
append
(
where
,
"id = ?"
),
append
(
args
,
*
v
)
where
,
args
=
append
(
where
,
"id = ?"
),
append
(
args
,
*
v
)
}
}
...
...
store/user.go
View file @
506b477d
...
@@ -83,6 +83,9 @@ type FindUser struct {
...
@@ -83,6 +83,9 @@ type FindUser struct {
Email
*
string
Email
*
string
Nickname
*
string
Nickname
*
string
// Domain specific fields
Filters
[]
string
// The maximum number of users to return.
// The maximum number of users to return.
Limit
*
int
Limit
*
int
}
}
...
...
web/src/store/user.ts
View file @
506b477d
...
@@ -84,8 +84,8 @@ const userStore = (() => {
...
@@ -84,8 +84,8 @@ const userStore = (() => {
}
}
}
}
// Use search instead of the deprecated getUserByUsername
// Use search instead of the deprecated getUserByUsername
const
{
users
}
=
await
userServiceClient
.
search
Users
({
const
{
users
}
=
await
userServiceClient
.
list
Users
({
query
:
username
,
filter
:
`username == "
${
username
}
"`
,
pageSize
:
10
,
pageSize
:
10
,
});
});
const
user
=
users
.
find
((
u
)
=>
u
.
username
===
username
);
const
user
=
users
.
find
((
u
)
=>
u
.
username
===
username
);
...
...
web/src/types/proto/api/v1/user_service.ts
View file @
506b477d
...
@@ -114,11 +114,6 @@ export interface ListUsersRequest {
...
@@ -114,11 +114,6 @@ export interface ListUsersRequest {
* Supported fields: username, email, role, state, create_time, update_time
* Supported fields: username, email, role, state, create_time, update_time
*/
*/
filter
:
string
;
filter
:
string
;
/**
* Optional. The order to sort results by.
* Example: "create_time desc" or "username asc"
*/
orderBy
:
string
;
/** Optional. If true, show deleted users in the response. */
/** Optional. If true, show deleted users in the response. */
showDeleted
:
boolean
;
showDeleted
:
boolean
;
}
}
...
@@ -191,24 +186,6 @@ export interface DeleteUserRequest {
...
@@ -191,24 +186,6 @@ export interface DeleteUserRequest {
force
:
boolean
;
force
:
boolean
;
}
}
export
interface
SearchUsersRequest
{
/** Required. The search query. */
query
:
string
;
/** Optional. The maximum number of users to return. */
pageSize
:
number
;
/** Optional. A page token for pagination. */
pageToken
:
string
;
}
export
interface
SearchUsersResponse
{
/** The list of users matching the search query. */
users
:
User
[];
/** A token for the next page of results. */
nextPageToken
:
string
;
/** The total count of matching users. */
totalSize
:
number
;
}
export
interface
GetUserAvatarRequest
{
export
interface
GetUserAvatarRequest
{
/**
/**
* Required. The resource name of the user.
* Required. The resource name of the user.
...
@@ -780,7 +757,7 @@ export const User: MessageFns<User> = {
...
@@ -780,7 +757,7 @@ export const User: MessageFns<User> = {
};
};
function
createBaseListUsersRequest
():
ListUsersRequest
{
function
createBaseListUsersRequest
():
ListUsersRequest
{
return
{
pageSize
:
0
,
pageToken
:
""
,
filter
:
""
,
orderBy
:
""
,
showDeleted
:
false
};
return
{
pageSize
:
0
,
pageToken
:
""
,
filter
:
""
,
showDeleted
:
false
};
}
}
export
const
ListUsersRequest
:
MessageFns
<
ListUsersRequest
>
=
{
export
const
ListUsersRequest
:
MessageFns
<
ListUsersRequest
>
=
{
...
@@ -794,11 +771,8 @@ export const ListUsersRequest: MessageFns<ListUsersRequest> = {
...
@@ -794,11 +771,8 @@ export const ListUsersRequest: MessageFns<ListUsersRequest> = {
if
(
message
.
filter
!==
""
)
{
if
(
message
.
filter
!==
""
)
{
writer
.
uint32
(
26
).
string
(
message
.
filter
);
writer
.
uint32
(
26
).
string
(
message
.
filter
);
}
}
if
(
message
.
orderBy
!==
""
)
{
writer
.
uint32
(
34
).
string
(
message
.
orderBy
);
}
if
(
message
.
showDeleted
!==
false
)
{
if
(
message
.
showDeleted
!==
false
)
{
writer
.
uint32
(
40
).
bool
(
message
.
showDeleted
);
writer
.
uint32
(
32
).
bool
(
message
.
showDeleted
);
}
}
return
writer
;
return
writer
;
},
},
...
@@ -835,15 +809,7 @@ export const ListUsersRequest: MessageFns<ListUsersRequest> = {
...
@@ -835,15 +809,7 @@ export const ListUsersRequest: MessageFns<ListUsersRequest> = {
continue
;
continue
;
}
}
case
4
:
{
case
4
:
{
if
(
tag
!==
34
)
{
if
(
tag
!==
32
)
{
break
;
}
message
.
orderBy
=
reader
.
string
();
continue
;
}
case
5
:
{
if
(
tag
!==
40
)
{
break
;
break
;
}
}
...
@@ -867,7 +833,6 @@ export const ListUsersRequest: MessageFns<ListUsersRequest> = {
...
@@ -867,7 +833,6 @@ export const ListUsersRequest: MessageFns<ListUsersRequest> = {
message
.
pageSize
=
object
.
pageSize
??
0
;
message
.
pageSize
=
object
.
pageSize
??
0
;
message
.
pageToken
=
object
.
pageToken
??
""
;
message
.
pageToken
=
object
.
pageToken
??
""
;
message
.
filter
=
object
.
filter
??
""
;
message
.
filter
=
object
.
filter
??
""
;
message
.
orderBy
=
object
.
orderBy
??
""
;
message
.
showDeleted
=
object
.
showDeleted
??
false
;
message
.
showDeleted
=
object
.
showDeleted
??
false
;
return
message
;
return
message
;
},
},
...
@@ -1211,146 +1176,6 @@ export const DeleteUserRequest: MessageFns<DeleteUserRequest> = {
...
@@ -1211,146 +1176,6 @@ export const DeleteUserRequest: MessageFns<DeleteUserRequest> = {
},
},
};
};
function
createBaseSearchUsersRequest
():
SearchUsersRequest
{
return
{
query
:
""
,
pageSize
:
0
,
pageToken
:
""
};
}
export
const
SearchUsersRequest
:
MessageFns
<
SearchUsersRequest
>
=
{
encode
(
message
:
SearchUsersRequest
,
writer
:
BinaryWriter
=
new
BinaryWriter
()):
BinaryWriter
{
if
(
message
.
query
!==
""
)
{
writer
.
uint32
(
10
).
string
(
message
.
query
);
}
if
(
message
.
pageSize
!==
0
)
{
writer
.
uint32
(
16
).
int32
(
message
.
pageSize
);
}
if
(
message
.
pageToken
!==
""
)
{
writer
.
uint32
(
26
).
string
(
message
.
pageToken
);
}
return
writer
;
},
decode
(
input
:
BinaryReader
|
Uint8Array
,
length
?:
number
):
SearchUsersRequest
{
const
reader
=
input
instanceof
BinaryReader
?
input
:
new
BinaryReader
(
input
);
let
end
=
length
===
undefined
?
reader
.
len
:
reader
.
pos
+
length
;
const
message
=
createBaseSearchUsersRequest
();
while
(
reader
.
pos
<
end
)
{
const
tag
=
reader
.
uint32
();
switch
(
tag
>>>
3
)
{
case
1
:
{
if
(
tag
!==
10
)
{
break
;
}
message
.
query
=
reader
.
string
();
continue
;
}
case
2
:
{
if
(
tag
!==
16
)
{
break
;
}
message
.
pageSize
=
reader
.
int32
();
continue
;
}
case
3
:
{
if
(
tag
!==
26
)
{
break
;
}
message
.
pageToken
=
reader
.
string
();
continue
;
}
}
if
((
tag
&
7
)
===
4
||
tag
===
0
)
{
break
;
}
reader
.
skip
(
tag
&
7
);
}
return
message
;
},
create
(
base
?:
DeepPartial
<
SearchUsersRequest
>
):
SearchUsersRequest
{
return
SearchUsersRequest
.
fromPartial
(
base
??
{});
},
fromPartial
(
object
:
DeepPartial
<
SearchUsersRequest
>
):
SearchUsersRequest
{
const
message
=
createBaseSearchUsersRequest
();
message
.
query
=
object
.
query
??
""
;
message
.
pageSize
=
object
.
pageSize
??
0
;
message
.
pageToken
=
object
.
pageToken
??
""
;
return
message
;
},
};
function
createBaseSearchUsersResponse
():
SearchUsersResponse
{
return
{
users
:
[],
nextPageToken
:
""
,
totalSize
:
0
};
}
export
const
SearchUsersResponse
:
MessageFns
<
SearchUsersResponse
>
=
{
encode
(
message
:
SearchUsersResponse
,
writer
:
BinaryWriter
=
new
BinaryWriter
()):
BinaryWriter
{
for
(
const
v
of
message
.
users
)
{
User
.
encode
(
v
!
,
writer
.
uint32
(
10
).
fork
()).
join
();
}
if
(
message
.
nextPageToken
!==
""
)
{
writer
.
uint32
(
18
).
string
(
message
.
nextPageToken
);
}
if
(
message
.
totalSize
!==
0
)
{
writer
.
uint32
(
24
).
int32
(
message
.
totalSize
);
}
return
writer
;
},
decode
(
input
:
BinaryReader
|
Uint8Array
,
length
?:
number
):
SearchUsersResponse
{
const
reader
=
input
instanceof
BinaryReader
?
input
:
new
BinaryReader
(
input
);
let
end
=
length
===
undefined
?
reader
.
len
:
reader
.
pos
+
length
;
const
message
=
createBaseSearchUsersResponse
();
while
(
reader
.
pos
<
end
)
{
const
tag
=
reader
.
uint32
();
switch
(
tag
>>>
3
)
{
case
1
:
{
if
(
tag
!==
10
)
{
break
;
}
message
.
users
.
push
(
User
.
decode
(
reader
,
reader
.
uint32
()));
continue
;
}
case
2
:
{
if
(
tag
!==
18
)
{
break
;
}
message
.
nextPageToken
=
reader
.
string
();
continue
;
}
case
3
:
{
if
(
tag
!==
24
)
{
break
;
}
message
.
totalSize
=
reader
.
int32
();
continue
;
}
}
if
((
tag
&
7
)
===
4
||
tag
===
0
)
{
break
;
}
reader
.
skip
(
tag
&
7
);
}
return
message
;
},
create
(
base
?:
DeepPartial
<
SearchUsersResponse
>
):
SearchUsersResponse
{
return
SearchUsersResponse
.
fromPartial
(
base
??
{});
},
fromPartial
(
object
:
DeepPartial
<
SearchUsersResponse
>
):
SearchUsersResponse
{
const
message
=
createBaseSearchUsersResponse
();
message
.
users
=
object
.
users
?.
map
((
e
)
=>
User
.
fromPartial
(
e
))
||
[];
message
.
nextPageToken
=
object
.
nextPageToken
??
""
;
message
.
totalSize
=
object
.
totalSize
??
0
;
return
message
;
},
};
function
createBaseGetUserAvatarRequest
():
GetUserAvatarRequest
{
function
createBaseGetUserAvatarRequest
():
GetUserAvatarRequest
{
return
{
name
:
""
};
return
{
name
:
""
};
}
}
...
@@ -3586,46 +3411,6 @@ export const UserServiceDefinition = {
...
@@ -3586,46 +3411,6 @@ export const UserServiceDefinition = {
},
},
},
},
},
},
/** SearchUsers searches for users based on query. */
searchUsers
:
{
name
:
"SearchUsers"
,
requestType
:
SearchUsersRequest
,
requestStream
:
false
,
responseType
:
SearchUsersResponse
,
responseStream
:
false
,
options
:
{
_unknownFields
:
{
8410
:
[
new
Uint8Array
([
5
,
113
,
117
,
101
,
114
,
121
])],
578365826
:
[
new
Uint8Array
([
22
,
18
,
20
,
47
,
97
,
112
,
105
,
47
,
118
,
49
,
47
,
117
,
115
,
101
,
114
,
115
,
58
,
115
,
101
,
97
,
114
,
99
,
104
,
]),
],
},
},
},
/** GetUserAvatar gets the avatar of a user. */
/** GetUserAvatar gets the avatar of a user. */
getUserAvatar
:
{
getUserAvatar
:
{
name
:
"GetUserAvatar"
,
name
:
"GetUserAvatar"
,
...
...
web/src/types/proto/google/protobuf/descriptor.ts
View file @
506b477d
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment