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

Compare changes

Choose any two refs to compare.

Changed files
+235 -28
appview
db
middleware
pages
templates
repo
issues
pagination
state
docs
+35 -20
appview/db/issues.go
···
"time"
"github.com/bluesky-social/indigo/atproto/syntax"
+
"tangled.sh/tangled.sh/core/appview/pagination"
)
type Issue struct {
···
return ownerDid, err
}
-
func GetIssues(e Execer, repoAt syntax.ATURI, isOpen bool) ([]Issue, error) {
+
func GetIssues(e Execer, repoAt syntax.ATURI, isOpen bool, page pagination.Page) ([]Issue, error) {
var issues []Issue
openValue := 0
if isOpen {
···
}
rows, err := e.Query(
-
`select
-
i.owner_did,
-
i.issue_id,
-
i.created,
-
i.title,
-
i.body,
-
i.open,
-
count(c.id)
-
from
-
issues i
-
left join
-
comments c on i.repo_at = c.repo_at and i.issue_id = c.issue_id
-
where
-
i.repo_at = ? and i.open = ?
-
group by
-
i.id, i.owner_did, i.issue_id, i.created, i.title, i.body, i.open
-
order by
-
i.created desc`,
-
repoAt, openValue)
+
`
+
with numbered_issue as (
+
select
+
i.owner_did,
+
i.issue_id,
+
i.created,
+
i.title,
+
i.body,
+
i.open,
+
count(c.id) as comment_count,
+
row_number() over (order by i.created desc) as row_num
+
from
+
issues i
+
left join
+
comments c on i.repo_at = c.repo_at and i.issue_id = c.issue_id
+
where
+
i.repo_at = ? and i.open = ?
+
group by
+
i.id, i.owner_did, i.issue_id, i.created, i.title, i.body, i.open
+
)
+
select
+
owner_did,
+
issue_id,
+
created,
+
title,
+
body,
+
open,
+
comment_count
+
from
+
numbered_issue
+
where
+
row_num between ? and ?`,
+
repoAt, openValue, page.Offset+1, page.Offset+page.Limit)
if err != nil {
return nil, err
}
+32
appview/middleware/middleware.go
···
package middleware
import (
+
"context"
"log"
"net/http"
+
"strconv"
"time"
comatproto "github.com/bluesky-social/indigo/api/atproto"
"github.com/bluesky-social/indigo/xrpc"
"tangled.sh/tangled.sh/core/appview"
"tangled.sh/tangled.sh/core/appview/auth"
+
"tangled.sh/tangled.sh/core/appview/pagination"
)
type Middleware func(http.Handler) http.Handler
···
})
}
}
+
+
func Paginate(next http.Handler) http.Handler {
+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+
page := pagination.FirstPage()
+
+
offsetVal := r.URL.Query().Get("offset")
+
if offsetVal != "" {
+
offset, err := strconv.Atoi(offsetVal)
+
if err != nil {
+
log.Println("invalid offset")
+
} else {
+
page.Offset = offset
+
}
+
}
+
+
limitVal := r.URL.Query().Get("limit")
+
if limitVal != "" {
+
limit, err := strconv.Atoi(limitVal)
+
if err != nil {
+
log.Println("invalid limit")
+
} else {
+
page.Limit = limit
+
}
+
}
+
+
ctx := context.WithValue(r.Context(), "page", page)
+
next.ServeHTTP(w, r.WithContext(ctx))
+
})
+
}
+7 -6
appview/pages/pages.go
···
"tangled.sh/tangled.sh/core/appview/auth"
"tangled.sh/tangled.sh/core/appview/db"
"tangled.sh/tangled.sh/core/appview/pages/markup"
+
"tangled.sh/tangled.sh/core/appview/pagination"
"tangled.sh/tangled.sh/core/appview/state/userutil"
"tangled.sh/tangled.sh/core/patchutil"
"tangled.sh/tangled.sh/core/types"
···
}
type RepoIssuesParams struct {
-
LoggedInUser *auth.User
-
RepoInfo RepoInfo
-
Active string
-
Issues []db.Issue
-
DidHandleMap map[string]string
-
+
LoggedInUser *auth.User
+
RepoInfo RepoInfo
+
Active string
+
Issues []db.Issue
+
DidHandleMap map[string]string
+
Page pagination.Page
FilteringByOpen bool
}
+38
appview/pages/templates/repo/issues/issues.html
···
</div>
{{ end }}
</div>
+
+
{{ block "pagination" . }} {{ end }}
+
+
{{ end }}
+
+
{{ define "pagination" }}
+
<div class="flex justify-end mt-4 gap-2">
+
{{ $currentState := "closed" }}
+
{{ if .FilteringByOpen }}
+
{{ $currentState = "open" }}
+
{{ end }}
+
+
{{ if gt .Page.Offset 0 }}
+
{{ $prev := .Page.Previous }}
+
<a
+
class="btn flex items-center gap-2 no-underline hover:no-underline dark:text-white dark:hover:bg-gray-700"
+
hx-boost="true"
+
href = "/{{ $.RepoInfo.FullName }}/issues?state={{ $currentState }}&offset={{ $prev.Offset }}&limit={{ $prev.Limit }}"
+
>
+
{{ i "chevron-left" "w-4 h-4" }}
+
previous
+
</a>
+
{{ else }}
+
<div></div>
+
{{ end }}
+
+
{{ if eq (len .Issues) .Page.Limit }}
+
{{ $next := .Page.Next }}
+
<a
+
class="btn flex items-center gap-2 no-underline hover:no-underline dark:text-white dark:hover:bg-gray-700"
+
hx-boost="true"
+
href = "/{{ $.RepoInfo.FullName }}/issues?state={{ $currentState }}&offset={{ $next.Offset }}&limit={{ $next.Limit }}"
+
>
+
next
+
{{ i "chevron-right" "w-4 h-4" }}
+
</a>
+
{{ end }}
+
</div>
{{ end }}
+31
appview/pagination/page.go
···
+
package pagination
+
+
type Page struct {
+
Offset int // where to start from
+
Limit int // number of items in a page
+
}
+
+
func FirstPage() Page {
+
return Page{
+
Offset: 0,
+
Limit: 10,
+
}
+
}
+
+
func (p Page) Previous() Page {
+
if p.Offset-p.Limit < 0 {
+
return FirstPage()
+
} else {
+
return Page{
+
Offset: p.Offset - p.Limit,
+
Limit: p.Limit,
+
}
+
}
+
}
+
+
func (p Page) Next() Page {
+
return Page{
+
Offset: p.Offset + p.Limit,
+
Limit: p.Limit,
+
}
+
}
+9 -1
appview/state/repo.go
···
"tangled.sh/tangled.sh/core/appview/db"
"tangled.sh/tangled.sh/core/appview/pages"
"tangled.sh/tangled.sh/core/appview/pages/markup"
+
"tangled.sh/tangled.sh/core/appview/pagination"
"tangled.sh/tangled.sh/core/types"
comatproto "github.com/bluesky-social/indigo/api/atproto"
···
isOpen = true
+
page, ok := r.Context().Value("page").(pagination.Page)
+
if !ok {
+
log.Println("failed to get page")
+
page = pagination.FirstPage()
+
}
+
user := s.auth.GetUser(r)
f, err := fullyResolvedRepo(r)
if err != nil {
···
return
-
issues, err := db.GetIssues(s.db, f.RepoAt, isOpen)
+
issues, err := db.GetIssues(s.db, f.RepoAt, isOpen, page)
if err != nil {
log.Println("failed to get issues", err)
s.pages.Notice(w, "issues", "Failed to load issues. Try again later.")
···
Issues: issues,
DidHandleMap: didHandleMap,
FilteringByOpen: isOpen,
+
Page: page,
})
return
+1 -1
appview/state/router.go
···
r.Get("/blob/{ref}/raw/*", s.RepoBlobRaw)
r.Route("/issues", func(r chi.Router) {
-
r.Get("/", s.RepoIssues)
+
r.With(middleware.Paginate).Get("/", s.RepoIssues)
r.Get("/{issue}", s.RepoSingleIssue)
r.Group(func(r chi.Router) {
+82
docs/knot-hosting.md
···
You should now have a running knot server! You can finalize your registration by hitting the
`initialize` button on the [/knots](/knots) page.
+
+
### custom paths
+
+
(This section applies to manual setup only. Docker users should edit the mounts
+
in `docker-compose.yml` instead.)
+
+
Right now, the database and repositories of your knot lives in `/home/git`. You
+
can move these paths if you'd like to store them in another folder. Be careful
+
when adjusting these paths:
+
+
* Stop your knot when moving data (e.g. `systemctl stop knotserver`) to prevent
+
any possible side effects. Remember to restart it once you're done.
+
* Make backups before moving in case something goes wrong.
+
* Make sure the `git` user can read and write from the new paths.
+
+
#### database
+
+
As an example, let's say the current database is at `/home/git/knotserver.db`,
+
and we want to move it to `/home/git/database/knotserver.db`.
+
+
Copy the current database to the new location. Make sure to copy the `.db-shm`
+
and `.db-wal` files if they exist.
+
+
```
+
mkdir /home/git/database
+
cp /home/git/knotserver.db* /home/git/database
+
```
+
+
In the environment (e.g. `/home/git/.knot.env`), set `KNOT_SERVER_DB_PATH` to
+
the new file path (_not_ the directory):
+
+
```
+
KNOT_SERVER_DB_PATH=/home/git/database/knotserver.db
+
```
+
+
#### repositories
+
+
As an example, let's say the repositories are currently in `/home/git`, and we
+
want to move them into `/home/git/repositories`.
+
+
Create the new folder, then move the existing repositories (if there are any):
+
+
```
+
mkdir /home/git/repositories
+
# move all DIDs into the new folder; these will vary for you!
+
mv /home/git/did:plc:wshs7t2adsemcrrd4snkeqli /home/git/repositories
+
```
+
+
In the environment (e.g. `/home/git/.knot.env`), update `KNOT_REPO_SCAN_PATH`
+
to the new directory:
+
+
```
+
KNOT_REPO_SCAN_PATH=/home/git/repositories
+
```
+
+
In your SSH config (e.g. `/etc/ssh/sshd_config.d/authorized_keys_command.conf`),
+
update the `AuthorizedKeysCommand` line to use the new folder. For example:
+
+
```
+
Match User git
+
AuthorizedKeysCommand /usr/local/libexec/tangled-keyfetch -git-dir /home/git/repositories
+
AuthorizedKeysCommandUser nobody
+
```
+
+
Make sure to restart your SSH server!
+
+
#### git
+
+
The keyfetch executable takes multiple arguments to change certain paths. You
+
can view a full list by running `/usr/local/libexec/tangled-keyfetch -h`.
+
+
As an example, if you wanted to change the path to the repoguard executable,
+
you would edit your SSH config (e.g. `/etc/ssh/sshd_config.d/authorized_keys_command.conf`)
+
and update the `AuthorizedKeysCommand` line:
+
+
```
+
Match User git
+
AuthorizedKeysCommand /usr/local/libexec/tangled-keyfetch -repoguard-path /path/to/repoguard
+
AuthorizedKeysCommandUser nobody
+
```
+
+
Make sure to restart your SSH server!