forked from tangled.org/core
this repo has no description

add collaborating-on

Changed files
+124 -24
appview
db
pages
templates
state
knotserver
git
types
appview/appview

This is a binary file and will not be displayed.

+6
appview/db/db.go
···
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,
+57 -7
appview/db/repos.go
···
package db
-
import "time"
+
import (
+
"database/sql"
+
"time"
+
)
type Repo struct {
Did string
···
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 {
···
_, 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
+
}
+11 -4
appview/pages/pages.go
···
"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
},
···
}
return strings.Join(paragraphs, "\n\n")
+
},
+
"sequence": func(n int) []struct{} {
+
return make([]struct{}, n)
},
}
}
···
}
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 {
+5 -4
appview/pages/templates/repo/commit.html
···
{{ 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 -}}
+25 -1
appview/pages/templates/user/profile.html
···
{{ 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 }}
<div
id="repo-card"
···
</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 }}
+6
appview/state/repo.go
···
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())))
}
+10 -4
appview/state/state.go
···
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,
})
}
+2 -2
knotserver/git/diff.go
···
for _, 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 {
+2 -2
types/diff.go
···
)
type TextFragment struct {
-
Header string `json:"header"`
-
Lines []gitdiff.Line `json:"lines"`
+
Comment string `json:"comment"`
+
Lines []gitdiff.Line `json:"lines"`
}
type Diff struct {