+76
appview/db/collaborators.go
+76
appview/db/collaborators.go
···
1
+
package db
2
+
3
+
import (
4
+
"fmt"
5
+
"strings"
6
+
"time"
7
+
8
+
"github.com/bluesky-social/indigo/atproto/syntax"
9
+
)
10
+
11
+
type Collaborator struct {
12
+
// identifiers for the record
13
+
Id int64
14
+
Did syntax.DID
15
+
Rkey string
16
+
17
+
// content
18
+
SubjectDid syntax.DID
19
+
RepoAt syntax.ATURI
20
+
21
+
// meta
22
+
Created time.Time
23
+
}
24
+
25
+
func AddCollaborator(e Execer, c Collaborator) error {
26
+
_, err := e.Exec(
27
+
`insert into collaborators (did, rkey, subject_did, repo_at) values (?, ?, ?, ?);`,
28
+
c.Did, c.Rkey, c.SubjectDid, c.RepoAt,
29
+
)
30
+
return err
31
+
}
32
+
33
+
func DeleteCollaborator(e Execer, filters ...filter) error {
34
+
var conditions []string
35
+
var args []any
36
+
for _, filter := range filters {
37
+
conditions = append(conditions, filter.Condition())
38
+
args = append(args, filter.Arg()...)
39
+
}
40
+
41
+
whereClause := ""
42
+
if conditions != nil {
43
+
whereClause = " where " + strings.Join(conditions, " and ")
44
+
}
45
+
46
+
query := fmt.Sprintf(`delete from collaborators %s`, whereClause)
47
+
48
+
_, err := e.Exec(query, args...)
49
+
return err
50
+
}
51
+
52
+
func CollaboratingIn(e Execer, collaborator string) ([]Repo, error) {
53
+
rows, err := e.Query(`select repo_at from collaborators where did = ?`, collaborator)
54
+
if err != nil {
55
+
return nil, err
56
+
}
57
+
defer rows.Close()
58
+
59
+
var repoAts []string
60
+
for rows.Next() {
61
+
var aturi string
62
+
err := rows.Scan(&aturi)
63
+
if err != nil {
64
+
return nil, err
65
+
}
66
+
repoAts = append(repoAts, aturi)
67
+
}
68
+
if err := rows.Err(); err != nil {
69
+
return nil, err
70
+
}
71
+
if repoAts == nil {
72
+
return nil, nil
73
+
}
74
+
75
+
return GetRepos(e, 0, FilterIn("at_uri", repoAts))
76
+
}
+55
appview/db/db.go
+55
appview/db/db.go
···
585
585
return nil
586
586
})
587
587
588
+
// recreate and add rkey + created columns with default constraint
589
+
runMigration(db, "rework-collaborators-table", func(tx *sql.Tx) error {
590
+
// create new table
591
+
// - repo_at instead of repo integer
592
+
// - rkey field
593
+
// - created field
594
+
_, err := tx.Exec(`
595
+
create table collaborators_new (
596
+
-- identifiers for the record
597
+
id integer primary key autoincrement,
598
+
did text not null,
599
+
rkey text,
600
+
601
+
-- content
602
+
subject_did text not null,
603
+
repo_at text not null,
604
+
605
+
-- meta
606
+
created text default (strftime('%y-%m-%dt%h:%m:%sz', 'now')),
607
+
608
+
-- constraints
609
+
foreign key (repo_at) references repos(at_uri) on delete cascade
610
+
)
611
+
`)
612
+
if err != nil {
613
+
return err
614
+
}
615
+
616
+
// copy data
617
+
_, err = tx.Exec(`
618
+
insert into collaborators_new (id, did, rkey, subject_did, repo_at)
619
+
select
620
+
c.id,
621
+
r.did,
622
+
'',
623
+
c.did,
624
+
r.at_uri
625
+
from collaborators c
626
+
join repos r on c.repo = r.id
627
+
`)
628
+
if err != nil {
629
+
return err
630
+
}
631
+
632
+
// drop old table
633
+
_, err = tx.Exec(`drop table collaborators`)
634
+
if err != nil {
635
+
return err
636
+
}
637
+
638
+
// rename new table
639
+
_, err = tx.Exec(`alter table collaborators_new rename to collaborators`)
640
+
return err
641
+
})
642
+
588
643
return &DB{db}, nil
589
644
}
590
645
-34
appview/db/repos.go
-34
appview/db/repos.go
···
550
550
return &repo, nil
551
551
}
552
552
553
-
func AddCollaborator(e Execer, collaborator, repoOwnerDid, repoName, repoKnot string) error {
554
-
_, err := e.Exec(
555
-
`insert into collaborators (did, repo)
556
-
values (?, (select id from repos where did = ? and name = ? and knot = ?));`,
557
-
collaborator, repoOwnerDid, repoName, repoKnot)
558
-
return err
559
-
}
560
-
561
553
func UpdateDescription(e Execer, repoAt, newDescription string) error {
562
554
_, err := e.Exec(
563
555
`update repos set description = ? where at_uri = ?`, newDescription, repoAt)
···
568
560
_, err := e.Exec(
569
561
`update repos set spindle = ? where at_uri = ?`, spindle, repoAt)
570
562
return err
571
-
}
572
-
573
-
func CollaboratingIn(e Execer, collaborator string) ([]Repo, error) {
574
-
rows, err := e.Query(`select repo from collaborators where did = ?`, collaborator)
575
-
if err != nil {
576
-
return nil, err
577
-
}
578
-
defer rows.Close()
579
-
580
-
var repoIds []int
581
-
for rows.Next() {
582
-
var id int
583
-
err := rows.Scan(&id)
584
-
if err != nil {
585
-
return nil, err
586
-
}
587
-
repoIds = append(repoIds, id)
588
-
}
589
-
if err := rows.Err(); err != nil {
590
-
return nil, err
591
-
}
592
-
if repoIds == nil {
593
-
return nil, nil
594
-
}
595
-
596
-
return GetRepos(e, 0, FilterIn("id", repoIds))
597
563
}
598
564
599
565
type RepoStats struct {
+39
-3
appview/repo/repo.go
+39
-3
appview/repo/repo.go
···
39
39
"github.com/go-git/go-git/v5/plumbing"
40
40
41
41
comatproto "github.com/bluesky-social/indigo/api/atproto"
42
+
"github.com/bluesky-social/indigo/atproto/syntax"
42
43
lexutil "github.com/bluesky-social/indigo/lex/util"
43
44
)
44
45
···
751
752
fail("You seem to be adding yourself as a collaborator.", nil)
752
753
return
753
754
}
754
-
755
755
l = l.With("collaborator", collaboratorIdent.Handle)
756
756
l = l.With("knot", f.Knot)
757
-
l.Info("adding to knot")
757
+
758
+
// announce this relation into the firehose, store into owners' pds
759
+
client, err := rp.oauth.AuthorizedClient(r)
760
+
if err != nil {
761
+
fail("Failed to write to PDS.", err)
762
+
return
763
+
}
764
+
765
+
// emit a record
766
+
currentUser := rp.oauth.GetUser(r)
767
+
rkey := tid.TID()
768
+
createdAt := time.Now()
769
+
resp, err := client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
770
+
Collection: tangled.RepoCollaboratorNSID,
771
+
Repo: currentUser.Did,
772
+
Rkey: rkey,
773
+
Record: &lexutil.LexiconTypeDecoder{
774
+
Val: &tangled.RepoCollaborator{
775
+
Subject: collaboratorIdent.DID.String(),
776
+
Repo: string(f.RepoAt),
777
+
CreatedAt: createdAt.Format(time.RFC3339),
778
+
}},
779
+
})
780
+
// invalid record
781
+
if err != nil {
782
+
fail("Failed to write record to PDS.", err)
783
+
return
784
+
}
785
+
l = l.With("at-uri", resp.Uri)
786
+
l.Info("wrote record to PDS")
758
787
788
+
l.Info("adding to knot")
759
789
secret, err := db.GetRegistrationKey(rp.db, f.Knot)
760
790
if err != nil {
761
791
fail("Failed to add to knot.", err)
···
798
828
return
799
829
}
800
830
801
-
err = db.AddCollaborator(rp.db, collaboratorIdent.DID.String(), f.OwnerDid(), f.RepoName, f.Knot)
831
+
err = db.AddCollaborator(rp.db, db.Collaborator{
832
+
Did: syntax.DID(currentUser.Did),
833
+
Rkey: rkey,
834
+
SubjectDid: collaboratorIdent.DID,
835
+
RepoAt: f.RepoAt,
836
+
Created: createdAt,
837
+
})
802
838
if err != nil {
803
839
fail("Failed to add collaborator.", err)
804
840
return