A community based topic aggregation platform built on atproto
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
27// ValidationError represents a validation error with field context
28type ValidationError struct {
29 Field string
30 Message string
31}
32
33func (e *ValidationError) Error() string {
34 return fmt.Sprintf("validation error (%s): %s", e.Field, e.Message)
35}
36
37// NewValidationError creates a new validation error
38func NewValidationError(field, message string) error {
39 return &ValidationError{
40 Field: field,
41 Message: message,
42 }
43}
44
45// IsValidationError checks if error is a validation error
46func IsValidationError(err error) bool {
47 var valErr *ValidationError
48 return errors.As(err, &valErr)
49}
50
51// ContentRuleViolation represents a violation of community content rules
52// (Deferred to Beta - included here for future compatibility)
53type ContentRuleViolation struct {
54 Rule string // e.g., "requireText", "allowedEmbedTypes"
55 Message string // Human-readable explanation
56}
57
58func (e *ContentRuleViolation) Error() string {
59 return fmt.Sprintf("content rule violation (%s): %s", e.Rule, e.Message)
60}
61
62// NewContentRuleViolation creates a new content rule violation error
63func NewContentRuleViolation(rule, message string) error {
64 return &ContentRuleViolation{
65 Rule: rule,
66 Message: message,
67 }
68}
69
70// IsContentRuleViolation checks if error is a content rule violation
71func IsContentRuleViolation(err error) bool {
72 var violation *ContentRuleViolation
73 return errors.As(err, &violation)
74}
75
76// NotFoundError represents a resource not found error
77type NotFoundError struct {
78 Resource string // e.g., "post", "community"
79 ID string // Resource identifier
80}
81
82func (e *NotFoundError) Error() string {
83 return fmt.Sprintf("%s not found: %s", e.Resource, e.ID)
84}
85
86// NewNotFoundError creates a new not found error
87func NewNotFoundError(resource, id string) error {
88 return &NotFoundError{
89 Resource: resource,
90 ID: id,
91 }
92}
93
94// IsNotFound checks if error is a not found error
95func IsNotFound(err error) bool {
96 var notFoundErr *NotFoundError
97 return errors.As(err, ¬FoundErr) || err == ErrCommunityNotFound || err == ErrNotFound
98}
99
100// IsConflict checks if error is due to duplicate/conflict
101func IsConflict(err error) bool {
102 if err == nil {
103 return false
104 }
105 // Check for common conflict indicators in error message
106 errStr := err.Error()
107 return contains(errStr, "already indexed") ||
108 contains(errStr, "duplicate key") ||
109 contains(errStr, "already exists")
110}
111
112func contains(s, substr string) bool {
113 return len(s) >= len(substr) && anySubstring(s, substr)
114}
115
116func anySubstring(s, substr string) bool {
117 for i := 0; i <= len(s)-len(substr); i++ {
118 if s[i:i+len(substr)] == substr {
119 return true
120 }
121 }
122 return false
123}