diff --git a/api/tangled/tangledrepo.go b/api/tangled/tangledrepo.go index 55febe5c..2970a7c0 100644 --- a/api/tangled/tangledrepo.go +++ b/api/tangled/tangledrepo.go @@ -19,6 +19,7 @@ func init() { type Repo struct { LexiconTypeID string `json:"$type,const=sh.tangled.repo" cborgen:"$type,const=sh.tangled.repo"` AddedAt *string `json:"addedAt,omitempty" cborgen:"addedAt,omitempty"` + Description *string `json:"description,omitempty" cborgen:"description,omitempty"` // knot: knot where the repo was created Knot string `json:"knot" cborgen:"knot"` // name: name of the repo diff --git a/appview/auth/auth.go b/appview/auth/auth.go index 2687339b..a015d528 100644 --- a/appview/auth/auth.go +++ b/appview/auth/auth.go @@ -140,7 +140,7 @@ func (a *Auth) StoreSession(r *http.Request, w http.ResponseWriter, atSessionish clientSession.Values[appview.SessionPds] = pdsEndpoint clientSession.Values[appview.SessionAccessJwt] = atSessionish.GetAccessJwt() clientSession.Values[appview.SessionRefreshJwt] = atSessionish.GetRefreshJwt() - clientSession.Values[appview.SessionExpiry] = time.Now().Add(time.Second * 5).Format(time.RFC3339) + clientSession.Values[appview.SessionExpiry] = time.Now().Add(time.Minute * 15).Format(time.RFC3339) clientSession.Values[appview.SessionAuthenticated] = true return clientSession.Save(r, w) } diff --git a/appview/db/repos.go b/appview/db/repos.go index c7e75d41..98ba98b9 100644 --- a/appview/db/repos.go +++ b/appview/db/repos.go @@ -6,19 +6,20 @@ import ( ) type Repo struct { - Did string - Name string - Knot string - Rkey string - Created time.Time - AtUri string + Did string + Name string + Knot string + Rkey string + Created time.Time + AtUri string + Description string } func GetAllRepos(e Execer, limit int) ([]Repo, error) { var repos []Repo rows, err := e.Query( - `select did, name, knot, rkey, created + `select did, name, knot, rkey, description, created from repos order by created desc limit ? @@ -32,7 +33,9 @@ func GetAllRepos(e Execer, limit int) ([]Repo, error) { for rows.Next() { var repo Repo - err := scanRepo(rows, &repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, &repo.Created) + err := scanRepo( + rows, &repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, &repo.Description, &repo.Created, + ) if err != nil { return nil, err } @@ -49,7 +52,7 @@ func GetAllRepos(e Execer, limit int) ([]Repo, error) { func GetAllReposByDid(e Execer, did string) ([]Repo, error) { var repos []Repo - rows, err := e.Query(`select did, name, knot, rkey, created from repos where did = ?`, did) + rows, err := e.Query(`select did, name, knot, rkey, description, created from repos where did = ?`, did) if err != nil { return nil, err } @@ -57,7 +60,7 @@ func GetAllReposByDid(e Execer, did string) ([]Repo, error) { for rows.Next() { var repo Repo - err := scanRepo(rows, &repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, &repo.Created) + err := scanRepo(rows, &repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, &repo.Description, &repo.Created) if err != nil { return nil, err } @@ -73,36 +76,55 @@ func GetAllReposByDid(e Execer, did string) ([]Repo, error) { func GetRepo(e Execer, did, name string) (*Repo, error) { var repo Repo + var nullableDescription sql.NullString - row := e.QueryRow(`select did, name, knot, created, at_uri from repos where did = ? and name = ?`, did, name) + row := e.QueryRow(`select did, name, knot, created, at_uri, description from repos where did = ? and name = ?`, did, name) var createdAt string - if err := row.Scan(&repo.Did, &repo.Name, &repo.Knot, &createdAt, &repo.AtUri); err != nil { + if err := row.Scan(&repo.Did, &repo.Name, &repo.Knot, &createdAt, &repo.AtUri, &nullableDescription); err != nil { return nil, err } createdAtTime, _ := time.Parse(time.RFC3339, createdAt) repo.Created = createdAtTime + if nullableDescription.Valid { + repo.Description = nullableDescription.String + } else { + repo.Description = "" + } + return &repo, nil } func GetRepoByAtUri(e Execer, atUri string) (*Repo, error) { var repo Repo + var nullableDescription sql.NullString - row := e.QueryRow(`select did, name, knot, created, at_uri from repos where at_uri = ?`, atUri) + row := e.QueryRow(`select did, name, knot, created, at_uri, description from repos where at_uri = ?`, atUri) var createdAt string - if err := row.Scan(&repo.Did, &repo.Name, &repo.Knot, &createdAt, &repo.AtUri); err != nil { + if err := row.Scan(&repo.Did, &repo.Name, &repo.Knot, &createdAt, &repo.AtUri, &nullableDescription); err != nil { return nil, err } createdAtTime, _ := time.Parse(time.RFC3339, createdAt) repo.Created = createdAtTime + if nullableDescription.Valid { + repo.Description = nullableDescription.String + } else { + repo.Description = "" + } + return &repo, nil } func AddRepo(e Execer, repo *Repo) error { - _, err := e.Exec(`insert into repos (did, name, knot, rkey, at_uri) values (?, ?, ?, ?, ?)`, repo.Did, repo.Name, repo.Knot, repo.Rkey, repo.AtUri) + _, err := e.Exec( + `insert into repos + (did, name, knot, rkey, at_uri, description) + values (?, ?, ?, ?, ?, ?)`, + repo.Did, repo.Name, repo.Knot, repo.Rkey, repo.AtUri, repo.Description, + ) return err } @@ -119,6 +141,12 @@ func AddCollaborator(e Execer, collaborator, repoOwnerDid, repoName, repoKnot st return err } +func UpdateDescription(e Execer, repoAt, newDescription string) error { + _, err := e.Exec( + `update repos set description = ? where at_uri = ?`, newDescription, repoAt) + return err +} + func CollaboratingIn(e Execer, collaborator string) ([]Repo, error) { var repos []Repo @@ -130,7 +158,7 @@ func CollaboratingIn(e Execer, collaborator string) ([]Repo, error) { for rows.Next() { var repo Repo - err := scanRepo(rows, &repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, &repo.Created) + err := scanRepo(rows, &repo.Did, &repo.Name, &repo.Knot, &repo.Rkey, &repo.Description, &repo.Created) if err != nil { return nil, err } @@ -149,12 +177,19 @@ type RepoStats struct { IssueCount IssueCount } -func scanRepo(rows *sql.Rows, did, name, knot, rkey *string, created *time.Time) error { +func scanRepo(rows *sql.Rows, did, name, knot, rkey, description *string, created *time.Time) error { var createdAt string - if err := rows.Scan(did, name, knot, rkey, &createdAt); err != nil { + var nullableDescription sql.NullString + if err := rows.Scan(did, name, knot, rkey, &nullableDescription, &createdAt); err != nil { return err } + if nullableDescription.Valid { + *description = nullableDescription.String + } else { + *description = "" + } + createdAtTime, err := time.Parse(time.RFC3339, createdAt) if err != nil { *created = time.Now() diff --git a/appview/pages/pages.go b/appview/pages/pages.go index a183af04..7a15370b 100644 --- a/appview/pages/pages.go +++ b/appview/pages/pages.go @@ -11,6 +11,7 @@ import ( "net/http" "path" "path/filepath" + "slices" "strings" "github.com/alecthomas/chroma/v2" @@ -194,16 +195,40 @@ func (p *Pages) StarFragment(w io.Writer, params StarFragmentParams) error { return p.executePlain("fragments/star", w, params) } +type RepoDescriptionParams struct { + RepoInfo RepoInfo +} + +func (p *Pages) EditRepoDescriptionFragment(w io.Writer, params RepoDescriptionParams) error { + return p.executePlain("fragments/editRepoDescription", w, params) +} + +func (p *Pages) RepoDescriptionFragment(w io.Writer, params RepoDescriptionParams) error { + return p.executePlain("fragments/repoDescription", w, params) +} + type RepoInfo struct { - Name string - OwnerDid string - OwnerHandle string - Description string - Knot string - RepoAt syntax.ATURI - SettingsAllowed bool - IsStarred bool - Stats db.RepoStats + Name string + OwnerDid string + OwnerHandle string + Description string + Knot string + RepoAt syntax.ATURI + IsStarred bool + Stats db.RepoStats + Roles RolesInRepo +} + +type RolesInRepo struct { + Roles []string +} + +func (r RolesInRepo) SettingsAllowed() bool { + return slices.Contains(r.Roles, "repo:settings") +} + +func (r RolesInRepo) IsOwner() bool { + return slices.Contains(r.Roles, "repo:owner") } func (r RepoInfo) OwnerWithAt() string { @@ -225,7 +250,7 @@ func (r RepoInfo) GetTabs() [][]string { {"pulls", "/pulls"}, } - if r.SettingsAllowed { + if r.Roles.SettingsAllowed() { tabs = append(tabs, []string{"settings", "/settings"}) } diff --git a/appview/pages/templates/fragments/editRepoDescription.html b/appview/pages/templates/fragments/editRepoDescription.html new file mode 100644 index 00000000..503f2098 --- /dev/null +++ b/appview/pages/templates/fragments/editRepoDescription.html @@ -0,0 +1,9 @@ +{{ define "fragments/editRepoDescription" }} +
+ + + +
+{{ end }} diff --git a/appview/pages/templates/fragments/repoDescription.html b/appview/pages/templates/fragments/repoDescription.html new file mode 100644 index 00000000..dfff3e85 --- /dev/null +++ b/appview/pages/templates/fragments/repoDescription.html @@ -0,0 +1,15 @@ +{{ define "fragments/repoDescription" }} + + {{ if .RepoInfo.Description }} + {{ .RepoInfo.Description }} + {{ else }} + this repo has no description + {{ end }} + + {{ if .RepoInfo.Roles.IsOwner }} + + {{ end }} + +{{ end }} diff --git a/appview/pages/templates/layouts/repobase.html b/appview/pages/templates/layouts/repobase.html index 9c3866b8..0af4cc73 100644 --- a/appview/pages/templates/layouts/repobase.html +++ b/appview/pages/templates/layouts/repobase.html @@ -10,13 +10,7 @@

{{ template "fragments/star" .RepoInfo }} - - {{ if .RepoInfo.Description }} - {{ .RepoInfo.Description }} - {{ else }} - this repo has no description - {{ end }} - + {{ template "fragments/repoDescription" . }}