add collaborating-on
ADDED
appview/appview
ADDED
appview/appview
MODIFIED
appview/db/db.go
MODIFIED
appview/db/db.go
@@ -49,6 +49,12 @@ knot text not null,created text not null default (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),unique(did, name, knot));+ create table if not exists collaborators (+ id integer primary key autoincrement,+ did text not null,+ repo integer not null,+ foreign key (repo) references repos(id) on delete cascade+ );create table if not exists follows (user_did text not null,subject_did text not null,
MODIFIED
appview/db/repos.go
MODIFIED
appview/db/repos.go
@@ -1,6 +1,9 @@package db-import "time"+import (+ "database/sql"+ "time"+)type Repo struct {Did string@@ -19,14 +22,11 @@ }defer rows.Close()for rows.Next() {- var repo Repo- var createdAt string- if err := rows.Scan(&repo.Did, &repo.Name, &repo.Knot, &createdAt); err != nil {+ repo, err := scanRepo(rows)+ if err != nil {return nil, err}- createdAtTime, _ := time.Parse(time.RFC3339, createdAt)- repo.Created = &createdAtTime- repos = append(repos, repo)+ repos = append(repos, *repo)}if err := rows.Err(); err != nil {@@ -60,3 +60,53 @@ func (d *DB) RemoveRepo(did, name, knot string) error {_, err := d.db.Exec(`delete from repos where did = ? and name = ? and knot = ?`, did, name, knot)return err}++func (d *DB) AddCollaborator(collaborator, repoOwnerDid, repoName, repoKnot string) error {+ _, err := d.db.Exec(+ `insert into collaborators (did, repo)+ values (?, (select id from repos where did = ? and name = ? and knot = ?));`,+ collaborator, repoOwnerDid, repoName, repoKnot)+ return err+}++func (d *DB) CollaboratingIn(collaborator string) ([]Repo, error) {+ var repos []Repo++ rows, err := d.db.Query(`select r.* from repos r join collaborators c on r.id = c.repo where c.did = ?;`, collaborator)+ if err != nil {+ return nil, err+ }+ defer rows.Close()++ for rows.Next() {+ repo, err := scanRepo(rows)+ if err != nil {+ return nil, err+ }+ repos = append(repos, *repo)+ }++ if err := rows.Err(); err != nil {+ return nil, err+ }++ return repos, nil+}++func scanRepo(rows *sql.Rows) (*Repo, error) {+ var repo Repo+ var createdAt string+ if err := rows.Scan(&repo.Did, &repo.Name, &repo.Knot, &createdAt); err != nil {+ return nil, err+ }++ createdAtTime, err := time.Parse(time.RFC3339, createdAt)+ if err != nil {+ now := time.Now()+ repo.Created = &now+ }++ repo.Created = &createdAtTime++ return &repo, nil+}
MODIFIED
appview/pages/pages.go
MODIFIED
appview/pages/pages.go
@@ -29,6 +29,9 @@ return template.FuncMap{"split": func(s string) []string {return strings.Split(s, "\n")},+ "splitOn": func(s, sep string) []string {+ return strings.Split(s, sep)+ },"add": func(a, b int) int {return a + b},@@ -89,6 +92,9 @@ paragraphs[i] = strings.Join(lines, " ")}return strings.Join(paragraphs, "\n\n")+ },+ "sequence": func(n int) []struct{} {+ return make([]struct{}, n)},}}@@ -200,10 +206,11 @@ return p.execute("repo/new", w, params)}type ProfilePageParams struct {- LoggedInUser *auth.User- UserDid string- UserHandle string- Repos []db.Repo+ LoggedInUser *auth.User+ UserDid string+ UserHandle string+ Repos []db.Repo+ CollaboratingRepos []db.Repo}func (p *Pages) ProfilePage(w io.Writer, params ProfilePageParams) error {
@@ -102,18 +102,19 @@ <p>Not showing binary file.</p>{{ else }}<pre class="overflow-auto">{{- range .TextFragments -}}- <div class="bg-gray-100 text-gray-500">{{ nl2br .Header }}</div>+ <div class="bg-gray-100 text-gray-500 select-none">{{ .Comment }}</div>+{{- range .Lines -}}{{- if eq .Op.String "+" -}}- <div class="bg-green-100 text-green-700">{{ .String }}</div>+ <div class="bg-green-100 text-green-700"><span class="select-none">{{ .Op.String }}</span><span>{{ .Line }}</span></div>{{- end -}}{{- if eq .Op.String "-" -}}- <div class="bg-red-100 text-red-700">{{ .String }}</div>+ <div class="bg-red-100 text-red-700"><span class="select-none">{{ .Op.String }}</span><span>{{ .Line }}</span></div>{{- end -}}{{- if eq .Op.String " " -}}- <div class="text-gray-500">{{ .String }}</div>+ <div class="text-gray-500"><span class="select-none">{{ .Op.String }}</span><span>{{ .Line }}</span></div>{{- end -}}{{- end -}}
@@ -2,7 +2,8 @@ {{ define "title" }}{{ or .UserHandle .UserDid }}{{ end }}{{ define "content" }}<h1>{{ didOrHandle .UserDid .UserHandle }}</h1>- <div id="my-repos" class="grid grid-cols-1 md:grid-cols-2 gap-4">+ <p class="text-xs font-bold py-2">REPOS</p>+ <div id="repos" class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">{{ range .Repos }}<divid="repo-card"@@ -22,6 +23,29 @@ </div></div>{{ else }}<p>This user does not have any repos yet.</p>+ {{ end }}+ </div>+ <p class="text-xs font-bold py-2">COLLABORATING ON</p>+ <div id="collaborating" class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">+ {{ range .CollaboratingRepos }}+ <div+ id="repo-card"+ class="border border-black p-4 shadow-sm bg-white"+ >+ <div id="repo-card-name" class="font-medium">+ <a href="/@{{ or $.UserHandle $.UserDid }}/{{ .Name }}">+ @{{ or $.UserHandle $.UserDid }}/{{ .Name }}+ </a>+ </div>+ <div+ id="repo-knot-name"+ class="text-gray-600 text-sm font-mono"+ >+ {{ .Knot }}+ </div>+ </div>+ {{ else }}+ <p>This user is not collaborating.</p>{{ end }}</div>{{ end }}
MODIFIED
appview/state/repo.go
MODIFIED
appview/state/repo.go
@@ -393,6 +393,12 @@ w.Write([]byte(fmt.Sprint("failed to add collaborator: ", err)))return}+ err = s.db.AddCollaborator(collaboratorIdent.DID.String(), f.OwnerDid(), f.RepoName, f.Knot)+ if err != nil {+ w.Write([]byte(fmt.Sprint("failed to add collaborator: ", err)))+ return+ }+w.Write([]byte(fmt.Sprint("added collaborator: ", collaboratorIdent.Handle.String())))}
MODIFIED
appview/state/state.go
MODIFIED
appview/state/state.go
@@ -580,11 +580,17 @@ if err != nil {log.Printf("getting repos for %s: %s", ident.DID.String(), err)}+ collaboratingRepos, err := s.db.CollaboratingIn(ident.DID.String())+ if err != nil {+ log.Printf("getting collaborating repos for %s: %s", ident.DID.String(), err)+ }+s.pages.ProfilePage(w, pages.ProfilePageParams{- LoggedInUser: s.auth.GetUser(r),- UserDid: ident.DID.String(),- UserHandle: ident.Handle.String(),- Repos: repos,+ LoggedInUser: s.auth.GetUser(r),+ UserDid: ident.DID.String(),+ UserHandle: ident.Handle.String(),+ Repos: repos,+ CollaboratingRepos: collaboratingRepos,})}
MODIFIED
knotserver/git/diff.go
MODIFIED
knotserver/git/diff.go
@@ -66,8 +66,8 @@ ndiff.IsDelete = d.IsDeletefor _, tf := range d.TextFragments {ndiff.TextFragments = append(ndiff.TextFragments, types.TextFragment{- Header: tf.Header(),- Lines: tf.Lines,+ Comment: tf.Comment,+ Lines: tf.Lines,})for _, l := range tf.Lines {switch l.Op {
MODIFIED
types/diff.go
MODIFIED
types/diff.go
@@ -6,8 +6,8 @@ "github.com/go-git/go-git/v5/plumbing/object")type TextFragment struct {- Header string `json:"header"`- Lines []gitdiff.Line `json:"lines"`+ Comment string `json:"comment"`+ Lines []gitdiff.Line `json:"lines"`}type Diff struct {