mirror of
https://github.com/usememos/memos.git
synced 2025-06-05 22:09:59 +02:00
chore: update list users
This commit is contained in:
@ -27,6 +27,29 @@ var (
|
|||||||
usernameMatcher = regexp.MustCompile("^[a-z0-9]([a-z0-9-]{1,30}[a-z0-9])$")
|
usernameMatcher = regexp.MustCompile("^[a-z0-9]([a-z0-9-]{1,30}[a-z0-9])$")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (s *APIV2Service) ListUsers(ctx context.Context, _ *apiv2pb.ListUsersRequest) (*apiv2pb.ListUsersResponse, error) {
|
||||||
|
currentUser, err := getCurrentUser(ctx, s.Store)
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
|
||||||
|
users, err := s.Store.ListUsers(ctx, &store.FindUser{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.Errorf(codes.Internal, "failed to list users: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
response := &apiv2pb.ListUsersResponse{
|
||||||
|
Users: []*apiv2pb.User{},
|
||||||
|
}
|
||||||
|
for _, user := range users {
|
||||||
|
response.Users = append(response.Users, convertUserFromStore(user))
|
||||||
|
}
|
||||||
|
return response, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *APIV2Service) GetUser(ctx context.Context, request *apiv2pb.GetUserRequest) (*apiv2pb.GetUserResponse, error) {
|
func (s *APIV2Service) GetUser(ctx context.Context, request *apiv2pb.GetUserRequest) (*apiv2pb.GetUserResponse, error) {
|
||||||
username, err := ExtractUsernameFromName(request.Name)
|
username, err := ExtractUsernameFromName(request.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -12,6 +12,10 @@ import "google/protobuf/timestamp.proto";
|
|||||||
option go_package = "gen/api/v2";
|
option go_package = "gen/api/v2";
|
||||||
|
|
||||||
service UserService {
|
service UserService {
|
||||||
|
// ListUsers returns a list of users.
|
||||||
|
rpc ListUsers(ListUsersRequest) returns (ListUsersResponse) {
|
||||||
|
option (google.api.http) = {get: "/api/v2/users"};
|
||||||
|
}
|
||||||
// GetUser gets a user by name.
|
// GetUser gets a user by name.
|
||||||
rpc GetUser(GetUserRequest) returns (GetUserResponse) {
|
rpc GetUser(GetUserRequest) returns (GetUserResponse) {
|
||||||
option (google.api.http) = {get: "/api/v2/{name=users/*}"};
|
option (google.api.http) = {get: "/api/v2/{name=users/*}"};
|
||||||
@ -99,6 +103,12 @@ message User {
|
|||||||
google.protobuf.Timestamp update_time = 10;
|
google.protobuf.Timestamp update_time = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message ListUsersRequest {}
|
||||||
|
|
||||||
|
message ListUsersResponse {
|
||||||
|
repeated User users = 1;
|
||||||
|
}
|
||||||
|
|
||||||
message GetUserRequest {
|
message GetUserRequest {
|
||||||
// The name of the user.
|
// The name of the user.
|
||||||
// Format: users/{username}
|
// Format: users/{username}
|
||||||
|
@ -31,6 +31,8 @@
|
|||||||
- [GetUserSettingResponse](#memos-api-v2-GetUserSettingResponse)
|
- [GetUserSettingResponse](#memos-api-v2-GetUserSettingResponse)
|
||||||
- [ListUserAccessTokensRequest](#memos-api-v2-ListUserAccessTokensRequest)
|
- [ListUserAccessTokensRequest](#memos-api-v2-ListUserAccessTokensRequest)
|
||||||
- [ListUserAccessTokensResponse](#memos-api-v2-ListUserAccessTokensResponse)
|
- [ListUserAccessTokensResponse](#memos-api-v2-ListUserAccessTokensResponse)
|
||||||
|
- [ListUsersRequest](#memos-api-v2-ListUsersRequest)
|
||||||
|
- [ListUsersResponse](#memos-api-v2-ListUsersResponse)
|
||||||
- [UpdateUserRequest](#memos-api-v2-UpdateUserRequest)
|
- [UpdateUserRequest](#memos-api-v2-UpdateUserRequest)
|
||||||
- [UpdateUserResponse](#memos-api-v2-UpdateUserResponse)
|
- [UpdateUserResponse](#memos-api-v2-UpdateUserResponse)
|
||||||
- [UpdateUserSettingRequest](#memos-api-v2-UpdateUserSettingRequest)
|
- [UpdateUserSettingRequest](#memos-api-v2-UpdateUserSettingRequest)
|
||||||
@ -541,6 +543,31 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="memos-api-v2-ListUsersRequest"></a>
|
||||||
|
|
||||||
|
### ListUsersRequest
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="memos-api-v2-ListUsersResponse"></a>
|
||||||
|
|
||||||
|
### ListUsersResponse
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
| Field | Type | Label | Description |
|
||||||
|
| ----- | ---- | ----- | ----------- |
|
||||||
|
| users | [User](#memos-api-v2-User) | repeated | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="memos-api-v2-UpdateUserRequest"></a>
|
<a name="memos-api-v2-UpdateUserRequest"></a>
|
||||||
|
|
||||||
### UpdateUserRequest
|
### UpdateUserRequest
|
||||||
@ -691,6 +718,7 @@
|
|||||||
|
|
||||||
| Method Name | Request Type | Response Type | Description |
|
| Method Name | Request Type | Response Type | Description |
|
||||||
| ----------- | ------------ | ------------- | ------------|
|
| ----------- | ------------ | ------------- | ------------|
|
||||||
|
| ListUsers | [ListUsersRequest](#memos-api-v2-ListUsersRequest) | [ListUsersResponse](#memos-api-v2-ListUsersResponse) | ListUsers returns a list of users. |
|
||||||
| GetUser | [GetUserRequest](#memos-api-v2-GetUserRequest) | [GetUserResponse](#memos-api-v2-GetUserResponse) | GetUser gets a user by name. |
|
| GetUser | [GetUserRequest](#memos-api-v2-GetUserRequest) | [GetUserResponse](#memos-api-v2-GetUserResponse) | GetUser gets a user by name. |
|
||||||
| CreateUser | [CreateUserRequest](#memos-api-v2-CreateUserRequest) | [CreateUserResponse](#memos-api-v2-CreateUserResponse) | CreateUser creates a new user. |
|
| CreateUser | [CreateUserRequest](#memos-api-v2-CreateUserRequest) | [CreateUserResponse](#memos-api-v2-CreateUserResponse) | CreateUser creates a new user. |
|
||||||
| UpdateUser | [UpdateUserRequest](#memos-api-v2-UpdateUserRequest) | [UpdateUserResponse](#memos-api-v2-UpdateUserResponse) | UpdateUser updates a user. |
|
| UpdateUser | [UpdateUserRequest](#memos-api-v2-UpdateUserRequest) | [UpdateUserResponse](#memos-api-v2-UpdateUserResponse) | UpdateUser updates a user. |
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -31,6 +31,24 @@ var _ = runtime.String
|
|||||||
var _ = utilities.NewDoubleArray
|
var _ = utilities.NewDoubleArray
|
||||||
var _ = metadata.Join
|
var _ = metadata.Join
|
||||||
|
|
||||||
|
func request_UserService_ListUsers_0(ctx context.Context, marshaler runtime.Marshaler, client UserServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
|
var protoReq ListUsersRequest
|
||||||
|
var metadata runtime.ServerMetadata
|
||||||
|
|
||||||
|
msg, err := client.ListUsers(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||||
|
return msg, metadata, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func local_request_UserService_ListUsers_0(ctx context.Context, marshaler runtime.Marshaler, server UserServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||||
|
var protoReq ListUsersRequest
|
||||||
|
var metadata runtime.ServerMetadata
|
||||||
|
|
||||||
|
msg, err := server.ListUsers(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 protoReq GetUserRequest
|
var protoReq GetUserRequest
|
||||||
var metadata runtime.ServerMetadata
|
var metadata runtime.ServerMetadata
|
||||||
@ -619,6 +637,31 @@ func local_request_UserService_DeleteUserAccessToken_0(ctx context.Context, mars
|
|||||||
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterUserServiceHandlerFromEndpoint instead.
|
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterUserServiceHandlerFromEndpoint instead.
|
||||||
func RegisterUserServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server UserServiceServer) error {
|
func RegisterUserServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server UserServiceServer) error {
|
||||||
|
|
||||||
|
mux.Handle("GET", pattern_UserService_ListUsers_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)
|
||||||
|
var err error
|
||||||
|
var annotatedContext context.Context
|
||||||
|
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/memos.api.v2.UserService/ListUsers", runtime.WithHTTPPathPattern("/api/v2/users"))
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := local_request_UserService_ListUsers_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_ListUsers_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
mux.Handle("GET", pattern_UserService_GetUser_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", 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()
|
||||||
@ -885,6 +928,28 @@ func RegisterUserServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn
|
|||||||
// "UserServiceClient" to call the correct interceptors.
|
// "UserServiceClient" to call the correct interceptors.
|
||||||
func RegisterUserServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client UserServiceClient) error {
|
func RegisterUserServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client UserServiceClient) error {
|
||||||
|
|
||||||
|
mux.Handle("GET", pattern_UserService_ListUsers_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)
|
||||||
|
var err error
|
||||||
|
var annotatedContext context.Context
|
||||||
|
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/memos.api.v2.UserService/ListUsers", runtime.WithHTTPPathPattern("/api/v2/users"))
|
||||||
|
if err != nil {
|
||||||
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resp, md, err := request_UserService_ListUsers_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_ListUsers_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
mux.Handle("GET", pattern_UserService_GetUser_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
mux.Handle("GET", 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()
|
||||||
@ -1087,6 +1152,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", "v2", "users"}, ""))
|
||||||
|
|
||||||
pattern_UserService_GetUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 2, 5, 3}, []string{"api", "v2", "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", "v2", "users", "name"}, ""))
|
||||||
|
|
||||||
pattern_UserService_CreateUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "users"}, ""))
|
pattern_UserService_CreateUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "users"}, ""))
|
||||||
@ -1107,6 +1174,8 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
forward_UserService_ListUsers_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
forward_UserService_GetUser_0 = runtime.ForwardResponseMessage
|
forward_UserService_GetUser_0 = runtime.ForwardResponseMessage
|
||||||
|
|
||||||
forward_UserService_CreateUser_0 = runtime.ForwardResponseMessage
|
forward_UserService_CreateUser_0 = runtime.ForwardResponseMessage
|
||||||
|
@ -19,6 +19,7 @@ import (
|
|||||||
const _ = grpc.SupportPackageIsVersion7
|
const _ = grpc.SupportPackageIsVersion7
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
UserService_ListUsers_FullMethodName = "/memos.api.v2.UserService/ListUsers"
|
||||||
UserService_GetUser_FullMethodName = "/memos.api.v2.UserService/GetUser"
|
UserService_GetUser_FullMethodName = "/memos.api.v2.UserService/GetUser"
|
||||||
UserService_CreateUser_FullMethodName = "/memos.api.v2.UserService/CreateUser"
|
UserService_CreateUser_FullMethodName = "/memos.api.v2.UserService/CreateUser"
|
||||||
UserService_UpdateUser_FullMethodName = "/memos.api.v2.UserService/UpdateUser"
|
UserService_UpdateUser_FullMethodName = "/memos.api.v2.UserService/UpdateUser"
|
||||||
@ -34,6 +35,8 @@ const (
|
|||||||
//
|
//
|
||||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||||
type UserServiceClient interface {
|
type UserServiceClient interface {
|
||||||
|
// ListUsers returns a list of users.
|
||||||
|
ListUsers(ctx context.Context, in *ListUsersRequest, opts ...grpc.CallOption) (*ListUsersResponse, error)
|
||||||
// GetUser gets a user by name.
|
// GetUser gets a user by name.
|
||||||
GetUser(ctx context.Context, in *GetUserRequest, opts ...grpc.CallOption) (*GetUserResponse, error)
|
GetUser(ctx context.Context, in *GetUserRequest, opts ...grpc.CallOption) (*GetUserResponse, error)
|
||||||
// CreateUser creates a new user.
|
// CreateUser creates a new user.
|
||||||
@ -60,6 +63,15 @@ func NewUserServiceClient(cc grpc.ClientConnInterface) UserServiceClient {
|
|||||||
return &userServiceClient{cc}
|
return &userServiceClient{cc}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *userServiceClient) ListUsers(ctx context.Context, in *ListUsersRequest, opts ...grpc.CallOption) (*ListUsersResponse, error) {
|
||||||
|
out := new(ListUsersResponse)
|
||||||
|
err := c.cc.Invoke(ctx, UserService_ListUsers_FullMethodName, in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *userServiceClient) GetUser(ctx context.Context, in *GetUserRequest, opts ...grpc.CallOption) (*GetUserResponse, error) {
|
func (c *userServiceClient) GetUser(ctx context.Context, in *GetUserRequest, opts ...grpc.CallOption) (*GetUserResponse, error) {
|
||||||
out := new(GetUserResponse)
|
out := new(GetUserResponse)
|
||||||
err := c.cc.Invoke(ctx, UserService_GetUser_FullMethodName, in, out, opts...)
|
err := c.cc.Invoke(ctx, UserService_GetUser_FullMethodName, in, out, opts...)
|
||||||
@ -145,6 +157,8 @@ func (c *userServiceClient) DeleteUserAccessToken(ctx context.Context, in *Delet
|
|||||||
// All implementations must embed UnimplementedUserServiceServer
|
// All implementations must embed UnimplementedUserServiceServer
|
||||||
// for forward compatibility
|
// for forward compatibility
|
||||||
type UserServiceServer interface {
|
type UserServiceServer interface {
|
||||||
|
// ListUsers returns a list of users.
|
||||||
|
ListUsers(context.Context, *ListUsersRequest) (*ListUsersResponse, error)
|
||||||
// GetUser gets a user by name.
|
// GetUser gets a user by name.
|
||||||
GetUser(context.Context, *GetUserRequest) (*GetUserResponse, error)
|
GetUser(context.Context, *GetUserRequest) (*GetUserResponse, error)
|
||||||
// CreateUser creates a new user.
|
// CreateUser creates a new user.
|
||||||
@ -168,6 +182,9 @@ type UserServiceServer interface {
|
|||||||
type UnimplementedUserServiceServer struct {
|
type UnimplementedUserServiceServer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (UnimplementedUserServiceServer) ListUsers(context.Context, *ListUsersRequest) (*ListUsersResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method ListUsers not implemented")
|
||||||
|
}
|
||||||
func (UnimplementedUserServiceServer) GetUser(context.Context, *GetUserRequest) (*GetUserResponse, error) {
|
func (UnimplementedUserServiceServer) GetUser(context.Context, *GetUserRequest) (*GetUserResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method GetUser not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method GetUser not implemented")
|
||||||
}
|
}
|
||||||
@ -208,6 +225,24 @@ func RegisterUserServiceServer(s grpc.ServiceRegistrar, srv UserServiceServer) {
|
|||||||
s.RegisterService(&UserService_ServiceDesc, srv)
|
s.RegisterService(&UserService_ServiceDesc, srv)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func _UserService_ListUsers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(ListUsersRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(UserServiceServer).ListUsers(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: UserService_ListUsers_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(UserServiceServer).ListUsers(ctx, req.(*ListUsersRequest))
|
||||||
|
}
|
||||||
|
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_GetUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
in := new(GetUserRequest)
|
in := new(GetUserRequest)
|
||||||
if err := dec(in); err != nil {
|
if err := dec(in); err != nil {
|
||||||
@ -377,6 +412,10 @@ var UserService_ServiceDesc = grpc.ServiceDesc{
|
|||||||
ServiceName: "memos.api.v2.UserService",
|
ServiceName: "memos.api.v2.UserService",
|
||||||
HandlerType: (*UserServiceServer)(nil),
|
HandlerType: (*UserServiceServer)(nil),
|
||||||
Methods: []grpc.MethodDesc{
|
Methods: []grpc.MethodDesc{
|
||||||
|
{
|
||||||
|
MethodName: "ListUsers",
|
||||||
|
Handler: _UserService_ListUsers_Handler,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
MethodName: "GetUser",
|
MethodName: "GetUser",
|
||||||
Handler: _UserService_GetUser_Handler,
|
Handler: _UserService_GetUser_Handler,
|
||||||
|
@ -39,7 +39,7 @@ func NewFrontendService(profile *profile.Profile, store *store.Store) *FrontendS
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *FrontendService) Serve(e *echo.Echo) {
|
func (s *FrontendService) Serve(e *echo.Echo) {
|
||||||
// Use echo static middleware to serve the built dist folder
|
// Use echo static middleware to serve the built dist folder.
|
||||||
// refer: https://github.com/labstack/echo/blob/master/middleware/static.go
|
// refer: https://github.com/labstack/echo/blob/master/middleware/static.go
|
||||||
e.Use(middleware.StaticWithConfig(middleware.StaticConfig{
|
e.Use(middleware.StaticWithConfig(middleware.StaticConfig{
|
||||||
Skipper: defaultAPIRequestSkipper,
|
Skipper: defaultAPIRequestSkipper,
|
||||||
@ -80,6 +80,10 @@ func (s *FrontendService) registerRoutes(e *echo.Echo) {
|
|||||||
return echo.NewHTTPError(http.StatusInternalServerError, "Instance URL system setting is not set")
|
return echo.NewHTTPError(http.StatusInternalServerError, "Instance URL system setting is not set")
|
||||||
}
|
}
|
||||||
instanceURL := instanceURLSetting.Value
|
instanceURL := instanceURLSetting.Value
|
||||||
|
if instanceURL == "" {
|
||||||
|
return echo.NewHTTPError(http.StatusInternalServerError, "Instance URL system setting is not set")
|
||||||
|
}
|
||||||
|
|
||||||
robotsTxt := fmt.Sprintf(`User-agent: *
|
robotsTxt := fmt.Sprintf(`User-agent: *
|
||||||
Allow: /
|
Allow: /
|
||||||
Host: %s
|
Host: %s
|
||||||
@ -98,8 +102,11 @@ Sitemap: %s/sitemap.xml`, instanceURL, instanceURL)
|
|||||||
if instanceURLSetting == nil {
|
if instanceURLSetting == nil {
|
||||||
return echo.NewHTTPError(http.StatusInternalServerError, "Instance URL system setting is not set")
|
return echo.NewHTTPError(http.StatusInternalServerError, "Instance URL system setting is not set")
|
||||||
}
|
}
|
||||||
|
|
||||||
instanceURL := instanceURLSetting.Value
|
instanceURL := instanceURLSetting.Value
|
||||||
|
if instanceURL == "" {
|
||||||
|
return echo.NewHTTPError(http.StatusInternalServerError, "Instance URL system setting is not set")
|
||||||
|
}
|
||||||
|
|
||||||
urlsets := []string{}
|
urlsets := []string{}
|
||||||
// Append memo list.
|
// Append memo list.
|
||||||
memoList, err := s.Store.ListMemos(ctx, &store.FindMemo{
|
memoList, err := s.Store.ListMemos(ctx, &store.FindMemo{
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { toast } from "react-hot-toast";
|
import { toast } from "react-hot-toast";
|
||||||
import { useUserV1Store, UserNamePrefix } from "@/store/v1";
|
import { useUserV1Store } from "@/store/v1";
|
||||||
|
import { User } from "@/types/proto/api/v2/user_service";
|
||||||
import { useTranslate } from "@/utils/i18n";
|
import { useTranslate } from "@/utils/i18n";
|
||||||
import { generateDialog } from "./Dialog";
|
import { generateDialog } from "./Dialog";
|
||||||
import Icon from "./Icon";
|
import Icon from "./Icon";
|
||||||
@ -49,7 +50,7 @@ const ChangeMemberPasswordDialog: React.FC<Props> = (props: Props) => {
|
|||||||
try {
|
try {
|
||||||
await userV1Store.updateUser(
|
await userV1Store.updateUser(
|
||||||
{
|
{
|
||||||
name: `${UserNamePrefix}${user.username}`,
|
name: user.name,
|
||||||
password: newPassword,
|
password: newPassword,
|
||||||
},
|
},
|
||||||
["password"]
|
["password"]
|
||||||
@ -66,7 +67,7 @@ const ChangeMemberPasswordDialog: React.FC<Props> = (props: Props) => {
|
|||||||
<>
|
<>
|
||||||
<div className="dialog-header-container !w-64">
|
<div className="dialog-header-container !w-64">
|
||||||
<p className="title-text">
|
<p className="title-text">
|
||||||
{t("setting.account-section.change-password")} ({user.username})
|
{t("setting.account-section.change-password")} ({user.nickname})
|
||||||
</p>
|
</p>
|
||||||
<button className="btn close-btn" onClick={handleCloseBtnClick}>
|
<button className="btn close-btn" onClick={handleCloseBtnClick}>
|
||||||
<Icon.X />
|
<Icon.X />
|
||||||
|
@ -2,11 +2,10 @@ import { Button, Dropdown, Input, Menu, MenuButton } from "@mui/joy";
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { toast } from "react-hot-toast";
|
import { toast } from "react-hot-toast";
|
||||||
import { userServiceClient } from "@/grpcweb";
|
import { userServiceClient } from "@/grpcweb";
|
||||||
import * as api from "@/helpers/api";
|
|
||||||
import useCurrentUser from "@/hooks/useCurrentUser";
|
import useCurrentUser from "@/hooks/useCurrentUser";
|
||||||
import { UserNamePrefix, useUserV1Store } from "@/store/v1";
|
import { UserNamePrefix, extractUsernameFromName, useUserV1Store } from "@/store/v1";
|
||||||
import { RowStatus } from "@/types/proto/api/v2/common";
|
import { RowStatus } from "@/types/proto/api/v2/common";
|
||||||
import { User_Role } from "@/types/proto/api/v2/user_service";
|
import { User, User_Role } from "@/types/proto/api/v2/user_service";
|
||||||
import { useTranslate } from "@/utils/i18n";
|
import { useTranslate } from "@/utils/i18n";
|
||||||
import showChangeMemberPasswordDialog from "../ChangeMemberPasswordDialog";
|
import showChangeMemberPasswordDialog from "../ChangeMemberPasswordDialog";
|
||||||
import { showCommonDialog } from "../Dialog/CommonDialog";
|
import { showCommonDialog } from "../Dialog/CommonDialog";
|
||||||
@ -32,8 +31,8 @@ const MemberSection = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const fetchUserList = async () => {
|
const fetchUserList = async () => {
|
||||||
const { data } = await api.getUserList();
|
const users = await userV1Store.fetchUsers();
|
||||||
setUserList(data.sort((a, b) => a.id - b.id));
|
setUserList(users);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleUsernameInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
const handleUsernameInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
@ -81,13 +80,13 @@ const MemberSection = () => {
|
|||||||
const handleArchiveUserClick = (user: User) => {
|
const handleArchiveUserClick = (user: User) => {
|
||||||
showCommonDialog({
|
showCommonDialog({
|
||||||
title: t("setting.member-section.archive-member"),
|
title: t("setting.member-section.archive-member"),
|
||||||
content: t("setting.member-section.archive-warning", { username: user.username }),
|
content: t("setting.member-section.archive-warning", { username: user.nickname }),
|
||||||
style: "danger",
|
style: "danger",
|
||||||
dialogName: "archive-user-dialog",
|
dialogName: "archive-user-dialog",
|
||||||
onConfirm: async () => {
|
onConfirm: async () => {
|
||||||
await userServiceClient.updateUser({
|
await userServiceClient.updateUser({
|
||||||
user: {
|
user: {
|
||||||
name: `${UserNamePrefix}${user.username}`,
|
name: user.name,
|
||||||
rowStatus: RowStatus.ARCHIVED,
|
rowStatus: RowStatus.ARCHIVED,
|
||||||
},
|
},
|
||||||
updateMask: ["row_status"],
|
updateMask: ["row_status"],
|
||||||
@ -100,7 +99,7 @@ const MemberSection = () => {
|
|||||||
const handleRestoreUserClick = async (user: User) => {
|
const handleRestoreUserClick = async (user: User) => {
|
||||||
await userServiceClient.updateUser({
|
await userServiceClient.updateUser({
|
||||||
user: {
|
user: {
|
||||||
name: `${UserNamePrefix}${user.username}`,
|
name: user.name,
|
||||||
rowStatus: RowStatus.ACTIVE,
|
rowStatus: RowStatus.ACTIVE,
|
||||||
},
|
},
|
||||||
updateMask: ["row_status"],
|
updateMask: ["row_status"],
|
||||||
@ -111,11 +110,11 @@ const MemberSection = () => {
|
|||||||
const handleDeleteUserClick = (user: User) => {
|
const handleDeleteUserClick = (user: User) => {
|
||||||
showCommonDialog({
|
showCommonDialog({
|
||||||
title: t("setting.member-section.delete-member"),
|
title: t("setting.member-section.delete-member"),
|
||||||
content: t("setting.member-section.delete-warning", { username: user.username }),
|
content: t("setting.member-section.delete-warning", { username: user.nickname }),
|
||||||
style: "danger",
|
style: "danger",
|
||||||
dialogName: "delete-user-dialog",
|
dialogName: "delete-user-dialog",
|
||||||
onConfirm: async () => {
|
onConfirm: async () => {
|
||||||
await userV1Store.deleteUser(`${UserNamePrefix}${user.username}`);
|
await userV1Store.deleteUser(user.name);
|
||||||
fetchUserList();
|
fetchUserList();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -165,8 +164,8 @@ const MemberSection = () => {
|
|||||||
<tr key={user.id}>
|
<tr key={user.id}>
|
||||||
<td className="whitespace-nowrap py-2 pl-4 pr-3 text-sm text-gray-900 dark:text-gray-300">{user.id}</td>
|
<td className="whitespace-nowrap py-2 pl-4 pr-3 text-sm text-gray-900 dark:text-gray-300">{user.id}</td>
|
||||||
<td className="whitespace-nowrap px-3 py-2 text-sm text-gray-500 dark:text-gray-300">
|
<td className="whitespace-nowrap px-3 py-2 text-sm text-gray-500 dark:text-gray-300">
|
||||||
{user.username}
|
{extractUsernameFromName(user.name)}
|
||||||
<span className="ml-1 italic">{user.rowStatus === "ARCHIVED" && "(Archived)"}</span>
|
<span className="ml-1 italic">{user.rowStatus === RowStatus.ARCHIVED && "(Archived)"}</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="whitespace-nowrap px-3 py-2 text-sm text-gray-500 dark:text-gray-300">{user.nickname}</td>
|
<td className="whitespace-nowrap px-3 py-2 text-sm text-gray-500 dark:text-gray-300">{user.nickname}</td>
|
||||||
<td className="whitespace-nowrap px-3 py-2 text-sm text-gray-500 dark:text-gray-300">{user.email}</td>
|
<td className="whitespace-nowrap px-3 py-2 text-sm text-gray-500 dark:text-gray-300">{user.email}</td>
|
||||||
@ -185,7 +184,7 @@ const MemberSection = () => {
|
|||||||
>
|
>
|
||||||
{t("setting.account-section.change-password")}
|
{t("setting.account-section.change-password")}
|
||||||
</button>
|
</button>
|
||||||
{user.rowStatus === "NORMAL" ? (
|
{user.rowStatus === RowStatus.ACTIVE ? (
|
||||||
<button
|
<button
|
||||||
className="w-full text-left text-sm leading-6 py-1 px-3 cursor-pointer rounded hover:bg-gray-100 dark:hover:bg-zinc-600"
|
className="w-full text-left text-sm leading-6 py-1 px-3 cursor-pointer rounded hover:bg-gray-100 dark:hover:bg-zinc-600"
|
||||||
onClick={() => handleArchiveUserClick(user)}
|
onClick={() => handleArchiveUserClick(user)}
|
||||||
|
@ -44,10 +44,6 @@ export function signout() {
|
|||||||
return axios.post("/api/v1/auth/signout");
|
return axios.post("/api/v1/auth/signout");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getUserList() {
|
|
||||||
return axios.get<User[]>("/api/v1/user");
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getMemoStats(username: string) {
|
export function getMemoStats(username: string) {
|
||||||
return axios.get<number[]>(`/api/v1/memo/stats?creatorUsername=${username}`);
|
return axios.get<number[]>(`/api/v1/memo/stats?creatorUsername=${username}`);
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
|
import { combine } from "zustand/middleware";
|
||||||
import { authServiceClient, userServiceClient } from "@/grpcweb";
|
import { authServiceClient, userServiceClient } from "@/grpcweb";
|
||||||
import { User, UserSetting } from "@/types/proto/api/v2/user_service";
|
import { User, UserSetting } from "@/types/proto/api/v2/user_service";
|
||||||
import { UserNamePrefix, extractUsernameFromName } from "./resourceName";
|
import { UserNamePrefix, extractUsernameFromName } from "./resourceName";
|
||||||
|
|
||||||
interface UserV1Store {
|
interface State {
|
||||||
userMapByUsername: Record<string, User>;
|
userMapByUsername: Record<string, User>;
|
||||||
currentUser?: User;
|
currentUser?: User;
|
||||||
userSetting?: UserSetting;
|
userSetting?: UserSetting;
|
||||||
getOrFetchUserByUsername: (username: string) => Promise<User>;
|
|
||||||
getUserByUsername: (username: string) => User;
|
|
||||||
updateUser: (user: Partial<User>, updateMask: string[]) => Promise<User>;
|
|
||||||
deleteUser: (name: string) => Promise<void>;
|
|
||||||
fetchCurrentUser: () => Promise<User>;
|
|
||||||
setCurrentUser: (user: User) => void;
|
|
||||||
updateUserSetting: (userSetting: Partial<UserSetting>, updateMark: string[]) => Promise<UserSetting>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getDefaultState = (): State => ({
|
||||||
|
userMapByUsername: {},
|
||||||
|
currentUser: undefined,
|
||||||
|
userSetting: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
const getDefaultUserSetting = () => {
|
const getDefaultUserSetting = () => {
|
||||||
return UserSetting.fromPartial({
|
return UserSetting.fromPartial({
|
||||||
locale: "en",
|
locale: "en",
|
||||||
@ -27,8 +27,18 @@ const getDefaultUserSetting = () => {
|
|||||||
// Request cache is used to prevent multiple requests.
|
// Request cache is used to prevent multiple requests.
|
||||||
const requestCache = new Map<string, Promise<any>>();
|
const requestCache = new Map<string, Promise<any>>();
|
||||||
|
|
||||||
export const useUserV1Store = create<UserV1Store>()((set, get) => ({
|
export const useUserV1Store = create(
|
||||||
userMapByUsername: {},
|
combine(getDefaultState(), (set, get) => ({
|
||||||
|
fetchUsers: async () => {
|
||||||
|
const { users } = await userServiceClient.listUsers({});
|
||||||
|
const userMap = get().userMapByUsername;
|
||||||
|
for (const user of users) {
|
||||||
|
const username = extractUsernameFromName(user.name);
|
||||||
|
userMap[username] = user;
|
||||||
|
}
|
||||||
|
set({ userMapByUsername: userMap });
|
||||||
|
return users;
|
||||||
|
},
|
||||||
getOrFetchUserByUsername: async (username: string) => {
|
getOrFetchUserByUsername: async (username: string) => {
|
||||||
const userMap = get().userMapByUsername;
|
const userMap = get().userMapByUsername;
|
||||||
if (userMap[username]) {
|
if (userMap[username]) {
|
||||||
@ -50,7 +60,7 @@ export const useUserV1Store = create<UserV1Store>()((set, get) => ({
|
|||||||
}
|
}
|
||||||
requestCache.delete(username);
|
requestCache.delete(username);
|
||||||
userMap[username] = user;
|
userMap[username] = user;
|
||||||
set(userMap);
|
set({ userMapByUsername: userMap });
|
||||||
return user;
|
return user;
|
||||||
},
|
},
|
||||||
getUserByUsername: (username: string) => {
|
getUserByUsername: (username: string) => {
|
||||||
@ -68,7 +78,7 @@ export const useUserV1Store = create<UserV1Store>()((set, get) => ({
|
|||||||
const username = extractUsernameFromName(updatedUser.name);
|
const username = extractUsernameFromName(updatedUser.name);
|
||||||
const userMap = get().userMapByUsername;
|
const userMap = get().userMapByUsername;
|
||||||
userMap[username] = updatedUser;
|
userMap[username] = updatedUser;
|
||||||
set(userMap);
|
set({ userMapByUsername: userMap });
|
||||||
return updatedUser;
|
return updatedUser;
|
||||||
},
|
},
|
||||||
deleteUser: async (name: string) => {
|
deleteUser: async (name: string) => {
|
||||||
@ -105,4 +115,5 @@ export const useUserV1Store = create<UserV1Store>()((set, get) => ({
|
|||||||
set({ userSetting: updatedUserSetting });
|
set({ userSetting: updatedUserSetting });
|
||||||
return updatedUserSetting;
|
return updatedUserSetting;
|
||||||
},
|
},
|
||||||
}));
|
}))
|
||||||
|
);
|
||||||
|
Reference in New Issue
Block a user