Author | Jakob Wakeling <[email protected]> |
Date | 2024-01-17 05:29:55 |
Commit | 778d467788ab9cebaa2c363dbafab8995ae70388 |
Parent | c8b452e408c53b747de7f8bcc271cd34b8766d78 |
Add limited visibility option for repositories
Diffstat
M | res/admin/repo_edit.html | | | 5 | +++-- |
M | res/repo/create.html | | | 5 | +++-- |
M | res/repo/edit.html | | | 5 | +++-- |
M | src/admin/repos.go | | | 18 | ++++++++++-------- |
M | src/goit/db.go | | | 49 | ++++++++++++++++++++++++++++++++++++++++++++++++- |
M | src/goit/git.go | | | 6 | +++--- |
M | src/goit/goit.go | | | 8 | ++++++-- |
M | src/goit/index.go | | | 5 | ++--- |
M | src/goit/repo.go | | | 69 | +++++++++++++++++++++++++++++++++++++++++++++++++++------------------ |
M | src/repo/commit.go | | | 2 | +- |
M | src/repo/create.go | | | 16 | ++++++++++------ |
M | src/repo/download.go | | | 2 | +- |
M | src/repo/edit.go | | | 16 | +++++++++------- |
M | src/repo/file.go | | | 2 | +- |
M | src/repo/log.go | | | 2 | +- |
M | src/repo/raw.go | | | 2 | +- |
M | src/repo/refs.go | | | 2 | +- |
M | src/repo/tree.go | | | 2 | +- |
18 files changed, 155 insertions, 61 deletions
diff --git a/res/admin/repo_edit.html b/res/admin/repo_edit.html index 610c1da..4d85d60 100644 --- a/res/admin/repo_edit.html +++ b/res/admin/repo_edit.html @@ -33,8 +33,9 @@ <td style="text-align: right;"><label for="visibility">Visibility:</label></td> <td> <select name="visibility"> - <option value="public">Public</option> - <option value="private" {{if .Edit.IsPrivate}}selected{{end}}>Private</option> + <option value="public" {{if eq .Edit.Visibility "public"}}selected{{end}}>Public</option> + <option value="private" {{if eq .Edit.Visibility "private"}}selected{{end}}>Private</option> + <option value="limited" {{if eq .Edit.Visibility "limited"}}selected{{end}}>Limited</option> </select> </td> </tr> diff --git a/res/repo/create.html b/res/repo/create.html index b06dada..40510d1 100644 --- a/res/repo/create.html +++ b/res/repo/create.html @@ -31,8 +31,9 @@ <td style="text-align: right;"><label for="visibility">Visibility</label></td> <td> <select name="visibility"> - <option value="public">Public</option> - <option value="private" {{if .IsPrivate}}selected{{end}}>Private</option> + <option value="public" {{if eq .Visibility "public"}}selected{{end}}>Public</option> + <option value="private" {{if eq .Visibility "private"}}selected{{end}}>Private</option> + <option value="limited" {{if eq .Visibility "limited"}}selected{{end}}>Limited</option> </select> </td> </tr> diff --git a/res/repo/edit.html b/res/repo/edit.html index a8537c9..fd43599 100644 --- a/res/repo/edit.html +++ b/res/repo/edit.html @@ -33,8 +33,9 @@ <td style="text-align: right;"><label for="visibility">Visibility</label></td> <td> <select name="visibility"> - <option value="public">Public</option> - <option value="private" {{if .Edit.IsPrivate}}selected{{end}}>Private</option> + <option value="public" {{if eq .Edit.Visibility "public"}}selected{{end}}>Public</option> + <option value="private" {{if eq .Edit.Visibility "private"}}selected{{end}}>Private</option> + <option value="limited" {{if eq .Edit.Visibility "limited"}}selected{{end}}>Limited</option> </select> </td> </tr> diff --git a/src/admin/repos.go b/src/admin/repos.go index 826d959..0ec15cb 100644 --- a/src/admin/repos.go +++ b/src/admin/repos.go @@ -58,7 +58,7 @@ func HandleRepos(w http.ResponseWriter, r *http.Request) { } data.Repos = append(data.Repos, row{ - fmt.Sprint(r.Id), u.Name, r.Name, util.If(r.IsPrivate, "private", "public"), humanize.IBytes(size), + fmt.Sprint(r.Id), u.Name, r.Name, r.Visibility.String(), humanize.IBytes(size), }) } @@ -110,10 +110,10 @@ func HandleRepoEdit(w http.ResponseWriter, r *http.Request) { Title, Name string Edit struct { - Id, Owner, Name, Description string - DefaultBranch, Upstream string - IsPrivate, IsMirror bool - Message string + Id, Owner, Name, Description string + DefaultBranch, Upstream, Visibility string + IsMirror bool + Message string } Transfer struct{ Owner, Message string } @@ -133,7 +133,7 @@ func HandleRepoEdit(w http.ResponseWriter, r *http.Request) { data.Edit.Description = repo.Description data.Edit.DefaultBranch = repo.DefaultBranch data.Edit.Upstream = repo.Upstream - data.Edit.IsPrivate = repo.IsPrivate + data.Edit.Visibility = repo.Visibility.String() data.Edit.IsMirror = repo.IsMirror if r.Method == http.MethodPost { @@ -143,7 +143,7 @@ func HandleRepoEdit(w http.ResponseWriter, r *http.Request) { data.Edit.Description = r.FormValue("description") data.Edit.DefaultBranch = util.If(r.FormValue("branch") == "", "master", r.FormValue("branch")) data.Edit.Upstream = r.FormValue("upstream") - data.Edit.IsPrivate = r.FormValue("visibility") == "private" + data.Edit.Visibility = r.FormValue("visibility") data.Edit.IsMirror = r.FormValue("mirror") == "mirror" if data.Edit.Name == "" { @@ -158,9 +158,11 @@ func HandleRepoEdit(w http.ResponseWriter, r *http.Request) { data.Edit.Message = "Name \"" + data.Edit.Name + "\" is taken" } else if len(data.Edit.Description) > 256 { data.Edit.Message = "Description cannot exceed 256 characters" + } else if visibility := goit.VisibilityFromString(data.Edit.Visibility); visibility == -1 { + data.Edit.Message = "Visibility \"" + data.Edit.Visibility + "\" is invalid" } else if err := goit.UpdateRepo(repo.Id, goit.Repo{ Name: data.Edit.Name, Description: data.Edit.Description, DefaultBranch: data.Edit.DefaultBranch, - Upstream: data.Edit.Upstream, IsPrivate: data.Edit.IsPrivate, IsMirror: data.Edit.IsMirror, + Upstream: data.Edit.Upstream, Visibility: visibility, IsMirror: data.Edit.IsMirror, }); err != nil { log.Println("[/admin/repo/edit]", err.Error()) goit.HttpError(w, http.StatusInternalServerError) diff --git a/src/goit/db.go b/src/goit/db.go index e3abea7..2f88de6 100644 --- a/src/goit/db.go +++ b/src/goit/db.go @@ -4,6 +4,8 @@ import ( "database/sql" "fmt" "log" + + "github.com/Jamozed/Goit/src/util" ) /* @@ -32,7 +34,7 @@ import ( */ func dbUpdate(db *sql.DB) error { - latestVersion := 2 + latestVersion := 3 var version int if err := db.QueryRow("PRAGMA user_version").Scan(&version); err != nil { @@ -94,6 +96,51 @@ func dbUpdate(db *sql.DB) error { } version = 2 + + case 2: /* 2 -> 3 */ + log.Println("Migrating database from version 2 to 3") + + if _, err := db.Exec( + "ALTER TABLE repos ADD COLUMN visibility INTEGER NOT NULL DEFAULT 0", + ); err != nil { + return err + } + + /* Set values for each repo according to is_private */ + var visibilities = map[int64]Visibility{} + + if rows, err := db.Query("SELECT id, is_private FROM repos"); err != nil { + return err + } else { + for rows.Next() { + var id int64 + var isPrivate bool + + if err := rows.Scan(&id, &isPrivate); err != nil { + return err + } + + visibilities[id] = util.If(isPrivate, Private, Public) + } + + rows.Close() + } + + for id, visibility := range visibilities { + if _, err := db.Exec( + "UPDATE repos SET visibility = ? WHERE id = ?", visibility, id, + ); err != nil { + return err + } + } + + /* Remove is_private column */ + if _, err := db.Exec("ALTER TABLE repos DROP COLUMN is_private"); err != nil { + return err + } + + version = 3 + default: /* No required migrations */ goto done } diff --git a/src/goit/git.go b/src/goit/git.go index d6b1737..5464296 100644 --- a/src/goit/git.go +++ b/src/goit/git.go @@ -103,7 +103,7 @@ func gitHttpBase(w http.ResponseWriter, r *http.Request, service string) *Repo { } /* Require authentication other than for public pull */ - if repo == nil || repo.IsPrivate || service == "git-receive-pack" { + if repo == nil || repo.Visibility != Public || service == "git-receive-pack" { username, password, ok := r.BasicAuth() if !ok { w.Header().Set("WWW-Authenticate", "Basic realm=\"git\"") @@ -125,8 +125,8 @@ func gitHttpBase(w http.ResponseWriter, r *http.Request, service string) *Repo { return nil } - /* If the repo doesn't exist or isn't owned by the user */ - if repo == nil || user.Id != repo.OwnerId { + /* If the repo doesn't exist or is private and not owned by the user */ + if repo == nil || (repo.Visibility == Private && user.Id != repo.OwnerId) { w.WriteHeader(http.StatusNotFound) return nil } diff --git a/src/goit/goit.go b/src/goit/goit.go index c96acb0..f2ed0c8 100644 --- a/src/goit/goit.go +++ b/src/goit/goit.go @@ -199,14 +199,18 @@ func Backup() error { rows.Close() /* Dump repositories */ - rows, err = db.Query("SELECT id, owner_id, name, description, is_private FROM repos") + rows, err = db.Query( + "SELECT id, owner_id, name, description, default_branch, upstream, visibility, is_mirror FROM repos", + ) if err != nil { return err } for rows.Next() { r := Repo{} - if err := rows.Scan(&r.Id, &r.OwnerId, &r.Name, &r.Description, &r.IsPrivate); err != nil { + if err := rows.Scan( + &r.Id, &r.OwnerId, &r.Name, &r.Description, &r.DefaultBranch, &r.Upstream, &r.Visibility, &r.IsMirror, + ); err != nil { return err } diff --git a/src/goit/index.go b/src/goit/index.go index d2b7fcf..e127415 100644 --- a/src/goit/index.go +++ b/src/goit/index.go @@ -11,7 +11,6 @@ import ( "strings" "time" - "github.com/Jamozed/Goit/src/util" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" ) @@ -47,7 +46,7 @@ func HandleIndex(w http.ResponseWriter, r *http.Request) { rtemp := repos[:0] for _, repo := range repos { - if !repo.IsPrivate || (auth && user.Id == repo.OwnerId) { + if IsVisible(&repo, auth, user) { rtemp = append(rtemp, repo) } } @@ -84,7 +83,7 @@ func HandleIndex(w http.ResponseWriter, r *http.Request) { data.Repos = append(data.Repos, row{ Name: repo.Name, Description: repo.Description, Owner: owner.Name, - Visibility: util.If(repo.IsPrivate, "private", "public"), LastCommit: lastCommit, + Visibility: repo.Visibility.String(), LastCommit: lastCommit, }) } diff --git a/src/goit/repo.go b/src/goit/repo.go index 32efa11..6a7bf86 100644 --- a/src/goit/repo.go +++ b/src/goit/repo.go @@ -18,21 +18,46 @@ import ( ) type Repo struct { - Id int64 `json:"id"` - OwnerId int64 `json:"owner_id"` - Name string `json:"name"` - Description string `json:"description"` - DefaultBranch string `json:"default_branch"` - Upstream string `json:"upstream"` - IsPrivate bool `json:"is_private"` - IsMirror bool `json:"is_mirror"` + Id int64 `json:"id"` + OwnerId int64 `json:"owner_id"` + Name string `json:"name"` + Description string `json:"description"` + DefaultBranch string `json:"default_branch"` + Upstream string `json:"upstream"` + Visibility Visibility `json:"visibility"` + IsMirror bool `json:"is_mirror"` +} + +type Visibility int32 + +const ( + Public Visibility = 0 + Private Visibility = 1 + Limited Visibility = 2 +) + +func VisibilityFromString(s string) Visibility { + switch strings.ToLower(s) { + case "public": + return Public + case "private": + return Private + case "limited": + return Limited + default: + return -1 + } +} + +func (v Visibility) String() string { + return [...]string{"public", "private", "limited"}[v] } func GetRepos() ([]Repo, error) { repos := []Repo{} rows, err := db.Query( - "SELECT id, owner_id, name, description, default_branch, upstream, is_private, is_mirror FROM repos", + "SELECT id, owner_id, name, description, default_branch, upstream, visibility, is_mirror FROM repos", ) if err != nil { return nil, err @@ -43,7 +68,7 @@ func GetRepos() ([]Repo, error) { for rows.Next() { r := Repo{} if err := rows.Scan( - &r.Id, &r.OwnerId, &r.Name, &r.Description, &r.DefaultBranch, &r.Upstream, &r.IsPrivate, &r.IsMirror, + &r.Id, &r.OwnerId, &r.Name, &r.Description, &r.DefaultBranch, &r.Upstream, &r.Visibility, &r.IsMirror, ); err != nil { return nil, err } @@ -62,10 +87,10 @@ func GetRepo(rid int64) (*Repo, error) { r := &Repo{} if err := db.QueryRow( - `SELECT id, owner_id, name, description, default_branch, upstream, is_private, is_mirror FROM repos + `SELECT id, owner_id, name, description, default_branch, upstream, visibility, is_mirror FROM repos WHERE id = ?`, rid, ).Scan( - &r.Id, &r.OwnerId, &r.Name, &r.Description, &r.DefaultBranch, &r.Upstream, &r.IsPrivate, &r.IsMirror, + &r.Id, &r.OwnerId, &r.Name, &r.Description, &r.DefaultBranch, &r.Upstream, &r.Visibility, &r.IsMirror, ); err != nil { if !errors.Is(err, sql.ErrNoRows) { return nil, err @@ -81,10 +106,10 @@ func GetRepoByName(name string) (*Repo, error) { r := &Repo{} if err := db.QueryRow( - `SELECT id, owner_id, name, description, default_branch, upstream, is_private, is_mirror FROM repos + `SELECT id, owner_id, name, description, default_branch, upstream, visibility, is_mirror FROM repos WHERE name = ?`, name, ).Scan( - &r.Id, &r.OwnerId, &r.Name, &r.Description, &r.DefaultBranch, &r.Upstream, &r.IsPrivate, &r.IsMirror, + &r.Id, &r.OwnerId, &r.Name, &r.Description, &r.DefaultBranch, &r.Upstream, &r.Visibility, &r.IsMirror, ); err != nil { if !errors.Is(err, sql.ErrNoRows) { return nil, err @@ -103,9 +128,9 @@ func CreateRepo(repo Repo) (int64, error) { } res, err := tx.Exec( - `INSERT INTO repos (owner_id, name, name_lower, description, default_branch, upstream, is_private, is_mirror) + `INSERT INTO repos (owner_id, name, name_lower, description, default_branch, upstream, visibility, is_mirror) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, repo.OwnerId, repo.Name, strings.ToLower(repo.Name), repo.Description, - repo.DefaultBranch, repo.Upstream, repo.IsPrivate, repo.IsMirror, + repo.DefaultBranch, repo.Upstream, repo.Visibility, repo.IsMirror, ) if err != nil { tx.Rollback() @@ -193,9 +218,9 @@ func UpdateRepo(rid int64, repo Repo) error { } if _, err := tx.Exec( - `UPDATE repos SET name = ?, name_lower = ?, description = ?, default_branch = ?, upstream = ?, is_private = ?, + `UPDATE repos SET name = ?, name_lower = ?, description = ?, default_branch = ?, upstream = ?, visibility = ?, is_mirror = ? WHERE id = ?`, repo.Name, strings.ToLower(repo.Name), repo.Description, repo.DefaultBranch, - repo.Upstream, repo.IsPrivate, repo.IsMirror, rid, + repo.Upstream, repo.Visibility, repo.IsMirror, rid, ); err != nil { tx.Rollback() return err @@ -305,3 +330,11 @@ func Pull(rid int64) error { return nil } + +func IsVisible(repo *Repo, auth bool, user *User) bool { + if repo.Visibility == Public || (repo.Visibility == Limited && auth) || (auth && user.Id == repo.OwnerId) { + return true + } + + return false +} diff --git a/src/repo/commit.go b/src/repo/commit.go index 6b353aa..4dd0e79 100644 --- a/src/repo/commit.go +++ b/src/repo/commit.go @@ -32,7 +32,7 @@ func HandleCommit(w http.ResponseWriter, r *http.Request) { if err != nil { goit.HttpError(w, http.StatusInternalServerError) return - } else if repo == nil || (repo.IsPrivate && (!auth || repo.OwnerId != user.Id)) { + } else if repo == nil || !goit.IsVisible(repo, auth, user) { goit.HttpError(w, http.StatusNotFound) return } diff --git a/src/repo/create.go b/src/repo/create.go index 6f380ea..9774fe3 100644 --- a/src/repo/create.go +++ b/src/repo/create.go @@ -29,10 +29,10 @@ func HandleCreate(w http.ResponseWriter, r *http.Request) { } data := struct { - Title, Message string - Name, Description string - DefaultBranch, Url string - IsPrivate, IsMirror bool + Title, Message string + Name, Description string + DefaultBranch, Url, Visibility string + IsMirror bool CsrfField template.HTML }{ @@ -46,7 +46,7 @@ func HandleCreate(w http.ResponseWriter, r *http.Request) { data.Description = r.FormValue("description") data.DefaultBranch = util.If(r.FormValue("branch") == "", "master", r.FormValue("branch")) data.Url = r.FormValue("url") - data.IsPrivate = r.FormValue("visibility") == "private" + data.Visibility = r.FormValue("visibility") data.IsMirror = r.FormValue("mirror") == "mirror" if data.Name == "" { @@ -59,9 +59,13 @@ func HandleCreate(w http.ResponseWriter, r *http.Request) { return } else if exists { data.Message = "Name \"" + data.Name + "\" is taken" + } else if len(data.Description) > 256 { + data.Message = "Description cannot exceed 256 characters" + } else if visibility := goit.VisibilityFromString(data.Visibility); visibility == -1 { + data.Message = "Visibility \"" + data.Visibility + "\" is invalid" } else if rid, err := goit.CreateRepo(goit.Repo{ OwnerId: user.Id, Name: data.Name, Description: data.Description, DefaultBranch: data.DefaultBranch, - Upstream: data.Url, IsPrivate: data.IsPrivate, IsMirror: data.IsMirror, + Upstream: data.Url, Visibility: visibility, IsMirror: data.IsMirror, }); err != nil { log.Println("[/repo/create]", err.Error()) goit.HttpError(w, http.StatusInternalServerError) diff --git a/src/repo/download.go b/src/repo/download.go index 6c24c0b..e7f91d8 100644 --- a/src/repo/download.go +++ b/src/repo/download.go @@ -35,7 +35,7 @@ func HandleDownload(w http.ResponseWriter, r *http.Request) { if err != nil { goit.HttpError(w, http.StatusInternalServerError) return - } else if repo == nil || (repo.IsPrivate && (!auth || user.Id != repo.OwnerId)) { + } else if repo == nil || !goit.IsVisible(repo, auth, user) { goit.HttpError(w, http.StatusNotFound) return } diff --git a/src/repo/edit.go b/src/repo/edit.go index a709f73..f738409 100644 --- a/src/repo/edit.go +++ b/src/repo/edit.go @@ -61,10 +61,10 @@ func HandleEdit(w http.ResponseWriter, r *http.Request) { Title string Edit struct { - Id, Owner, Name, Description string - DefaultBranch, Upstream string - IsPrivate, IsMirror bool - Message string + Id, Owner, Name, Description string + DefaultBranch, Upstream, Visibility string + IsMirror bool + Message string } Transfer struct{ Owner, Message string } @@ -84,7 +84,7 @@ func HandleEdit(w http.ResponseWriter, r *http.Request) { data.Edit.Description = repo.Description data.Edit.DefaultBranch = repo.DefaultBranch data.Edit.Upstream = repo.Upstream - data.Edit.IsPrivate = repo.IsPrivate + data.Edit.Visibility = repo.Visibility.String() data.Edit.IsMirror = repo.IsMirror gr, err := git.PlainOpen(goit.RepoPath(repo.Name, true)) @@ -117,7 +117,7 @@ func HandleEdit(w http.ResponseWriter, r *http.Request) { data.Edit.Description = r.FormValue("description") data.Edit.DefaultBranch = util.If(r.FormValue("branch") == "", "master", r.FormValue("branch")) data.Edit.Upstream = r.FormValue("upstream") - data.Edit.IsPrivate = r.FormValue("visibility") == "private" + data.Edit.Visibility = r.FormValue("visibility") data.Edit.IsMirror = r.FormValue("mirror") == "mirror" if data.Edit.Name == "" { @@ -132,9 +132,11 @@ func HandleEdit(w http.ResponseWriter, r *http.Request) { data.Edit.Message = "Name \"" + data.Edit.Name + "\" is taken" } else if len(data.Edit.Description) > 256 { data.Edit.Message = "Description cannot exceed 256 characters" + } else if visibility := goit.VisibilityFromString(data.Edit.Visibility); visibility == -1 { + data.Edit.Message = "Visibility \"" + data.Edit.Visibility + "\" is invalid" } else if err := goit.UpdateRepo(repo.Id, goit.Repo{ Name: data.Edit.Name, Description: data.Edit.Description, DefaultBranch: data.Edit.DefaultBranch, - Upstream: data.Edit.Upstream, IsPrivate: data.Edit.IsPrivate, IsMirror: data.Edit.IsMirror, + Upstream: data.Edit.Upstream, Visibility: visibility, IsMirror: data.Edit.IsMirror, }); err != nil { log.Println("[/repo/edit]", err.Error()) goit.HttpError(w, http.StatusInternalServerError) diff --git a/src/repo/file.go b/src/repo/file.go index 5a4ba8d..01badea 100644 --- a/src/repo/file.go +++ b/src/repo/file.go @@ -35,7 +35,7 @@ func HandleFile(w http.ResponseWriter, r *http.Request) { if err != nil { goit.HttpError(w, http.StatusInternalServerError) return - } else if repo == nil || (repo.IsPrivate && (!auth || repo.OwnerId != user.Id)) { + } else if repo == nil || !goit.IsVisible(repo, auth, user) { goit.HttpError(w, http.StatusNotFound) return } diff --git a/src/repo/log.go b/src/repo/log.go index 4c14f4a..248b9ba 100644 --- a/src/repo/log.go +++ b/src/repo/log.go @@ -37,7 +37,7 @@ func HandleLog(w http.ResponseWriter, r *http.Request) { if err != nil { goit.HttpError(w, http.StatusInternalServerError) return - } else if repo == nil || (repo.IsPrivate && (!auth || repo.OwnerId != user.Id)) { + } else if repo == nil || !goit.IsVisible(repo, auth, user) { goit.HttpError(w, http.StatusNotFound) return } diff --git a/src/repo/raw.go b/src/repo/raw.go index c46fab6..788dd0f 100644 --- a/src/repo/raw.go +++ b/src/repo/raw.go @@ -30,7 +30,7 @@ func HandleRaw(w http.ResponseWriter, r *http.Request) { if err != nil { goit.HttpError(w, http.StatusInternalServerError) return - } else if repo == nil || (repo.IsPrivate && (!auth || user.Id != repo.OwnerId)) { + } else if repo == nil || !goit.IsVisible(repo, auth, user) { goit.HttpError(w, http.StatusNotFound) return } diff --git a/src/repo/refs.go b/src/repo/refs.go index f76afb9..024c40a 100644 --- a/src/repo/refs.go +++ b/src/repo/refs.go @@ -30,7 +30,7 @@ func HandleRefs(w http.ResponseWriter, r *http.Request) { if err != nil { goit.HttpError(w, http.StatusInternalServerError) return - } else if repo == nil || (repo.IsPrivate && (!auth || repo.OwnerId != user.Id)) { + } else if repo == nil || !goit.IsVisible(repo, auth, user) { goit.HttpError(w, http.StatusNotFound) return } diff --git a/src/repo/tree.go b/src/repo/tree.go index 08ef072..22e307f 100644 --- a/src/repo/tree.go +++ b/src/repo/tree.go @@ -34,7 +34,7 @@ func HandleTree(w http.ResponseWriter, r *http.Request) { if err != nil { goit.HttpError(w, http.StatusInternalServerError) return - } else if repo == nil || (repo.IsPrivate && (!auth || repo.OwnerId != user.Id)) { + } else if repo == nil || !goit.IsVisible(repo, auth, user) { goit.HttpError(w, http.StatusNotFound) return }