A community based topic aggregation platform built on atproto
at main 3.9 kB view raw
1package posts 2 3import ( 4 "errors" 5 "fmt" 6) 7 8// Sentinel errors for common post operations 9var ( 10 // ErrCommunityNotFound is returned when the community doesn't exist in AppView 11 ErrCommunityNotFound = errors.New("community not found") 12 13 // ErrNotAuthorized is returned when user isn't authorized to post in community 14 // (e.g., banned, private community without membership - Beta) 15 ErrNotAuthorized = errors.New("user not authorized to post in this community") 16 17 // ErrBanned is returned when user is banned from community (Beta) 18 ErrBanned = errors.New("user is banned from this community") 19 20 // ErrInvalidContent is returned for general content violations 21 ErrInvalidContent = errors.New("invalid post content") 22 23 // ErrNotFound is returned when a post is not found by URI 24 ErrNotFound = errors.New("post not found") 25 26 // ErrRateLimitExceeded is returned when an aggregator exceeds rate limits 27 ErrRateLimitExceeded = errors.New("rate limit exceeded") 28 29 // ErrInvalidCursor is returned when a pagination cursor is malformed 30 ErrInvalidCursor = errors.New("invalid pagination cursor") 31 32 // ErrActorNotFound is returned when the requested actor does not exist 33 ErrActorNotFound = errors.New("actor not found") 34) 35 36// ValidationError represents a validation error with field context 37type ValidationError struct { 38 Field string 39 Message string 40} 41 42func (e *ValidationError) Error() string { 43 return fmt.Sprintf("validation error (%s): %s", e.Field, e.Message) 44} 45 46// NewValidationError creates a new validation error 47func NewValidationError(field, message string) error { 48 return &ValidationError{ 49 Field: field, 50 Message: message, 51 } 52} 53 54// IsValidationError checks if error is a validation error 55func IsValidationError(err error) bool { 56 var valErr *ValidationError 57 return errors.As(err, &valErr) 58} 59 60// ContentRuleViolation represents a violation of community content rules 61// (Deferred to Beta - included here for future compatibility) 62type ContentRuleViolation struct { 63 Rule string // e.g., "requireText", "allowedEmbedTypes" 64 Message string // Human-readable explanation 65} 66 67func (e *ContentRuleViolation) Error() string { 68 return fmt.Sprintf("content rule violation (%s): %s", e.Rule, e.Message) 69} 70 71// NewContentRuleViolation creates a new content rule violation error 72func NewContentRuleViolation(rule, message string) error { 73 return &ContentRuleViolation{ 74 Rule: rule, 75 Message: message, 76 } 77} 78 79// IsContentRuleViolation checks if error is a content rule violation 80func IsContentRuleViolation(err error) bool { 81 var violation *ContentRuleViolation 82 return errors.As(err, &violation) 83} 84 85// NotFoundError represents a resource not found error 86type NotFoundError struct { 87 Resource string // e.g., "post", "community" 88 ID string // Resource identifier 89} 90 91func (e *NotFoundError) Error() string { 92 return fmt.Sprintf("%s not found: %s", e.Resource, e.ID) 93} 94 95// NewNotFoundError creates a new not found error 96func NewNotFoundError(resource, id string) error { 97 return &NotFoundError{ 98 Resource: resource, 99 ID: id, 100 } 101} 102 103// IsNotFound checks if error is a not found error 104func IsNotFound(err error) bool { 105 var notFoundErr *NotFoundError 106 return errors.As(err, &notFoundErr) || err == ErrCommunityNotFound || err == ErrNotFound 107} 108 109// IsConflict checks if error is due to duplicate/conflict 110func IsConflict(err error) bool { 111 if err == nil { 112 return false 113 } 114 // Check for common conflict indicators in error message 115 errStr := err.Error() 116 return contains(errStr, "already indexed") || 117 contains(errStr, "duplicate key") || 118 contains(errStr, "already exists") 119} 120 121func contains(s, substr string) bool { 122 return len(s) >= len(substr) && anySubstring(s, substr) 123} 124 125func anySubstring(s, substr string) bool { 126 for i := 0; i <= len(s)-len(substr); i++ { 127 if s[i:i+len(substr)] == substr { 128 return true 129 } 130 } 131 return false 132}