| @@ -5,7 +5,7 @@ Gogs(Go Git Service) is a GitHub-like clone in the Go Programming Language. | |||
| Since we choose to use pure Go implmentation of Git manipulation, Gogs certainly supports **ALL platforms** that Go supports, including Linux, Max OS X, and Windows with **ZERO** dependency. | |||
| ##### Current version: 0.0.8 Alpha | |||
| ##### Current version: 0.0.9 Alpha | |||
| ## Purpose | |||
| @@ -12,7 +12,8 @@ | |||
| "models": "", | |||
| "others": [ | |||
| "modules", | |||
| "$GOPATH/src/github.com/gogits/binding" | |||
| "$GOPATH/src/github.com/gogits/binding", | |||
| "$GOPATH/src/github.com/gogits/git" | |||
| ] | |||
| }, | |||
| "cmd_args": [ | |||
| @@ -7,6 +7,7 @@ LANG_IGNS=Google Go|C|Python|Ruby | |||
| LICENSES=Apache v2 License|GPL v2|MIT License|BSD (3-Clause) License | |||
| [server] | |||
| DOMAIN = gogits.org | |||
| HTTP_ADDR = | |||
| HTTP_PORT = 3000 | |||
| @@ -20,7 +20,7 @@ import ( | |||
| // Test that go1.1 tag above is included in builds. main.go refers to this definition. | |||
| const go11tag = true | |||
| const APP_VER = "0.0.8.0316.1" | |||
| const APP_VER = "0.0.9.0317.1" | |||
| func init() { | |||
| base.AppVer = APP_VER | |||
| @@ -44,6 +44,10 @@ func (a Action) GetRepoName() string { | |||
| return a.RepoName | |||
| } | |||
| func (a Action) GetContent() string { | |||
| return a.Content | |||
| } | |||
| // CommitRepoAction records action for commit repository. | |||
| func CommitRepoAction(userId int64, userName string, | |||
| repoId int64, repoName string, commits [][]string) error { | |||
| @@ -307,6 +307,9 @@ func DeleteRepository(userId, repoId int64, userName string) (err error) { | |||
| } | |||
| session := orm.NewSession() | |||
| if err = session.Begin(); err != nil { | |||
| return err | |||
| } | |||
| if _, err = session.Delete(&Repository{Id: repoId}); err != nil { | |||
| session.Rollback() | |||
| return err | |||
| @@ -5,11 +5,26 @@ | |||
| package models | |||
| import ( | |||
| "fmt" | |||
| "path" | |||
| "strings" | |||
| "time" | |||
| git "github.com/gogits/git" | |||
| "github.com/Unknwon/com" | |||
| "github.com/gogits/git" | |||
| ) | |||
| type Commit struct { | |||
| Author string | |||
| Email string | |||
| Date time.Time | |||
| SHA string | |||
| Message string | |||
| } | |||
| var ( | |||
| ErrRepoFileNotLoaded = fmt.Errorf("repo file not loaded") | |||
| ) | |||
| type RepoFile struct { | |||
| @@ -18,6 +33,7 @@ type RepoFile struct { | |||
| Message string | |||
| Created time.Time | |||
| Size int64 | |||
| Repo *git.Repository | |||
| LastCommit string | |||
| } | |||
| @@ -43,10 +59,34 @@ func findTree(repo *git.Repository, tree *git.Tree, rpath string) *git.Tree { | |||
| return g | |||
| } | |||
| func GetReposFiles(userName, reposName, branchName, rpath string) ([]*RepoFile, error) { | |||
| f := RepoPath(userName, reposName) | |||
| func (file *RepoFile) LookupBlob() (*git.Blob, error) { | |||
| if file.Repo == nil { | |||
| return nil, ErrRepoFileNotLoaded | |||
| } | |||
| return file.Repo.LookupBlob(file.Id) | |||
| } | |||
| func GetBranches(userName, reposName string) ([]string, error) { | |||
| repo, err := git.OpenRepository(RepoPath(userName, reposName)) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| refs, err := repo.AllReferences() | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| brs := make([]string, len(refs)) | |||
| for i, ref := range refs { | |||
| brs[i] = ref.Name | |||
| } | |||
| return brs, nil | |||
| } | |||
| repo, err := git.OpenRepository(f) | |||
| func GetReposFiles(userName, reposName, branchName, rpath string) ([]*RepoFile, error) { | |||
| repo, err := git.OpenRepository(RepoPath(userName, reposName)) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| @@ -128,6 +168,7 @@ func GetReposFiles(userName, reposName, branchName, rpath string) ([]*RepoFile, | |||
| cm.Message(), | |||
| cm.Committer.When, | |||
| size, | |||
| repo, | |||
| cm.Id().String(), | |||
| } | |||
| @@ -142,3 +183,33 @@ func GetReposFiles(userName, reposName, branchName, rpath string) ([]*RepoFile, | |||
| return append(repodirs, repofiles...), nil | |||
| } | |||
| func GetLastestCommit(userName, repoName string) (*Commit, error) { | |||
| stdout, _, err := com.ExecCmd("git", "--git-dir="+RepoPath(userName, repoName), "log", "-1") | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| commit := new(Commit) | |||
| for _, line := range strings.Split(stdout, "\n") { | |||
| if len(line) == 0 { | |||
| continue | |||
| } | |||
| switch { | |||
| case line[0] == 'c': | |||
| commit.SHA = line[7:] | |||
| case line[0] == 'A': | |||
| infos := strings.SplitN(line, " ", 3) | |||
| commit.Author = infos[1] | |||
| commit.Email = infos[2][1 : len(infos[2])-1] | |||
| case line[0] == 'D': | |||
| commit.Date, err = time.Parse("Mon Jan 02 15:04:05 2006 -0700", line[8:]) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| case line[:4] == " ": | |||
| commit.Message = line[4:] | |||
| } | |||
| } | |||
| return commit, nil | |||
| } | |||
| @@ -17,7 +17,6 @@ import ( | |||
| ) | |||
| type CreateRepoForm struct { | |||
| UserId int64 `form:"userId"` | |||
| RepoName string `form:"repo" binding:"Required;AlphaDash"` | |||
| Visibility string `form:"visibility"` | |||
| Description string `form:"desc" binding:"MaxSize(100)"` | |||
| @@ -52,9 +51,3 @@ func (f *CreateRepoForm) Validate(errors *binding.Errors, req *http.Request, con | |||
| validate(errors, data, f) | |||
| } | |||
| type DeleteRepoForm struct { | |||
| UserId int64 `form:"userId" binding:"Required"` | |||
| UserName string `form:"userName" binding:"Required"` | |||
| RepoId int64 `form:"repoId" binding:"Required"` | |||
| } | |||
| @@ -18,6 +18,7 @@ import ( | |||
| var ( | |||
| AppVer string | |||
| AppName string | |||
| Domain string | |||
| Cfg *goconfig.ConfigFile | |||
| ) | |||
| @@ -58,4 +59,5 @@ func init() { | |||
| Cfg.BlockMode = false | |||
| AppName = Cfg.MustValue("", "APP_NAME") | |||
| Domain = Cfg.MustValue("server", "DOMAIN") | |||
| } | |||
| @@ -0,0 +1,39 @@ | |||
| // Copyright 2014 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 base | |||
| import ( | |||
| "github.com/slene/blackfriday" | |||
| ) | |||
| func RenderMarkdown(rawBytes []byte) []byte { | |||
| htmlFlags := 0 | |||
| htmlFlags |= blackfriday.HTML_USE_XHTML | |||
| // htmlFlags |= blackfriday.HTML_USE_SMARTYPANTS | |||
| // htmlFlags |= blackfriday.HTML_SMARTYPANTS_FRACTIONS | |||
| // htmlFlags |= blackfriday.HTML_SMARTYPANTS_LATEX_DASHES | |||
| htmlFlags |= blackfriday.HTML_SKIP_HTML | |||
| htmlFlags |= blackfriday.HTML_SKIP_STYLE | |||
| htmlFlags |= blackfriday.HTML_SKIP_SCRIPT | |||
| htmlFlags |= blackfriday.HTML_GITHUB_BLOCKCODE | |||
| htmlFlags |= blackfriday.HTML_OMIT_CONTENTS | |||
| htmlFlags |= blackfriday.HTML_COMPLETE_PAGE | |||
| renderer := blackfriday.HtmlRenderer(htmlFlags, "", "") | |||
| // set up the parser | |||
| extensions := 0 | |||
| extensions |= blackfriday.EXTENSION_NO_INTRA_EMPHASIS | |||
| extensions |= blackfriday.EXTENSION_TABLES | |||
| extensions |= blackfriday.EXTENSION_FENCED_CODE | |||
| extensions |= blackfriday.EXTENSION_AUTOLINK | |||
| extensions |= blackfriday.EXTENSION_STRIKETHROUGH | |||
| extensions |= blackfriday.EXTENSION_HARD_LINE_BREAK | |||
| extensions |= blackfriday.EXTENSION_SPACE_HEADERS | |||
| extensions |= blackfriday.EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK | |||
| body := blackfriday.Markdown(rawBytes, renderer, extensions) | |||
| return body | |||
| } | |||
| @@ -19,6 +19,10 @@ var TemplateFuncs template.FuncMap = map[string]interface{}{ | |||
| "AppVer": func() string { | |||
| return AppVer | |||
| }, | |||
| "AppDomain": func() string { | |||
| return Domain | |||
| }, | |||
| "AvatarLink": AvatarLink, | |||
| "str2html": Str2html, | |||
| "TimeSince": TimeSince, | |||
| "FileSize": FileSize, | |||
| @@ -5,8 +5,10 @@ | |||
| package base | |||
| import ( | |||
| "bytes" | |||
| "crypto/md5" | |||
| "encoding/hex" | |||
| "encoding/json" | |||
| "fmt" | |||
| "math" | |||
| "strings" | |||
| @@ -20,6 +22,11 @@ func EncodeMd5(str string) string { | |||
| return hex.EncodeToString(m.Sum(nil)) | |||
| } | |||
| // AvatarLink returns avatar link by given e-mail. | |||
| func AvatarLink(email string) string { | |||
| return "http://1.gravatar.com/avatar/" + EncodeMd5(email) | |||
| } | |||
| // Seconds-based time units | |||
| const ( | |||
| Minute = 60 | |||
| @@ -235,6 +242,7 @@ type Actioner interface { | |||
| GetOpType() int | |||
| GetActUserName() string | |||
| GetRepoName() string | |||
| GetContent() string | |||
| } | |||
| // ActionIcon accepts a int that represents action operation type | |||
| @@ -243,23 +251,39 @@ func ActionIcon(opType int) string { | |||
| switch opType { | |||
| case 1: // Create repository. | |||
| return "plus-circle" | |||
| case 5: // Commit repository. | |||
| return "arrow-circle-o-right" | |||
| default: | |||
| return "invalid type" | |||
| } | |||
| } | |||
| const ( | |||
| CreateRepoTpl = `<a href="/user/%s">%s</a> created repository <a href="/%s/%s">%s</a>` | |||
| TPL_CREATE_REPO = `<a href="/user/%s">%s</a> created repository <a href="/%s/%s">%s</a>` | |||
| TPL_COMMIT_REPO = `<a href="/user/%s">%s</a> pushed to <a href="/%s/%s/tree/%s">%s</a> at <a href="/%s/%s">%s/%s</a>%s` | |||
| TPL_COMMIT_REPO_LI = `<div><img id="gogs-user-avatar-commit" src="%s?s=16" alt="user-avatar" title="username"/> <a href="/%s/%s/commit/%s">%s</a> %s</div>` | |||
| ) | |||
| // ActionDesc accepts int that represents action operation type | |||
| // and returns the description. | |||
| func ActionDesc(act Actioner) string { | |||
| func ActionDesc(act Actioner, avatarLink string) string { | |||
| actUserName := act.GetActUserName() | |||
| repoName := act.GetRepoName() | |||
| content := act.GetContent() | |||
| switch act.GetOpType() { | |||
| case 1: // Create repository. | |||
| return fmt.Sprintf(CreateRepoTpl, actUserName, actUserName, actUserName, repoName, repoName) | |||
| return fmt.Sprintf(TPL_CREATE_REPO, actUserName, actUserName, actUserName, repoName, repoName) | |||
| case 5: // Commit repository. | |||
| var commits [][]string | |||
| if err := json.Unmarshal([]byte(content), &commits); err != nil { | |||
| return err.Error() | |||
| } | |||
| buf := bytes.NewBuffer([]byte("\n")) | |||
| for _, commit := range commits { | |||
| buf.WriteString(fmt.Sprintf(TPL_COMMIT_REPO_LI, avatarLink, actUserName, repoName, commit[0], commit[0][:7], commit[1]) + "\n") | |||
| } | |||
| return fmt.Sprintf(TPL_COMMIT_REPO, actUserName, actUserName, actUserName, repoName, "master", "master", actUserName, repoName, actUserName, repoName, | |||
| buf.String()) | |||
| default: | |||
| return "invalid type" | |||
| } | |||
| @@ -6,6 +6,7 @@ package middleware | |||
| import ( | |||
| "errors" | |||
| "strings" | |||
| "github.com/codegangsta/martini" | |||
| @@ -23,8 +24,7 @@ func RepoAssignment(redirect bool) martini.Handler { | |||
| ) | |||
| // get repository owner | |||
| ctx.Repo.IsOwner = ctx.IsSigned && ctx.User.LowerName == params["username"] | |||
| ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner | |||
| ctx.Repo.IsOwner = ctx.IsSigned && ctx.User.LowerName == strings.ToLower(params["username"]) | |||
| if !ctx.Repo.IsOwner { | |||
| user, err = models.GetUserByName(params["username"]) | |||
| @@ -70,5 +70,6 @@ func RepoAssignment(redirect bool) martini.Handler { | |||
| ctx.Data["Owner"] = user | |||
| ctx.Data["Title"] = user.Name + "/" + repo.Name | |||
| ctx.Data["RepositoryLink"] = ctx.Data["Title"] | |||
| ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner | |||
| } | |||
| } | |||
| @@ -10,6 +10,7 @@ body { | |||
| html, body { | |||
| height: 100%; | |||
| font-family: Helvetica, Arial, sans-serif; | |||
| } | |||
| /* override bs3 */ | |||
| @@ -50,7 +51,6 @@ html, body { | |||
| .gogs-masthead { | |||
| background-color: #428bca; | |||
| box-shadow: inset 0 -2px 5px rgba(0, 0, 0, .1); | |||
| padding: 0 16px; | |||
| margin: 0; | |||
| } | |||
| @@ -65,6 +65,12 @@ html, body { | |||
| height: 46px; | |||
| } | |||
| #gogs-nav-logo{ | |||
| padding-left: 0; | |||
| padding-right: 0; | |||
| margin-right: 10px; | |||
| } | |||
| .gogs-nav-item:hover, | |||
| .gogs-nav-item:focus { | |||
| color: #fff; | |||
| @@ -128,6 +134,11 @@ html, body { | |||
| padding: 5px 0; | |||
| margin-left: 10px; | |||
| height: 28px; | |||
| float: right; | |||
| } | |||
| #gogs-nav-signin{ | |||
| float: right; | |||
| } | |||
| #gogs-nav-out .fa { | |||
| @@ -228,6 +239,12 @@ html, body { | |||
| border-radius: 6px; | |||
| } | |||
| #gogs-user-avatar-commit { | |||
| width: 16px; | |||
| height: 16px; | |||
| border-radius: 2px; | |||
| } | |||
| #gogs-user-name { | |||
| margin-top: 20px; | |||
| font-size: 1.6em; | |||
| @@ -338,10 +355,6 @@ html, body { | |||
| /* #gogs-feed */ | |||
| #gogs-feed-left { | |||
| padding-left: 0; | |||
| } | |||
| #gogs-feed-right .repo-panel .panel-heading .btn { | |||
| margin-top: -4px; | |||
| } | |||
| @@ -399,18 +412,11 @@ html, body { | |||
| .gogs-repo-nav h3 .fa { | |||
| color: #BBB; | |||
| margin-left: 0; | |||
| } | |||
| .gogs-repo-btns { | |||
| margin-top: 18px; | |||
| } | |||
| .gogs-repo-btns .btn-group { | |||
| margin-left: 1em; | |||
| } | |||
| .gogs-repo-btns .btn-group .btn { | |||
| padding-left: 6px; | |||
| .gogs-repo-nav .actions { | |||
| padding-top: 20px; | |||
| } | |||
| #gogs-repo-watching .dropdown-menu { | |||
| @@ -475,7 +481,7 @@ html, body { | |||
| .activity-list .info { | |||
| float: left; | |||
| padding:0 0 0 10px; | |||
| padding: 0 0 0 10px; | |||
| line-height: 1.7em; | |||
| } | |||
| @@ -525,6 +531,10 @@ html, body { | |||
| } | |||
| /* #gogs-source */ | |||
| #gogs-source { | |||
| margin-top: -20px; | |||
| } | |||
| #gogs-source .source-toolbar:after { | |||
| clear: both; | |||
| } | |||
| @@ -560,7 +570,9 @@ html, body { | |||
| .file-list .icon { | |||
| font-size: 17px; | |||
| padding: 5px 0 4px 10px; | |||
| width: 40px; | |||
| width: 50px; | |||
| color: #999; | |||
| text-align: right; | |||
| } | |||
| .file-list .wrap { | |||
| @@ -581,13 +593,87 @@ html, body { | |||
| .file-list .date .wrap { | |||
| max-width: 120px; | |||
| padding: 0 20px 0 0; | |||
| padding: 0 20px 0 0; | |||
| } | |||
| .file-list .date { | |||
| text-align: right; | |||
| } | |||
| .file-content .file-head { | |||
| font-size: 18px; | |||
| } | |||
| .file-content .file-head .icon { | |||
| color: #666; | |||
| margin: 0 .5em 0 0; | |||
| } | |||
| .file-content .file-body { | |||
| padding: 30px 30px 50px; | |||
| } | |||
| .branch-list th{ | |||
| background-color: #FFF; | |||
| line-height: 28px !important; | |||
| } | |||
| .branch-list td{ | |||
| line-height: 36px !important; | |||
| } | |||
| .branch-box tr:hover td{ | |||
| background-color: rgba(19, 95, 215, 0.06) !important; | |||
| } | |||
| .branch-box .name{ | |||
| padding-left: 20px; | |||
| font-size: 15px; | |||
| } | |||
| .branch-box .action{ | |||
| width: 150px; | |||
| } | |||
| .branch-box td.date,.branch-box td.behind,.branch-box td.ahead{ | |||
| width: 120px; | |||
| font-family: Verdana, Arial, sans-serif; | |||
| } | |||
| .branch-box .graph{ | |||
| display: block; | |||
| height: 3px; | |||
| } | |||
| .branch-box .behind{ | |||
| text-align: right; | |||
| direction: rtl; | |||
| } | |||
| .branch-box .behind .graph{ | |||
| background-color: #888; | |||
| } | |||
| .branch-box .ahead .graph{ | |||
| background-color: #0093c4; | |||
| } | |||
| .branch-box .branch-main{ | |||
| background-color: #444; | |||
| color: #FFF; | |||
| border-color: #444; | |||
| } | |||
| .branch-box .branch-main a{ | |||
| color: #FFF; | |||
| } | |||
| .branch-box .branch-main .name .btn{ | |||
| margin-left: .5em; | |||
| } | |||
| /* wrapper and footer */ | |||
| #wrapper { | |||
| min-height: 100%; | |||
| height: auto !important; | |||
| @@ -604,7 +690,7 @@ html, body { | |||
| } | |||
| #footer .footer-wrap { | |||
| padding: 20px 0; | |||
| padding: 20px 15px; | |||
| } | |||
| #footer a { | |||
| @@ -0,0 +1,317 @@ | |||
| .markdown { | |||
| font-size: 14px; | |||
| } | |||
| .markdown a { | |||
| color: #4183C4; | |||
| } | |||
| .markdown h1, | |||
| .markdown h2, | |||
| .markdown h3, | |||
| .markdown h4, | |||
| .markdown h5, | |||
| .markdown h6 { | |||
| line-height: 1.7; | |||
| padding: 15px 0 0; | |||
| margin: 0 0 15px; | |||
| color: #666; | |||
| } | |||
| .markdown h1, | |||
| .markdown h2 { | |||
| border-bottom: 1px solid #EEE; | |||
| } | |||
| .markdown h2 { | |||
| border-bottom: 1px solid #EEE; | |||
| } | |||
| .markdown h1 { | |||
| color: #000; | |||
| font-size: 33px | |||
| } | |||
| .markdown h2 { | |||
| color: #333; | |||
| font-size: 28px | |||
| } | |||
| .markdown h3 { | |||
| font-size: 22px | |||
| } | |||
| .markdown h4 { | |||
| font-size: 18px | |||
| } | |||
| .markdown h5 { | |||
| font-size: 14px | |||
| } | |||
| .markdown h6 { | |||
| font-size: 14px | |||
| } | |||
| .markdown table { | |||
| border-collapse: collapse; | |||
| border-spacing: 0; | |||
| display: block; | |||
| overflow: auto; | |||
| width: 100%; | |||
| margin: 0 0 9px; | |||
| } | |||
| .markdown table th { | |||
| font-weight: 700 | |||
| } | |||
| .markdown table th, | |||
| .markdown table td { | |||
| border: 1px solid #DDD; | |||
| padding: 6px 13px; | |||
| } | |||
| .markdown table tr { | |||
| background-color: #FFF; | |||
| border-top: 1px solid #CCC; | |||
| } | |||
| .markdown table tr:nth-child(2n) { | |||
| background-color: #F8F8F8 | |||
| } | |||
| .markdown li { | |||
| line-height: 1.6; | |||
| margin-top: 6px; | |||
| } | |||
| .markdown dl dt { | |||
| font-style: italic; | |||
| margin-top: 9px; | |||
| } | |||
| .markdown dl dd { | |||
| margin: 0 0 9px; | |||
| padding: 0 9px; | |||
| } | |||
| .markdown blockquote, | |||
| .markdown blockquote p { | |||
| font-size: 14px; | |||
| background-color: #f5f5f5; | |||
| } | |||
| .markdown > pre { | |||
| line-height: 1.6; | |||
| overflow: auto; | |||
| background: #fff; | |||
| padding: 6px 10px; | |||
| border: 1px solid #ddd; | |||
| } | |||
| .markdown > pre.linenums { | |||
| padding: 0; | |||
| } | |||
| .markdown > pre > ol.linenums { | |||
| -webkit-box-shadow: inset 40px 0 0 #f5f5f5, inset 41px 0 0 #ccc; | |||
| box-shadow: inset 40px 0 0 #f5f5f5, inset 41px 0 0 #ccc; | |||
| } | |||
| .markdown > pre > code, | |||
| .markdown > pre > ol.linenums > li > code { | |||
| white-space: pre; | |||
| word-wrap: normal; | |||
| } | |||
| .markdown > pre > ol.linenums > li > code { | |||
| padding: 0 10px; | |||
| } | |||
| .markdown > pre > ol.linenums > li:first-child { | |||
| padding-top: 6px; | |||
| } | |||
| .markdown > pre > ol.linenums > li:last-child { | |||
| padding-bottom: 6px; | |||
| } | |||
| .markdown > pre > ol.linenums > li { | |||
| border-left: 1px solid #ddd; | |||
| } | |||
| .markdown hr { | |||
| border: none; | |||
| color: #ccc; | |||
| height: 4px; | |||
| padding: 0; | |||
| margin: 15px 0; | |||
| border-bottom: 2px solid #EEE; | |||
| } | |||
| .markdown blockquote:last-child, | |||
| .markdown ul:last-child, | |||
| .markdown ol:last-child, | |||
| .markdown > pre:last-child, | |||
| .markdown > pre:last-child, | |||
| .markdown p:last-child { | |||
| margin-bottom: 0; | |||
| } | |||
| .markdown .btn { | |||
| color: #fff; | |||
| } | |||
| /* Author: jmblog */ | |||
| /* Project: https://github.com/jmblog/color-themes-for-google-code-prettify */ | |||
| /* GitHub Theme */ | |||
| /* Pretty printing styles. Used with prettify.js. */ | |||
| /* SPAN elements with the classes below are added by prettyprint. */ | |||
| /* plain text */ | |||
| .pln { | |||
| color: #333333; | |||
| } | |||
| @media screen { | |||
| /* string content */ | |||
| .str { | |||
| color: #dd1144; | |||
| } | |||
| /* a keyword */ | |||
| .kwd { | |||
| color: #333333; | |||
| } | |||
| /* a comment */ | |||
| .com { | |||
| color: #999988; | |||
| } | |||
| /* a type name */ | |||
| .typ { | |||
| color: #445588; | |||
| } | |||
| /* a literal value */ | |||
| .lit { | |||
| color: #445588; | |||
| } | |||
| /* punctuation */ | |||
| .pun { | |||
| color: #333333; | |||
| } | |||
| /* lisp open bracket */ | |||
| .opn { | |||
| color: #333333; | |||
| } | |||
| /* lisp close bracket */ | |||
| .clo { | |||
| color: #333333; | |||
| } | |||
| /* a markup tag name */ | |||
| .tag { | |||
| color: navy; | |||
| } | |||
| /* a markup attribute name */ | |||
| .atn { | |||
| color: teal; | |||
| } | |||
| /* a markup attribute value */ | |||
| .atv { | |||
| color: #dd1144; | |||
| } | |||
| /* a declaration */ | |||
| .dec { | |||
| color: #333333; | |||
| } | |||
| /* a variable name */ | |||
| .var { | |||
| color: teal; | |||
| } | |||
| /* a function name */ | |||
| .fun { | |||
| color: #990000; | |||
| } | |||
| } | |||
| /* Use higher contrast and text-weight for printable form. */ | |||
| @media print, projection { | |||
| .str { | |||
| color: #006600; | |||
| } | |||
| .kwd { | |||
| color: #006; | |||
| font-weight: bold; | |||
| } | |||
| .com { | |||
| color: #600; | |||
| font-style: italic; | |||
| } | |||
| .typ { | |||
| color: #404; | |||
| font-weight: bold; | |||
| } | |||
| .lit { | |||
| color: #004444; | |||
| } | |||
| .pun, .opn, .clo { | |||
| color: #444400; | |||
| } | |||
| .tag { | |||
| color: #006; | |||
| font-weight: bold; | |||
| } | |||
| .atn { | |||
| color: #440044; | |||
| } | |||
| .atv { | |||
| color: #006600; | |||
| } | |||
| } | |||
| /* Specify class=linenums on a pre to get line numbering */ | |||
| ol.linenums { | |||
| margin-top: 0; | |||
| margin-bottom: 0; | |||
| } | |||
| /* IE indents via margin-left */ | |||
| li.L0, | |||
| li.L1, | |||
| li.L2, | |||
| li.L3, | |||
| li.L4, | |||
| li.L5, | |||
| li.L6, | |||
| li.L7, | |||
| li.L8, | |||
| li.L9 { | |||
| /* */ | |||
| } | |||
| /* Alternate shading for lines */ | |||
| li.L1, | |||
| li.L3, | |||
| li.L5, | |||
| li.L7, | |||
| li.L9 { | |||
| /* */ | |||
| } | |||
| @@ -40,10 +40,37 @@ var Gogits = { | |||
| //container: "body" | |||
| }); | |||
| }; | |||
| Gogits.initPopovers = function () { | |||
| var hideAllPopovers = function() { | |||
| $('[data-toggle=popover]').each(function() { | |||
| $(this).popover('hide'); | |||
| }); | |||
| }; | |||
| $(document).on('click', function(e) { | |||
| var $e = $(e.target); | |||
| if($e.data('toggle') == 'popover'||$e.parents("[data-toggle=popover], .popover").length > 0){ | |||
| return; | |||
| } | |||
| hideAllPopovers(); | |||
| }); | |||
| $("body").popover({ | |||
| selector: "[data-toggle=popover]" | |||
| }); | |||
| }; | |||
| Gogits.initTabs = function () { | |||
| var $tabs = $('[data-init=tabs]'); | |||
| $tabs.find("li:eq(0) a").tab("show"); | |||
| }; | |||
| // render markdown | |||
| Gogits.renderMarkdown = function () { | |||
| var $pre = $('.markdown').find('pre > code').parent(); | |||
| $pre.addClass("prettyprint"); | |||
| prettyPrint(); | |||
| } | |||
| })(jQuery); | |||
| // ajax utils | |||
| @@ -68,8 +95,10 @@ var Gogits = { | |||
| function initCore() { | |||
| Gogits.initTooltips(); | |||
| Gogits.initPopovers(); | |||
| Gogits.initTabs(); | |||
| Gogits.initModals(); | |||
| Gogits.renderMarkdown(); | |||
| } | |||
| function initRegister() { | |||
| @@ -98,17 +127,30 @@ function initRegister() { | |||
| }); | |||
| } | |||
| function initUserSetting(){ | |||
| function initUserSetting() { | |||
| $('#gogs-ssh-keys .delete').confirmation({ | |||
| singleton: true, | |||
| onConfirm: function(e, $this){ | |||
| Gogits.ajaxDelete("",{"id":$this.data("del")},function(json){ | |||
| if(json.ok){ | |||
| onConfirm: function (e, $this) { | |||
| Gogits.ajaxDelete("", {"id": $this.data("del")}, function (json) { | |||
| if (json.ok) { | |||
| window.location.reload(); | |||
| }else{ | |||
| } else { | |||
| alert(json.err); | |||
| } | |||
| }); | |||
| } | |||
| }); | |||
| } | |||
| } | |||
| (function ($) { | |||
| $(function () { | |||
| initCore(); | |||
| var body = $("#gogs-body"); | |||
| if (body.data("page") == "user-signup") { | |||
| initRegister(); | |||
| } | |||
| if (body.data("page") == "user") { | |||
| initUserSetting(); | |||
| } | |||
| }); | |||
| })(jQuery); | |||
| @@ -20,49 +20,35 @@ func Create(ctx *middleware.Context, form auth.CreateRepoForm) { | |||
| return | |||
| } | |||
| if ctx.HasError() { | |||
| ctx.Render.HTML(200, "repo/create", ctx.Data) | |||
| if _, err := models.CreateRepository(ctx.User, | |||
| form.RepoName, form.Description, form.Language, form.License, | |||
| form.Visibility == "private", form.InitReadme == "on"); err == nil { | |||
| ctx.Render.Redirect("/"+ctx.User.Name+"/"+form.RepoName, 302) | |||
| return | |||
| } | |||
| // TODO: access check | |||
| user, err := models.GetUserById(form.UserId) | |||
| if err != nil { | |||
| if err.Error() == models.ErrUserNotExist.Error() { | |||
| ctx.RenderWithErr("User does not exist", "repo/create", &form) | |||
| return | |||
| } | |||
| } | |||
| if err == nil { | |||
| if _, err = models.CreateRepository(user, | |||
| form.RepoName, form.Description, form.Language, form.License, | |||
| form.Visibility == "private", form.InitReadme == "on"); err == nil { | |||
| ctx.Render.Redirect("/"+user.Name+"/"+form.RepoName, 302) | |||
| return | |||
| } | |||
| } | |||
| if err.Error() == models.ErrRepoAlreadyExist.Error() { | |||
| } else if err == models.ErrRepoAlreadyExist { | |||
| ctx.RenderWithErr("Repository name has already been used", "repo/create", &form) | |||
| return | |||
| } | |||
| ctx.Handle(200, "repo.Create", err) | |||
| } | |||
| func Delete(ctx *middleware.Context, form auth.DeleteRepoForm) { | |||
| ctx.Data["Title"] = "Delete repository" | |||
| if ctx.Req.Method == "GET" { | |||
| ctx.Render.HTML(200, "repo/delete", ctx.Data) | |||
| func SettingPost(ctx *middleware.Context) { | |||
| if !ctx.Repo.IsOwner { | |||
| ctx.Render.Error(404) | |||
| return | |||
| } | |||
| if err := models.DeleteRepository(form.UserId, form.RepoId, form.UserName); err != nil { | |||
| ctx.Handle(200, "repo.Delete", err) | |||
| return | |||
| switch ctx.Query("action") { | |||
| case "delete": | |||
| if len(ctx.Repo.Repository.Name) == 0 || ctx.Repo.Repository.Name != ctx.Query("repository") { | |||
| ctx.Data["ErrorMsg"] = "Please make sure you entered repository name is correct." | |||
| ctx.Render.HTML(200, "repo/setting", ctx.Data) | |||
| return | |||
| } | |||
| if err := models.DeleteRepository(ctx.User.Id, ctx.Repo.Repository.Id, ctx.User.LowerName); err != nil { | |||
| ctx.Handle(200, "repo.Delete", err) | |||
| return | |||
| } | |||
| } | |||
| ctx.Render.Redirect("/", 302) | |||
| @@ -9,10 +9,33 @@ import ( | |||
| "github.com/codegangsta/martini" | |||
| "github.com/gogits/git" | |||
| "github.com/gogits/gogs/models" | |||
| "github.com/gogits/gogs/modules/base" | |||
| "github.com/gogits/gogs/modules/middleware" | |||
| ) | |||
| func Branches(ctx *middleware.Context, params martini.Params) { | |||
| if !ctx.Repo.IsValid { | |||
| return | |||
| } | |||
| ctx.Data["Username"] = params["username"] | |||
| ctx.Data["Reponame"] = params["reponame"] | |||
| brs, err := models.GetBranches(params["username"], params["reponame"]) | |||
| if err != nil { | |||
| ctx.Handle(200, "repo.Branches", err) | |||
| return | |||
| } | |||
| ctx.Data["Branches"] = brs | |||
| ctx.Data["IsRepoToolbarBranches"] = true | |||
| ctx.Render.HTML(200, "repo/branches", ctx.Data) | |||
| } | |||
| func Single(ctx *middleware.Context, params martini.Params) { | |||
| if !ctx.Repo.IsValid { | |||
| return | |||
| @@ -22,17 +45,28 @@ func Single(ctx *middleware.Context, params martini.Params) { | |||
| params["branchname"] = "master" | |||
| } | |||
| // Get tree path | |||
| treename := params["_1"] | |||
| // Directory and file list. | |||
| files, err := models.GetReposFiles(params["username"], params["reponame"], | |||
| params["branchname"], treename) | |||
| if err != nil { | |||
| ctx.Handle(200, "repo.Single", err) | |||
| ctx.Render.Error(404) | |||
| return | |||
| } | |||
| ctx.Data["Username"] = params["username"] | |||
| ctx.Data["Reponame"] = params["reponame"] | |||
| ctx.Data["Branchname"] = params["branchname"] | |||
| // Branches. | |||
| brs, err := models.GetBranches(params["username"], params["reponame"]) | |||
| if err != nil { | |||
| ctx.Render.Error(404) | |||
| return | |||
| } | |||
| ctx.Data["Branches"] = brs | |||
| var treenames []string | |||
| Paths := make([]string, 0) | |||
| @@ -43,16 +77,52 @@ func Single(ctx *middleware.Context, params martini.Params) { | |||
| } | |||
| } | |||
| // Get latest commit according username and repo name | |||
| commit, err := models.GetLastestCommit(params["username"], params["reponame"]) | |||
| if err != nil { | |||
| ctx.Render.Error(404) | |||
| return | |||
| } | |||
| ctx.Data["LatestCommit"] = commit | |||
| var readmeFile *models.RepoFile | |||
| for _, f := range files { | |||
| if !f.IsFile() { | |||
| continue | |||
| } | |||
| if len(f.Name) < 6 { | |||
| continue | |||
| } | |||
| if strings.ToLower(f.Name[:6]) == "readme" { | |||
| readmeFile = f | |||
| break | |||
| } | |||
| } | |||
| if readmeFile != nil { | |||
| // if file large than 1M not show it | |||
| if readmeFile.Size > 1024*1024 || readmeFile.Filemode != git.FileModeBlob { | |||
| ctx.Data["FileIsLarge"] = true | |||
| } else if blob, err := readmeFile.LookupBlob(); err != nil { | |||
| ctx.Data["FileIsLarge"] = true | |||
| } else { | |||
| ctx.Data["ReadmeContent"] = string(base.RenderMarkdown(blob.Contents())) | |||
| } | |||
| } | |||
| ctx.Data["Paths"] = Paths | |||
| ctx.Data["Treenames"] = treenames | |||
| ctx.Data["IsRepoToolbarSource"] = true | |||
| ctx.Data["IsRepositoryOwner"] = strings.ToLower(params["username"]) == ctx.User.LowerName | |||
| ctx.Data["Files"] = files | |||
| ctx.Render.HTML(200, "repo/single", ctx.Data) | |||
| } | |||
| func Setting(ctx *middleware.Context, params martini.Params) { | |||
| if !ctx.Repo.IsValid { | |||
| if !ctx.Repo.IsOwner { | |||
| ctx.Render.Error(404) | |||
| return | |||
| } | |||
| @@ -63,7 +133,6 @@ func Setting(ctx *middleware.Context, params martini.Params) { | |||
| ctx.Data["Title"] = title + " - settings" | |||
| ctx.Data["IsRepoToolbarSetting"] = true | |||
| ctx.Data["IsRepositoryOwner"] = strings.ToLower(params["username"]) == ctx.User.LowerName | |||
| ctx.Render.HTML(200, "repo/setting", ctx.Data) | |||
| } | |||
| @@ -195,7 +195,7 @@ func Feeds(ctx *middleware.Context, form auth.FeedsForm) { | |||
| feeds := make([]string, len(actions)) | |||
| for i := range actions { | |||
| feeds[i] = fmt.Sprintf(feedTpl, base.ActionIcon(actions[i].OpType), | |||
| base.TimeSince(actions[i].Created), base.ActionDesc(actions[i])) | |||
| base.TimeSince(actions[i].Created), base.ActionDesc(actions[i], ctx.User.AvatarLink())) | |||
| } | |||
| ctx.Render.JSON(200, &feeds) | |||
| } | |||
| @@ -1,19 +1,12 @@ | |||
| <script> | |||
| $(function(){ | |||
| initCore();{{if .PageIsSignUp}} | |||
| initRegister();{{end}}{{if .PageIsUserSetting}} | |||
| initUserSetting();{{end}} | |||
| }); | |||
| </script> | |||
| <div class="wrapper-push"></div> | |||
| <div class="wrapper-push"></div> | |||
| </div> | |||
| <footer id="footer"> | |||
| <div class="container footer-wrap"> | |||
| <p> | |||
| © 2014 Gogs · ver {{AppVer}} · <i class="fa fa-github"></i><a target="_blank" href="https://github.com/gogits/gogs">GitHub</a> | |||
| </p> | |||
| <p class="desc"></p> | |||
| </div> | |||
| <div class="container footer-wrap"> | |||
| <p>© 2014 Gogs · ver {{AppVer}} · | |||
| <i class="fa fa-github"></i><a target="_blank" href="https://github.com/gogits/gogs">GitHub</a> | |||
| </p> | |||
| <p class="desc"></p> | |||
| </div> | |||
| </footer> | |||
| </body> | |||
| </html> | |||
| @@ -3,7 +3,9 @@ | |||
| <head> | |||
| <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> | |||
| <link rel="shortcut icon" href="/img/favicon.png" /> | |||
| <meta name="author" content="Gogs - Go Git Service" /> | |||
| <meta http-equiv="X-UA-Compatible" content="IE=edge"/> | |||
| <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/> | |||
| <meta name="author" content="Gogs - Go Git Service" /> | |||
| <meta name="description" content="Gogs(Go Git Service) is a GitHub-like clone in the Go Programming Language" /> | |||
| <meta name="keywords" content="go, git"> | |||
| @@ -11,10 +13,12 @@ | |||
| <link href="/css/bootstrap.min.css" rel="stylesheet" /> | |||
| <link href="/css/todc-bootstrap.min.css" rel="stylesheet" /> | |||
| <link href="/css/font-awesome.min.css" rel="stylesheet" /> | |||
| <link href="/css/markdown.css" rel="stylesheet" /> | |||
| <link href="/css/gogs.css" rel="stylesheet" /> | |||
| <script src="/js/jquery-1.10.1.min.js"></script> | |||
| <script src="/js/bootstrap.min.js"></script> | |||
| <script src="/js/lib.js"></script> | |||
| <script src="/js/app.js"></script> | |||
| <title>{{if .Title}}{{.Title}} - {{end}}{{AppName}}</title> | |||
| </head> | |||
| @@ -0,0 +1,42 @@ | |||
| {{template "base/head" .}} | |||
| {{template "base/navbar" .}} | |||
| {{template "repo/nav" .}} | |||
| {{template "repo/toolbar" .}} | |||
| <div id="gogs-body" class="container"> | |||
| <div id="gogs-source"> | |||
| <div class="panel panel-default branch-box info-box"> | |||
| <div class="panel-heading info-head"> | |||
| <h4>Branches</h4> | |||
| </div> | |||
| <table class="panel-footer table branch-list table table-hover"> | |||
| <thead> | |||
| <tr> | |||
| <th class="name"></th> | |||
| <th class="behind">Behind</th> | |||
| <th class="ahead">Ahead</th> | |||
| <th class="date">Last Commit</th> | |||
| <th class="action"></th> | |||
| </tr> | |||
| </thead> | |||
| <tbody> | |||
| <tr class="branch-main"> | |||
| <td class="name" colspan="3"> | |||
| <a href="#"><strong>BranchName</strong></a> | |||
| <button class="btn btn-primary btn-sm">base branch</button> | |||
| </td> | |||
| <td class="date">3 years ago</td> | |||
| <td class="action"></td> | |||
| </tr> | |||
| <tr> | |||
| <td class="name"><a href="#"><strong>BranchName</strong></a></td> | |||
| <td class="behind">102 <span class="graph" style="width: 100%"></span></td> | |||
| <td class="ahead"><span class="graph" style="width: 4%"></span>4</td> | |||
| <td class="date">3 years ago</td> | |||
| <td class="action"><a class="btn btn-info btn-sm" href="#">compare</a></td> | |||
| </tr> | |||
| </tbody> | |||
| </table> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| {{template "base/footer" .}} | |||
| @@ -1,12 +0,0 @@ | |||
| {{template "base/head" .}} | |||
| {{template "base/navbar" .}} | |||
| <div class="container"> | |||
| <form action="/repo/delete" method="post" class="form-horizontal"> | |||
| <div class="form-group"> | |||
| <div class="col-md-offset-4 col-md-3"> | |||
| <button type="submit" class="btn btn-danger">Delete repository</button> | |||
| </div> | |||
| </div> | |||
| </form> | |||
| </div> | |||
| {{template "base/footer" .}} | |||
| @@ -1,42 +1,41 @@ | |||
| <div id="gogs-body-nav" class="gogs-repo-nav"> | |||
| <div class="container"> | |||
| <div class="gogs-repo-btns pull-right"> | |||
| <div class="btn-group" id="gogs-repo-clone"> | |||
| <button type="button" class="btn btn-default"><i class="fa fa-download"></i>Clone</button> | |||
| <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"> | |||
| <span class="caret"></span> | |||
| <span class="sr-only">Toggle Dropdown</span> | |||
| </button> | |||
| <div class="dropdown-menu" role="menu"> | |||
| <div data-val="down-http">http link</div> | |||
| <div data-val="down-git">git link</div> | |||
| </div> | |||
| <div class="row"> | |||
| <div class="col-md-6"> | |||
| <h3><i class="fa fa-book fa-lg"></i><a href="{{.Owner.HomeLink}}">{{.Owner.Name}}</a> / {{.Repository.Name}}</h3> | |||
| </div> | |||
| <div class="btn-group" id="gogs-repo-watching"> | |||
| <button type="button" class="btn btn-default"><i class="fa fa-eye"></i>Watch {x}</button> | |||
| <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"> | |||
| <span class="caret"></span> | |||
| <span class="sr-only">Toggle Dropdown</span> | |||
| </button> | |||
| <div class="dropdown-menu" role="menu"> | |||
| <div class="dropdown-item" data-val="not-watching"> | |||
| <h4 role="presentation" class="dropdown-header">Not Watching</h4> | |||
| <p class="description">You only receive notifications for conversations in which you participate or are @mentioned.</p> | |||
| <p class="divider"></p> | |||
| </div> | |||
| <div class="dropdown-item" data-val="watching"> | |||
| <h4 role="presentation" class="dropdown-header">Watching</h4> | |||
| <p class="description">You receive notifications for all conversations in this repository.</p> | |||
| <div class="col-md-6 actions text-right"> | |||
| <div class="btn-group" id="gogs-repo-clone"> | |||
| <button type="button" class="btn btn-default"><i class="fa fa-download"></i>Clone</button> | |||
| <button type="button" class="btn btn-default dropdown-toggle" data-container="body" data-toggle="popover" data-placement="bottom" data-content="<label>SSH:</label><div class='input-group'><input type='text' class='form-control' value='git@{{AppDomain}}:{{.Owner.Name}}/{{.Repository.Name}}.git'></div>" data-html="1"> | |||
| <span class="caret"></span> | |||
| </button> | |||
| </div> | |||
| <div class="btn-group" id="gogs-repo-watching"> | |||
| <button type="button" class="btn btn-default"><i class="fa fa-eye"></i>Watch {x}</button> | |||
| <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"> | |||
| <span class="caret"></span> | |||
| <span class="sr-only">Toggle Dropdown</span> | |||
| </button> | |||
| <div class="dropdown-menu" role="menu"> | |||
| <div class="dropdown-item" data-val="not-watching"> | |||
| <h4 role="presentation" class="dropdown-header">Not Watching</h4> | |||
| <p class="description">You only receive notifications for conversations in which you participate or are @mentioned.</p> | |||
| <p class="divider"></p> | |||
| </div> | |||
| <div class="dropdown-item" data-val="watching"> | |||
| <h4 role="presentation" class="dropdown-header">Watching</h4> | |||
| <p class="description">You receive notifications for all conversations in this repository.</p> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class="btn-group"> | |||
| <button type="button" class="btn btn-default"><i class="fa fa-star"></i>Star {{.Repository.NumStars}}</button> | |||
| </div> | |||
| <div class="btn-group"> | |||
| <button type="button" class="btn btn-default"><i class="fa fa-code-fork"></i>Fork {{.Repository.NumForks}}</button> | |||
| <div class="btn-group"> | |||
| <button type="button" class="btn btn-default"><i class="fa fa-star"></i>Star {{.Repository.NumStars}}</button> | |||
| </div> | |||
| <div class="btn-group"> | |||
| <button type="button" class="btn btn-default"><i class="fa fa-code-fork"></i>Fork {{.Repository.NumForks}}</button> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <h3><i class="fa fa-book fa-lg"></i><a href="{{.Owner.HomeLink}}">{{.Owner.Name}}</a> / {{.Repository.Name}}</h3> | |||
| </div> | |||
| </div> | |||
| @@ -4,30 +4,60 @@ | |||
| {{template "repo/toolbar" .}} | |||
| <div id="gogs-body" class="container"> | |||
| <div id="gogs-user-setting-nav" class="col-md-3"> | |||
| <h4>Repository Settings</h4> | |||
| <ul class="list-group" data-init="tabs"> | |||
| <li class="list-group-item"><a href="#options" data-toggle="tab">Options</a></li> | |||
| <!--<li class="list-group-item" data-toggle="tab"><a href="#">Collaborators</a></li> | |||
| <li class="list-group-item" data-toggle="tab"><a href="#">Notifications</a></li>--> | |||
| <li class="list-group-item"><a href="#delete" data-toggle="tab">Delete</a></li> | |||
| <li class="list-group-item active"><a href="/{{.Owner.Name}}/{{.Repository.Name}}/settings">Options</a></li> | |||
| <!--<li class="list-group-item"><a href="#">Collaborators</a></li> | |||
| <li class="list-group-item"><a href="#">Notifications</a></li>--> | |||
| </ul> | |||
| </div> | |||
| <div id="gogs-repo-setting-container" class="col-md-9 tab-content"> | |||
| <div id="options" class="tab-pane"> | |||
| <h4>Repository Options</h4> | |||
| <div id="gogs-repo-setting-container" class="col-md-9"> | |||
| {{if .ErrorMsg}}<p class="alert alert-danger">{{.ErrorMsg}}</p>{{end}} | |||
| <div class="panel panel-default"> | |||
| <div class="panel-heading"> | |||
| Repository Options | |||
| </div> | |||
| <div class="panel-body"> | |||
| </div> | |||
| </div> | |||
| <div id="delete" class="tab-pane"> | |||
| <h4>Delete Repository</h4> | |||
| <p class="alert alert-warning">Unexpected bad things will happen if you don't read this!</p> | |||
| <p>This action <strong>CANNOT</strong> be undone. This will delete the repository, wiki, issues, and comments permanently. </p> | |||
| <div class="panel panel-warning"> | |||
| <div class="panel-heading"> | |||
| Danger Zone | |||
| </div> | |||
| <div class="panel-body"> | |||
| <button type="button" class="btn btn-default pull-right" href="#delete-repository-modal" data-toggle="modal"> | |||
| Delete this repository | |||
| </button> | |||
| <dd> | |||
| <dt>Delete this repository.</dt> | |||
| <dl>Once you delete a repository, there is no going back. Please be certain.</dl> | |||
| </dd> | |||
| <form action="/repo/delete" method="post"> | |||
| <input type="hidden" name="userId" value="{{.Owner.Id}}"/> | |||
| <input type="hidden" name="userName" value="{{.Owner.Name}}"/> | |||
| <input type="hidden" name="repoId" value="{{.Repository.Id}}"/> | |||
| <hr/> | |||
| <button class="btn btn-danger btn-lg">I understand the consequences, delete this repository</button> | |||
| </form> | |||
| <div class="modal fade" id="delete-repository-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> | |||
| <div class="modal-dialog"> | |||
| <form action="/{{.Owner.Name}}/{{.Repository.Name}}/settings" method="post" class="modal-content"> | |||
| <input type="hidden" name="action" value="delete"> | |||
| <div class="modal-header"> | |||
| <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> | |||
| <h4 class="modal-title" id="myModalLabel">Delete repository</h4> | |||
| </div> | |||
| <div class="modal-body"> | |||
| <div class="form-group"> | |||
| <label>Please enter your repository name "<strong class="text-danger">{{.Repository.Name}}</strong>"</label> | |||
| <input name="repository" class="form-control" type="text" placeholder="Type your repository name" required="required"> | |||
| </div> | |||
| </div> | |||
| <div class="modal-footer"> | |||
| <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> | |||
| <button class="btn btn-danger btn-lg">I understand the consequences, delete this repository</button> | |||
| </div> | |||
| </form> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| @@ -5,56 +5,61 @@ | |||
| <div id="gogs-body" class="container"> | |||
| <div id="gogs-source"> | |||
| <div class="source-toolbar"> | |||
| {{ $username := .Username}} | |||
| {{ $reponame := .Reponame}} | |||
| {{ $branchname := .Branchname}} | |||
| {{ $treenames := .Treenames}} | |||
| {{ $repoLink := .RepositoryLink}} | |||
| {{ $n := len $treenames}} | |||
| <button class="btn btn-default pull-right"><i class="fa fa-plus-square"></i>Add File</button> | |||
| <div class="dropdown branch-switch"> | |||
| <a href="#" class="btn btn-success dropdown-toggle" data-toggle="dropdown"><i class="fa fa-chain"></i>master | |||
| <a href="#" class="btn btn-success dropdown-toggle" data-toggle="dropdown"><i class="fa fa-chain"></i>{{$branchname}} | |||
| <b class="caret"></b></a> | |||
| <ul class="dropdown-menu"> | |||
| <li><a class="current" href="/{{.RepositoryLink}}/tree/master">master</a></li> | |||
| <li><a href="/{{.RepositoryLink}}/tree/develop">develop</a></li> | |||
| {{range .Branches}} | |||
| <li><a {{if eq . $branchname}}class="current" {{end}}href="/{{$repoLink}}/tree/{{.}}">{{.}}</a></li> | |||
| {{end}} | |||
| </ul> | |||
| </div> | |||
| {{$paths := .Paths}} | |||
| {{ $username := .Username}} | |||
| {{ $reponame := .Reponame}} | |||
| {{ $branchname := .Branchname}} | |||
| {{ $treenames := .Treenames}} | |||
| {{ $n := len $treenames}} | |||
| {{ $l := Subtract $n 1}} | |||
| <ol class="breadcrumb"> | |||
| <li class="root dir"><a href="/{{$username}}/{{$reponame}}/tree/{{$branchname}}">{{.Repository.Name}}</a></li> | |||
| <li class="root dir"> | |||
| <a href="/{{$username}}/{{$reponame}}/tree/{{$branchname}}">{{.Repository.Name}}</a></li> | |||
| {{range $i, $v := $treenames}} | |||
| <li class="dir"> | |||
| {{if eq $i $l}}{{$v}} | |||
| {{else}} | |||
| <a href="/{{$username}}/{{$reponame}}/tree/{{$branchname}}/{{index $paths $i}}">{{$v}}</a> | |||
| {{end}}</li> | |||
| {{if eq $i $l}}{{$v}} | |||
| {{else}} | |||
| <a href="/{{$username}}/{{$reponame}}/tree/{{$branchname}}/{{index $paths $i}}">{{$v}}</a> | |||
| {{end}} | |||
| </li> | |||
| {{end}} | |||
| </ol> | |||
| </div> | |||
| <div class="panel panel-default info-box"> | |||
| <div class="panel-heading info-head"> | |||
| Merge branch 'release/1.1.1' | |||
| <a href="/{{$username}}/{{$reponame}}/commit/{{.LatestCommit.SHA}}">{{.LatestCommit.Message}}</a> | |||
| </div> | |||
| <div class="panel-body info-content"> | |||
| slene authored 4 days ago | |||
| <a href="/user/{{.LatestCommit.Author}}">{{.LatestCommit.Author}}</a> <span class="text-muted">{{TimeSince .LatestCommit.Date}}</span> | |||
| </div> | |||
| <table class="panel-footer table file-list"> | |||
| <thead class="hidden"> | |||
| <tr> | |||
| <th class="icon"></th> | |||
| <th class="name">Filename</th> | |||
| <th class="text">Message</th> | |||
| <th class="date">Date modified</th> | |||
| </tr> | |||
| <tr> | |||
| <th class="icon"></th> | |||
| <th class="name">Filename</th> | |||
| <th class="text">Message</th> | |||
| <th class="date">Date modified</th> | |||
| </tr> | |||
| </thead> | |||
| <tbody> | |||
| {{range .Files}} | |||
| <tr {{if .IsDir}}class="is-dir"{{end}}> | |||
| <td class="icon"> | |||
| <i class="fa {{if .IsDir}}fa-folder{{else}}fa-file-text-o{{end}}"></i> | |||
| </td> | |||
| <td class="name"> | |||
| {{range .Files}} | |||
| <tr | |||
| {{if .IsDir}}class="is-dir"{{end}}> | |||
| <td class="icon"> | |||
| <i class="fa {{if .IsDir}}fa-folder{{else}}fa-file-text-o{{end}}"></i> | |||
| </td> | |||
| <td class="name"> | |||
| <span class="wrap"> | |||
| {{if .IsDir}} | |||
| <a href="/{{$username}}/{{$reponame}}/tree/{{$branchname}}/{{.Path}}">{{.Name}}</a> | |||
| @@ -62,29 +67,35 @@ | |||
| <a href="/{{$username}}/{{$reponame}}/blob/{{$branchname}}/{{.Name}}">{{.Name}}</a> | |||
| {{end}} | |||
| </span> | |||
| </td> | |||
| <td class="text"> | |||
| </td> | |||
| <td class="text"> | |||
| <span class="wrap"> | |||
| {{.Message}} | |||
| </span> | |||
| </td> | |||
| <td class="date"> | |||
| </td> | |||
| <td class="date"> | |||
| <span class="wrap"> | |||
| {{TimeSince .Created}} | |||
| </span> | |||
| </td> | |||
| </tr> | |||
| {{end}} | |||
| </td> | |||
| </tr> | |||
| {{end}} | |||
| </tbody> | |||
| </table> | |||
| </div> | |||
| <div class="panel panel-default file-content"> | |||
| <div class="panel-heading"> | |||
| README.md | |||
| </div> | |||
| <div class="panel-body markdown"> | |||
| httplib | |||
| <div class="panel-heading file-head"> | |||
| <i class="icon fa fa-book"></i> README.md | |||
| </div> | |||
| {{if .FileIsLarge}} | |||
| <div class="panel-footer"> | |||
| Large file size 1000kb | |||
| </div> | |||
| {{else}} | |||
| <div class="panel-body file-body markdown"> | |||
| {{.ReadmeContent|str2html}} | |||
| </div> | |||
| {{end}} | |||
| </div> | |||
| </div> | |||
| </div> | |||
| @@ -4,9 +4,10 @@ | |||
| <div class="collapse navbar-collapse"> | |||
| <ul class="nav navbar-nav"> | |||
| <li class="{{if .IsRepoToolbarSource}}active{{end}}"><a href="/{{.RepositoryLink}}">Source</a></li> | |||
| <li><a href="/{{.RepositoryLink}}/commits">Commits</a></li> | |||
| <li><a href="/{{.RepositoryLink}}/issues">Issues <!--<span class="badge">42</span>--></a></li> | |||
| <li><a href="/{{.RepositoryLink}}/pulls">Pull Requests</a></li> | |||
| <li class="{{if .IsRepoToolbarCommits}}active{{end}}"><a href="/{{.RepositoryLink}}/commits">Commits</a></li> | |||
| <li class="{{if .IsRepoToolbarBranches}}active{{end}}"><a href="/{{.RepositoryLink}}/branches">Branches</a></li> | |||
| <li class="{{if .IsRepoToolbarPulls}}active{{end}}"><a href="/{{.RepositoryLink}}/pulls">Pull Requests</a></li> | |||
| <li class="{{if .IsRepoToolbarIssues}}active{{end}}"><a href="/{{.RepositoryLink}}/issues">Issues <!--<span class="badge">42</span>--></a></li> | |||
| <li class="dropdown"> | |||
| <a href="#" class="dropdown-toggle" data-toggle="dropdown">More <b class="caret"></b></a> | |||
| <ul class="dropdown-menu"> | |||
| @@ -11,7 +11,7 @@ | |||
| <h3>News Feed</h3> | |||
| </div> | |||
| </div> | |||
| <div id="gogs-body" class="container"> | |||
| <div id="gogs-body" class="container" data-page="user"> | |||
| {{if .HasInfo}}<div class="alert alert-info">{{.InfoMsg}}</div>{{end}} | |||
| <div id="gogs-feed-left" class="col-md-8"> | |||
| <ul class="list-unstyled activity-list"> | |||
| @@ -1,6 +1,6 @@ | |||
| {{template "base/head" .}} | |||
| {{template "base/navbar" .}} | |||
| <div id="gogs-body" class="container"> | |||
| <div id="gogs-body" class="container" data-page="user"> | |||
| <div id="gogs-user-setting-nav" class="col-md-3"> | |||
| <h4>Account Setting</h4> | |||
| <ul class="list-group"> | |||
| @@ -1,6 +1,6 @@ | |||
| {{template "base/head" .}} | |||
| {{template "base/navbar" .}} | |||
| <div id="gogs-body" class="container"> | |||
| <div id="gogs-body" class="container" data-page="user"> | |||
| <div id="gogs-user-setting-nav" class="col-md-3"> | |||
| <h4>Account Setting</h4> | |||
| <ul class="list-group"> | |||
| @@ -1,6 +1,6 @@ | |||
| {{template "base/head" .}} | |||
| {{template "base/navbar" .}} | |||
| <div id="gogs-body" class="container"> | |||
| <div id="gogs-body" class="container" data-page="user"> | |||
| <div id="gogs-user-setting-nav" class="col-md-3"> | |||
| <h4>Account Setting</h4> | |||
| <ul class="list-group"> | |||
| @@ -1,6 +1,6 @@ | |||
| {{template "base/head" .}} | |||
| {{template "base/navbar" .}} | |||
| <div id="gogs-body" class="container"> | |||
| <div id="gogs-body" class="container" data-page="user"> | |||
| <div id="gogs-user-profile" class="col-md-3"> | |||
| <div class="profile-avatar text-center"> | |||
| <a href="{{.Owner.HomeLink}}" class="center-block" data-toggle="tooltip" data-placement="bottom" title="Change Avatar"> | |||
| @@ -32,10 +32,11 @@ | |||
| {{if eq .TabName "activity"}} | |||
| <div class="tab-pane active"> | |||
| <ul class="list-unstyled activity-list"> | |||
| {{$avatarLink := .Owner.AvatarLink}} | |||
| {{range .Feeds}} | |||
| <li> | |||
| <i class="icon fa fa-{{ActionIcon .OpType}}"></i> | |||
| <div class="info"><span class="meta">{{TimeSince .Created}}</span><br>{{ActionDesc . | str2html}}</div> | |||
| <div class="info"><span class="meta">{{TimeSince .Created}}</span><br>{{ActionDesc . $avatarLink | str2html}}</div> | |||
| <span class="clearfix"></span> | |||
| </li> | |||
| {{else}} | |||
| @@ -1,6 +1,6 @@ | |||
| {{template "base/head" .}} | |||
| {{template "base/navbar" .}} | |||
| <div id="gogs-body" class="container"> | |||
| <div id="gogs-body" class="container" data-page="user"> | |||
| <div id="gogs-user-setting-nav" class="col-md-3"> | |||
| <h4>Account Setting</h4> | |||
| <ul class="list-group"> | |||
| @@ -1,6 +1,6 @@ | |||
| {{template "base/head" .}} | |||
| {{template "base/navbar" .}} | |||
| <div id="gogs-body" class="container"> | |||
| <div id="gogs-body" class="container" data-page="user"> | |||
| <div id="gogs-user-setting-nav" class="col-md-3"> | |||
| <h4>Account Setting</h4> | |||
| <ul class="list-group"> | |||
| @@ -1,6 +1,6 @@ | |||
| {{template "base/head" .}} | |||
| {{template "base/navbar" .}} | |||
| <div id="gogs-body" class="container"> | |||
| <div id="gogs-body" class="container" data-page="user"> | |||
| <div id="gogs-user-setting-nav" class="col-md-3"> | |||
| <h4>Account Setting</h4> | |||
| <ul class="list-group"> | |||
| @@ -1,6 +1,6 @@ | |||
| {{template "base/head" .}} | |||
| {{template "base/navbar" .}} | |||
| <div class="container" id="gogs-body"> | |||
| <div class="container" id="gogs-body" data-page="user-signin"> | |||
| <form action="/user/login" method="post" class="form-horizontal gogs-card" id="gogs-login-card"> | |||
| <h3>Log in</h3> | |||
| <div class="alert alert-danger form-error{{if .HasError}}{{else}} hidden{{end}}">{{.ErrorMsg}}</div> | |||
| @@ -1,6 +1,6 @@ | |||
| {{template "base/head" .}} | |||
| {{template "base/navbar" .}} | |||
| <div class="container" id="gogs-body"> | |||
| <div class="container" id="gogs-body" data-page="user-signup"> | |||
| <form action="/user/sign_up" method="post" class="form-horizontal gogs-card" id="gogs-login-card"> | |||
| <h3>Sign Up</h3> | |||
| <div class="alert alert-danger form-error{{if .HasError}}{{else}} hidden{{end}}">{{.ErrorMsg}}</div> | |||
| @@ -68,14 +68,16 @@ func runWeb(*cli.Context) { | |||
| m.Get("/user/:username", middleware.SignInRequire(false), user.Profile) | |||
| m.Any("/repo/create", middleware.SignInRequire(true), binding.BindIgnErr(auth.CreateRepoForm{}), repo.Create) | |||
| m.Any("/repo/delete", middleware.SignInRequire(true), binding.Bind(auth.DeleteRepoForm{}), repo.Delete) | |||
| m.Get("/help", routers.Help) | |||
| m.Get("/:username/:reponame/settings", middleware.SignInRequire(false), middleware.RepoAssignment(true), repo.Setting) | |||
| m.Post("/:username/:reponame/settings", middleware.SignInRequire(true), middleware.RepoAssignment(true), repo.SettingPost) | |||
| m.Get("/:username/:reponame/settings", middleware.SignInRequire(true), middleware.RepoAssignment(true), repo.Setting) | |||
| m.Get("/:username/:reponame/commits", middleware.SignInRequire(false), middleware.RepoAssignment(true), repo.Commits) | |||
| m.Get("/:username/:reponame/issues", middleware.SignInRequire(false), middleware.RepoAssignment(true), repo.Issues) | |||
| m.Get("/:username/:reponame/pulls", middleware.SignInRequire(false), middleware.RepoAssignment(true), repo.Pulls) | |||
| m.Get("/:username/:reponame/branches", middleware.SignInRequire(false), middleware.RepoAssignment(true), repo.Branches) | |||
| m.Get("/:username/:reponame/tree/:branchname/**", | |||
| middleware.SignInRequire(false), middleware.RepoAssignment(true), repo.Single) | |||
| m.Get("/:username/:reponame/tree/:branchname", | |||