Files
at-container-registry/pkg/atproto/profile.go
T
2025-10-02 11:03:59 -05:00

96 lines
2.9 KiB
Go

package atproto
import (
"context"
"encoding/json"
"fmt"
)
// Profile record key is always "self" per lexicon
const ProfileRKey = "self"
// EnsureProfile checks if a user's profile exists and creates it if needed
// This should be called during authentication (OAuth exchange or token service)
// If defaultHoldEndpoint is provided and profile doesn't exist, creates profile with that default
func EnsureProfile(ctx context.Context, client *Client, defaultHoldEndpoint string) error {
// Check if profile already exists
profile, err := client.GetRecord(ctx, SailorProfileCollection, ProfileRKey)
if err == nil && profile != nil {
// Profile exists, nothing to do
return nil
}
// Profile doesn't exist
// Only create if we have a default hold endpoint to set
if defaultHoldEndpoint == "" {
// No default configured, don't create empty profile
return nil
}
// Create new profile with default hold
newProfile := NewSailorProfileRecord(defaultHoldEndpoint)
_, err = client.PutRecord(ctx, SailorProfileCollection, ProfileRKey, newProfile)
if err != nil {
return fmt.Errorf("failed to create sailor profile: %w", err)
}
return nil
}
// GetProfile retrieves the user's profile from their PDS
// Returns nil if profile doesn't exist
func GetProfile(ctx context.Context, client *Client) (*SailorProfileRecord, error) {
record, err := client.GetRecord(ctx, SailorProfileCollection, ProfileRKey)
if err != nil {
// Check if it's a 404 (profile doesn't exist)
if isNotFoundError(err) {
return nil, nil
}
return nil, fmt.Errorf("failed to get profile: %w", err)
}
// Parse the profile record
var profile SailorProfileRecord
if err := json.Unmarshal(record.Value, &profile); err != nil {
return nil, fmt.Errorf("failed to parse profile: %w", err)
}
return &profile, nil
}
// UpdateProfile updates the user's profile
func UpdateProfile(ctx context.Context, client *Client, profile *SailorProfileRecord) error {
_, err := client.PutRecord(ctx, SailorProfileCollection, ProfileRKey, profile)
if err != nil {
return fmt.Errorf("failed to update profile: %w", err)
}
return nil
}
// isNotFoundError checks if an error is a 404 not found error
func isNotFoundError(err error) bool {
// This is a simple check - in practice, you might need to parse the error more carefully
if err == nil {
return false
}
errStr := err.Error()
return contains(errStr, "404") || contains(errStr, "not found") || contains(errStr, "RecordNotFound")
}
// contains checks if a string contains a substring (case-insensitive helper)
func contains(s, substr string) bool {
return len(s) >= len(substr) && (s == substr || len(s) > len(substr) &&
(s[:len(substr)] == substr || s[len(s)-len(substr):] == substr ||
findSubstring(s, substr)))
}
func findSubstring(s, substr string) bool {
for i := 0; i <= len(s)-len(substr); i++ {
if s[i:i+len(substr)] == substr {
return true
}
}
return false
}