aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--http/server.go31
-rw-r--r--models/model.go1
-rw-r--r--models/outbox_item.go11
-rw-r--r--models/persister.go26
-rw-r--r--registry/registry.go22
-rw-r--r--urls/urls.go17
-rw-r--r--views/activity.go20
-rw-r--r--views/outbox.go17
8 files changed, 123 insertions, 22 deletions
diff --git a/http/server.go b/http/server.go
index 98b4083..7d18085 100644
--- a/http/server.go
+++ b/http/server.go
@@ -8,6 +8,7 @@ import (
"github.com/gin-gonic/gin"
)
+// TODO rename to Router and router.go
type Server struct {
registry *registry.Registry
}
@@ -76,22 +77,20 @@ func (s *Server) Start(zapWriter io.Writer) {
}
})
- // // outbox single
- // router.GET("/actors/:actor/outbox/:id", func(c *gin.Context) {
- // actorParam := c.Param("actor")
- // var resource map[string]interface{}
- // if c.Query("page") == "true" {
- // resource, _ = s.registry.OutboxPage(actorParam)
- // } else {
- // resource, _ = s.registry.Outbox(actorParam)
- // }
- // if resource != nil {
- // c.Writer.Header().Set("Content-Type", "application/activity+json")
- // c.JSON(http.StatusOK, resource)
- // } else {
- // c.JSON(http.StatusNotFound, nil)
- // }
- // })
+ // Single activity
+ router.GET("/actors/:actor/outbox/:id/activity", func(c *gin.Context) {
+ actorParam := c.Param("actor")
+ idParam := c.Param("id")
+ var resource map[string]interface{}
+ resource, _ = s.registry.Activity(actorParam, idParam)
+
+ if resource != nil {
+ c.Writer.Header().Set("Content-Type", "application/activity+json")
+ c.JSON(http.StatusOK, resource)
+ } else {
+ c.JSON(http.StatusNotFound, nil)
+ }
+ })
router.Run()
}
diff --git a/models/model.go b/models/model.go
index 56f1680..354b3bd 100644
--- a/models/model.go
+++ b/models/model.go
@@ -5,4 +5,5 @@ import "github.com/dgraph-io/badger/v3"
type model interface {
Save(txn *badger.Txn) error
Keybase() string
+ Key() string
}
diff --git a/models/outbox_item.go b/models/outbox_item.go
index 9950d9c..9d9de97 100644
--- a/models/outbox_item.go
+++ b/models/outbox_item.go
@@ -18,7 +18,7 @@ type OutboxItem struct {
CreatedAt time.Time
}
-// used for lookup purposes (count, collect)
+// used for lookup purposes (count, collect, find)
func NewOutboxItem(h config.Handler) *OutboxItem {
aso := &OutboxItem{Handler: h}
return aso
@@ -31,14 +31,13 @@ func CreateOutboxItem(h config.Handler, content []byte) *OutboxItem {
Handler: h,
CreatedAt: t,
Content: content,
- Id: k.Bytes(),
+ Id: []byte(k.String()), // NOTE: we want the bytes of the string representation of a hash, NOT a binary hash
}
return aso
}
-func (a *OutboxItem) keyName() []byte {
- key := fmt.Sprintf("%s:%s", a.Keybase(), a.Id)
- return []byte(key)
+func (a *OutboxItem) Key() string {
+ return fmt.Sprintf("%s:%s", a.Keybase(), a.Id)
}
func (a *OutboxItem) Keybase() string {
@@ -59,6 +58,6 @@ func (a *OutboxItem) Save(txn *badger.Txn) error {
if err != nil {
return fmt.Errorf("could not encode outbox item: %w", err)
}
- e := badger.NewEntry(a.keyName(), network.Bytes())
+ e := badger.NewEntry([]byte(a.Key()), network.Bytes())
return txn.SetEntry(e)
}
diff --git a/models/persister.go b/models/persister.go
index 669480e..69e79f4 100644
--- a/models/persister.go
+++ b/models/persister.go
@@ -60,3 +60,29 @@ func (p *Persister) Collect(model model) ([][]byte, error) {
})
return result, err
}
+
+func (p *Persister) Find(model model) ([]byte, error) {
+ var result []byte
+ var item *badger.Item
+ err := p.db.View(func(txn *badger.Txn) error {
+ var getErr error
+ item, getErr = txn.Get([]byte(model.Key()))
+ if getErr != nil {
+ return getErr
+ }
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+ err = item.Value(func(v []byte) error {
+ result = v
+ return nil
+ })
+
+ if err != nil {
+ return nil, err
+ }
+
+ return result, nil
+}
diff --git a/registry/registry.go b/registry/registry.go
index 2518d55..4a1329a 100644
--- a/registry/registry.go
+++ b/registry/registry.go
@@ -14,6 +14,7 @@ type Handler struct {
handlerCfg config.Handler
}
+// TODO rename to controller and controller.go
type Registry struct {
cfg config.Config
persister *models.Persister
@@ -74,6 +75,27 @@ func (r *Registry) OutboxCollection(name string) (map[string]interface{}, error)
return views.RenderOutboxCollection(handler.handlerCfg.Name, r.cfg.Domain, outboxItems)
}
+func (r *Registry) Activity(name, id string) (map[string]interface{}, error) {
+ handler := r.findByName(name)
+ if handler == nil {
+ return nil, nil
+ }
+ lookup := models.NewOutboxItem(handler.handlerCfg)
+ lookup.Id = []byte(id)
+ result, err := r.persister.Find(lookup)
+ if err != nil {
+ return nil, err
+ }
+ buf := bytes.NewBuffer(result)
+ dec := gob.NewDecoder(buf)
+ var outboxItem models.OutboxItem
+ err = dec.Decode(&outboxItem)
+ if err != nil {
+ return nil, err
+ }
+ return views.RenderActivity(handler.handlerCfg.Name, r.cfg.Domain, outboxItem)
+}
+
func (r *Registry) WebfingerResource(fqn string) (*views.WebfingerResource, error) {
handler := r.findByFQN(fqn)
if handler == nil {
diff --git a/urls/urls.go b/urls/urls.go
index 5f563a7..3c08e07 100644
--- a/urls/urls.go
+++ b/urls/urls.go
@@ -22,6 +22,23 @@ func UrlOutbox(name, domain string) (*url.URL, error) {
return u, nil
}
+func UrlActivity(name, domain, id string) (*url.URL, error) {
+ u, err := url.Parse(path.Join(domain, "actors", name, "outbox", id, "activity"))
+ if err != nil {
+ panic(err)
+ return nil, fmt.Errorf("could not build activity url: %w", err)
+ }
+ return u, nil
+}
+
+func UrlNote(name, domain, id string) (*url.URL, error) {
+ u, err := url.Parse(path.Join("https://", domain, "actors", name, "outbox", id, "note"))
+ if err != nil {
+ return nil, fmt.Errorf("could not build note url: %w", err)
+ }
+ return u, nil
+}
+
func UrlOutboxPage(name, domain string) (*url.URL, error) {
u, err := UrlOutbox(name, domain)
if err != nil {
diff --git a/views/activity.go b/views/activity.go
new file mode 100644
index 0000000..cd34b6c
--- /dev/null
+++ b/views/activity.go
@@ -0,0 +1,20 @@
+package views
+
+import (
+ "net/url"
+
+ "git.capotej.com/capotej/communique/models"
+ "github.com/go-fed/activity/streams"
+)
+
+func RenderActivity(name, domain string, item models.OutboxItem) (map[string]interface{}, error) {
+ publicUrl, err := url.Parse("https://www.w3.org/ns/activitystreams#Public")
+ if err != nil {
+ return nil, err
+ }
+ toProp := streams.NewActivityStreamsToProperty()
+ toProp.AppendIRI(publicUrl)
+ crea := streams.NewActivityStreamsCreate()
+ crea.SetActivityStreamsTo(toProp)
+ return streams.Serialize(crea)
+}
diff --git a/views/outbox.go b/views/outbox.go
index bfe225a..ee28842 100644
--- a/views/outbox.go
+++ b/views/outbox.go
@@ -44,11 +44,28 @@ func RenderOutboxCollection(name, domain string, page []models.OutboxItem) (map[
publishedProp.Set(v.CreatedAt)
crea := streams.NewActivityStreamsCreate()
obj := streams.NewActivityStreamsObjectProperty()
+
+ creaIdProp := streams.NewJSONLDIdProperty()
+ activityUrl, err := urls.UrlActivity(name, domain, string(v.Id))
+ if err != nil {
+ return nil, err
+ }
+ creaIdProp.Set(activityUrl)
+ crea.SetJSONLDId(creaIdProp)
+
crea.SetActivityStreamsObject(obj)
crea.SetActivityStreamsTo(toProp)
crea.SetActivityStreamsPublished(publishedProp)
+ noteUrl, err := urls.UrlNote(name, domain, string(v.Id))
+ if err != nil {
+ return nil, err
+ }
+
note := streams.NewActivityStreamsNote()
+ noteIdProp := streams.NewJSONLDIdProperty()
+ noteIdProp.Set(noteUrl)
+ note.SetJSONLDId(noteIdProp)
contentProp := streams.NewActivityStreamsContentProperty()
contentProp.AppendXMLSchemaString(string(v.Content))
note.SetActivityStreamsContent(contentProp)