🎨 Update project structure
This commit is contained in:
70
pkg/internal/grpc/auth.go
Normal file
70
pkg/internal/grpc/auth.go
Normal file
@ -0,0 +1,70 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/grpc/proto"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/services"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
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 &proto.AuthReply{
|
||||
IsValid: false,
|
||||
}, nil
|
||||
} else {
|
||||
user := ctx.Account
|
||||
rawPerms, _ := jsoniter.Marshal(perms)
|
||||
|
||||
userinfo := &proto.Userinfo{
|
||||
Id: uint64(user.ID),
|
||||
Name: user.Name,
|
||||
Nick: user.Nick,
|
||||
Email: user.GetPrimaryEmail().Content,
|
||||
Description: &user.Description,
|
||||
}
|
||||
|
||||
if user.Avatar != nil {
|
||||
userinfo.Avatar = *user.GetAvatar()
|
||||
}
|
||||
if user.Banner != nil {
|
||||
userinfo.Banner = *user.GetBanner()
|
||||
}
|
||||
|
||||
return &proto.AuthReply{
|
||||
IsValid: true,
|
||||
AccessToken: &atk,
|
||||
RefreshToken: &rtk,
|
||||
Permissions: rawPerms,
|
||||
TicketId: lo.ToPtr(uint64(ctx.Ticket.ID)),
|
||||
Userinfo: userinfo,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (v *Server) CheckPerm(_ context.Context, in *proto.CheckPermRequest) (*proto.CheckPermReply, error) {
|
||||
claims, err := services.DecodeJwt(in.GetToken())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ctx, err := services.GetAuthContext(claims.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var heldPerms map[string]any
|
||||
rawHeldPerms, _ := jsoniter.Marshal(ctx.Account.PermNodes)
|
||||
_ = jsoniter.Unmarshal(rawHeldPerms, &heldPerms)
|
||||
|
||||
var value any
|
||||
_ = jsoniter.Unmarshal(in.GetValue(), &value)
|
||||
perms := services.FilterPermNodes(heldPerms, ctx.Ticket.Claims)
|
||||
valid := services.HasPermNode(perms, in.GetKey(), value)
|
||||
|
||||
return &proto.CheckPermReply{
|
||||
IsValid: valid,
|
||||
}, nil
|
||||
}
|
21
pkg/internal/grpc/client.go
Normal file
21
pkg/internal/grpc/client.go
Normal file
@ -0,0 +1,21 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
pcpb "git.solsynth.dev/hydrogen/paperclip/pkg/grpc/proto"
|
||||
"github.com/spf13/viper"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
)
|
||||
|
||||
var Attachments pcpb.AttachmentsClient
|
||||
|
||||
func ConnectPaperclip() error {
|
||||
addr := viper.GetString("paperclip.grpc_endpoint")
|
||||
if conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials())); err != nil {
|
||||
return err
|
||||
} else {
|
||||
Attachments = pcpb.NewAttachmentsClient(conn)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
46
pkg/internal/grpc/friendships.go
Normal file
46
pkg/internal/grpc/friendships.go
Normal file
@ -0,0 +1,46 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/grpc/proto"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/models"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/services"
|
||||
"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
|
||||
}
|
57
pkg/internal/grpc/notify.go
Normal file
57
pkg/internal/grpc/notify.go
Normal file
@ -0,0 +1,57 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/grpc/proto"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/models"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/services"
|
||||
"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
|
||||
}
|
151
pkg/internal/grpc/realms.go
Normal file
151
pkg/internal/grpc/realms.go
Normal file
@ -0,0 +1,151 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/database"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/models"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/proto"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/services"
|
||||
"github.com/samber/lo"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
)
|
||||
|
||||
func (v *Server) ListCommunityRealm(ctx context.Context, empty *emptypb.Empty) (*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{
|
||||
Id: uint64(item.ID),
|
||||
Alias: item.Alias,
|
||||
Name: item.Name,
|
||||
Description: item.Description,
|
||||
IsPublic: item.IsPublic,
|
||||
IsCommunity: item.IsCommunity,
|
||||
}
|
||||
}),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (v *Server) ListAvailableRealm(ctx context.Context, request *proto.RealmLookupWithUserRequest) (*proto.ListRealmResponse, error) {
|
||||
account, err := services.GetAccount(uint(request.GetUserId()))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to find target account: %v", err)
|
||||
}
|
||||
realms, err := services.ListAvailableRealm(account)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &proto.ListRealmResponse{
|
||||
Data: lo.Map(realms, func(item models.Realm, index int) *proto.RealmResponse {
|
||||
return &proto.RealmResponse{
|
||||
Id: uint64(item.ID),
|
||||
Alias: item.Alias,
|
||||
Name: item.Name,
|
||||
Description: item.Description,
|
||||
IsPublic: item.IsPublic,
|
||||
IsCommunity: item.IsCommunity,
|
||||
}
|
||||
}),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (v *Server) ListOwnedRealm(ctx context.Context, request *proto.RealmLookupWithUserRequest) (*proto.ListRealmResponse, error) {
|
||||
account, err := services.GetAccount(uint(request.GetUserId()))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to find target account: %v", err)
|
||||
}
|
||||
realms, err := services.ListOwnedRealm(account)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &proto.ListRealmResponse{
|
||||
Data: lo.Map(realms, func(item models.Realm, index int) *proto.RealmResponse {
|
||||
return &proto.RealmResponse{
|
||||
Id: uint64(item.ID),
|
||||
Alias: item.Alias,
|
||||
Name: item.Name,
|
||||
Description: item.Description,
|
||||
IsPublic: item.IsPublic,
|
||||
IsCommunity: item.IsCommunity,
|
||||
}
|
||||
}),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (v *Server) GetRealm(ctx context.Context, request *proto.RealmLookupRequest) (*proto.RealmResponse, error) {
|
||||
var realm models.Realm
|
||||
|
||||
tx := database.C.Model(&models.Realm{})
|
||||
if request.Id != nil {
|
||||
tx = tx.Where("id = ?", request.GetId())
|
||||
}
|
||||
if request.Alias != nil {
|
||||
tx = tx.Where("alias = ?", request.GetAlias())
|
||||
}
|
||||
if request.IsPublic != nil {
|
||||
tx = tx.Where("is_public = ?", request.GetIsPublic())
|
||||
}
|
||||
if request.IsCommunity != nil {
|
||||
tx = tx.Where("is_community = ?", request.GetIsCommunity())
|
||||
}
|
||||
|
||||
if err := tx.First(&realm).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &proto.RealmResponse{
|
||||
Id: uint64(realm.ID),
|
||||
Alias: realm.Alias,
|
||||
Name: realm.Name,
|
||||
Description: realm.Description,
|
||||
IsPublic: realm.IsPublic,
|
||||
IsCommunity: realm.IsCommunity,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (v *Server) ListRealmMember(ctx context.Context, request *proto.RealmMemberLookupRequest) (*proto.ListRealmMemberResponse, error) {
|
||||
var members []models.RealmMember
|
||||
tx := database.C.Where("realm_id = ?", request.GetRealmId())
|
||||
if request.UserId != nil {
|
||||
tx = tx.Where("account_id = ?", request.GetUserId())
|
||||
}
|
||||
|
||||
if err := tx.Find(&members).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &proto.ListRealmMemberResponse{
|
||||
Data: lo.Map(members, func(item models.RealmMember, index int) *proto.RealmMemberResponse {
|
||||
return &proto.RealmMemberResponse{
|
||||
RealmId: uint64(item.RealmID),
|
||||
UserId: uint64(item.AccountID),
|
||||
PowerLevel: int32(item.PowerLevel),
|
||||
}
|
||||
}),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (v *Server) GetRealmMember(ctx context.Context, request *proto.RealmMemberLookupRequest) (*proto.RealmMemberResponse, error) {
|
||||
var member models.RealmMember
|
||||
tx := database.C.Where("realm_id = ?", request.GetRealmId())
|
||||
if request.UserId != nil {
|
||||
tx = tx.Where("account_id = ?", request.GetUserId())
|
||||
}
|
||||
|
||||
if err := tx.First(&member).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &proto.RealmMemberResponse{
|
||||
RealmId: uint64(member.RealmID),
|
||||
UserId: uint64(member.AccountID),
|
||||
PowerLevel: int32(member.PowerLevel),
|
||||
}, nil
|
||||
}
|
35
pkg/internal/grpc/server.go
Normal file
35
pkg/internal/grpc/server.go
Normal file
@ -0,0 +1,35 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/grpc/proto"
|
||||
"github.com/spf13/viper"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/reflection"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
proto.UnimplementedAuthServer
|
||||
proto.UnimplementedNotifyServer
|
||||
proto.UnimplementedFriendshipsServer
|
||||
proto.UnimplementedRealmsServer
|
||||
}
|
||||
|
||||
func StartGrpc() error {
|
||||
listen, err := net.Listen("tcp", viper.GetString("grpc_bind"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
server := grpc.NewServer()
|
||||
|
||||
proto.RegisterAuthServer(server, &Server{})
|
||||
proto.RegisterNotifyServer(server, &Server{})
|
||||
proto.RegisterFriendshipsServer(server, &Server{})
|
||||
proto.RegisterRealmsServer(server, &Server{})
|
||||
|
||||
reflection.Register(server)
|
||||
|
||||
return server.Serve(listen)
|
||||
}
|
Reference in New Issue
Block a user