relationships

package
v1.1.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 13, 2026 License: AGPL-3.0 Imports: 16 Imported by: 0

README

Relationships Service

The Relationships Service handles all relationship operations in the Lesser ActivityPub implementation, including follows, blocks, mutes, and relationship status management. This service is part of Phase 2.3 of the API Alignment Implementation.

Features

Core Operations
  • Follow/Unfollow: Handle follow relationships with support for locked accounts and follow requests
  • Block/Unblock: Block users with automatic unfollowing and privacy-aware events
  • Mute/Unmute: Mute users to hide from timelines with optional duration support
  • Relationship Status: Query comprehensive relationship data between users
Advanced Features
  • Follow Requests: Full support for locked accounts requiring follow approval
  • Mutual Relationship Detection: Detect and report mutual follows
  • Privacy Controls: Privacy-aware event emission (blocks/mutes only to actor's stream)
  • Batch Queries: Support for querying multiple relationship statuses efficiently
  • Federation Support: Queue ActivityPub activities for remote users

Architecture

Service Dependencies
type Service struct {
    relationshipRepo interfaces.RelationshipRepository
    accountRepo      interfaces.AccountRepository
    publisher        streaming.Publisher
    federation       FederationService
    logger           *zap.Logger
    domainName       string
}
Command Pattern

The service follows the established command pattern with structured input validation:

  • FollowCommand - Follow a user with options for reblogs and notifications
  • UnfollowCommand - Unfollow a user
  • BlockCommand - Block a user with optional reason
  • UnblockCommand - Unblock a user
  • MuteCommand - Mute a user with optional duration and notification settings
  • UnmuteCommand - Unmute a user
Result Pattern

All operations return structured results with relationship data and emitted events:

  • RelationshipResult - Single relationship with events
  • RelationshipsResult - Multiple relationships (batch queries)
  • FollowResult - Follow-specific data including request ID for locked accounts

Usage Examples

Following a User
cmd := &relationships.FollowCommand{
    FollowerID:  "alice",
    FollowingID: "bob",
    ShowReblogs: true,
    Notify:      false,
}

result, err := service.Follow(ctx, cmd)
if err != nil {
    return err
}

if result.IsFollowing {
    log.Info("Now following user")
} else {
    log.Info("Follow request sent", "requestID", result.RequestID)
}
Blocking a User
cmd := &relationships.BlockCommand{
    BlockerID: "alice",
    BlockedID: "spam_user",
    Reason:    "spam and harassment",
}

result, err := service.Block(ctx, cmd)
if err != nil {
    return err
}

log.Info("User blocked", "blocking", result.Relationship.Blocking)
Getting Relationship Status
query := &relationships.GetRelationshipQuery{
    RequesterID: "alice",
    TargetID:    "bob",
}

relationship, err := service.GetRelationship(ctx, query)
if err != nil {
    return err
}

fmt.Printf("Following: %v, Followed by: %v, Blocked: %v\n",
    relationship.Following, relationship.FollowedBy, relationship.Blocking)
Batch Relationship Queries
query := &relationships.GetRelationshipsQuery{
    RequesterID: "alice",
    TargetIDs:   []string{"bob", "charlie", "diana"},
}

result, err := service.GetRelationships(ctx, query)
if err != nil {
    return err
}

for _, rel := range result.Relationships {
    fmt.Printf("User %s: following=%v, blocked=%v\n", 
        rel.ID, rel.Following, rel.Blocking)
}

Event System

The service emits structured events for real-time streaming:

Follow Events
  • relationship.follow_requested - Follow request sent (locked accounts)
  • relationship.follow_accepted - Follow request accepted
  • relationship.unfollowed - User unfollowed

Events are sent to both users' streams for follow operations.

Block Events
  • relationship.blocked - User blocked
  • relationship.unblocked - User unblocked

Events are sent only to the blocker's stream for privacy.

Mute Events
  • relationship.muted - User muted (with optional duration)
  • relationship.unmuted - User unmuted

Events are sent only to the muter's stream for privacy.

Federation Integration

The service automatically queues ActivityPub activities for remote users:

Follow Activities
{
  "@context": "https://www.w3.org/ns/activitystreams",
  "type": "Follow",
  "id": "https://example.com/activities/123",
  "actor": "https://example.com/users/alice",
  "object": "https://remote.com/users/bob"
}
Block Activities
{
  "@context": "https://www.w3.org/ns/activitystreams",
  "type": "Block",
  "id": "https://example.com/activities/456",
  "actor": "https://example.com/users/alice",
  "object": "https://remote.com/users/spammer"
}
Undo Activities
{
  "@context": "https://www.w3.org/ns/activitystreams",
  "type": "Undo",
  "id": "https://example.com/activities/789",
  "actor": "https://example.com/users/alice",
  "object": {
    "type": "Follow",
    "actor": "https://example.com/users/alice",
    "object": "https://remote.com/users/bob"
  }
}

Relationship Data Structure

The service returns comprehensive relationship information:

type RelationshipData struct {
    ID                  string    `json:"id"`                    // Target user ID
    Following           bool      `json:"following"`             // Following target
    ShowingReblogs      bool      `json:"showing_reblogs"`      // Show reblogs
    Notifying           bool      `json:"notifying"`            // Notify on posts
    Languages           []string  `json:"languages"`            // Language filter
    FollowedBy          bool      `json:"followed_by"`          // Followed by target
    Blocking            bool      `json:"blocking"`             // Blocking target
    BlockedBy           bool      `json:"blocked_by"`           // Blocked by target
    Muting              bool      `json:"muting"`               // Muting target
    MutingNotifications bool      `json:"muting_notifications"` // Muting notifications
    Requested           bool      `json:"requested"`            // Follow request sent
    RequestedBy         bool      `json:"requested_by"`         // Follow request received
    DomainBlocking      bool      `json:"domain_blocking"`      // Domain blocked
    Endorsed            bool      `json:"endorsed"`             // Endorsed user
    Note                string    `json:"note"`                 // Private note
    CreatedAt           time.Time `json:"created_at"`           // Relationship created
    UpdatedAt           time.Time `json:"updated_at"`           // Last updated
}

Business Logic

Follow Workflow
  1. Validation: Prevent self-follows, check user existence
  2. Existing Check: Return current status if already following
  3. Block Check: Reject if blocked by target user
  4. Follow Request: Create follow request in repository
  5. Approval Logic:
    • Public accounts: Auto-accept follow
    • Locked accounts: Leave pending for manual approval
  6. Events: Emit appropriate events based on approval status
  7. Federation: Queue ActivityPub Follow activity for remote users
Block Workflow
  1. Validation: Prevent self-blocks, check user existence
  2. Existing Check: Return current status if already blocked
  3. Auto-Unfollow: Remove existing follow relationships (both directions)
  4. Block Creation: Create block record in repository
  5. Events: Emit block event only to blocker's stream (privacy)
  6. Federation: Queue ActivityPub Block activity for remote users
Relationship Queries

The service builds comprehensive relationship data by querying:

  • Follow status in both directions
  • Block status in both directions
  • Mute status
  • Follow request status (pending/accepted/rejected)
  • Additional metadata (reblogs, notifications, etc.)

Error Handling

The service provides detailed error messages for various scenarios:

  • Validation Errors: Missing required fields, invalid data
  • Business Logic Errors: Self-actions, blocked users, etc.
  • Repository Errors: Database failures, constraint violations
  • Federation Errors: Remote delivery failures (logged, not propagated)

Testing

The service includes comprehensive test coverage:

  • Unit Tests: All public methods with mocked dependencies
  • Integration Tests: End-to-end workflows with real dependencies
  • Edge Cases: Error conditions, validation failures, race conditions
  • Mock Support: Full mock implementations for testing
Running Tests
go test ./pkg/services/relationships/...

Performance Considerations

Batch Operations
  • GetRelationships supports up to 40 relationships per query
  • Repository queries are optimized for DynamoDB single-table design
  • Relationship data is cached where appropriate
Event Publishing
  • Events are published asynchronously
  • Failed event delivery doesn't fail the operation
  • Event publishing includes retry logic and error logging
Federation Queuing
  • Federation activities are queued asynchronously
  • Failed federation delivery is logged but doesn't fail operations
  • Only remote users receive federation activities (local users filtered out)

Security & Privacy

Privacy Controls
  • Block Events: Only sent to blocker's stream, never to blocked user
  • Mute Events: Only sent to muter's stream, never to muted user
  • Follow Events: Sent to both users' streams as they're public actions
Access Control
  • Users can only modify their own relationships
  • Relationship queries show privacy-appropriate data
  • Blocked users cannot follow or interact
Data Validation
  • All commands are validated before processing
  • User existence is verified for all operations
  • Business logic prevents invalid state transitions

Integration with Other Services

Storage Layer
  • Uses RelationshipRepository for all relationship data operations
  • Uses AccountRepository for user existence checks and data
Streaming System
  • Publishes events via streaming.Publisher interface
  • Events follow established patterns for consistency
Federation System
  • Queues activities via FederationService interface
  • Activities follow ActivityPub specification

Monitoring & Logging

Structured Logging

All operations include structured logging with:

  • User IDs involved in the operation
  • Operation type and result
  • Timing information
  • Error details for debugging
Metrics

The service tracks:

  • Relationship operation counts by type
  • Success/failure rates
  • Event publishing success rates
  • Federation queuing success rates

Future Enhancements

Planned Features
  • Relationship Notes: Private notes on relationships
  • Endorsements: Public endorsements of users
  • Domain Blocking: Block entire domains
  • Temporary Mutes: Time-based muting with automatic expiration
  • Relationship Analytics: Statistics and insights
Performance Optimizations
  • Relationship Caching: Cache frequently accessed relationship data
  • Batch Event Publishing: Group multiple events for efficiency
  • Federation Batching: Batch federation activities where possible

Compatibility

This service is designed to be fully compatible with:

  • Mastodon API: All relationship endpoints match Mastodon behavior
  • ActivityPub: All federation activities follow AP specification
  • Lesser Architecture: Integrates with existing services and patterns

Documentation

Overview

Package relationships provides error handling utilities for relationship operations.

Package relationships provides the core Relationships Service for the Lesser project's API alignment. This service handles all relationship operations including follows, blocks, mutes, and relationship status management. It emits appropriate events for real-time streaming and queues federation activities for remote users.

Index

Constants

This section is empty.

Variables

View Source
var ErrFollowRequestNotFound = pkgerrors.NewAppError(pkgerrors.CodeNotFound, pkgerrors.CategoryBusiness, "follow request not found")

ErrFollowRequestNotFound is specific to relationships - keep as local error

View Source
var ErrFollowWhileBlocked = pkgerrors.BusinessRuleViolated("follow_while_blocked", map[string]interface{}{"reason": "user is blocked"})

ErrFollowWhileBlocked is a unique business rule - keep as local error

View Source
var ErrUnsupportedRelationType = pkgerrors.NewValidationError("relation_type", "unsupported")

ErrUnsupportedRelationType is specific to relationships - keep as local error

Functions

func CannotAcceptOwnFollowRequest

func CannotAcceptOwnFollowRequest() *pkgerrors.AppError

CannotAcceptOwnFollowRequest returns an error when trying to accept one's own follow request.

func CannotBlockSelf

func CannotBlockSelf() *pkgerrors.AppError

CannotBlockSelf returns an error when trying to block oneself.

func CannotFollowSelf

func CannotFollowSelf() *pkgerrors.AppError

CannotFollowSelf returns an error when trying to follow oneself.

func CannotMuteSelf

func CannotMuteSelf() *pkgerrors.AppError

CannotMuteSelf returns an error when trying to mute oneself.

func CannotRejectOwnFollowRequest

func CannotRejectOwnFollowRequest() *pkgerrors.AppError

CannotRejectOwnFollowRequest returns an error when trying to reject one's own follow request.

func CheckFollowingRelationship

func CheckFollowingRelationship(err error) *pkgerrors.AppError

CheckFollowingRelationship returns an error when failing to check following relationship.

func DomainBlockRepositoryNotAvailable

func DomainBlockRepositoryNotAvailable() *pkgerrors.AppError

DomainBlockRepositoryNotAvailable returns an error when domain block repository is not available.

func FailedToAcceptFollowRequest

func FailedToAcceptFollowRequest(err error) *pkgerrors.AppError

FailedToAcceptFollowRequest returns an error when failing to accept follow request.

func FailedToAddDomainBlock

func FailedToAddDomainBlock(err error) *pkgerrors.AppError

FailedToAddDomainBlock returns an error when failing to add domain block.

func FailedToBlockUser

func FailedToBlockUser(err error) *pkgerrors.AppError

FailedToBlockUser returns an error when failing to block user.

func FailedToBuildRelationshipData

func FailedToBuildRelationshipData(err error) *pkgerrors.AppError

FailedToBuildRelationshipData returns an error when failing to build relationship data.

func FailedToCheckBlockStatus

func FailedToCheckBlockStatus(err error) *pkgerrors.AppError

FailedToCheckBlockStatus returns an error when failing to check block status.

func FailedToCheckFollowStatus

func FailedToCheckFollowStatus(err error) *pkgerrors.AppError

FailedToCheckFollowStatus returns an error when failing to check follow status.

func FailedToCheckMuteStatus

func FailedToCheckMuteStatus(err error) *pkgerrors.AppError

FailedToCheckMuteStatus returns an error when failing to check mute status.

func FailedToCountFollowers

func FailedToCountFollowers(err error) *pkgerrors.AppError

FailedToCountFollowers returns an error when failing to count followers.

func FailedToCountFollowing

func FailedToCountFollowing(err error) *pkgerrors.AppError

FailedToCountFollowing returns an error when failing to count following.

func FailedToCreateFollowRequest

func FailedToCreateFollowRequest(err error) *pkgerrors.AppError

FailedToCreateFollowRequest returns an error when failing to create follow request.

func FailedToGetAccount

func FailedToGetAccount(err error) *pkgerrors.AppError

FailedToGetAccount returns an error when failing to get account.

func FailedToGetActor

func FailedToGetActor(err error) *pkgerrors.AppError

FailedToGetActor returns an error when failing to get actor.

func FailedToGetBlockedUsers

func FailedToGetBlockedUsers(err error) *pkgerrors.AppError

FailedToGetBlockedUsers returns an error when failing to get blocked users.

func FailedToGetDomainBlocks

func FailedToGetDomainBlocks(err error) *pkgerrors.AppError

FailedToGetDomainBlocks returns an error when failing to get domain blocks.

func FailedToGetExistingRelationship

func FailedToGetExistingRelationship(err error) *pkgerrors.AppError

FailedToGetExistingRelationship returns an error when failing to get existing relationship.

func FailedToGetMutedUsers

func FailedToGetMutedUsers(err error) *pkgerrors.AppError

FailedToGetMutedUsers returns an error when failing to get muted users.

func FailedToGetPendingFollowRequests

func FailedToGetPendingFollowRequests(err error) *pkgerrors.AppError

FailedToGetPendingFollowRequests returns an error when failing to get pending follow requests.

func FailedToGetRelationshipUsers

func FailedToGetRelationshipUsers(err error) *pkgerrors.AppError

FailedToGetRelationshipUsers returns an error when failing to get relationship users.

func FailedToGetUpdatedRelationship

func FailedToGetUpdatedRelationship(err error) *pkgerrors.AppError

FailedToGetUpdatedRelationship returns an error when failing to get updated relationship.

func FailedToMuteUser

func FailedToMuteUser(err error) *pkgerrors.AppError

FailedToMuteUser returns an error when failing to mute user.

func FailedToRejectFollowRequest

func FailedToRejectFollowRequest(err error) *pkgerrors.AppError

FailedToRejectFollowRequest returns an error when failing to reject follow request.

func FailedToRemoveDomainBlock

func FailedToRemoveDomainBlock(err error) *pkgerrors.AppError

FailedToRemoveDomainBlock returns an error when failing to remove domain block.

func FailedToUnblockUser

func FailedToUnblockUser(err error) *pkgerrors.AppError

FailedToUnblockUser returns an error when failing to unblock user.

func FailedToUnfollow

func FailedToUnfollow(err error) *pkgerrors.AppError

FailedToUnfollow returns an error when failing to unfollow.

func FailedToUnmuteUser

func FailedToUnmuteUser(err error) *pkgerrors.AppError

FailedToUnmuteUser returns an error when failing to unmute user.

func NoRepositoryOrStorage

func NoRepositoryOrStorage() *pkgerrors.AppError

NoRepositoryOrStorage returns an error when neither repository nor storage is available.

func RepositoryNotAvailable

func RepositoryNotAvailable(repoType string) *pkgerrors.AppError

RepositoryNotAvailable returns an error when a repository is not available.

func SocialRepositoryNotAvailable

func SocialRepositoryNotAvailable() *pkgerrors.AppError

SocialRepositoryNotAvailable returns an error when social repository is not available.

func StorageNotAvailable

func StorageNotAvailable() *pkgerrors.AppError

StorageNotAvailable returns an error when storage is not available.

func TargetIDsEmpty

func TargetIDsEmpty() *pkgerrors.AppError

TargetIDsEmpty returns an error when target IDs are empty.

func TooManyTargetIDs

func TooManyTargetIDs(count int) *pkgerrors.AppError

TooManyTargetIDs returns an error when too many target IDs are provided.

func ValidationFailed

func ValidationFailed() *pkgerrors.AppError

ValidationFailed returns an error when validation fails.

Types

type AcceptFollowRequestCommand

type AcceptFollowRequestCommand struct {
	RequesterID string `json:"requester_id" validate:"required"` // User accepting the request
	FollowerID  string `json:"follower_id" validate:"required"`  // User who sent the request
}

AcceptFollowRequestCommand contains data needed to accept a follow request

type AcknowledgeSeveranceCommand

type AcknowledgeSeveranceCommand struct {
	UserID      string `json:"user_id" validate:"required"`
	SeveranceID string `json:"severance_id" validate:"required"`
}

AcknowledgeSeveranceCommand contains data needed to acknowledge a severance

type AcknowledgeSeveranceResult

type AcknowledgeSeveranceResult struct {
	Success bool               `json:"success"`
	Events  []*streaming.Event `json:"events"`
}

AcknowledgeSeveranceResult contains the result of acknowledging a severance

type AddDomainBlockCommand

type AddDomainBlockCommand struct {
	UserID string `json:"user_id" validate:"required"`
	Domain string `json:"domain" validate:"required"`
}

AddDomainBlockCommand contains data needed to add a domain block

type AffectedRelationship

type AffectedRelationship struct {
	ID           string       `json:"id"`
	Type         string       `json:"type"`
	AffectedUser storage.User `json:"affected_user"`
}

AffectedRelationship represents a relationship affected by severance

type BlockCommand

type BlockCommand struct {
	BlockerID string `json:"blocker_id" validate:"required"`
	BlockedID string `json:"blocked_id" validate:"required"`
	Reason    string `json:"reason"` // Optional reason for blocking
}

BlockCommand contains all data needed to block a user

type BlockedUsersResult

type BlockedUsersResult struct {
	BlockedUsers []*storage.Account `json:"blocked_users"`
	NextCursor   string             `json:"next_cursor,omitempty"`
	Events       []*streaming.Event `json:"events"`
}

BlockedUsersResult contains blocked users data

type DomainBlocksResult

type DomainBlocksResult struct {
	Domains    []string           `json:"domains"`
	NextCursor string             `json:"next_cursor,omitempty"`
	Events     []*streaming.Event `json:"events"`
}

DomainBlocksResult contains domain blocks data

type FederationService

type FederationService interface {
	QueueActivity(ctx context.Context, activity *activitypub.Activity) error
}

FederationService defines the interface for federation operations

type FollowCommand

type FollowCommand struct {
	FollowerID  string   `json:"follower_id" validate:"required"`
	FollowingID string   `json:"following_id" validate:"required"`
	ShowReblogs bool     `json:"show_reblogs"` // Whether to show reblogs from this user
	Notify      bool     `json:"notify"`       // Whether to notify on new posts
	Languages   []string `json:"languages"`    // Filter to specific languages
}

FollowCommand contains all data needed to follow a user

type FollowRequestsResult

type FollowRequestsResult struct {
	FollowerIDs []string           `json:"follower_ids"`
	NextCursor  string             `json:"next_cursor,omitempty"`
	Events      []*streaming.Event `json:"events"`
}

FollowRequestsResult contains follow requests data

type FollowResult

type FollowResult struct {
	Relationship *RelationshipData     `json:"relationship"`
	RequestID    string                `json:"request_id,omitempty"` // If follow requires approval
	IsFollowing  bool                  `json:"is_following"`         // Whether follow was immediately accepted
	Events       []*streaming.Event    `json:"events"`
	Activity     *activitypub.Activity `json:"activity,omitempty"`
}

FollowResult contains follow-specific data and events

type FollowersResult

type FollowersResult struct {
	Followers  []*storage.Account `json:"followers"`
	NextCursor string             `json:"next_cursor,omitempty"`
	Events     []*streaming.Event `json:"events"`
}

FollowersResult contains followers data

type GetAffectedRelationshipsQuery

type GetAffectedRelationshipsQuery struct {
	UserID                string `json:"user_id" validate:"required"`
	SeveredRelationshipID string `json:"severed_relationship_id" validate:"required"`
}

GetAffectedRelationshipsQuery contains data needed to get affected relationships

type GetAffectedRelationshipsResult

type GetAffectedRelationshipsResult struct {
	Relationships   []*AffectedRelationship `json:"relationships"`
	HasNextPage     bool                    `json:"has_next_page"`
	HasPreviousPage bool                    `json:"has_previous_page"`
	Events          []*streaming.Event      `json:"events"`
}

GetAffectedRelationshipsResult contains the result of getting affected relationships

type GetBlockedUsersQuery

type GetBlockedUsersQuery struct {
	UserID string `json:"user_id" validate:"required"`
	Limit  int    `json:"limit"`
	Cursor string `json:"cursor"`
}

GetBlockedUsersQuery contains parameters for retrieving blocked users

type GetDomainBlocksQuery

type GetDomainBlocksQuery struct {
	UserID string `json:"user_id" validate:"required"`
	Limit  int    `json:"limit"`
	Cursor string `json:"cursor"`
}

GetDomainBlocksQuery contains parameters for retrieving domain blocks

type GetFollowRequestsQuery

type GetFollowRequestsQuery struct {
	UserID string `json:"user_id" validate:"required"`
	Limit  int    `json:"limit"`
	Cursor string `json:"cursor"`
}

GetFollowRequestsQuery contains parameters for retrieving pending follow requests

type GetFollowersQuery

type GetFollowersQuery struct {
	UserID string `json:"user_id" validate:"required"`
	Limit  int    `json:"limit"`
	Cursor string `json:"cursor"`
}

GetFollowersQuery contains parameters for retrieving followers

type GetMutedUsersQuery

type GetMutedUsersQuery struct {
	UserID string `json:"user_id" validate:"required"`
	Limit  int    `json:"limit"`
	Cursor string `json:"cursor"`
}

GetMutedUsersQuery contains parameters for retrieving muted users

type GetRelationshipQuery

type GetRelationshipQuery struct {
	RequesterID string `json:"requester_id" validate:"required"`
	TargetID    string `json:"target_id" validate:"required"`
}

GetRelationshipQuery contains parameters for retrieving relationship status

type GetRelationshipsQuery

type GetRelationshipsQuery struct {
	RequesterID string   `json:"requester_id" validate:"required"`
	TargetIDs   []string `json:"target_ids" validate:"required,max=40"`
}

GetRelationshipsQuery contains parameters for retrieving multiple relationship statuses

type MuteCommand

type MuteCommand struct {
	MuterID           string         `json:"muter_id" validate:"required"`
	MutedID           string         `json:"muted_id" validate:"required"`
	MuteNotifications bool           `json:"mute_notifications"` // Also mute notifications
	Duration          *time.Duration `json:"duration"`           // Optional duration, nil for indefinite
	Reason            string         `json:"reason"`             // Optional reason for muting
}

MuteCommand contains all data needed to mute a user

type MutedUsersResult

type MutedUsersResult struct {
	MutedUsers []*storage.Account `json:"muted_users"`
	NextCursor string             `json:"next_cursor,omitempty"`
	Events     []*streaming.Event `json:"events"`
}

MutedUsersResult contains muted users data

type RejectFollowRequestCommand

type RejectFollowRequestCommand struct {
	RequesterID string `json:"requester_id" validate:"required"` // User rejecting the request
	FollowerID  string `json:"follower_id" validate:"required"`  // User who sent the request
}

RejectFollowRequestCommand contains data needed to reject a follow request

type RelationshipData

type RelationshipData struct {
	ID                  string    `json:"id"`
	Following           bool      `json:"following"`
	ShowingReblogs      bool      `json:"showing_reblogs"`
	Notifying           bool      `json:"notifying"`
	Languages           []string  `json:"languages"`
	FollowedBy          bool      `json:"followed_by"`
	Blocking            bool      `json:"blocking"`
	BlockedBy           bool      `json:"blocked_by"`
	Muting              bool      `json:"muting"`
	MutingNotifications bool      `json:"muting_notifications"`
	Requested           bool      `json:"requested"`
	RequestedBy         bool      `json:"requested_by"`
	DomainBlocking      bool      `json:"domain_blocking"`
	Endorsed            bool      `json:"endorsed"`
	Note                string    `json:"note"`
	CreatedAt           time.Time `json:"created_at"`
	UpdatedAt           time.Time `json:"updated_at"`
}

RelationshipData contains comprehensive relationship information

type RelationshipResult

type RelationshipResult struct {
	Relationship *RelationshipData  `json:"relationship"`
	Events       []*streaming.Event `json:"events"`
}

RelationshipResult contains a relationship and associated events that were emitted

type RemoveDomainBlockCommand

type RemoveDomainBlockCommand struct {
	UserID string `json:"user_id" validate:"required"`
	Domain string `json:"domain" validate:"required"`
}

RemoveDomainBlockCommand contains data needed to remove a domain block

type Result

type Result struct {
	Relationships []*RelationshipData `json:"relationships"`
	Events        []*streaming.Event  `json:"events"`
}

Result contains multiple relationships

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service provides relationship operations

func NewService

func NewService(
	relationshipRepo interfaces.RelationshipRepository,
	accountRepo interfaces.AccountRepository,
	publisher streaming.Publisher,
	federation FederationService,
	logger *zap.Logger,
	domainName string,
) *Service

NewService creates a new Relationships Service with the required dependencies

func NewServiceWithStorage

func NewServiceWithStorage(
	storage core.RepositoryStorage,
	publisher streaming.Publisher,
	federation FederationService,
	logger *zap.Logger,
	domainName string,
) *Service

NewServiceWithStorage creates a new Relationships Service with full storage access

func (*Service) AcceptFollowRequest

func (s *Service) AcceptFollowRequest(ctx context.Context, cmd *AcceptFollowRequestCommand) (*RelationshipResult, error)

AcceptFollowRequest accepts a pending follow request

func (*Service) AcknowledgeSeverance

func (s *Service) AcknowledgeSeverance(ctx context.Context, cmd *AcknowledgeSeveranceCommand) (*AcknowledgeSeveranceResult, error)

AcknowledgeSeverance acknowledges a relationship severance

func (*Service) AddDomainBlock

func (s *Service) AddDomainBlock(ctx context.Context, cmd *AddDomainBlockCommand) error

AddDomainBlock adds a domain block for a user

func (*Service) Block

func (s *Service) Block(ctx context.Context, cmd *BlockCommand) (*RelationshipResult, error)

Block blocks a user, automatically unfollows, and emits events

func (*Service) CountFollowers

func (s *Service) CountFollowers(ctx context.Context, username string) (int64, error)

CountFollowers counts the number of followers for a user

func (*Service) CountFollowing

func (s *Service) CountFollowing(ctx context.Context, username string) (int64, error)

CountFollowing counts the number of users that an actor is following

func (*Service) Follow

func (s *Service) Follow(ctx context.Context, cmd *FollowCommand) (*FollowResult, error)

Follow initiates a follow relationship, handling locked accounts and emitting events

func (*Service) GetAffectedRelationships

func (s *Service) GetAffectedRelationships(_ context.Context, query *GetAffectedRelationshipsQuery) (*GetAffectedRelationshipsResult, error)

GetAffectedRelationships retrieves relationships affected by a severance

func (*Service) GetBlockedUsers

func (s *Service) GetBlockedUsers(ctx context.Context, query *GetBlockedUsersQuery) (*BlockedUsersResult, error)

GetBlockedUsers retrieves blocked users for a user

func (*Service) GetDomainBlocks

func (s *Service) GetDomainBlocks(ctx context.Context, query *GetDomainBlocksQuery) (*DomainBlocksResult, error)

GetDomainBlocks retrieves domain blocks for a user

func (*Service) GetFollowers

func (s *Service) GetFollowers(ctx context.Context, username string, limit int, cursor string) ([]*storage.Account, string, error)

GetFollowers retrieves followers for a user

func (*Service) GetFollowing

func (s *Service) GetFollowing(ctx context.Context, username string, limit int, cursor string) ([]*storage.Account, string, error)

GetFollowing retrieves users being followed by a user

func (*Service) GetMutedUsers

func (s *Service) GetMutedUsers(ctx context.Context, query *GetMutedUsersQuery) (*MutedUsersResult, error)

GetMutedUsers retrieves muted users for a user

func (*Service) GetPendingFollowRequests

func (s *Service) GetPendingFollowRequests(ctx context.Context, query *GetFollowRequestsQuery) (*FollowRequestsResult, error)

GetPendingFollowRequests retrieves pending follow requests for a user

func (*Service) GetRelationship

func (s *Service) GetRelationship(ctx context.Context, requesterID, targetID string) (*RelationshipData, error)

GetRelationship retrieves relationship status between two users

func (*Service) GetRelationships

func (s *Service) GetRelationships(ctx context.Context, query *GetRelationshipsQuery) (*Result, error)

GetRelationships retrieves relationship statuses for multiple users

func (*Service) IsBlocked

func (s *Service) IsBlocked(ctx context.Context, blockerID, blockedID string) (bool, error)

IsBlocked checks if one user has blocked another

func (*Service) IsMuted

func (s *Service) IsMuted(ctx context.Context, muterID, mutedID string) (bool, error)

IsMuted checks if one user has muted another

func (*Service) Mute

func (s *Service) Mute(ctx context.Context, cmd *MuteCommand) (*RelationshipResult, error)

Mute mutes a user (hides from timelines) and emits events

func (*Service) RejectFollowRequest

func (s *Service) RejectFollowRequest(ctx context.Context, cmd *RejectFollowRequestCommand) (*RelationshipResult, error)

RejectFollowRequest rejects a pending follow request

func (*Service) RemoveDomainBlock

func (s *Service) RemoveDomainBlock(ctx context.Context, cmd *RemoveDomainBlockCommand) error

RemoveDomainBlock removes a domain block for a user

func (*Service) Unblock

func (s *Service) Unblock(ctx context.Context, cmd *UnblockCommand) (*RelationshipResult, error)

Unblock removes a user block and emits events

func (*Service) Unfollow

func (s *Service) Unfollow(ctx context.Context, cmd *UnfollowCommand) (*RelationshipResult, error)

Unfollow removes a follow relationship and emits events

func (*Service) Unmute

func (s *Service) Unmute(ctx context.Context, cmd *UnmuteCommand) (*RelationshipResult, error)

Unmute removes a user mute and emits events

func (*Service) UpdateRelationship

func (s *Service) UpdateRelationship(ctx context.Context, cmd *UpdateRelationshipCommand) (*RelationshipData, error)

UpdateRelationship updates preferences for an existing relationship

type UnblockCommand

type UnblockCommand struct {
	BlockerID string `json:"blocker_id" validate:"required"`
	BlockedID string `json:"blocked_id" validate:"required"`
}

UnblockCommand contains all data needed to unblock a user

type UnfollowCommand

type UnfollowCommand struct {
	FollowerID  string `json:"follower_id" validate:"required"`
	FollowingID string `json:"following_id" validate:"required"`
}

UnfollowCommand contains all data needed to unfollow a user

type UnmuteCommand

type UnmuteCommand struct {
	MuterID string `json:"muter_id" validate:"required"`
	MutedID string `json:"muted_id" validate:"required"`
}

UnmuteCommand contains all data needed to unmute a user

type UpdateRelationshipCommand

type UpdateRelationshipCommand struct {
	FollowerID  string    `json:"follower_id" validate:"required"`
	FollowingID string    `json:"following_id" validate:"required"`
	Notify      *bool     `json:"notify,omitempty"`       // Update notification settings
	ShowReblogs *bool     `json:"show_reblogs,omitempty"` // Update reblog visibility
	Languages   *[]string `json:"languages,omitempty"`    // Update language filter
	Note        *string   `json:"note,omitempty"`         // Update private note
}

UpdateRelationshipCommand contains data for updating relationship preferences

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL