♻️ Refactored relation system

⬆️ Support new realm & relation api
This commit is contained in:
2024-07-16 00:02:28 +08:00
parent 4143a7b2c8
commit a8d919dc5b
35 changed files with 426 additions and 2559 deletions

View File

@ -2,23 +2,24 @@ package grpc
import (
"context"
"git.solsynth.dev/hydrogen/passport/pkg/internal/models"
exproto "git.solsynth.dev/hydrogen/dealer/pkg/proto"
"git.solsynth.dev/hydrogen/dealer/pkg/proto"
"git.solsynth.dev/hydrogen/passport/pkg/internal/services"
jsoniter "github.com/json-iterator/go"
)
func (v *Server) Authenticate(_ context.Context, in *exproto.AuthRequest) (*exproto.AuthReply, error) {
func (v *Server) Authenticate(_ context.Context, in *proto.AuthRequest) (*proto.AuthReply, error) {
ctx, perms, atk, rtk, err := services.Authenticate(in.GetAccessToken(), in.GetRefreshToken(), 0)
if err != nil {
return &exproto.AuthReply{
return &proto.AuthReply{
IsValid: false,
}, nil
} else {
user := ctx.Account
rawPerms, _ := jsoniter.Marshal(perms)
userinfo := &exproto.UserInfo{
userinfo := &proto.UserInfo{
Id: uint64(user.ID),
Name: user.Name,
Nick: user.Nick,
@ -33,9 +34,9 @@ func (v *Server) Authenticate(_ context.Context, in *exproto.AuthRequest) (*expr
userinfo.Banner = *user.GetBanner()
}
return &exproto.AuthReply{
return &proto.AuthReply{
IsValid: true,
Info: &exproto.AuthInfo{
Info: &proto.AuthInfo{
NewAccessToken: &atk,
NewRefreshToken: &rtk,
Permissions: rawPerms,
@ -46,7 +47,7 @@ func (v *Server) Authenticate(_ context.Context, in *exproto.AuthRequest) (*expr
}
}
func (v *Server) EnsurePermGranted(_ context.Context, in *exproto.CheckPermRequest) (*exproto.CheckPermReply, error) {
func (v *Server) EnsurePermGranted(_ context.Context, in *proto.CheckPermRequest) (*proto.CheckPermResponse, error) {
claims, err := services.DecodeJwt(in.GetToken())
if err != nil {
return nil, err
@ -65,7 +66,26 @@ func (v *Server) EnsurePermGranted(_ context.Context, in *exproto.CheckPermReque
perms := services.FilterPermNodes(heldPerms, ctx.Ticket.Claims)
valid := services.HasPermNode(perms, in.GetKey(), value)
return &exproto.CheckPermReply{
return &proto.CheckPermResponse{
IsValid: valid,
}, nil
}
func (v *Server) EnsureUserPermGranted(_ context.Context, in *proto.CheckUserPermRequest) (*proto.CheckUserPermResponse, error) {
relation, err := services.GetRelationWithTwoNode(uint(in.GetUserId()), uint(in.GetOtherId()))
if err != nil {
return &proto.CheckUserPermResponse{
IsValid: false,
}, nil
}
defaultPerm := relation.Status == models.RelationshipFriend
var value any
_ = jsoniter.Unmarshal(in.GetValue(), &value)
valid := services.HasPermNodeWithDefault(relation.PermNodes, in.GetKey(), value, defaultPerm)
return &proto.CheckUserPermResponse{
IsValid: valid,
}, nil
}

View File

@ -1,46 +0,0 @@
package grpc
import (
"context"
"fmt"
"git.solsynth.dev/hydrogen/passport/pkg/internal/models"
"git.solsynth.dev/hydrogen/passport/pkg/internal/services"
"git.solsynth.dev/hydrogen/passport/pkg/proto"
"github.com/samber/lo"
)
func (v *Server) ListFriendship(_ context.Context, request *proto.FriendshipLookupRequest) (*proto.ListFriendshipResponse, error) {
account, err := services.GetAccount(uint(request.GetAccountId()))
if err != nil {
return nil, err
}
friends, err := services.ListFriend(account, models.FriendshipStatus(request.GetStatus()))
if err != nil {
return nil, err
}
return &proto.ListFriendshipResponse{
Data: lo.Map(friends, func(item models.AccountFriendship, index int) *proto.FriendshipResponse {
return &proto.FriendshipResponse{
AccountId: uint64(item.AccountID),
RelatedId: uint64(item.RelatedID),
Status: uint32(item.Status),
}
}),
}, nil
}
func (v *Server) GetFriendship(ctx context.Context, request *proto.FriendshipTwoSideLookupRequest) (*proto.FriendshipResponse, error) {
friend, err := services.GetFriendWithTwoSides(uint(request.GetAccountId()), uint(request.GetRelatedId()))
if err != nil {
return nil, err
} else if friend.Status != models.FriendshipStatus(request.GetStatus()) {
return nil, fmt.Errorf("status mismatch")
}
return &proto.FriendshipResponse{
AccountId: uint64(friend.AccountID),
RelatedId: uint64(friend.RelatedID),
Status: uint32(friend.Status),
}, nil
}

View File

@ -0,0 +1,47 @@
package grpc
import (
"context"
"fmt"
jsoniter "github.com/json-iterator/go"
"git.solsynth.dev/hydrogen/dealer/pkg/proto"
"git.solsynth.dev/hydrogen/passport/pkg/internal/models"
"git.solsynth.dev/hydrogen/passport/pkg/internal/services"
)
func (v *Server) NotifyUser(_ context.Context, in *proto.NotifyUserRequest) (*proto.NotifyResponse, error) {
var err error
var user models.Account
if user, err = services.GetAccount(uint(in.GetUserId())); err != nil {
return nil, fmt.Errorf("unable to get account: %v", err)
}
var metadata map[string]any
_ = jsoniter.Unmarshal(in.GetNotify().GetMetadata(), &metadata)
notification := models.Notification{
Topic: in.GetNotify().GetTopic(),
Title: in.GetNotify().GetTitle(),
Subtitle: in.GetNotify().Subtitle,
Body: in.GetNotify().GetBody(),
Metadata: metadata,
IsRealtime: in.GetNotify().GetIsRealtime(),
IsForcePush: in.GetNotify().GetIsForcePush(),
UserID: user.ID,
}
if notification.IsRealtime {
if err := services.PushNotification(notification); err != nil {
return nil, err
}
} else {
if err := services.NewNotification(notification); err != nil {
return nil, err
}
}
return &proto.NotifyResponse{
IsSuccess: true,
}, nil
}

View File

@ -1,57 +0,0 @@
package grpc
import (
"context"
jsoniter "github.com/json-iterator/go"
"git.solsynth.dev/hydrogen/passport/pkg/internal/models"
"git.solsynth.dev/hydrogen/passport/pkg/internal/services"
"git.solsynth.dev/hydrogen/passport/pkg/proto"
"github.com/samber/lo"
)
func (v *Server) NotifyUser(_ context.Context, in *proto.NotifyRequest) (*proto.NotifyReply, error) {
client, err := services.GetThirdClientWithSecret(in.GetClientId(), in.GetClientSecret())
if err != nil {
return nil, err
}
var user models.Account
if user, err = services.GetAccount(uint(in.GetRecipientId())); err != nil {
return nil, err
}
var metadata map[string]any
_ = jsoniter.Unmarshal(in.GetMetadata(), &metadata)
links := lo.Map(in.GetLinks(), func(item *proto.NotifyLink, index int) models.NotificationLink {
return models.NotificationLink{
Label: item.Label,
Url: item.Url,
}
})
notification := models.Notification{
Type: lo.Ternary(len(in.GetType()) > 0, in.GetType(), "common"),
Subject: in.GetSubject(),
Content: in.GetContent(),
Metadata: metadata,
Links: links,
IsRealtime: in.GetIsRealtime(),
IsForcePush: in.GetIsForcePush(),
RecipientID: user.ID,
SenderID: &client.ID,
}
if in.GetIsRealtime() {
if err := services.PushNotification(notification); err != nil {
return nil, err
}
} else {
if err := services.NewNotification(notification); err != nil {
return nil, err
}
}
return &proto.NotifyReply{IsSent: true}, nil
}

View File

@ -3,23 +3,22 @@ package grpc
import (
"context"
"fmt"
"git.solsynth.dev/hydrogen/dealer/pkg/proto"
"git.solsynth.dev/hydrogen/passport/pkg/internal/database"
"git.solsynth.dev/hydrogen/passport/pkg/internal/models"
"git.solsynth.dev/hydrogen/passport/pkg/internal/services"
"git.solsynth.dev/hydrogen/passport/pkg/proto"
"github.com/samber/lo"
"google.golang.org/protobuf/types/known/emptypb"
)
func (v *Server) ListCommunityRealm(ctx context.Context, empty *emptypb.Empty) (*proto.ListRealmResponse, error) {
func (v *Server) ListCommunityRealm(ctx context.Context, empty *proto.ListRealmRequest) (*proto.ListRealmResponse, error) {
realms, err := services.ListCommunityRealm()
if err != nil {
return nil, err
}
return &proto.ListRealmResponse{
Data: lo.Map(realms, func(item models.Realm, index int) *proto.RealmResponse {
return &proto.RealmResponse{
Data: lo.Map(realms, func(item models.Realm, index int) *proto.RealmInfo {
return &proto.RealmInfo{
Id: uint64(item.ID),
Alias: item.Alias,
Name: item.Name,
@ -31,7 +30,7 @@ func (v *Server) ListCommunityRealm(ctx context.Context, empty *emptypb.Empty) (
}, nil
}
func (v *Server) ListAvailableRealm(ctx context.Context, request *proto.RealmLookupWithUserRequest) (*proto.ListRealmResponse, error) {
func (v *Server) ListAvailableRealm(ctx context.Context, request *proto.LookupUserRealmRequest) (*proto.ListRealmResponse, error) {
account, err := services.GetAccount(uint(request.GetUserId()))
if err != nil {
return nil, fmt.Errorf("unable to find target account: %v", err)
@ -42,8 +41,8 @@ func (v *Server) ListAvailableRealm(ctx context.Context, request *proto.RealmLoo
}
return &proto.ListRealmResponse{
Data: lo.Map(realms, func(item models.Realm, index int) *proto.RealmResponse {
return &proto.RealmResponse{
Data: lo.Map(realms, func(item models.Realm, index int) *proto.RealmInfo {
return &proto.RealmInfo{
Id: uint64(item.ID),
Alias: item.Alias,
Name: item.Name,
@ -55,7 +54,7 @@ func (v *Server) ListAvailableRealm(ctx context.Context, request *proto.RealmLoo
}, nil
}
func (v *Server) ListOwnedRealm(ctx context.Context, request *proto.RealmLookupWithUserRequest) (*proto.ListRealmResponse, error) {
func (v *Server) ListOwnedRealm(ctx context.Context, request *proto.LookupUserRealmRequest) (*proto.ListRealmResponse, error) {
account, err := services.GetAccount(uint(request.GetUserId()))
if err != nil {
return nil, fmt.Errorf("unable to find target account: %v", err)
@ -66,8 +65,8 @@ func (v *Server) ListOwnedRealm(ctx context.Context, request *proto.RealmLookupW
}
return &proto.ListRealmResponse{
Data: lo.Map(realms, func(item models.Realm, index int) *proto.RealmResponse {
return &proto.RealmResponse{
Data: lo.Map(realms, func(item models.Realm, index int) *proto.RealmInfo {
return &proto.RealmInfo{
Id: uint64(item.ID),
Alias: item.Alias,
Name: item.Name,
@ -79,7 +78,7 @@ func (v *Server) ListOwnedRealm(ctx context.Context, request *proto.RealmLookupW
}, nil
}
func (v *Server) GetRealm(ctx context.Context, request *proto.RealmLookupRequest) (*proto.RealmResponse, error) {
func (v *Server) GetRealm(ctx context.Context, request *proto.LookupRealmRequest) (*proto.RealmInfo, error) {
var realm models.Realm
tx := database.C.Model(&models.Realm{})
@ -100,7 +99,7 @@ func (v *Server) GetRealm(ctx context.Context, request *proto.RealmLookupRequest
return nil, err
}
return &proto.RealmResponse{
return &proto.RealmInfo{
Id: uint64(realm.ID),
Alias: realm.Alias,
Name: realm.Name,
@ -122,8 +121,8 @@ func (v *Server) ListRealmMember(ctx context.Context, request *proto.RealmMember
}
return &proto.ListRealmMemberResponse{
Data: lo.Map(members, func(item models.RealmMember, index int) *proto.RealmMemberResponse {
return &proto.RealmMemberResponse{
Data: lo.Map(members, func(item models.RealmMember, index int) *proto.MemberInfo {
return &proto.MemberInfo{
RealmId: uint64(item.RealmID),
UserId: uint64(item.AccountID),
PowerLevel: int32(item.PowerLevel),
@ -132,7 +131,7 @@ func (v *Server) ListRealmMember(ctx context.Context, request *proto.RealmMember
}, nil
}
func (v *Server) GetRealmMember(ctx context.Context, request *proto.RealmMemberLookupRequest) (*proto.RealmMemberResponse, error) {
func (v *Server) GetRealmMember(ctx context.Context, request *proto.RealmMemberLookupRequest) (*proto.MemberInfo, error) {
var member models.RealmMember
tx := database.C.Where("realm_id = ?", request.GetRealmId())
if request.UserId != nil {
@ -143,9 +142,26 @@ func (v *Server) GetRealmMember(ctx context.Context, request *proto.RealmMemberL
return nil, err
}
return &proto.RealmMemberResponse{
return &proto.MemberInfo{
RealmId: uint64(member.RealmID),
UserId: uint64(member.AccountID),
PowerLevel: int32(member.PowerLevel),
}, nil
}
func (v *Server) CheckRealmMemberPerm(ctx context.Context, request *proto.CheckRealmPermRequest) (*proto.CheckRealmPermResponse, error) {
var member models.RealmMember
tx := database.C.
Where("realm_id = ?", request.GetRealmId()).
Where("account_id = ?", request.GetUserId())
if err := tx.First(&member).Error; err != nil {
return &proto.CheckRealmPermResponse{
IsSuccess: false,
}, nil
}
return &proto.CheckRealmPermResponse{
IsSuccess: member.PowerLevel >= int(request.GetPowerLevel()),
}, nil
}

View File

@ -4,8 +4,7 @@ import (
"google.golang.org/grpc/reflection"
"net"
exproto "git.solsynth.dev/hydrogen/dealer/pkg/proto"
"git.solsynth.dev/hydrogen/passport/pkg/proto"
"git.solsynth.dev/hydrogen/dealer/pkg/proto"
"github.com/spf13/viper"
"google.golang.org/grpc"
)
@ -13,10 +12,9 @@ import (
import health "google.golang.org/grpc/health/grpc_health_v1"
type Server struct {
exproto.UnimplementedAuthServer
proto.UnimplementedNotifyServer
proto.UnimplementedFriendshipsServer
proto.UnimplementedRealmsServer
proto.UnimplementedAuthServer
proto.UnimplementedNotifierServer
proto.UnimplementedRealmServer
health.UnimplementedHealthServer
srv *grpc.Server
@ -27,11 +25,10 @@ func NewServer() *Server {
srv: grpc.NewServer(),
}
exproto.RegisterAuthServer(server.srv, &Server{})
proto.RegisterNotifyServer(server.srv, &Server{})
proto.RegisterFriendshipsServer(server.srv, &Server{})
proto.RegisterRealmsServer(server.srv, &Server{})
health.RegisterHealthServer(server.srv, &Server{})
proto.RegisterAuthServer(server.srv, server)
proto.RegisterNotifierServer(server.srv, server)
proto.RegisterRealmServer(server.srv, server)
health.RegisterHealthServer(server.srv, server)
reflection.Register(server.srv)