summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gopmfile1
-rw-r--r--cmd/web.go3
-rw-r--r--models/pull.go7
-rw-r--r--models/release.go8
-rw-r--r--models/repo.go129
-rw-r--r--models/wiki.go56
-rw-r--r--modules/auth/repo_form.go18
-rw-r--r--modules/middleware/repo.go6
-rw-r--r--modules/process/manager.go3
-rw-r--r--routers/install.go3
-rw-r--r--routers/repo/http.go2
-rw-r--r--routers/repo/pull.go14
-rw-r--r--routers/repo/wiki.go27
-rw-r--r--templates/repo/wiki/new.tmpl3
-rw-r--r--templates/status/401.tmpl5
-rw-r--r--templates/status/403.tmpl5
16 files changed, 155 insertions, 135 deletions
diff --git a/.gopmfile b/.gopmfile
index db9c9b9586..e8224d7448 100644
--- a/.gopmfile
+++ b/.gopmfile
@@ -17,6 +17,7 @@ github.com/go-sql-driver/mysql = commit:d512f20
github.com/go-xorm/core = commit:3e10003353
github.com/go-xorm/xorm = commit:c643188
github.com/gogits/chardet = commit:2404f77725
+github.com/gogits/git-shell =
github.com/gogits/go-gogs-client = commit:7c02c95
github.com/issue9/identicon = commit:5a61672
github.com/klauspost/compress = commit:bbfa9dc
diff --git a/cmd/web.go b/cmd/web.go
index cb634a0eb2..56759ce72b 100644
--- a/cmd/web.go
+++ b/cmd/web.go
@@ -536,7 +536,8 @@ func runWeb(ctx *cli.Context) {
m.Get("/?:page", repo.Wiki)
m.Group("", func() {
- m.Get("/_new", repo.NewWiki)
+ m.Combo("/_new").Get(repo.NewWiki).
+ Post(bindIgnErr(auth.NewWikiForm{}), repo.NewWikiPost)
m.Get("/:page/_edit", repo.EditWiki)
}, reqSignIn)
}, middleware.RepoRef())
diff --git a/models/pull.go b/models/pull.go
index dfd80635e4..080819cb04 100644
--- a/models/pull.go
+++ b/models/pull.go
@@ -415,12 +415,7 @@ func (pr *PullRequest) UpdatePatch() (err error) {
return fmt.Errorf("GetOwner: %v", err)
}
- headRepoPath, err := pr.HeadRepo.RepoPath()
- if err != nil {
- return fmt.Errorf("HeadRepo.RepoPath: %v", err)
- }
-
- headGitRepo, err := git.OpenRepository(headRepoPath)
+ headGitRepo, err := git.OpenRepository(pr.HeadRepo.RepoPath())
if err != nil {
return fmt.Errorf("OpenRepository: %v", err)
}
diff --git a/models/release.go b/models/release.go
index ef1d640d72..fbb7b9a85e 100644
--- a/models/release.go
+++ b/models/release.go
@@ -175,12 +175,8 @@ func DeleteReleaseByID(id int64) error {
return fmt.Errorf("GetRepositoryByID: %v", err)
}
- repoPath, err := repo.RepoPath()
- if err != nil {
- return fmt.Errorf("RepoPath: %v", err)
- }
-
- _, stderr, err := process.ExecDir(-1, repoPath, fmt.Sprintf("DeleteReleaseByID (git tag -d): %d", rel.ID),
+ _, stderr, err := process.ExecDir(-1, repo.RepoPath(),
+ fmt.Sprintf("DeleteReleaseByID (git tag -d): %d", rel.ID),
"git", "tag", "-d", rel.TagName)
if err != nil && !strings.Contains(stderr, "not found") {
return fmt.Errorf("git tag -d: %v - %s", err, stderr)
diff --git a/models/repo.go b/models/repo.go
index 485523a0f1..7d4c2b6637 100644
--- a/models/repo.go
+++ b/models/repo.go
@@ -24,11 +24,14 @@ import (
"github.com/Unknwon/cae/zip"
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
+ "github.com/mcuadros/go-version"
"gopkg.in/ini.v1"
+ "github.com/gogits/git-shell"
+
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/bindata"
- "github.com/gogits/gogs/modules/git"
+ oldgit "github.com/gogits/gogs/modules/git"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/process"
"github.com/gogits/gogs/modules/setting"
@@ -95,19 +98,15 @@ func NewRepoContext() {
}
// Check Git version.
- ver, err := git.GetVersion()
+ gitVer, err := git.Version()
if err != nil {
log.Fatal(4, "Fail to get Git version: %v", err)
}
- reqVer, err := git.ParseVersion("1.7.1")
- if err != nil {
- log.Fatal(4, "Fail to parse required Git version: %v", err)
- }
- if ver.LessThan(reqVer) {
+ log.Info("Git Version: %s", gitVer)
+ if version.Compare("1.7.1", gitVer, ">") {
log.Fatal(4, "Gogs requires Git version greater or equal to 1.7.1")
}
- log.Info("Git Version: %s", ver.String())
// Git requires setting user.name and user.email in order to commit changes.
for configKey, defaultValue := range map[string]string{"user.name": "Gogs", "user.email": "gogs@fake.local"} {
@@ -197,6 +196,25 @@ func (repo *Repository) GetOwner() error {
return repo.getOwner(x)
}
+func (repo *Repository) mustOwner(e Engine) *User {
+ if err := repo.getOwner(e); err != nil {
+ return &User{
+ Name: "error",
+ FullName: err.Error(),
+ }
+ }
+
+ return repo.Owner
+}
+
+// MustOwner always returns a valid *User object to avoid
+// conceptually impossible error handling.
+// It creates a fake object that contains error deftail
+// when error occurs.
+func (repo *Repository) MustOwner() *User {
+ return repo.mustOwner(x)
+}
+
// GetAssignees returns all users that have write access of repository.
func (repo *Repository) GetAssignees() (_ []*User, err error) {
if err = repo.GetOwner(); err != nil {
@@ -253,30 +271,16 @@ func (repo *Repository) GetBaseRepo() (err error) {
return err
}
-func (repo *Repository) repoPath(e Engine) (string, error) {
- if err := repo.getOwner(e); err != nil {
- return "", err
- }
- return RepoPath(repo.Owner.Name, repo.Name), nil
+func (repo *Repository) repoPath(e Engine) string {
+ return RepoPath(repo.mustOwner(e).Name, repo.Name)
}
-func (repo *Repository) RepoPath() (string, error) {
+func (repo *Repository) RepoPath() string {
return repo.repoPath(x)
}
-func (repo *Repository) WikiPath() (string, error) {
- if err := repo.GetOwner(); err != nil {
- return "", err
- }
-
- return WikiPath(repo.Owner.Name, repo.Name), nil
-}
-
-func (repo *Repository) RepoLink() (string, error) {
- if err := repo.GetOwner(); err != nil {
- return "", err
- }
- return setting.AppSubUrl + "/" + repo.Owner.Name + "/" + repo.Name, nil
+func (repo *Repository) RepoLink() string {
+ return setting.AppSubUrl + "/" + repo.MustOwner().Name + "/" + repo.Name
}
func (repo *Repository) HasAccess(u *User) bool {
@@ -315,11 +319,7 @@ func (repo *Repository) LocalCopyPath() string {
// UpdateLocalCopy makes sure the local copy of repository is up-to-date.
func (repo *Repository) UpdateLocalCopy() error {
- repoPath, err := repo.RepoPath()
- if err != nil {
- return err
- }
-
+ repoPath := repo.RepoPath()
localPath := repo.LocalCopyPath()
if !com.IsExist(localPath) {
_, stderr, err := process.Exec(
@@ -399,7 +399,7 @@ func (repo *Repository) CloneLink() (cl CloneLink, err error) {
var (
reservedNames = []string{"debug", "raw", "install", "api", "avatar", "user", "org", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin", "new"}
- reservedPatterns = []string{"*.git", "*.keys"}
+ reservedPatterns = []string{"*.git", "*.keys", "*.wiki"}
)
// IsUsableName checks if name is reserved or pattern of name is not allowed.
@@ -569,7 +569,7 @@ func MigrateRepository(u *User, opts MigrateRepoOptions) (*Repository, error) {
}
// Check if repository has master branch, if so set it to default branch.
- gitRepo, err := git.OpenRepository(repoPath)
+ gitRepo, err := oldgit.OpenRepository(repoPath)
if err != nil {
return repo, fmt.Errorf("open git repository: %v", err)
}
@@ -581,7 +581,7 @@ func MigrateRepository(u *User, opts MigrateRepoOptions) (*Repository, error) {
}
// initRepoCommit temporarily changes with work directory.
-func initRepoCommit(tmpPath string, sig *git.Signature) (err error) {
+func initRepoCommit(tmpPath string, sig *oldgit.Signature) (err error) {
var stderr string
if _, stderr, err = process.ExecDir(-1,
tmpPath, fmt.Sprintf("initRepoCommit (git add): %s", tmpPath),
@@ -885,11 +885,6 @@ func RepoPath(userName, repoName string) string {
return filepath.Join(UserPath(userName), strings.ToLower(repoName)+".git")
}
-// WikiPath returns wiki data path by given user and repository name.
-func WikiPath(userName, repoName string) string {
- return filepath.Join(UserPath(userName), strings.ToLower(repoName)+".wiki.git")
-}
-
// TransferOwnership transfers all corresponding setting from old user to new one.
func TransferOwnership(u *User, newOwnerName string, repo *Repository) error {
newOwner, err := GetUserByName(newOwnerName)
@@ -1177,10 +1172,7 @@ func DeleteRepository(uid, repoID int64) error {
}
// Remove repository files.
- repoPath, err := repo.repoPath(sess)
- if err != nil {
- return fmt.Errorf("RepoPath: %v", err)
- }
+ repoPath := repo.repoPath(sess)
if err = os.RemoveAll(repoPath); err != nil {
desc := fmt.Sprintf("delete repository files[%s]: %v", repoPath, err)
log.Warn(desc)
@@ -1328,14 +1320,7 @@ func DeleteRepositoryArchives() error {
return x.Where("id > 0").Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
- repoPath, err := repo.RepoPath()
- if err != nil {
- if err2 := CreateRepositoryNotice(fmt.Sprintf("DeleteRepositoryArchives.RepoPath [%d]: %v", repo.ID, err)); err2 != nil {
- log.Error(4, "CreateRepositoryNotice: %v", err2)
- }
- return nil
- }
- return os.RemoveAll(filepath.Join(repoPath, "archives"))
+ return os.RemoveAll(filepath.Join(repo.RepoPath(), "archives"))
})
}
@@ -1345,15 +1330,7 @@ func DeleteMissingRepositories() error {
if err := x.Where("id > 0").Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
- repoPath, err := repo.RepoPath()
- if err != nil {
- if err2 := CreateRepositoryNotice(fmt.Sprintf("DeleteRepositoryArchives.RepoPath [%d]: %v", repo.ID, err)); err2 != nil {
- log.Error(4, "CreateRepositoryNotice: %v", err2)
- }
- return nil
- }
-
- if !com.IsDir(repoPath) {
+ if !com.IsDir(repo.RepoPath()) {
repos = append(repos, repo)
}
return nil
@@ -1384,14 +1361,7 @@ func RewriteRepositoryUpdateHook() error {
return x.Where("id > 0").Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
- repoPath, err := repo.RepoPath()
- if err != nil {
- if err2 := CreateRepositoryNotice(fmt.Sprintf("RewriteRepositoryUpdateHook[%d]: %v", repo.ID, err)); err2 != nil {
- log.Error(4, "CreateRepositoryNotice: %v", err2)
- }
- return nil
- }
- return createUpdateHook(repoPath)
+ return createUpdateHook(repo.RepoPath())
})
}
@@ -1458,11 +1428,7 @@ func MirrorUpdate() {
return nil
}
- repoPath, err := m.Repo.RepoPath()
- if err != nil {
- return fmt.Errorf("Repo.RepoPath: %v", err)
- }
-
+ repoPath := m.Repo.RepoPath()
if _, stderr, err := process.ExecDir(10*time.Minute,
repoPath, fmt.Sprintf("MirrorUpdate: %s", repoPath),
"git", "remote", "update", "--prune"); err != nil {
@@ -1502,12 +1468,8 @@ func GitFsck() {
if err := x.Where("id>0").Iterate(new(Repository),
func(idx int, bean interface{}) error {
repo := bean.(*Repository)
- repoPath, err := repo.RepoPath()
- if err != nil {
- return fmt.Errorf("RepoPath: %v", err)
- }
-
- _, _, err = process.ExecDir(-1, repoPath, "Repository health check", "git", args...)
+ repoPath := repo.RepoPath()
+ _, _, err := process.ExecDir(-1, repoPath, "Repository health check", "git", args...)
if err != nil {
desc := fmt.Sprintf("Fail to health check repository(%s)", repoPath)
log.Warn(desc)
@@ -1925,15 +1887,10 @@ func ForkRepository(u *User, oldRepo *Repository, name, desc string) (_ *Reposit
return nil, err
}
- oldRepoPath, err := oldRepo.RepoPath()
- if err != nil {
- return nil, fmt.Errorf("get old repository path: %v", err)
- }
-
repoPath := RepoPath(u.Name, repo.Name)
_, stderr, err := process.ExecTimeout(10*time.Minute,
fmt.Sprintf("ForkRepository(git clone): %s/%s", u.Name, repo.Name),
- "git", "clone", "--bare", oldRepoPath, repoPath)
+ "git", "clone", "--bare", oldRepo.RepoPath(), repoPath)
if err != nil {
return nil, fmt.Errorf("git clone: %v", stderr)
}
diff --git a/models/wiki.go b/models/wiki.go
new file mode 100644
index 0000000000..e08505d2bb
--- /dev/null
+++ b/models/wiki.go
@@ -0,0 +1,56 @@
+// Copyright 2015 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package models
+
+import (
+ "fmt"
+ "path/filepath"
+ "strings"
+
+ "github.com/Unknwon/com"
+
+ "github.com/gogits/git-shell"
+)
+
+// ToWikiPageName formats a string to corresponding wiki URL name.
+func ToWikiPageName(name string) string {
+ return strings.Replace(name, " ", "-", -1)
+}
+
+// WikiPath returns wiki data path by given user and repository name.
+func WikiPath(userName, repoName string) string {
+ return filepath.Join(UserPath(userName), strings.ToLower(repoName)+".wiki.git")
+}
+
+func (repo *Repository) WikiPath() string {
+ return WikiPath(repo.MustOwner().Name, repo.Name)
+}
+
+// HasWiki returns true if repository has wiki.
+func (repo *Repository) HasWiki() bool {
+ return com.IsDir(repo.WikiPath())
+}
+
+// InitWiki initializes a wiki for repository,
+// it does nothing when repository already has wiki.
+func (repo *Repository) InitWiki() error {
+ if repo.HasWiki() {
+ return nil
+ }
+
+ if err := git.InitRepository(repo.WikiPath(), true); err != nil {
+ return fmt.Errorf("InitRepository: %v", err)
+ }
+ return nil
+}
+
+// AddWikiPage adds new page to repository wiki.
+func (repo *Repository) AddWikiPage(title, content, message string) (err error) {
+ if err = repo.InitWiki(); err != nil {
+ return fmt.Errorf("InitWiki: %v", err)
+ }
+
+ return nil
+}
diff --git a/modules/auth/repo_form.go b/modules/auth/repo_form.go
index 8e10dc24db..b876f27910 100644
--- a/modules/auth/repo_form.go
+++ b/modules/auth/repo_form.go
@@ -237,3 +237,21 @@ type EditReleaseForm struct {
func (f *EditReleaseForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
+
+// __ __.__ __ .__
+// / \ / \__| | _|__|
+// \ \/\/ / | |/ / |
+// \ /| | <| |
+// \__/\ / |__|__|_ \__|
+// \/ \/
+
+type NewWikiForm struct {
+ Title string `binding:"Required"`
+ Content string
+ Message string
+}
+
+// FIXME: use code generation to generate this method.
+func (f *NewWikiForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
+ return validate(errs, ctx.Data, f, ctx.Locale)
+}
diff --git a/modules/middleware/repo.go b/modules/middleware/repo.go
index 9fe454dd46..210e563730 100644
--- a/modules/middleware/repo.go
+++ b/modules/middleware/repo.go
@@ -311,11 +311,7 @@ func RepoAssignment(args ...bool) macaron.Handler {
return
}
ctx.Repo.GitRepo = gitRepo
- ctx.Repo.RepoLink, err = repo.RepoLink()
- if err != nil {
- ctx.Handle(500, "RepoLink", err)
- return
- }
+ ctx.Repo.RepoLink = repo.RepoLink()
ctx.Data["RepoLink"] = ctx.Repo.RepoLink
ctx.Data["RepoRelPath"] = ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name
diff --git a/modules/process/manager.go b/modules/process/manager.go
index 68c33315d0..1f98ca7cfb 100644
--- a/modules/process/manager.go
+++ b/modules/process/manager.go
@@ -113,7 +113,8 @@ func Remove(pid int64) {
func Kill(pid int64) error {
for i, proc := range Processes {
if proc.Pid == pid {
- if proc.Cmd.Process != nil && proc.Cmd.ProcessState != nil && !proc.Cmd.ProcessState.Exited() {
+ if proc.Cmd != nil && proc.Cmd.Process != nil &&
+ proc.Cmd.ProcessState != nil && !proc.Cmd.ProcessState.Exited() {
if err := proc.Cmd.Process.Kill(); err != nil {
return fmt.Errorf("fail to kill process(%d/%s): %v", proc.Pid, proc.Description, err)
}
diff --git a/routers/install.go b/routers/install.go
index f3c51d06ac..dc0ff2f2f1 100644
--- a/routers/install.go
+++ b/routers/install.go
@@ -17,6 +17,8 @@ import (
"gopkg.in/ini.v1"
"gopkg.in/macaron.v1"
+ "github.com/gogits/git-shell"
+
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/models/cron"
"github.com/gogits/gogs/modules/auth"
@@ -39,6 +41,7 @@ func checkRunMode() {
macaron.Env = macaron.PROD
macaron.ColorLog = false
setting.ProdMode = true
+ git.Debug = false
}
log.Info("Run Mode: %s", strings.Title(macaron.Env))
}
diff --git a/routers/repo/http.go b/routers/repo/http.go
index 7bc5f1aff6..e8f29ebe86 100644
--- a/routers/repo/http.go
+++ b/routers/repo/http.go
@@ -31,7 +31,7 @@ import (
func authRequired(ctx *middleware.Context) {
ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=\".\"")
ctx.Data["ErrorMsg"] = "no basic auth and digit auth"
- ctx.HTML(401, base.TplName("status/401"))
+ ctx.Error(401)
}
func HTTP(ctx *middleware.Context) {
diff --git a/routers/repo/pull.go b/routers/repo/pull.go
index d7b4828a91..8d6b4c7d7b 100644
--- a/routers/repo/pull.go
+++ b/routers/repo/pull.go
@@ -210,13 +210,7 @@ func PrepareViewPullInfo(ctx *middleware.Context, pull *models.Issue) *git.PullR
}
if pull.HeadRepo != nil {
- headRepoPath, err := pull.HeadRepo.RepoPath()
- if err != nil {
- ctx.Handle(500, "HeadRepo.RepoPath", err)
- return nil
- }
-
- headGitRepo, err = git.OpenRepository(headRepoPath)
+ headGitRepo, err = git.OpenRepository(pull.HeadRepo.RepoPath())
if err != nil {
ctx.Handle(500, "OpenRepository", err)
return nil
@@ -496,11 +490,7 @@ func PrepareCompareDiff(
)
// Get diff information.
- ctx.Data["CommitRepoLink"], err = headRepo.RepoLink()
- if err != nil {
- ctx.Handle(500, "RepoLink", err)
- return false
- }
+ ctx.Data["CommitRepoLink"] = headRepo.RepoLink()
headCommitID, err := headGitRepo.GetCommitIdOfBranch(headBranch)
if err != nil {
diff --git a/routers/repo/wiki.go b/routers/repo/wiki.go
index c18e67de67..30bd7b63c7 100644
--- a/routers/repo/wiki.go
+++ b/routers/repo/wiki.go
@@ -5,9 +5,8 @@
package repo
import (
- "github.com/Unknwon/com"
-
"github.com/gogits/gogs/models"
+ "github.com/gogits/gogs/modules/auth"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/middleware"
)
@@ -22,8 +21,7 @@ func Wiki(ctx *middleware.Context) {
ctx.Data["Title"] = ctx.Tr("repo.wiki")
ctx.Data["PageIsWiki"] = true
- wikiPath := models.WikiPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
- if !com.IsDir(wikiPath) {
+ if !ctx.Repo.Repository.HasWiki() {
ctx.HTML(200, WIKI_START)
return
}
@@ -36,14 +34,31 @@ func NewWiki(ctx *middleware.Context) {
ctx.Data["PageIsWiki"] = true
ctx.Data["RequireSimpleMDE"] = true
- wikiPath := models.WikiPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
- if !com.IsDir(wikiPath) {
+ if !ctx.Repo.Repository.HasWiki() {
ctx.Data["title"] = "Home"
}
ctx.HTML(200, WIKI_NEW)
}
+func NewWikiPost(ctx *middleware.Context, form auth.NewWikiForm) {
+ ctx.Data["Title"] = ctx.Tr("repo.wiki.new_page")
+ ctx.Data["PageIsWiki"] = true
+ ctx.Data["RequireSimpleMDE"] = true
+
+ if ctx.HasError() {
+ ctx.HTML(200, WIKI_NEW)
+ return
+ }
+
+ if err := ctx.Repo.Repository.AddWikiPage(form.Title, form.Content, form.Message); err != nil {
+ ctx.Handle(500, "AddWikiPage", err)
+ return
+ }
+
+ ctx.Redirect(ctx.Repo.RepoLink + "/wiki/" + models.ToWikiPageName(form.Title))
+}
+
func EditWiki(ctx *middleware.Context) {
ctx.PlainText(200, []byte(ctx.Params(":page")))
}
diff --git a/templates/repo/wiki/new.tmpl b/templates/repo/wiki/new.tmpl
index cdf5225d3b..ede6a46757 100644
--- a/templates/repo/wiki/new.tmpl
+++ b/templates/repo/wiki/new.tmpl
@@ -7,8 +7,9 @@
{{.i18n.Tr "repo.wiki.new_page"}}
</div>
<form class="ui form" action="{{.Link}}" method="post">
+ {{.CsrfTokenHtml}}
<div class="field">
- <input name="title" value="{{.title}}" autofocus>
+ <input name="title" value="{{.title}}" autofocus required>
</div>
<div class="field">
<textarea id="edit-area" name="content" data-url="{{AppSubUrl}}/api/v1/markdown" data-context="{{.RepoLink}}">{{.i18n.Tr "repo.wiki.welcome"}}</textarea>
diff --git a/templates/status/401.tmpl b/templates/status/401.tmpl
deleted file mode 100644
index f00101fd3c..0000000000
--- a/templates/status/401.tmpl
+++ /dev/null
@@ -1,5 +0,0 @@
-{{template "base/head" .}}
-<div class="ui container center">
- 401 Unauthorized
-</div>
-{{template "base/footer" .}} \ No newline at end of file
diff --git a/templates/status/403.tmpl b/templates/status/403.tmpl
deleted file mode 100644
index 5c413a2974..0000000000
--- a/templates/status/403.tmpl
+++ /dev/null
@@ -1,5 +0,0 @@
-{{template "base/head" .}}
-<div class="ui container center">
- 403 Forbidden
-</div>
-{{template "base/footer" .}} \ No newline at end of file