···84848585// CachedDataNote explains what cached data exists and how to access it
8686type CachedDataNote struct {
8787- Message string `json:"message"`
8888- DeletionNotice string `json:"deletion_notice"`
8787+ Message string `json:"message"`
8888+ DeletionNotice string `json:"deletion_notice"`
8989 YourPDSCollections []string `json:"your_pds_collections"`
9090- HowToAccess string `json:"how_to_access"`
9090+ HowToAccess string `json:"how_to_access"`
9191}
92929393// ExportUserData gathers all user data for GDPR export
+7-3
pkg/appview/handlers/settings.go
···83838484 // Parse permissions JSON if present
8585 if hold.Permissions != "" {
8686- json.Unmarshal([]byte(hold.Permissions), &display.Permissions)
8686+ if err := json.Unmarshal([]byte(hold.Permissions), &display.Permissions); err != nil {
8787+ slog.Warn("Failed to parse permissions JSON", "component", "settings", "did", user.DID, "hold_did", hold.HoldDID, "error", err)
8888+ }
8789 }
88908991 // Add to data map for JavaScript
···221223222224 if !hasAccess {
223225 w.Header().Set("Content-Type", "text/html")
224224- h.Templates.ExecuteTemplate(w, "alert", map[string]string{
226226+ if err := h.Templates.ExecuteTemplate(w, "alert", map[string]string{
225227 "Class": "error",
226228 "Icon": "alert-circle",
227229 "Message": "You don't have access to this hold",
228228- })
230230+ }); err != nil {
231231+ http.Error(w, err.Error(), http.StatusInternalServerError)
232232+ }
229233 return
230234 }
231235 }
-1
pkg/hold/config.go
···217217 return defaultValue
218218}
219219220220-221220// RequestCrawl sends a crawl request to the ATProto relay for the given hostname.
222221// This makes the hold's PDS discoverable by the relay network.
223222func RequestCrawl(relayEndpoint, publicURL string) error {
+7-7
pkg/hold/pds/xrpc.go
···1497149714981498// HoldUserDataExport represents the GDPR data export from a hold service
14991499type HoldUserDataExport struct {
15001500- ExportedAt time.Time `json:"exported_at"`
15011501- HoldDID string `json:"hold_did"`
15021502- UserDID string `json:"user_did"`
15031503- IsCaptain bool `json:"is_captain"`
15041504- CrewRecord *CrewExport `json:"crew_record,omitempty"`
15051505- LayerRecords []LayerExport `json:"layer_records"`
15061506- StatsRecords []StatsExport `json:"stats_records"`
15001500+ ExportedAt time.Time `json:"exported_at"`
15011501+ HoldDID string `json:"hold_did"`
15021502+ UserDID string `json:"user_did"`
15031503+ IsCaptain bool `json:"is_captain"`
15041504+ CrewRecord *CrewExport `json:"crew_record,omitempty"`
15051505+ LayerRecords []LayerExport `json:"layer_records"`
15061506+ StatsRecords []StatsExport `json:"stats_records"`
15071507}
1508150815091509// CrewExport represents a sanitized crew record for export