| @@ -5,7 +5,7 @@ Gogs(Go Git Service) is a Self Hosted Git Service in the Go Programming Language | |||
|  | |||
| ##### Current version: 0.2.6 Alpha | |||
| ##### Current version: 0.2.7 Alpha | |||
| #### Due to testing purpose, data of [try.gogits.org](http://try.gogits.org) has been reset in April 6, 2014 and will reset multiple times after. Please do NOT put your important data on the site. | |||
| @@ -5,7 +5,7 @@ Gogs(Go Git Service) 是一个由 Go 语言编写的自助 Git 托管服务。 | |||
|  | |||
| ##### 当前版本:0.2.6 Alpha | |||
| ##### 当前版本:0.2.7 Alpha | |||
| ## 开发目的 | |||
| @@ -19,7 +19,7 @@ import ( | |||
| // Test that go1.2 tag above is included in builds. main.go refers to this definition. | |||
| const go12tag = true | |||
| const APP_VER = "0.2.6.0411 Alpha" | |||
| const APP_VER = "0.2.7.0411 Alpha" | |||
| func init() { | |||
| base.AppVer = APP_VER | |||
| @@ -53,10 +53,17 @@ func UpdateAccessWithSession(sess *xorm.Session, access *Access) error { | |||
| // HasAccess returns true if someone can read or write to given repository. | |||
| func HasAccess(userName, repoName string, mode int) (bool, error) { | |||
| return orm.Get(&Access{ | |||
| Id: 0, | |||
| access := &Access{ | |||
| UserName: strings.ToLower(userName), | |||
| RepoName: strings.ToLower(repoName), | |||
| Mode: mode, | |||
| }) | |||
| } | |||
| has, err := orm.Get(access) | |||
| if err != nil { | |||
| return false, err | |||
| } else if !has { | |||
| return false, nil | |||
| } else if mode > access.Mode { | |||
| return false, nil | |||
| } | |||
| return true, nil | |||
| } | |||
| @@ -295,6 +295,9 @@ func DeleteUser(user *User) error { | |||
| } | |||
| // Delete oauth2. | |||
| if _, err = orm.Delete(&Oauth2{Uid: user.Id}); err != nil { | |||
| return err | |||
| } | |||
| // Delete all feeds. | |||
| if _, err = orm.Delete(&Action{UserId: user.Id}); err != nil { | |||
| @@ -18,7 +18,7 @@ import ( | |||
| type CreateRepoForm struct { | |||
| RepoName string `form:"repo" binding:"Required;AlphaDash"` | |||
| Visibility string `form:"visibility"` | |||
| Private string `form:"private"` | |||
| Description string `form:"desc" binding:"MaxSize(100)"` | |||
| Language string `form:"language"` | |||
| License string `form:"license"` | |||
| @@ -49,6 +49,7 @@ type Context struct { | |||
| IsBranch bool | |||
| IsTag bool | |||
| IsCommit bool | |||
| HasAccess bool | |||
| Repository *models.Repository | |||
| Owner *models.User | |||
| Commit *git.Commit | |||
| @@ -102,12 +103,10 @@ func (ctx *Context) RenderWithErr(msg, tpl string, form auth.Form) { | |||
| // Handle handles and logs error by given status. | |||
| func (ctx *Context) Handle(status int, title string, err error) { | |||
| log.Error("%s: %v", title, err) | |||
| if martini.Dev == martini.Prod { | |||
| ctx.HTML(200, "status/500") | |||
| return | |||
| if martini.Dev != martini.Prod { | |||
| ctx.Data["ErrorMsg"] = err | |||
| } | |||
| ctx.Data["ErrorMsg"] = err | |||
| ctx.HTML(status, fmt.Sprintf("status/%d", status)) | |||
| } | |||
| @@ -67,12 +67,14 @@ func RepoAssignment(redirect bool, args ...bool) martini.Handler { | |||
| ctx.Handle(200, "RepoAssignment", errors.New("invliad user account for single repository")) | |||
| return | |||
| } | |||
| ctx.Repo.Owner = user | |||
| // get repository | |||
| repo, err := models.GetRepositoryByName(user.Id, repoName) | |||
| if err != nil { | |||
| if err == models.ErrRepoNotExist { | |||
| ctx.Handle(404, "RepoAssignment", err) | |||
| return | |||
| } else if redirect { | |||
| ctx.Redirect("/") | |||
| return | |||
| @@ -80,6 +82,26 @@ func RepoAssignment(redirect bool, args ...bool) martini.Handler { | |||
| ctx.Handle(500, "RepoAssignment", err) | |||
| return | |||
| } | |||
| // Check access. | |||
| if repo.IsPrivate { | |||
| if ctx.User == nil { | |||
| ctx.Handle(404, "RepoAssignment(HasAccess)", nil) | |||
| return | |||
| } | |||
| hasAccess, err := models.HasAccess(ctx.User.Name, ctx.Repo.Owner.Name+"/"+repo.Name, models.AU_READABLE) | |||
| if err != nil { | |||
| ctx.Handle(500, "RepoAssignment(HasAccess)", err) | |||
| return | |||
| } else if !hasAccess { | |||
| ctx.Handle(404, "RepoAssignment(HasAccess)", nil) | |||
| return | |||
| } | |||
| } | |||
| ctx.Repo.HasAccess = true | |||
| ctx.Data["HasAccess"] = true | |||
| repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues | |||
| ctx.Repo.Repository = repo | |||
| @@ -91,8 +113,6 @@ func RepoAssignment(redirect bool, args ...bool) martini.Handler { | |||
| return | |||
| } | |||
| ctx.Repo.GitRepo = gitRepo | |||
| ctx.Repo.Owner = user | |||
| ctx.Repo.RepoLink = "/" + user.Name + "/" + repo.Name | |||
| ctx.Data["Title"] = user.Name + "/" + repo.Name | |||
| @@ -170,3 +190,27 @@ func RepoAssignment(redirect bool, args ...bool) martini.Handler { | |||
| ctx.Data["IsRepositoryWatching"] = ctx.Repo.IsWatching | |||
| } | |||
| } | |||
| func WriteAccess() martini.Handler { | |||
| return func(ctx *Context) { | |||
| if ctx.Repo.Repository.IsPrivate { | |||
| ctx.Repo.HasAccess = false | |||
| ctx.Data["HasAccess"] = false | |||
| if ctx.User == nil { | |||
| ctx.Handle(404, "WriteAccess", nil) | |||
| return | |||
| } | |||
| hasAccess, err := models.HasAccess(ctx.User.Name, ctx.Repo.Owner.Name+"/"+ctx.Repo.Repository.Name, models.AU_WRITABLE) | |||
| if err != nil { | |||
| ctx.Handle(500, "WriteAccess(HasAccess)", err) | |||
| return | |||
| } else if !hasAccess { | |||
| ctx.Handle(404, "WriteAccess(HasAccess)", nil) | |||
| return | |||
| } | |||
| } | |||
| ctx.Repo.HasAccess = true | |||
| ctx.Data["HasAccess"] = true | |||
| } | |||
| } | |||
| @@ -41,7 +41,7 @@ func CreatePost(ctx *middleware.Context, form auth.CreateRepoForm) { | |||
| } | |||
| _, err := models.CreateRepository(ctx.User, form.RepoName, form.Description, | |||
| form.Language, form.License, form.Visibility == "private", form.InitReadme == "on") | |||
| form.Language, form.License, form.Private == "on", form.InitReadme == "on") | |||
| if err == nil { | |||
| log.Trace("%s Repository created: %s/%s", ctx.Req.RequestURI, ctx.User.LowerName, form.RepoName) | |||
| ctx.Redirect("/" + ctx.User.Name + "/" + form.RepoName) | |||
| @@ -72,7 +72,7 @@ func MirrorPost(ctx *middleware.Context, form auth.CreateRepoForm) { | |||
| } | |||
| _, err := models.CreateRepository(ctx.User, form.RepoName, form.Description, | |||
| "", form.License, form.Visibility == "private", false) | |||
| "", form.License, form.Private == "on", false) | |||
| if err == nil { | |||
| log.Trace("%s Repository created: %s/%s", ctx.Req.RequestURI, ctx.User.LowerName, form.RepoName) | |||
| ctx.Redirect("/" + ctx.User.Name + "/" + form.RepoName) | |||
| @@ -120,10 +120,7 @@ func runServ(k *cli.Context) { | |||
| qlog.Fatalf("Unavilable repository %v", args) | |||
| } | |||
| repoUserName := rr[0] | |||
| repoName := rr[1] | |||
| if strings.HasSuffix(repoName, ".git") { | |||
| repoName = repoName[:len(repoName)-4] | |||
| } | |||
| repoName := strings.TrimSuffix(rr[1], ".git") | |||
| isWrite := In(verb, COMMANDS_WRITE) | |||
| isRead := In(verb, COMMANDS_READONLY) | |||
| @@ -156,7 +153,7 @@ func runServ(k *cli.Context) { | |||
| break | |||
| } | |||
| has, err := models.HasAccess(user.Name, repoPath, models.AU_READABLE) | |||
| has, err := models.HasAccess(user.Name, path.Join(repoUserName, repoName), models.AU_READABLE) | |||
| if err != nil { | |||
| println("Inernel error") | |||
| qlog.Fatal(err) | |||
| @@ -4,7 +4,7 @@ | |||
| <a id="nav-logo" class="nav-item pull-left{{if .PageIsHome}} active{{end}}" href="/"><img src="/img/favicon.png" alt="Gogs Logo" id="logo"></a> | |||
| <a class="nav-item pull-left{{if .PageIsUserDashboard}} active{{end}}" href="/">Dashboard</a> | |||
| <a class="nav-item pull-left{{if .PageIsHelp}} active{{end}}" href="https://github.com/gogits/gogs/wiki">Help</a>{{if .IsSigned}} | |||
| <form class="nav-item pull-left{{if .PageIsNewRepo}} active{{end}}" id="nav-search-form"> | |||
| {{if .HasAccess}}<form class="nav-item pull-left{{if .PageIsNewRepo}} active{{end}}" id="nav-search-form"> | |||
| <div class="input-group"> | |||
| <div class="input-group-btn"> | |||
| <button type="button" class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown">{{if .Repository}}This Repository{{else}}All Repositories{{end}} <span class="caret"></span></button> | |||
| @@ -16,7 +16,7 @@ | |||
| </div> | |||
| <input type="search" class="form-control input-sm" name="q" placeholder="search code, commits and issues"/> | |||
| </div> | |||
| </form> | |||
| </form>{{end}} | |||
| <a id="nav-out" class="nav-item navbar-right navbar-btn btn btn-danger" href="/user/logout/"><i class="fa fa-power-off fa-lg"></i></a> | |||
| <a id="nav-avatar" class="nav-item navbar-right{{if .PageIsUserProfile}} active{{end}}" href="{{.SignedUser.HomeLink}}" data-toggle="tooltip" data-placement="bottom" title="{{.SignedUserName}}"> | |||
| <img src="{{.SignedUser.AvatarLink}}?s=28" alt="user-avatar" title="username"/> | |||
| @@ -22,10 +22,14 @@ | |||
| </div> | |||
| <div class="form-group"> | |||
| <label class="col-md-2 control-label">Visibility<strong class="text-danger">*</strong></label> | |||
| <label class="col-md-2 control-label">Visibility</label> | |||
| <div class="col-md-8"> | |||
| <p class="form-control-static">Public</p> | |||
| <input type="hidden" value="public" name="visibility"/> | |||
| <div class="checkbox"> | |||
| <label> | |||
| <input type="checkbox" name="private" {{if .private}}checked{{end}}> | |||
| <strong>This repository is private</strong> | |||
| </label> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| @@ -156,22 +156,24 @@ func runWeb(*cli.Context) { | |||
| m.Get("/template/**", dev.TemplatePreview) | |||
| } | |||
| writeable := middleware.WriteAccess() | |||
| m.Group("/:username/:reponame", func(r martini.Router) { | |||
| r.Post("/settings", repo.SettingPost) | |||
| r.Get("/settings", repo.Setting) | |||
| r.Get("/settings", writeable, repo.Setting) | |||
| r.Post("/settings", writeable, repo.SettingPost) | |||
| r.Get("/action/:action", repo.Action) | |||
| r.Get("/issues/new", repo.CreateIssue) | |||
| r.Post("/issues/new", bindIgnErr(auth.CreateIssueForm{}), repo.CreateIssuePost) | |||
| r.Post("/issues/:index", bindIgnErr(auth.CreateIssueForm{}), repo.UpdateIssue) | |||
| r.Post("/comment/:action", repo.Comment) | |||
| r.Post("/import", repo.Import) | |||
| r.Post("/import", writeable, repo.Import) | |||
| }, reqSignIn, middleware.RepoAssignment(true)) | |||
| m.Group("/:username/:reponame", func(r martini.Router) { | |||
| r.Get("/issues", repo.Issues) | |||
| r.Get("/issues/:index", repo.ViewIssue) | |||
| r.Get("/releases", repo.Releases) | |||
| r.Any("/releases/new", repo.ReleasesNew) // TODO: | |||
| r.Any("/releases/new", writeable, repo.ReleasesNew) // TODO: | |||
| r.Get("/pulls", repo.Pulls) | |||
| r.Get("/branches", repo.Branches) | |||
| }, ignSignIn, middleware.RepoAssignment(true)) | |||
| @@ -187,8 +189,8 @@ func runWeb(*cli.Context) { | |||
| }, ignSignIn, middleware.RepoAssignment(true, true)) | |||
| m.Group("/:username", func(r martini.Router) { | |||
| r.Any("/:reponame/**", repo.Http) | |||
| r.Get("/:reponame", middleware.RepoAssignment(true, true, true), repo.Single) | |||
| r.Any("/:reponame/**", repo.Http) | |||
| }, ignSignInAndCsrf) | |||
| // Not found handler. | |||