Skip to content

Commit fa81c42

Browse files
committed
get users grpc methods
1 parent 0b1a87e commit fa81c42

File tree

17 files changed

+404
-120
lines changed

17 files changed

+404
-120
lines changed

cmd/auth-service/main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ func main() {
6262
authService := service.NewAuthService(zapLogger, authStorage, oauthCodesCache, oauthConfig, authConfig.JWTConfig.SigningKey)
6363
authHandler := handler.NewHandler(zapLogger, authService)
6464

65-
srv := server.NewServiceServer(authConfig.ServerConfig.Port, authHandler.InitRoutes())
65+
srv := server.NewHTTPServer(authConfig.ServerConfig.Port, authHandler.InitRoutes())
6666

6767
go func() {
6868
if err := srv.Start(); !errors.Is(err, http.ErrServerClosed) {

cmd/static-server/main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func main() {
4141

4242
h := handler.NewHandler(zapLogger)
4343

44-
srv := server.NewServiceServer(cfg.ServerConfig.Port, h.InitRoutes())
44+
srv := server.NewHTTPServer(cfg.ServerConfig.Port, h.InitRoutes())
4545

4646
go func() {
4747
if err := srv.Start(); !errors.Is(err, http.ErrServerClosed) {

cmd/user-service/main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func main() {
4949
}()
5050

5151
postgresStorage := storage.NewUserStorage(zapLogger, dbConn, cfg.DatabaseTimeout)
52-
h := handler.NewUserServiceHandler(zapLogger, postgresStorage)
52+
h := handler.NewUserServiceHandler(zapLogger, postgresStorage, cfg.JWTConfig.SigningKey)
5353

5454
srv := server.NewGRPCServer(zapLogger, true, true)
5555

go.mod

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ go 1.23.0
55
require (
66
github.com/Masterminds/squirrel v1.5.4
77
github.com/MicahParks/keyfunc/v3 v3.3.5
8-
github.com/Newella-HQ/protos v0.0.4
8+
github.com/Newella-HQ/protos v0.0.5
99
github.com/akyoto/cache v1.0.6
1010
github.com/gin-gonic/gin v1.10.0
1111
github.com/golang-jwt/jwt/v5 v5.2.1
@@ -15,6 +15,7 @@ require (
1515
go.uber.org/zap v1.27.0
1616
golang.org/x/oauth2 v0.24.0
1717
google.golang.org/grpc v1.67.1
18+
google.golang.org/protobuf v1.35.2
1819
)
1920

2021
require (
@@ -52,6 +53,5 @@ require (
5253
golang.org/x/text v0.20.0 // indirect
5354
golang.org/x/time v0.5.0 // indirect
5455
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect
55-
google.golang.org/protobuf v1.35.2 // indirect
5656
gopkg.in/yaml.v3 v3.0.1 // indirect
5757
)

go.sum

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ github.com/MicahParks/jwkset v0.5.19 h1:XZCsgJv05DBCvxEHYEHlSafqiuVn5ESG0VRB331F
66
github.com/MicahParks/jwkset v0.5.19/go.mod h1:q8ptTGn/Z9c4MwbcfeCDssADeVQb3Pk7PnVxrvi+2QY=
77
github.com/MicahParks/keyfunc/v3 v3.3.5 h1:7ceAJLUAldnoueHDNzF8Bx06oVcQ5CfJnYwNt1U3YYo=
88
github.com/MicahParks/keyfunc/v3 v3.3.5/go.mod h1:SdCCyMJn/bYqWDvARspC6nCT8Sk74MjuAY22C7dCST8=
9-
github.com/Newella-HQ/protos v0.0.4 h1:UMM18tIX8N8oWc424VAQsOgUJOMGhXCogq0YJfQOIAw=
10-
github.com/Newella-HQ/protos v0.0.4/go.mod h1:rXAPPTyeQ079UkDysCL/l0a2JRN4/YCB8PMevuYcqDM=
9+
github.com/Newella-HQ/protos v0.0.5 h1:Zyd6G++dNP/iDtpZhLgMiqe/V9PaSVEIvcoMCKrnxbk=
10+
github.com/Newella-HQ/protos v0.0.5/go.mod h1:rXAPPTyeQ079UkDysCL/l0a2JRN4/YCB8PMevuYcqDM=
1111
github.com/akyoto/cache v1.0.6 h1:5XGVVYoi2i+DZLLPuVIXtsNIJ/qaAM16XT0LaBaXd2k=
1212
github.com/akyoto/cache v1.0.6/go.mod h1:WfxTRqKhfgAG71Xh6E3WLpjhBtZI37O53G4h5s+3iM4=
1313
github.com/bytedance/sonic v1.12.5 h1:hoZxY8uW+mT+OpkcUWw4k0fDINtOcVavEsGfzwzFU/w=

internal/auth-service/service/auth.go

+2-16
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313

1414
"github.com/Newella-HQ/newella-backend/internal/logger"
1515
"github.com/Newella-HQ/newella-backend/internal/model"
16+
"github.com/Newella-HQ/newella-backend/internal/token"
1617
)
1718

1819
const (
@@ -199,22 +200,7 @@ func (s *AuthService) RefreshTokens(ctx context.Context, tokenPair model.TokenPa
199200
}
200201

201202
func (s *AuthService) ParseAccessToken(signed string) (*model.NewellaJWTToken, error) {
202-
token, err := jwt.ParseWithClaims(signed, &model.NewellaJWTToken{}, func(token *jwt.Token) (interface{}, error) {
203-
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
204-
return nil, fmt.Errorf("ivalid signing method")
205-
}
206-
return []byte(s.singingKey), nil
207-
})
208-
if err != nil {
209-
return nil, fmt.Errorf("can't parse jwt token: %w", err)
210-
}
211-
212-
accessToken, ok := token.Claims.(*model.NewellaJWTToken)
213-
if !ok {
214-
return nil, fmt.Errorf("can't cast to newella jwt token: %w", err)
215-
}
216-
217-
return accessToken, nil
203+
return token.ParseAccessToken(signed, s.singingKey)
218204
}
219205

220206
func (s *AuthService) RemoveTokens(ctx context.Context, userID string) error {

internal/logger/logger.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func NewZapLogger(level config.LogLevel) (*ZapLogger, error) {
5858

5959
func (l *ZapLogger) With(args ...interface{}) Logger {
6060
return &ZapLogger{
61-
logger: l.logger.With(args),
61+
logger: l.logger.With(args...),
6262
}
6363
}
6464

internal/model/user.go

+14-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
package model
22

3-
import "time"
3+
import (
4+
"time"
5+
6+
"github.com/Newella-HQ/protos/gen/go/user"
7+
)
48

59
type User struct {
6-
ID int `db:"id"`
10+
ID string `db:"id"`
711
Username string `db:"username"`
12+
RealName string `db:"real_name"`
813
Description string `db:"description"`
914
Email string `db:"email"`
1015
Picture string `db:"picture"`
@@ -14,6 +19,13 @@ type User struct {
1419

1520
type Role string
1621

22+
func (r *Role) ToProto() user.Role {
23+
if r == nil {
24+
return -1
25+
}
26+
return user.Role(user.Role_value[string(*r)])
27+
}
28+
1729
const (
1830
UserRole Role = "user"
1931
ModeratorRole Role = "moderator"

internal/server/grpc_server.go

+14
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,20 @@ func InterceptorLogger(l logger.Logger) logging.Logger {
6363
})
6464
}
6565

66+
func filterNilsAndEmptyStrings(l []any) []any {
67+
var filtered []any
68+
for _, v := range l {
69+
if v != nil {
70+
if str := fmt.Sprintf("%s", v); str == "" {
71+
filtered = append(filtered, " ")
72+
continue
73+
}
74+
filtered = append(filtered, v)
75+
}
76+
}
77+
return filtered
78+
}
79+
6680
func (g *GRPCServer) Run(port string) error {
6781
lis, err := net.Listen("tcp", ":"+port)
6882
if err != nil {

internal/server/http_server.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ import (
66
"time"
77
)
88

9-
type ServiceServer struct {
9+
type HTTPServer struct {
1010
s *http.Server
1111
}
1212

13-
func NewServiceServer(port string, handler http.Handler) *ServiceServer {
14-
return &ServiceServer{
13+
func NewHTTPServer(port string, handler http.Handler) *HTTPServer {
14+
return &HTTPServer{
1515
s: &http.Server{
1616
Handler: handler,
1717
Addr: ":" + port,
@@ -20,10 +20,10 @@ func NewServiceServer(port string, handler http.Handler) *ServiceServer {
2020
}
2121
}
2222

23-
func (s *ServiceServer) Start() error {
23+
func (s *HTTPServer) Start() error {
2424
return s.s.ListenAndServe()
2525
}
2626

27-
func (s *ServiceServer) Shutdown(ctx context.Context) error {
27+
func (s *HTTPServer) Shutdown(ctx context.Context) error {
2828
return s.s.Shutdown(ctx)
2929
}

internal/token/token.go

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package token
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/golang-jwt/jwt/v5"
7+
8+
"github.com/Newella-HQ/newella-backend/internal/model"
9+
)
10+
11+
func ParseAccessToken(signedToken, signingKey string) (*model.NewellaJWTToken, error) {
12+
token, err := jwt.ParseWithClaims(signedToken, &model.NewellaJWTToken{}, func(token *jwt.Token) (interface{}, error) {
13+
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
14+
return nil, fmt.Errorf("ivalid signing method")
15+
}
16+
return []byte(signingKey), nil
17+
})
18+
if err != nil {
19+
return nil, fmt.Errorf("can't parse jwt token: %w", err)
20+
}
21+
22+
accessToken, ok := token.Claims.(*model.NewellaJWTToken)
23+
if !ok {
24+
return nil, fmt.Errorf("can't cast to newella jwt token: %w", err)
25+
}
26+
27+
return accessToken, nil
28+
}

internal/user-service/config/config.go

+4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
type UserServiceConfig struct {
1313
PostgresConfig config.PostgresConfig
1414
ServerConfig config.ServerConfig
15+
JWTConfig config.JWTConfig
1516
LogLevel config.LogLevel
1617
DatabaseTimeout time.Duration
1718
}
@@ -40,6 +41,9 @@ func InitUserServiceConfig() (cfg *UserServiceConfig, err error) {
4041
Host: config.GetAndValidateEnv("SERVER_HOST"),
4142
Port: config.GetAndValidateEnv("USER_SERVICE_GRPC_PORT"),
4243
},
44+
JWTConfig: config.JWTConfig{
45+
SigningKey: config.GetAndValidateEnv("JWT_SIGNING_KEY"),
46+
},
4347
LogLevel: config.ConvertLogLevel(config.GetAndValidateEnv("LOG_LEVEL")),
4448
DatabaseTimeout: 15 * time.Second,
4549
}, nil
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package handler
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
8+
"google.golang.org/grpc/metadata"
9+
10+
"github.com/Newella-HQ/newella-backend/internal/model"
11+
"github.com/Newella-HQ/newella-backend/internal/token"
12+
)
13+
14+
const AuthHeader = "authorization"
15+
16+
func (h *UserServiceHandler) VerifyAndGetUserToken(ctx context.Context) (*model.NewellaJWTToken, error) {
17+
md, ok := metadata.FromIncomingContext(ctx)
18+
if !ok {
19+
return nil, fmt.Errorf("can't get metadata from ctx")
20+
}
21+
22+
authHeader, ok := md[AuthHeader]
23+
if !ok || len(authHeader) == 0 {
24+
return nil, fmt.Errorf("can't get authorization header from metadata")
25+
}
26+
27+
headerParts := strings.Split(authHeader[0], " ")
28+
if len(headerParts) != 2 || headerParts[0] != "Bearer" || len(headerParts[1]) == 0 {
29+
return nil, fmt.Errorf("invalid auth header")
30+
}
31+
32+
parsedToken, err := token.ParseAccessToken(headerParts[0], h.singingKey)
33+
if err != nil {
34+
return nil, fmt.Errorf("can't parse access token: %w", err)
35+
}
36+
37+
return parsedToken, nil
38+
}
+98-1
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,121 @@
11
package handler
22

33
import (
4+
"context"
5+
46
"github.com/Newella-HQ/protos/gen/go/user"
7+
"google.golang.org/grpc/codes"
8+
"google.golang.org/grpc/status"
9+
"google.golang.org/protobuf/types/known/emptypb"
510

611
"github.com/Newella-HQ/newella-backend/internal/logger"
712
)
813

914
type UserStorage interface {
15+
GetUser(ctx context.Context, id string) (*user.User, error)
16+
GetUsers(ctx context.Context, search string, limit, offset int) (int, []*user.User, error)
1017
}
1118

1219
type UserServiceHandler struct {
1320
logger logger.Logger
1421
userStorage UserStorage
22+
singingKey string
1523

1624
user.UnimplementedUserServiceServer
1725
}
1826

19-
func NewUserServiceHandler(logger logger.Logger, userStorage UserStorage) *UserServiceHandler {
27+
func NewUserServiceHandler(logger logger.Logger, userStorage UserStorage, singingKey string) *UserServiceHandler {
2028
return &UserServiceHandler{
2129
logger: logger,
2230
userStorage: userStorage,
31+
singingKey: singingKey,
2332
}
2433
}
34+
35+
// GetUser with authority
36+
func (h *UserServiceHandler) GetUser(ctx context.Context, request *user.GetUserRequest) (*user.GetUserResponse, error) {
37+
userToken, err := h.VerifyAndGetUserToken(ctx)
38+
if err != nil {
39+
return nil, status.Errorf(codes.Unauthenticated, err.Error())
40+
}
41+
h.logger.Debugf("got user token: %v", userToken)
42+
43+
id := request.GetId()
44+
if id == "" {
45+
return nil, status.Errorf(codes.InvalidArgument, "empty ID field")
46+
}
47+
48+
userData, err := h.userStorage.GetUser(ctx, id)
49+
if err != nil {
50+
return nil, status.Errorf(codes.Internal, "can't get user from db: %s", err)
51+
}
52+
53+
return &user.GetUserResponse{User: userData}, nil
54+
}
55+
56+
func (h *UserServiceHandler) GetUsers(ctx context.Context, request *user.GetUsersRequest) (*user.GetUsersResponse, error) {
57+
limit, page := 50, 0
58+
if l := request.GetLimit(); l >= 0 {
59+
limit = int(l)
60+
}
61+
if p := request.GetPage(); p >= 0 {
62+
page = int(p)
63+
}
64+
offset := limit * page
65+
search := request.GetSearch()
66+
67+
count, users, err := h.userStorage.GetUsers(ctx, search, limit, offset)
68+
if err != nil {
69+
return nil, status.Errorf(codes.Internal, "can't get users from db: %s", err)
70+
}
71+
72+
return &user.GetUsersResponse{
73+
Count: int64(count),
74+
Users: users,
75+
}, nil
76+
}
77+
78+
func (h *UserServiceHandler) ChangeUsername(ctx context.Context, request *user.ChangeUsernameRequest) (*emptypb.Empty, error) {
79+
//TODO implement me
80+
panic("implement me")
81+
}
82+
83+
func (h *UserServiceHandler) ChangeUserData(ctx context.Context, request *user.ChangeUserDataRequest) (*emptypb.Empty, error) {
84+
//TODO implement me
85+
panic("implement me")
86+
}
87+
88+
func (h *UserServiceHandler) ChangePicture(server user.UserService_ChangePictureServer) error {
89+
//TODO implement me
90+
panic("implement me")
91+
}
92+
93+
func (h *UserServiceHandler) ChangeRole(ctx context.Context, request *user.ChangeRoleRequest) (*emptypb.Empty, error) {
94+
//TODO implement me
95+
panic("implement me")
96+
}
97+
98+
func (h *UserServiceHandler) GetSubscribers(ctx context.Context, request *user.GetSubsRequest) (*user.GetSubsResponse, error) {
99+
//TODO implement me
100+
panic("implement me")
101+
}
102+
103+
func (h *UserServiceHandler) GetSubscriptions(ctx context.Context, request *user.GetSubsRequest) (*user.GetSubsResponse, error) {
104+
//TODO implement me
105+
panic("implement me")
106+
}
107+
108+
func (h *UserServiceHandler) Subscribe(ctx context.Context, request *user.SubRequest) (*emptypb.Empty, error) {
109+
//TODO implement me
110+
panic("implement me")
111+
}
112+
113+
func (h *UserServiceHandler) Unsubscribe(ctx context.Context, request *user.SubRequest) (*emptypb.Empty, error) {
114+
//TODO implement me
115+
panic("implement me")
116+
}
117+
118+
func (h *UserServiceHandler) DeleteSubscriber(ctx context.Context, request *user.SubRequest) (*emptypb.Empty, error) {
119+
//TODO implement me
120+
panic("implement me")
121+
}

0 commit comments

Comments
 (0)