forked from tangled.org/core
Monorepo for Tangled — https://tangled.org

spindle: improve member ingestion

Signed-off-by: oppiliappan <me@oppi.li>

oppi.li 23776d5e 4e03f297

verified
Changed files
+121 -8
appview
spindle
+4
appview/ingester.go
···
if err != nil {
return fmt.Errorf("failed to update ACLs: %w", err)
}
+
+
l.Info("added spindle member")
case models.CommitOperationDelete:
rkey := e.Commit.RKey
···
if err = i.Enforcer.E.SavePolicy(); err != nil {
return fmt.Errorf("failed to save ACLs: %w", err)
}
+
+
l.Info("removed spindle member")
}
return nil
+4 -4
appview/spindles/spindles.go
···
if string(spindles[0].Owner) != user.Did {
l.Error("unauthorized", "user", user.Did, "owner", spindles[0].Owner)
-
s.Pages.Notice(w, noticeId, "Failed to add member, unauthorized attempt.")
+
s.Pages.Notice(w, noticeId, "Failed to remove member, unauthorized attempt.")
return
}
member := r.FormValue("member")
if member == "" {
l.Error("empty member")
-
s.Pages.Notice(w, noticeId, "Failed to add member, empty form.")
+
s.Pages.Notice(w, noticeId, "Failed to remove member, empty form.")
return
}
l = l.With("member", member)
···
memberId, err := s.IdResolver.ResolveIdent(r.Context(), member)
if err != nil {
l.Error("failed to resolve member identity to handle", "err", err)
-
s.Pages.Notice(w, noticeId, "Failed to add member, identity resolution failed.")
+
s.Pages.Notice(w, noticeId, "Failed to remove member, identity resolution failed.")
return
}
if memberId.Handle.IsInvalidHandle() {
l.Error("failed to resolve member identity to handle")
-
s.Pages.Notice(w, noticeId, "Failed to add member, identity resolution failed.")
+
s.Pages.Notice(w, noticeId, "Failed to remove member, identity resolution failed.")
return
}
+15
spindle/db/db.go
···
unique(owner, name)
);
+
create table if not exists spindle_members (
+
-- identifiers for the record
+
id integer primary key autoincrement,
+
did text not null,
+
rkey text not null,
+
+
-- data
+
instance text not null,
+
subject text not null,
+
created text not null default (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
+
+
-- constraints
+
unique (did, instance, subject)
+
);
+
-- status event for a single workflow
create table if not exists events (
rkey text not null,
+59
spindle/db/member.go
···
+
package db
+
+
import (
+
"time"
+
+
"github.com/bluesky-social/indigo/atproto/syntax"
+
)
+
+
type SpindleMember struct {
+
Id int
+
Did syntax.DID // owner of the record
+
Rkey string // rkey of the record
+
Instance string
+
Subject syntax.DID // the member being added
+
Created time.Time
+
}
+
+
func AddSpindleMember(db *DB, member SpindleMember) error {
+
_, err := db.Exec(
+
`insert or ignore into spindle_members (did, rkey, instance, subject) values (?, ?, ?, ?)`,
+
member.Did,
+
member.Rkey,
+
member.Instance,
+
member.Subject,
+
)
+
return err
+
}
+
+
func RemoveSpindleMember(db *DB, owner_did, rkey string) error {
+
_, err := db.Exec(
+
"delete from spindle_members where did = ? and rkey = ?",
+
owner_did,
+
rkey,
+
)
+
return err
+
}
+
+
func GetSpindleMember(db *DB, did, rkey string) (*SpindleMember, error) {
+
query :=
+
`select id, did, rkey, instance, subject, created
+
from spindle_members
+
where did = ? and rkey = ?`
+
+
var member SpindleMember
+
var createdAt string
+
err := db.QueryRow(query, did, rkey).Scan(
+
&member.Id,
+
&member.Did,
+
&member.Rkey,
+
&member.Instance,
+
&member.Subject,
+
&createdAt,
+
)
+
if err != nil {
+
return nil, err
+
}
+
+
return &member, nil
+
}
+39 -4
spindle/ingester.go
···
"encoding/json"
"errors"
"fmt"
+
"time"
"tangled.sh/tangled.sh/core/api/tangled"
"tangled.sh/tangled.sh/core/eventconsumer"
"tangled.sh/tangled.sh/core/idresolver"
"tangled.sh/tangled.sh/core/rbac"
+
"tangled.sh/tangled.sh/core/spindle/db"
comatproto "github.com/bluesky-social/indigo/api/atproto"
"github.com/bluesky-social/indigo/atproto/identity"
···
}
func (s *Spindle) ingestMember(_ context.Context, e *models.Event) error {
+
var err error
did := e.Did
-
var err error
+
rkey := e.Commit.RKey
l := s.l.With("component", "ingester", "record", tangled.SpindleMemberNSID)
···
}
domain := s.cfg.Server.Hostname
-
if s.cfg.Server.Dev {
-
domain = s.cfg.Server.ListenAddr
-
}
recordInstance := record.Instance
if recordInstance != domain {
···
return fmt.Errorf("failed to enforce permissions: %w", err)
}
+
if err := db.AddSpindleMember(s.db, db.SpindleMember{
+
Did: syntax.DID(did),
+
Rkey: rkey,
+
Instance: recordInstance,
+
Subject: syntax.DID(record.Subject),
+
Created: time.Now(),
+
}); err != nil {
+
l.Error("failed to add member", "error", err)
+
return fmt.Errorf("failed to add member: %w", err)
+
}
+
if err := s.e.AddSpindleMember(rbacDomain, record.Subject); err != nil {
l.Error("failed to add member", "error", err)
return fmt.Errorf("failed to add member: %w", err)
···
s.jc.AddDid(record.Subject)
return nil
+
+
case models.CommitOperationDelete:
+
record, err := db.GetSpindleMember(s.db, did, rkey)
+
if err != nil {
+
l.Error("failed to find member", "error", err)
+
return fmt.Errorf("failed to find member: %w", err)
+
}
+
+
if err := db.RemoveSpindleMember(s.db, did, rkey); err != nil {
+
l.Error("failed to remove member", "error", err)
+
return fmt.Errorf("failed to remove member: %w", err)
+
}
+
+
if err := s.e.RemoveSpindleMember(rbacDomain, record.Subject.String()); err != nil {
+
l.Error("failed to add member", "error", err)
+
return fmt.Errorf("failed to add member: %w", err)
+
}
+
l.Info("added member from firehose", "member", record.Subject)
+
+
if err := s.db.RemoveDid(record.Subject.String()); err != nil {
+
l.Error("failed to add did", "error", err)
+
return fmt.Errorf("failed to add did: %w", err)
+
}
+
s.jc.RemoveDid(record.Subject.String())
}
return nil