2024-08-11 03:51:22 +02:00
|
|
|
package svc_impls
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"github.com/google/uuid"
|
|
|
|
|
"github.com/lysand-org/versia-go/internal/repository"
|
|
|
|
|
"github.com/lysand-org/versia-go/internal/service"
|
2024-08-22 23:03:38 +02:00
|
|
|
"github.com/lysand-org/versia-go/pkg/versia"
|
2024-08-11 03:51:22 +02:00
|
|
|
|
|
|
|
|
"git.devminer.xyz/devminer/unitel"
|
|
|
|
|
"github.com/go-logr/logr"
|
|
|
|
|
"github.com/lysand-org/versia-go/ent"
|
|
|
|
|
"github.com/lysand-org/versia-go/ent/user"
|
|
|
|
|
"github.com/lysand-org/versia-go/internal/api_schema"
|
|
|
|
|
"github.com/lysand-org/versia-go/internal/entity"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var _ service.InboxService = (*InboxServiceImpl)(nil)
|
|
|
|
|
|
|
|
|
|
type InboxServiceImpl struct {
|
|
|
|
|
federationService service.FederationService
|
|
|
|
|
|
2024-08-20 22:43:26 +02:00
|
|
|
repositories repository.Manager
|
|
|
|
|
|
2024-08-11 03:51:22 +02:00
|
|
|
telemetry *unitel.Telemetry
|
|
|
|
|
log logr.Logger
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-20 22:43:26 +02:00
|
|
|
func NewInboxService(federationService service.FederationService, repositories repository.Manager, telemetry *unitel.Telemetry, log logr.Logger) *InboxServiceImpl {
|
2024-08-11 03:51:22 +02:00
|
|
|
return &InboxServiceImpl{
|
|
|
|
|
federationService: federationService,
|
2024-08-20 22:43:26 +02:00
|
|
|
|
|
|
|
|
repositories: repositories,
|
|
|
|
|
|
|
|
|
|
telemetry: telemetry,
|
|
|
|
|
log: log,
|
2024-08-11 03:51:22 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (i InboxServiceImpl) WithRepositories(repositories repository.Manager) service.InboxService {
|
2024-08-20 22:43:26 +02:00
|
|
|
return NewInboxService(i.federationService, repositories, i.telemetry, i.log)
|
2024-08-11 03:51:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (i InboxServiceImpl) Handle(ctx context.Context, obj any, userId uuid.UUID) error {
|
2024-08-20 22:43:26 +02:00
|
|
|
s := i.telemetry.StartSpan(ctx, "function", "svc_impls/InboxServiceImpl.Handle")
|
2024-08-11 03:51:22 +02:00
|
|
|
defer s.End()
|
|
|
|
|
ctx = s.Context()
|
|
|
|
|
|
|
|
|
|
return i.repositories.Atomic(ctx, func(ctx context.Context, tx repository.Manager) error {
|
|
|
|
|
i := i.WithRepositories(tx).(*InboxServiceImpl)
|
|
|
|
|
|
|
|
|
|
u, err := i.repositories.Users().GetLocalByID(ctx, userId)
|
|
|
|
|
if err != nil {
|
|
|
|
|
i.log.Error(err, "Failed to get user", "id", userId)
|
|
|
|
|
|
|
|
|
|
return api_schema.ErrInternalServerError(nil)
|
|
|
|
|
}
|
|
|
|
|
if u == nil {
|
|
|
|
|
return api_schema.ErrNotFound(map[string]any{
|
|
|
|
|
"id": userId,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: Implement more types
|
|
|
|
|
switch o := obj.(type) {
|
2024-08-22 23:03:38 +02:00
|
|
|
case versia.Note:
|
2024-08-11 03:51:22 +02:00
|
|
|
i.log.Info("Received note", "note", o)
|
|
|
|
|
if err := i.handleNote(ctx, o, u); err != nil {
|
|
|
|
|
i.log.Error(err, "Failed to handle note", "note", o)
|
|
|
|
|
return err
|
|
|
|
|
}
|
2024-08-22 23:03:38 +02:00
|
|
|
case versia.Follow:
|
2024-08-11 03:51:22 +02:00
|
|
|
if err := i.handleFollow(ctx, o, u); err != nil {
|
|
|
|
|
i.log.Error(err, "Failed to handle follow", "follow", o)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
i.log.Info("Unimplemented object type", "object", obj)
|
|
|
|
|
return api_schema.ErrNotImplemented(nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-22 23:03:38 +02:00
|
|
|
func (i InboxServiceImpl) handleFollow(ctx context.Context, o versia.Follow, u *entity.User) error {
|
2024-08-20 22:43:26 +02:00
|
|
|
s := i.telemetry.StartSpan(ctx, "function", "svc_impls/InboxServiceImpl.handleFollow")
|
2024-08-11 03:51:22 +02:00
|
|
|
defer s.End()
|
|
|
|
|
ctx = s.Context()
|
|
|
|
|
|
|
|
|
|
author, err := i.repositories.Users().Resolve(ctx, o.Author)
|
|
|
|
|
if err != nil {
|
|
|
|
|
i.log.Error(err, "Failed to resolve author", "author", o.Author)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
f, err := i.repositories.Follows().Follow(ctx, author, u)
|
|
|
|
|
if err != nil {
|
|
|
|
|
// TODO: Handle constraint errors
|
|
|
|
|
if ent.IsConstraintError(err) {
|
|
|
|
|
i.log.Error(err, "Follow already exists", "user", user.ID, "author", author.ID)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
i.log.Error(err, "Failed to create follow", "user", user.ID, "author", author.ID)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch u.PrivacyLevel {
|
|
|
|
|
case user.PrivacyLevelPublic:
|
|
|
|
|
if err := i.repositories.Follows().AcceptFollow(ctx, author, u); err != nil {
|
|
|
|
|
i.log.Error(err, "Failed to accept follow", "user", user.ID, "author", author.ID)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-27 19:59:12 +02:00
|
|
|
if _, err := i.federationService.SendToInbox(ctx, u, author, f.ToVersiaAccept()); err != nil {
|
2024-08-11 03:51:22 +02:00
|
|
|
i.log.Error(err, "Failed to send follow accept to inbox", "user", user.ID, "author", author.ID)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case user.PrivacyLevelRestricted:
|
|
|
|
|
case user.PrivacyLevelPrivate:
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-22 23:03:38 +02:00
|
|
|
func (i InboxServiceImpl) handleNote(ctx context.Context, o versia.Note, u *entity.User) error {
|
2024-08-20 22:43:26 +02:00
|
|
|
s := i.telemetry.StartSpan(ctx, "function", "svc_impls/InboxServiceImpl.handleNote")
|
2024-08-11 03:51:22 +02:00
|
|
|
defer s.End()
|
|
|
|
|
ctx = s.Context()
|
|
|
|
|
|
|
|
|
|
author, err := i.repositories.Users().Resolve(ctx, o.Author)
|
|
|
|
|
if err != nil {
|
|
|
|
|
i.log.Error(err, "Failed to resolve author", "author", o.Author)
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: Implement
|
|
|
|
|
|
|
|
|
|
_ = author
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|