package federation import ( "xorm.io/xorm" "github.com/forgeo/forgebucket/internal/models" ) const activitiesPerPage = 20 // Collection builds an ActivityStreams OrderedCollection (or page) for an actor's outbox. // page=0 returns the collection summary; page≄1 returns a paginated OrderedCollectionPage. func Collection(db *xorm.Engine, actorAPID string, outboxURL string, page int) map[string]any { total, _ := db.Where("actor_ap_id = ? AND direction = 'outbound'", actorAPID). Count(&models.FederationActivity{}) if page == 0 { return map[string]any{ "@context": "https://www.w3.org/ns/activitystreams", "id": outboxURL, "type": "OrderedCollection", "totalItems": total, "first": outboxURL + "?page=1", } } offset := (page - 1) * activitiesPerPage var activities []models.FederationActivity db.Where("actor_ap_id = ? AND direction = 'outbound'", actorAPID). Desc("published"). Limit(activitiesPerPage, offset). Find(&activities) items := make([]any, 0, len(activities)) for _, a := range activities { items = append(items, rawJSON(a.ObjectJSON)) } coll := map[string]any{ "@context": "https://www.w3.org/ns/activitystreams", "id": outboxURL + "?page=" + itoa(page), "type": "OrderedCollectionPage", "partOf": outboxURL, "orderedItems": items, } if int64(offset+activitiesPerPage) < total { coll["next"] = outboxURL + "?page=" + itoa(page+1) } return coll } // StubCollection returns a minimal OrderedCollection with zero items. // Used for followers/following until the social graph is implemented. func StubCollection(collectionURL string) map[string]any { return map[string]any{ "@context": "https://www.w3.org/ns/activitystreams", "id": collectionURL, "type": "OrderedCollection", "totalItems": 0, "orderedItems": []any{}, } } func itoa(n int) string { if n == 0 { return "0" } result := "" for n > 0 { result = string(rune('0'+n%10)) + result n /= 10 } return result } // rawJSON wraps a JSON string so it marshals as-is (not double-encoded). type rawJSON string func (r rawJSON) MarshalJSON() ([]byte, error) { if r == "" { return []byte("null"), nil } return []byte(r), nil }