Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 17 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,23 @@ Oauth2 restrictions on SPA sites. You can read more about this here: https://arr

# How to use

1. Create a (private or public doesn't matter) repo in github under your user name called: "MyBookmarks"
2. Create 1 file in it called `bookmarks.txt` Put the following content (or anything you want really):
```text
Category: Search
http://www.google.com.au Google
Category: Wikies
http://en.wikipedia.org/wiki/Main_Page Wikipedia
http://mathworld.wolfram.com/ Math World
http://gentoo-wiki.com/Main_Page Gentoo-wiki
```
Ie:
![img_3.png](media/img_3.png)
3. Goto the URL this app is deployed at, your private instance or: https://bookmarks.arran.net.au
4. Enjoy
1. Sign up or log in using Git, GitHub or GitLab. On first use the service
creates a repository called `MyBookmarks` in your account containing a
`bookmarks.txt` file like:

```text
Category: Search
http://www.google.com.au Google
Category: Wikies
http://en.wikipedia.org/wiki/Main_Page Wikipedia
http://mathworld.wolfram.com/ Math World
http://gentoo-wiki.com/Main_Page Gentoo-wiki
```

![img_3.png](media/img_3.png)
2. Goto the URL this app is deployed at, your private instance or:
https://bookmarks.arran.net.au
3. Enjoy

## File format

Expand Down
26 changes: 26 additions & 0 deletions authHandlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/gorilla/mux"
"github.com/gorilla/securecookie"
"github.com/gorilla/sessions"
"golang.org/x/oauth2"
"log"
"net/http"
)
Expand Down Expand Up @@ -39,6 +40,21 @@ var (
SessionName string
)

// ensureRepo checks for the bookmarks repository and creates it with
// some default content when missing.
func ensureRepo(ctx context.Context, p Provider, user string, token *oauth2.Token) error {
if err := p.CreateBookmarks(ctx, user, token, "main", defaultBookmarks); err != nil {
if errors.Is(err, ErrRepoNotFound) {
if err := p.CreateRepo(ctx, user, token, RepoName); err != nil {
return err
}
return p.CreateBookmarks(ctx, user, token, "main", defaultBookmarks)
}
return err
}
return nil
}

func LoginWithProvider(w http.ResponseWriter, r *http.Request) error {
providerName := mux.Vars(r)["provider"]
p := GetProvider(providerName)
Expand Down Expand Up @@ -107,6 +123,13 @@ func Oauth2CallbackPage(w http.ResponseWriter, r *http.Request) error {
return fmt.Errorf("user lookup error: %w", err)
}

if err := ensureRepo(r.Context(), p, user.Login, token); err != nil {
// expire the session from the login step
session.Options.MaxAge = -1
_ = session.Save(r, w)
return fmt.Errorf("repository setup failed: %w", err)
}

session.Values["Provider"] = providerName
session.Values["GithubUser"] = user
session.Values["Token"] = token
Expand Down Expand Up @@ -165,6 +188,9 @@ func GitSignupAction(w http.ResponseWriter, r *http.Request) error {
if err := prov.CreateRepo(r.Context(), user, nil, RepoName); err != nil {
return err
}
if err := prov.CreateBookmarks(r.Context(), user, nil, "main", defaultBookmarks); err != nil {
return fmt.Errorf("create sample bookmarks: %w", err)
}
return nil
}

Expand Down
46 changes: 2 additions & 44 deletions bookmarkActionHandlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,43 +27,25 @@ func BookmarksEditSaveAction(w http.ResponseWriter, r *http.Request) error {
_, curSha, err := GetBookmarks(r.Context(), login, ref, token)
if err != nil {
if errors.Is(err, ErrRepoNotFound) {
// attempt to create the repository automatically
if p := providerFromContext(r.Context()); p != nil {
if err := p.CreateRepo(r.Context(), login, token, repoName); err == nil {
if err := CreateBookmarks(r.Context(), login, token, branch, text); err == nil {
http.Redirect(w, r, "/edit?ref=refs/heads/"+branch, http.StatusTemporaryRedirect)
// stop the handler chain so the default redirect isn't executed
return ErrHandled
}
}
}
return renderCreateRepoPrompt(w, r, text, branch, ref, sha, nil)
return fmt.Errorf("repository not found")
}
return fmt.Errorf("GetBookmarks: %w", err)
}
if sha != "" && curSha != sha {
return fmt.Errorf("bookmark modified concurrently")
}

if r.PostFormValue("createRepo") == "1" {
p := providerFromContext(r.Context())
if p == nil {
return fmt.Errorf("create repo: %w", ErrNoProvider)
}
if err := p.CreateRepo(r.Context(), login, token, repoName); err != nil {
return renderCreateRepoPrompt(w, r, text, branch, ref, sha, err)
}
if err := CreateBookmarks(r.Context(), login, token, branch, text); err != nil {
return fmt.Errorf("createBookmark error: %w", err)
}
http.Redirect(w, r, "/edit?ref=refs/heads/"+branch, http.StatusTemporaryRedirect)
// skip the chain's final redirect so we stay on the edit page
return ErrHandled
}

if err := UpdateBookmarks(r.Context(), login, token, ref, branch, text, curSha); err != nil {
if errors.Is(err, ErrRepoNotFound) {
return renderCreateRepoPrompt(w, r, text, branch, ref, sha, nil)
return fmt.Errorf("repository not found")
}
return fmt.Errorf("updateBookmark error: %w", err)
}
Expand Down Expand Up @@ -124,27 +106,3 @@ func CategoryEditSaveAction(w http.ResponseWriter, r *http.Request) error {
}
return nil
}

func renderCreateRepoPrompt(w http.ResponseWriter, r *http.Request, text, branch, ref, sha string, err error) error {
data := struct {
*CoreData
Text string
Branch string
Ref string
Sha string
Error string
}{
CoreData: r.Context().Value(ContextValues("coreData")).(*CoreData),
Text: text,
Branch: branch,
Ref: ref,
Sha: sha,
}
if err != nil {
data.Error = err.Error()
}
if tplErr := GetCompiledTemplates(NewFuncs(r)).ExecuteTemplate(w, "createRepo.gohtml", data); tplErr != nil {
return fmt.Errorf("template: %w", tplErr)
}
return ErrHandled
}
8 changes: 0 additions & 8 deletions data_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,14 +149,6 @@ func TestExecuteTemplates(t *testing.T) {
*CoreData
Error string
}{baseData.CoreData, "boom"}},
{"createRepo", "createRepo.gohtml", struct {
*CoreData
Text string
Branch string
Ref string
Sha string
Error string
}{baseData.CoreData, "text", "main", "ref", "sha", ""}},
}

for _, tt := range pages {
Expand Down
9 changes: 8 additions & 1 deletion provider_git.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,14 @@ func (GitProvider) CreateRepo(ctx context.Context, user string, token *oauth2.To
}
r, err := git.PlainInit(path, false)
if err != nil {
return err
if errors.Is(err, git.ErrRepositoryAlreadyExists) {
r, err = git.PlainOpen(path)
if err != nil {
return err
}
} else {
return err
}
}
wt, err := r.Worktree()
if err != nil {
Expand Down
9 changes: 7 additions & 2 deletions provider_github.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"encoding/base64"
"fmt"
"log"
"net/http"
"strings"

"github.com/google/go-github/v55/github"
Expand Down Expand Up @@ -164,8 +165,12 @@ func (p GitHubProvider) CreateRepo(ctx context.Context, user string, token *oaut
rep := &github.Repository{Name: &RepoName, Description: SP("Personal bookmarks"), Private: BP(true)}
rep, _, err := client.Repositories.Create(ctx, "", rep)
if err != nil {
log.Printf("github createRepo: %v", err)
return fmt.Errorf("Repositories.Create: %w", err)
if e, ok := err.(*github.ErrorResponse); ok && e.Response != nil && e.Response.StatusCode == http.StatusUnprocessableEntity {
// repository already exists
} else {
log.Printf("github createRepo: %v", err)
return fmt.Errorf("Repositories.Create: %w", err)
}
}
_, _, err = client.Repositories.CreateFile(ctx, user, RepoName, "readme.md", &github.RepositoryContentFileOptions{
Message: SP("Auto create from web"),
Expand Down
10 changes: 8 additions & 2 deletions provider_gitlab.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,8 +301,14 @@ func (p GitLabProvider) CreateRepo(ctx context.Context, user string, token *oaut
Visibility: gitlab.Ptr(gitlab.PrivateVisibility),
InitializeWithReadme: gitlab.Ptr(true),
})
if err != nil && gitlabUnauthorized(err) {
return ErrSignedOut
if err != nil {
if respErr, ok := err.(*gitlab.ErrorResponse); ok && respErr.Response != nil &&
(respErr.Response.StatusCode == http.StatusBadRequest || respErr.Response.StatusCode == http.StatusConflict) {
// repository already exists
err = nil
} else if gitlabUnauthorized(err) {
return ErrSignedOut
}
}
return err
}
23 changes: 0 additions & 23 deletions templates/createRepo.gohtml

This file was deleted.

Loading