#1146 finish new access rights for collaborators

This commit is contained in:
Unknwon 2016-03-05 20:45:23 -05:00
parent 045f14fbd0
commit a5b0400be7
22 changed files with 210 additions and 190 deletions

View File

@ -3,7 +3,7 @@ Gogs - Go Git Service [![Build Status](https://travis-ci.org/gogits/gogs.svg?bra
![](https://github.com/gogits/gogs/blob/master/public/img/gogs-large-resize.png?raw=true) ![](https://github.com/gogits/gogs/blob/master/public/img/gogs-large-resize.png?raw=true)
##### Current version: 0.8.58 ##### Current version: 0.8.59
| Web | UI | Preview | | Web | UI | Preview |
|:-------------:|:-------:|:-------:| |:-------------:|:-------:|:-------:|

View File

@ -334,7 +334,7 @@ func runWeb(ctx *cli.Context) {
} }
reqRepoAdmin := middleware.RequireRepoAdmin() reqRepoAdmin := middleware.RequireRepoAdmin()
reqRepoPusher := middleware.RequireRepoPusher() reqRepoWriter := middleware.RequireRepoWriter()
// ***** START: Organization ***** // ***** START: Organization *****
m.Group("/org", func() { m.Group("/org", func() {
@ -448,7 +448,7 @@ func runWeb(ctx *cli.Context) {
m.Post("/label", repo.UpdateIssueLabel) m.Post("/label", repo.UpdateIssueLabel)
m.Post("/milestone", repo.UpdateIssueMilestone) m.Post("/milestone", repo.UpdateIssueMilestone)
m.Post("/assignee", repo.UpdateIssueAssignee) m.Post("/assignee", repo.UpdateIssueAssignee)
}, reqRepoAdmin) }, reqRepoWriter)
m.Group("/:index", func() { m.Group("/:index", func() {
m.Post("/title", repo.UpdateIssueTitle) m.Post("/title", repo.UpdateIssueTitle)
@ -460,7 +460,7 @@ func runWeb(ctx *cli.Context) {
m.Post("/new", bindIgnErr(auth.CreateLabelForm{}), repo.NewLabel) m.Post("/new", bindIgnErr(auth.CreateLabelForm{}), repo.NewLabel)
m.Post("/edit", bindIgnErr(auth.CreateLabelForm{}), repo.UpdateLabel) m.Post("/edit", bindIgnErr(auth.CreateLabelForm{}), repo.UpdateLabel)
m.Post("/delete", repo.DeleteLabel) m.Post("/delete", repo.DeleteLabel)
}, reqRepoAdmin, middleware.RepoRef()) }, reqRepoWriter, middleware.RepoRef())
m.Group("/milestones", func() { m.Group("/milestones", func() {
m.Combo("/new").Get(repo.NewMilestone). m.Combo("/new").Get(repo.NewMilestone).
Post(bindIgnErr(auth.CreateMilestoneForm{}), repo.NewMilestonePost) Post(bindIgnErr(auth.CreateMilestoneForm{}), repo.NewMilestonePost)
@ -468,7 +468,7 @@ func runWeb(ctx *cli.Context) {
m.Post("/:id/edit", bindIgnErr(auth.CreateMilestoneForm{}), repo.EditMilestonePost) m.Post("/:id/edit", bindIgnErr(auth.CreateMilestoneForm{}), repo.EditMilestonePost)
m.Get("/:id/:action", repo.ChangeMilestonStatus) m.Get("/:id/:action", repo.ChangeMilestonStatus)
m.Post("/delete", repo.DeleteMilestone) m.Post("/delete", repo.DeleteMilestone)
}, reqRepoAdmin, middleware.RepoRef()) }, reqRepoWriter, middleware.RepoRef())
m.Group("/releases", func() { m.Group("/releases", func() {
m.Get("/new", repo.NewRelease) m.Get("/new", repo.NewRelease)
@ -476,7 +476,7 @@ func runWeb(ctx *cli.Context) {
m.Get("/edit/:tagname", repo.EditRelease) m.Get("/edit/:tagname", repo.EditRelease)
m.Post("/edit/:tagname", bindIgnErr(auth.EditReleaseForm{}), repo.EditReleasePost) m.Post("/edit/:tagname", bindIgnErr(auth.EditReleaseForm{}), repo.EditReleasePost)
m.Post("/delete", repo.DeleteRelease) m.Post("/delete", repo.DeleteRelease)
}, reqRepoAdmin, middleware.RepoRef()) }, reqRepoWriter, middleware.RepoRef())
m.Combo("/compare/*", repo.MustAllowPulls).Get(repo.CompareAndPullRequest). m.Combo("/compare/*", repo.MustAllowPulls).Get(repo.CompareAndPullRequest).
Post(bindIgnErr(auth.CreateIssueForm{}), repo.CompareAndPullRequestPost) Post(bindIgnErr(auth.CreateIssueForm{}), repo.CompareAndPullRequestPost)
@ -503,7 +503,7 @@ func runWeb(ctx *cli.Context) {
m.Combo("/:page/_edit").Get(repo.EditWiki). m.Combo("/:page/_edit").Get(repo.EditWiki).
Post(bindIgnErr(auth.NewWikiForm{}), repo.EditWikiPost) Post(bindIgnErr(auth.NewWikiForm{}), repo.EditWikiPost)
m.Post("/:page/delete", repo.DeleteWikiPagePost) m.Post("/:page/delete", repo.DeleteWikiPagePost)
}, reqSignIn, reqRepoPusher) }, reqSignIn, reqRepoWriter)
}, repo.MustEnableWiki, middleware.RepoRef()) }, repo.MustEnableWiki, middleware.RepoRef())
m.Get("/archive/*", repo.Download) m.Get("/archive/*", repo.Download)
@ -511,7 +511,7 @@ func runWeb(ctx *cli.Context) {
m.Group("/pulls/:index", func() { m.Group("/pulls/:index", func() {
m.Get("/commits", middleware.RepoRef(), repo.ViewPullCommits) m.Get("/commits", middleware.RepoRef(), repo.ViewPullCommits)
m.Get("/files", middleware.RepoRef(), repo.ViewPullFiles) m.Get("/files", middleware.RepoRef(), repo.ViewPullFiles)
m.Post("/merge", reqRepoAdmin, repo.MergePullRequest) m.Post("/merge", reqRepoWriter, repo.MergePullRequest)
}, repo.MustAllowPulls) }, repo.MustAllowPulls)
m.Group("", func() { m.Group("", func() {

View File

@ -476,7 +476,7 @@ issues.closed_at = `closed <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.reopened_at = `reopened <a id="%[1]s" href="#%[1]s">%[2]s</a>` issues.reopened_at = `reopened <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.commit_ref_at = `referenced this issue from a commit <a id="%[1]s" href="#%[1]s">%[2]s</a>` issues.commit_ref_at = `referenced this issue from a commit <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.poster = Poster issues.poster = Poster
issues.admin = Admin issues.collaborator = Collaborator
issues.owner = Owner issues.owner = Owner
issues.sign_up_for_free = Sign up for free issues.sign_up_for_free = Sign up for free
issues.sign_in_require_desc = to join this conversation. Already have an account? <a href="%s">Sign in to comment</a> issues.sign_in_require_desc = to join this conversation. Already have an account? <a href="%s">Sign in to comment</a>

View File

@ -17,7 +17,7 @@ import (
"github.com/gogits/gogs/modules/setting" "github.com/gogits/gogs/modules/setting"
) )
const APP_VER = "0.8.58.0305" const APP_VER = "0.8.59.0305"
func init() { func init() {
runtime.GOMAXPROCS(runtime.NumCPU()) runtime.GOMAXPROCS(runtime.NumCPU())

View File

@ -298,16 +298,18 @@ func newIssue(e *xorm.Session, repo *Repository, issue *Issue, labelIDs []int64,
return err return err
} }
// During the session, SQLite3 dirver cannot handle retrieve objects after update something. if len(labelIDs) > 0 {
// So we have to get all needed labels first. // During the session, SQLite3 dirver cannot handle retrieve objects after update something.
labels := make([]*Label, 0, len(labelIDs)) // So we have to get all needed labels first.
if err = e.In("id", labelIDs).Find(&labels); err != nil { labels := make([]*Label, 0, len(labelIDs))
return fmt.Errorf("find all labels: %v", err) if err = e.In("id", labelIDs).Find(&labels); err != nil {
} return fmt.Errorf("find all labels: %v", err)
}
for _, label := range labels { for _, label := range labels {
if err = issue.addLabel(e, label); err != nil { if err = issue.addLabel(e, label); err != nil {
return fmt.Errorf("addLabel: %v", err) return fmt.Errorf("addLabel: %v", err)
}
} }
} }

View File

@ -39,7 +39,7 @@ type CommentTag int
const ( const (
COMMENT_TAG_NONE CommentTag = iota COMMENT_TAG_NONE CommentTag = iota
COMMENT_TAG_POSTER COMMENT_TAG_POSTER
COMMENT_TAG_ADMIN COMMENT_TAG_WRITER
COMMENT_TAG_OWNER COMMENT_TAG_OWNER
) )

View File

@ -348,19 +348,15 @@ func (u *User) UploadAvatar(data []byte) error {
// IsAdminOfRepo returns true if user has admin or higher access of repository. // IsAdminOfRepo returns true if user has admin or higher access of repository.
func (u *User) IsAdminOfRepo(repo *Repository) bool { func (u *User) IsAdminOfRepo(repo *Repository) bool {
if repo.MustOwner().IsOrganization() { has, err := HasAccess(u, repo, ACCESS_MODE_ADMIN)
has, err := HasAccess(u, repo, ACCESS_MODE_ADMIN) if err != nil {
if err != nil { log.Error(3, "HasAccess: %v", err)
log.Error(3, "HasAccess: %v", err)
}
return has
} }
return has
return repo.IsOwnedBy(u.Id)
} }
// CanWriteTo returns true if user has write access to given repository. // IsWriterOfRepo returns true if user has write access to given repository.
func (u *User) CanWriteTo(repo *Repository) bool { func (u *User) IsWriterOfRepo(repo *Repository) bool {
has, err := HasAccess(u, repo, ACCESS_MODE_WRITE) has, err := HasAccess(u, repo, ACCESS_MODE_WRITE)
if err != nil { if err != nil {
log.Error(3, "HasAccess: %v", err) log.Error(3, "HasAccess: %v", err)

File diff suppressed because one or more lines are too long

View File

@ -84,12 +84,12 @@ func (r *RepoContext) IsAdmin() bool {
return r.AccessMode >= models.ACCESS_MODE_ADMIN return r.AccessMode >= models.ACCESS_MODE_ADMIN
} }
// IsPusher returns true if current user has write or higher access of repository. // IsWriter returns true if current user has write or higher access of repository.
func (r *RepoContext) IsPusher() bool { func (r *RepoContext) IsWriter() bool {
return r.AccessMode >= models.ACCESS_MODE_WRITE return r.AccessMode >= models.ACCESS_MODE_WRITE
} }
// Return if the current user has read access for this repository // HasAccess returns true if the current user has at least read access for this repository
func (r *RepoContext) HasAccess() bool { func (r *RepoContext) HasAccess() bool {
return r.AccessMode >= models.ACCESS_MODE_READ return r.AccessMode >= models.ACCESS_MODE_READ
} }

View File

@ -140,7 +140,7 @@ func RepoAssignment(args ...bool) macaron.Handler {
ctx.Data["Owner"] = ctx.Repo.Repository.Owner ctx.Data["Owner"] = ctx.Repo.Repository.Owner
ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner() ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner()
ctx.Data["IsRepositoryAdmin"] = ctx.Repo.IsAdmin() ctx.Data["IsRepositoryAdmin"] = ctx.Repo.IsAdmin()
ctx.Data["IsRepositoryPusher"] = ctx.Repo.IsPusher() ctx.Data["IsRepositoryWriter"] = ctx.Repo.IsWriter()
if repo.IsFork { if repo.IsFork {
RetrieveBaseRepo(ctx, repo) RetrieveBaseRepo(ctx, repo)
@ -150,7 +150,7 @@ func RepoAssignment(args ...bool) macaron.Handler {
} }
// People who have push access and propose a new pull request. // People who have push access and propose a new pull request.
if ctx.Repo.IsPusher() { if ctx.Repo.IsWriter() {
// Pull request is allowed if this is a fork repository // Pull request is allowed if this is a fork repository
// and base repository accepts pull requests. // and base repository accepts pull requests.
if repo.BaseRepo != nil { if repo.BaseRepo != nil {
@ -336,16 +336,16 @@ func RepoRef() macaron.Handler {
func RequireRepoAdmin() macaron.Handler { func RequireRepoAdmin() macaron.Handler {
return func(ctx *Context) { return func(ctx *Context) {
if !ctx.Repo.IsAdmin() { if !ctx.IsSigned || (!ctx.Repo.IsAdmin() && !ctx.User.IsAdmin) {
ctx.Handle(404, ctx.Req.RequestURI, nil) ctx.Handle(404, ctx.Req.RequestURI, nil)
return return
} }
} }
} }
func RequireRepoPusher() macaron.Handler { func RequireRepoWriter() macaron.Handler {
return func(ctx *Context) { return func(ctx *Context) {
if !ctx.Repo.IsPusher() { if !ctx.IsSigned || (!ctx.Repo.IsWriter() && !ctx.User.IsAdmin) {
ctx.Handle(404, ctx.Req.RequestURI, nil) ctx.Handle(404, ctx.Req.RequestURI, nil)
return return
} }

View File

@ -273,7 +273,7 @@ func RetrieveRepoMilestonesAndAssignees(ctx *middleware.Context, repo *models.Re
} }
func RetrieveRepoMetas(ctx *middleware.Context, repo *models.Repository) []*models.Label { func RetrieveRepoMetas(ctx *middleware.Context, repo *models.Repository) []*models.Label {
if !ctx.Repo.IsAdmin() { if !ctx.Repo.IsWriter() {
return nil return nil
} }
@ -356,7 +356,7 @@ func ValidateRepoMetas(ctx *middleware.Context, form auth.CreateIssueForm) ([]in
return nil, 0, 0 return nil, 0, 0
} }
if !ctx.Repo.IsAdmin() { if !ctx.Repo.IsWriter() {
return nil, 0, 0 return nil, 0, 0
} }
@ -624,7 +624,7 @@ func ViewIssue(ctx *middleware.Context) {
ctx.Data["Labels"] = labels ctx.Data["Labels"] = labels
// Check milestone and assignee. // Check milestone and assignee.
if ctx.Repo.IsAdmin() { if ctx.Repo.IsWriter() {
RetrieveRepoMilestonesAndAssignees(ctx, repo) RetrieveRepoMilestonesAndAssignees(ctx, repo)
if ctx.Written() { if ctx.Written() {
return return
@ -664,8 +664,8 @@ func ViewIssue(ctx *middleware.Context) {
if repo.IsOwnedBy(comment.PosterID) || if repo.IsOwnedBy(comment.PosterID) ||
(repo.Owner.IsOrganization() && repo.Owner.IsOwnedBy(comment.PosterID)) { (repo.Owner.IsOrganization() && repo.Owner.IsOwnedBy(comment.PosterID)) {
comment.ShowTag = models.COMMENT_TAG_OWNER comment.ShowTag = models.COMMENT_TAG_OWNER
} else if comment.Poster.IsAdminOfRepo(repo) { } else if comment.Poster.IsWriterOfRepo(repo) {
comment.ShowTag = models.COMMENT_TAG_ADMIN comment.ShowTag = models.COMMENT_TAG_WRITER
} else if comment.PosterID == issue.PosterID { } else if comment.PosterID == issue.PosterID {
comment.ShowTag = models.COMMENT_TAG_POSTER comment.ShowTag = models.COMMENT_TAG_POSTER
} }
@ -688,7 +688,7 @@ func ViewIssue(ctx *middleware.Context) {
ctx.Data["Participants"] = participants ctx.Data["Participants"] = participants
ctx.Data["NumParticipants"] = len(participants) ctx.Data["NumParticipants"] = len(participants)
ctx.Data["Issue"] = issue ctx.Data["Issue"] = issue
ctx.Data["IsIssueOwner"] = ctx.Repo.IsAdmin() || (ctx.IsSigned && issue.IsPoster(ctx.User.Id)) ctx.Data["IsIssueOwner"] = ctx.Repo.IsWriter() || (ctx.IsSigned && (issue.IsPoster(ctx.User.Id) || ctx.User.IsAdmin))
ctx.Data["SignInLink"] = setting.AppSubUrl + "/user/login" ctx.Data["SignInLink"] = setting.AppSubUrl + "/user/login"
ctx.Data["RequireHighlightJS"] = true ctx.Data["RequireHighlightJS"] = true
@ -715,7 +715,7 @@ func UpdateIssueTitle(ctx *middleware.Context) {
return return
} }
if !ctx.IsSigned || (ctx.User.Id != issue.PosterID && !ctx.Repo.IsAdmin()) { if !ctx.IsSigned || (ctx.User.Id != issue.PosterID && !ctx.Repo.IsWriter() && !ctx.User.IsAdmin) {
ctx.Error(403) ctx.Error(403)
return return
} }
@ -742,7 +742,7 @@ func UpdateIssueContent(ctx *middleware.Context) {
return return
} }
if !ctx.IsSigned || (ctx.User.Id != issue.PosterID && !ctx.Repo.IsAdmin()) { if !ctx.IsSigned || (ctx.User.Id != issue.PosterID && !ctx.Repo.IsWriter() && !ctx.User.IsAdmin) {
ctx.Error(403) ctx.Error(403)
return return
} }
@ -883,7 +883,7 @@ func NewComment(ctx *middleware.Context, form auth.CreateCommentForm) {
var comment *models.Comment var comment *models.Comment
defer func() { defer func() {
// Check if issue admin/poster changes the status of issue. // Check if issue admin/poster changes the status of issue.
if (ctx.Repo.IsAdmin() || (ctx.IsSigned && issue.IsPoster(ctx.User.Id))) && if (ctx.Repo.IsWriter() || (ctx.IsSigned && issue.IsPoster(ctx.User.Id))) &&
(form.Status == "reopen" || form.Status == "close") && (form.Status == "reopen" || form.Status == "close") &&
!(issue.IsPull && issue.HasMerged) { !(issue.IsPull && issue.HasMerged) {

View File

@ -490,7 +490,7 @@ func ParseCompareInfo(ctx *middleware.Context) (*models.User, *models.Repository
} }
} }
if !ctx.User.CanWriteTo(headRepo) && !ctx.User.IsAdmin { if !ctx.User.IsWriterOfRepo(headRepo) && !ctx.User.IsAdmin {
log.Trace("ParseCompareInfo[%d]: does not have write access or site admin", baseRepo.ID) log.Trace("ParseCompareInfo[%d]: does not have write access or site admin", baseRepo.ID)
ctx.Handle(404, "ParseCompareInfo", nil) ctx.Handle(404, "ParseCompareInfo", nil)
return nil, nil, nil, nil, "", "" return nil, nil, nil, nil, "", ""

View File

@ -142,6 +142,10 @@ func SettingsPost(ctx *middleware.Context, form auth.RepoSettingForm) {
ctx.Redirect(ctx.Repo.RepoLink + "/settings") ctx.Redirect(ctx.Repo.RepoLink + "/settings")
case "convert": case "convert":
if !ctx.Repo.IsOwner() {
ctx.Error(404)
return
}
if repo.Name != form.RepoName { if repo.Name != form.RepoName {
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), SETTINGS_OPTIONS, nil) ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), SETTINGS_OPTIONS, nil)
return return
@ -172,6 +176,10 @@ func SettingsPost(ctx *middleware.Context, form auth.RepoSettingForm) {
ctx.Redirect(setting.AppSubUrl + "/" + ctx.Repo.Owner.Name + "/" + repo.Name) ctx.Redirect(setting.AppSubUrl + "/" + ctx.Repo.Owner.Name + "/" + repo.Name)
case "transfer": case "transfer":
if !ctx.Repo.IsOwner() {
ctx.Error(404)
return
}
if repo.Name != form.RepoName { if repo.Name != form.RepoName {
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), SETTINGS_OPTIONS, nil) ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), SETTINGS_OPTIONS, nil)
return return
@ -205,7 +213,12 @@ func SettingsPost(ctx *middleware.Context, form auth.RepoSettingForm) {
log.Trace("Repository transfered: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newOwner) log.Trace("Repository transfered: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newOwner)
ctx.Flash.Success(ctx.Tr("repo.settings.transfer_succeed")) ctx.Flash.Success(ctx.Tr("repo.settings.transfer_succeed"))
ctx.Redirect(setting.AppSubUrl + "/" + newOwner + "/" + repo.Name) ctx.Redirect(setting.AppSubUrl + "/" + newOwner + "/" + repo.Name)
case "delete": case "delete":
if !ctx.Repo.IsOwner() {
ctx.Error(404)
return
}
if repo.Name != form.RepoName { if repo.Name != form.RepoName {
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), SETTINGS_OPTIONS, nil) ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), SETTINGS_OPTIONS, nil)
return return
@ -226,7 +239,12 @@ func SettingsPost(ctx *middleware.Context, form auth.RepoSettingForm) {
ctx.Flash.Success(ctx.Tr("repo.settings.deletion_success")) ctx.Flash.Success(ctx.Tr("repo.settings.deletion_success"))
ctx.Redirect(ctx.Repo.Owner.DashboardLink()) ctx.Redirect(ctx.Repo.Owner.DashboardLink())
case "delete-wiki": case "delete-wiki":
if !ctx.Repo.IsOwner() {
ctx.Error(404)
return
}
if repo.Name != form.RepoName { if repo.Name != form.RepoName {
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), SETTINGS_OPTIONS, nil) ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_repo_name"), SETTINGS_OPTIONS, nil)
return return

View File

@ -1 +1 @@
0.8.58.0305 0.8.59.0305

View File

@ -4,7 +4,7 @@
<div class="ui container"> <div class="ui container">
<div class="navbar"> <div class="navbar">
{{template "repo/issue/navbar" .}} {{template "repo/issue/navbar" .}}
{{if .IsRepositoryAdmin}} {{if .IsRepositoryWriter}}
<div class="ui right"> <div class="ui right">
<div class="ui green new-label button">{{.i18n.Tr "repo.issues.new_label"}}</div> <div class="ui green new-label button">{{.i18n.Tr "repo.issues.new_label"}}</div>
</div> </div>
@ -40,7 +40,7 @@
{{range .Labels}} {{range .Labels}}
<li class="item"> <li class="item">
<div class="ui label" style="color: {{.ForegroundColor}}; background-color: {{.Color}}"><i class="octicon octicon-tag"></i> {{.Name}}</div> <div class="ui label" style="color: {{.ForegroundColor}}; background-color: {{.Color}}"><i class="octicon octicon-tag"></i> {{.Name}}</div>
{{if $.IsRepositoryAdmin}} {{if $.IsRepositoryWriter}}
<a class="ui right delete-button" href="#" data-url="{{$.RepoLink}}/labels/delete" data-id="{{.ID}}"><i class="octicon octicon-trashcan"></i> {{$.i18n.Tr "repo.issues.label_delete"}}</a> <a class="ui right delete-button" href="#" data-url="{{$.RepoLink}}/labels/delete" data-id="{{.ID}}"><i class="octicon octicon-trashcan"></i> {{$.i18n.Tr "repo.issues.label_delete"}}</a>
<a class="ui right edit-label-button" href="#" data-id={{.ID}} data-title={{.Name}} data-color={{.Color}}><i class="octicon octicon-pencil"></i> {{$.i18n.Tr "repo.issues.label_edit"}}</a> <a class="ui right edit-label-button" href="#" data-id={{.ID}} data-title={{.Name}} data-color={{.Color}}><i class="octicon octicon-pencil"></i> {{$.i18n.Tr "repo.issues.label_edit"}}</a>
{{end}} {{end}}
@ -51,7 +51,7 @@
</div> </div>
</div> </div>
{{if .IsRepositoryAdmin}} {{if .IsRepositoryWriter}}
<div class="ui small basic delete modal"> <div class="ui small basic delete modal">
<div class="ui icon header"> <div class="ui icon header">
<i class="trash icon"></i> <i class="trash icon"></i>

View File

@ -4,7 +4,7 @@
<div class="ui container"> <div class="ui container">
<div class="navbar"> <div class="navbar">
{{template "repo/issue/navbar" .}} {{template "repo/issue/navbar" .}}
{{if and .IsRepositoryAdmin .PageIsEditMilestone}} {{if and .IsRepositoryWriter .PageIsEditMilestone}}
<div class="ui right floated secondary menu"> <div class="ui right floated secondary menu">
<a class="ui green button" href="{{$.RepoLink}}/milestones/new">{{.i18n.Tr "repo.milestones.new"}}</a> <a class="ui green button" href="{{$.RepoLink}}/milestones/new">{{.i18n.Tr "repo.milestones.new"}}</a>
</div> </div>

View File

@ -4,7 +4,7 @@
<div class="ui container"> <div class="ui container">
<div class="navbar"> <div class="navbar">
{{template "repo/issue/navbar" .}} {{template "repo/issue/navbar" .}}
{{if .IsRepositoryAdmin}} {{if .IsRepositoryWriter}}
<div class="ui right"> <div class="ui right">
<a class="ui green button" href="{{$.Link}}/new">{{.i18n.Tr "repo.milestones.new"}}</a> <a class="ui green button" href="{{$.Link}}/new">{{.i18n.Tr "repo.milestones.new"}}</a>
</div> </div>
@ -49,7 +49,7 @@
<i class="octicon octicon-issue-closed"></i> {{$.i18n.Tr "repo.issues.close_tab" .NumClosedIssues}} <i class="octicon octicon-issue-closed"></i> {{$.i18n.Tr "repo.issues.close_tab" .NumClosedIssues}}
</span> </span>
</div> </div>
{{if $.IsRepositoryAdmin}} {{if $.IsRepositoryWriter}}
<div class="ui right operate"> <div class="ui right operate">
<a href="{{$.Link}}/{{.ID}}/edit" data-id={{.ID}} data-title={{.Name}}><i class="octicon octicon-pencil"></i> {{$.i18n.Tr "repo.issues.label_edit"}}</a> <a href="{{$.Link}}/{{.ID}}/edit" data-id={{.ID}} data-title={{.Name}}><i class="octicon octicon-pencil"></i> {{$.i18n.Tr "repo.issues.label_edit"}}</a>
{{if .IsClosed}} {{if .IsClosed}}
@ -93,7 +93,7 @@
</div> </div>
</div> </div>
{{if .IsRepositoryAdmin}} {{if .IsRepositoryWriter}}
<div class="ui small basic delete modal"> <div class="ui small basic delete modal">
<div class="ui icon header"> <div class="ui icon header">
<i class="trash icon"></i> <i class="trash icon"></i>

View File

@ -65,7 +65,7 @@
{{if eq .ShowTag 1}} {{if eq .ShowTag 1}}
{{$.i18n.Tr "repo.issues.poster"}} {{$.i18n.Tr "repo.issues.poster"}}
{{else if eq .ShowTag 2}} {{else if eq .ShowTag 2}}
{{$.i18n.Tr "repo.issues.admin"}} {{$.i18n.Tr "repo.issues.collaborator"}}
{{else if eq .ShowTag 3}} {{else if eq .ShowTag 3}}
{{$.i18n.Tr "repo.issues.owner"}} {{$.i18n.Tr "repo.issues.owner"}}
{{end}} {{end}}
@ -165,7 +165,7 @@
<span class="octicon octicon-check"></span> <span class="octicon octicon-check"></span>
{{$.i18n.Tr "repo.pulls.can_auto_merge_desc"}} {{$.i18n.Tr "repo.pulls.can_auto_merge_desc"}}
</div> </div>
{{if .IsRepositoryAdmin}} {{if .IsRepositoryWriter}}
<div class="ui divider"></div> <div class="ui divider"></div>
<div> <div>
<form class="ui form" action="{{.Link}}/merge" method="post"> <form class="ui form" action="{{.Link}}/merge" method="post">
@ -231,7 +231,7 @@
<div class="four wide column"> <div class="four wide column">
<div class="ui segment metas"> <div class="ui segment metas">
<div class="ui {{if not .IsRepositoryAdmin}}disabled{{end}} floating jump select-label dropdown"> <div class="ui {{if not .IsRepositoryWriter}}disabled{{end}} floating jump select-label dropdown">
<span class="text"> <span class="text">
<strong>{{.i18n.Tr "repo.issues.new.labels"}}</strong> <strong>{{.i18n.Tr "repo.issues.new.labels"}}</strong>
<span class="octicon octicon-gear"></span> <span class="octicon octicon-gear"></span>
@ -252,7 +252,7 @@
<div class="ui divider"></div> <div class="ui divider"></div>
<div class="ui {{if not .IsRepositoryAdmin}}disabled{{end}} floating jump select-milestone dropdown"> <div class="ui {{if not .IsRepositoryWriter}}disabled{{end}} floating jump select-milestone dropdown">
<span class="text"> <span class="text">
<strong>{{.i18n.Tr "repo.issues.new.milestone"}}</strong> <strong>{{.i18n.Tr "repo.issues.new.milestone"}}</strong>
<span class="octicon octicon-gear"></span> <span class="octicon octicon-gear"></span>
@ -293,7 +293,7 @@
<div class="ui divider"></div> <div class="ui divider"></div>
<input id="assignee_id" name="assignee_id" type="hidden" value="{{.assignee_id}}"> <input id="assignee_id" name="assignee_id" type="hidden" value="{{.assignee_id}}">
<div class="ui {{if not .IsRepositoryAdmin}}disabled{{end}} floating jump select-assignee dropdown"> <div class="ui {{if not .IsRepositoryWriter}}disabled{{end}} floating jump select-assignee dropdown">
<span class="text"> <span class="text">
<strong>{{.i18n.Tr "repo.issues.new.assignee"}}</strong> <strong>{{.i18n.Tr "repo.issues.new.assignee"}}</strong>
<span class="octicon octicon-gear"></span> <span class="octicon octicon-gear"></span>

View File

@ -5,7 +5,7 @@
{{template "base/alert" .}} {{template "base/alert" .}}
<h2 class="ui header"> <h2 class="ui header">
{{.i18n.Tr "repo.release.releases"}} {{.i18n.Tr "repo.release.releases"}}
{{if .IsRepositoryAdmin}} {{if .IsRepositoryWriter}}
<div class="ui right"> <div class="ui right">
<a class="ui small green button" href="{{$.RepoLink}}/releases/new"> <a class="ui small green button" href="{{$.RepoLink}}/releases/new">
{{.i18n.Tr "repo.release.new_release"}} {{.i18n.Tr "repo.release.new_release"}}
@ -37,7 +37,7 @@
{{if .PublisherID}} {{if .PublisherID}}
<h3> <h3>
<a href="{{$.RepoLink}}/src/{{.TagName}}">{{.Title}}</a> <a href="{{$.RepoLink}}/src/{{.TagName}}">{{.Title}}</a>
{{if $.IsRepositoryAdmin}}<small>(<a href="{{$.RepoLink}}/releases/edit/{{.TagName}}" rel="nofollow">{{$.i18n.Tr "repo.release.edit"}}</a>)</small>{{end}} {{if $.IsRepositoryWriter}}<small>(<a href="{{$.RepoLink}}/releases/edit/{{.TagName}}" rel="nofollow">{{$.i18n.Tr "repo.release.edit"}}</a>)</small>{{end}}
</h3> </h3>
<p class="text grey"> <p class="text grey">
<span class="author"> <span class="author">

View File

@ -136,6 +136,7 @@
</form> </form>
</div> </div>
{{if .IsRepositoryOwner}}
<h4 class="ui top attached warning header"> <h4 class="ui top attached warning header">
{{.i18n.Tr "repo.settings.danger_zone"}} {{.i18n.Tr "repo.settings.danger_zone"}}
</h4> </h4>
@ -189,145 +190,148 @@
</div> </div>
</div> </div>
</div> </div>
{{end}}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{{if .Repository.IsMirror}} {{if .IsRepositoryOwner}}
<div class="ui small modal" id="convert-repo-modal"> {{if .Repository.IsMirror}}
<div class="header"> <div class="ui small modal" id="convert-repo-modal">
{{.i18n.Tr "repo.settings.convert"}} <div class="header">
</div> {{.i18n.Tr "repo.settings.convert"}}
<div class="content">
<div class="ui warning message text left">
{{.i18n.Tr "repo.settings.convert_notices_1" | Safe}}
</div> </div>
<form class="ui form" action="{{.Link}}" method="post"> <div class="content">
{{.CsrfTokenHtml}} <div class="ui warning message text left">
<input type="hidden" name="action" value="convert"> {{.i18n.Tr "repo.settings.convert_notices_1" | Safe}}
<div class="field">
<label>
{{.i18n.Tr "repo.settings.transfer_form_title"}}
<span class="text red">{{.Repository.Name}}</span>
</label>
</div>
<div class="required field">
<label for="repo_name">{{.i18n.Tr "repo.repo_name"}}</label>
<input id="repo_name" name="repo_name" required>
</div> </div>
<form class="ui form" action="{{.Link}}" method="post">
{{.CsrfTokenHtml}}
<input type="hidden" name="action" value="convert">
<div class="field">
<label>
{{.i18n.Tr "repo.settings.transfer_form_title"}}
<span class="text red">{{.Repository.Name}}</span>
</label>
</div>
<div class="required field">
<label for="repo_name">{{.i18n.Tr "repo.repo_name"}}</label>
<input id="repo_name" name="repo_name" required>
</div>
<div class="text right actions"> <div class="text right actions">
<div class="ui cancel button">{{.i18n.Tr "settings.cancel"}}</div> <div class="ui cancel button">{{.i18n.Tr "settings.cancel"}}</div>
<button class="ui red button">{{.i18n.Tr "repo.settings.convert_confirm"}}</button> <button class="ui red button">{{.i18n.Tr "repo.settings.convert_confirm"}}</button>
</div> </div>
</form> </form>
</div>
</div>
{{end}}
<div class="ui small modal" id="transfer-repo-modal">
<div class="header">
{{.i18n.Tr "repo.settings.transfer"}}
</div>
<div class="content">
<div class="ui warning message text left">
{{.i18n.Tr "repo.settings.transfer_notices_1" | Safe}} <br>
{{.i18n.Tr "repo.settings.transfer_notices_2" | Safe}}
</div> </div>
<form class="ui form" action="{{.Link}}" method="post">
{{.CsrfTokenHtml}}
<input type="hidden" name="action" value="transfer">
<div class="field">
<label>
{{.i18n.Tr "repo.settings.transfer_form_title"}}
<span class="text red">{{.Repository.Name}}</span>
</label>
</div>
<div class="required field">
<label for="repo_name">{{.i18n.Tr "repo.repo_name"}}</label>
<input id="repo_name" name="repo_name" required>
</div>
<div class="required field">
<label for="new_owner_name">{{.i18n.Tr "repo.settings.transfer_owner"}}</label>
<input id="new_owner_name" name="new_owner_name" required>
</div>
<div class="text right actions">
<div class="ui cancel button">{{.i18n.Tr "settings.cancel"}}</div>
<button class="ui red button">{{.i18n.Tr "repo.settings.make_transfer"}}</button>
</div>
</form>
</div> </div>
</div> {{end}}
<div class="ui small modal" id="delete-repo-modal"> <div class="ui small modal" id="transfer-repo-modal">
<div class="header"> <div class="header">
{{.i18n.Tr "repo.settings.delete"}} {{.i18n.Tr "repo.settings.transfer"}}
</div>
<div class="content">
<div class="ui warning message text left">
{{.i18n.Tr "repo.settings.delete_notices_1" | Safe}} <br>
{{.i18n.Tr "repo.settings.delete_notices_2" | Safe}}
{{if .Repository.NumForks}}<br>
{{.i18n.Tr "repo.settings.delete_notices_fork_1" | Safe}} <br>
{{.i18n.Tr "repo.settings.delete_notices_fork_2" | Safe}} <br>
{{.i18n.Tr "repo.settings.delete_notices_fork_3" | Safe}}
{{end}}
</div> </div>
<form class="ui form" action="{{.Link}}" method="post"> <div class="content">
{{.CsrfTokenHtml}} <div class="ui warning message text left">
<input type="hidden" name="action" value="delete"> {{.i18n.Tr "repo.settings.transfer_notices_1" | Safe}} <br>
<div class="field"> {{.i18n.Tr "repo.settings.transfer_notices_2" | Safe}}
<label>
{{.i18n.Tr "repo.settings.transfer_form_title"}}
<span class="text red">{{.Repository.Name}}</span>
</label>
</div>
<div class="required field">
<label for="repo_name">{{.i18n.Tr "repo.repo_name"}}</label>
<input id="repo_name" name="repo_name" required>
</div> </div>
<form class="ui form" action="{{.Link}}" method="post">
{{.CsrfTokenHtml}}
<input type="hidden" name="action" value="transfer">
<div class="field">
<label>
{{.i18n.Tr "repo.settings.transfer_form_title"}}
<span class="text red">{{.Repository.Name}}</span>
</label>
</div>
<div class="required field">
<label for="repo_name">{{.i18n.Tr "repo.repo_name"}}</label>
<input id="repo_name" name="repo_name" required>
</div>
<div class="required field">
<label for="new_owner_name">{{.i18n.Tr "repo.settings.transfer_owner"}}</label>
<input id="new_owner_name" name="new_owner_name" required>
</div>
<div class="text right actions"> <div class="text right actions">
<div class="ui cancel button">{{.i18n.Tr "settings.cancel"}}</div> <div class="ui cancel button">{{.i18n.Tr "settings.cancel"}}</div>
<button class="ui red button">{{.i18n.Tr "repo.settings.confirm_delete"}}</button> <button class="ui red button">{{.i18n.Tr "repo.settings.make_transfer"}}</button>
</div> </div>
</form> </form>
</div>
</div>
{{if .Repository.EnableWiki}}
<div class="ui small modal" id="delete-wiki-modal">
<div class="header">
{{.i18n.Tr "repo.settings.wiki-delete"}}
</div>
<div class="content">
<div class="ui warning message text left">
{{.i18n.Tr "repo.settings.delete_notices_1" | Safe}}<br>
{{.i18n.Tr "repo.settings.wiki_delete_notices_1" .Repository.Name | Safe}}
</div> </div>
<form class="ui form" action="{{.Link}}" method="post">
{{.CsrfTokenHtml}}
<input type="hidden" name="action" value="delete-wiki">
<div class="field">
<label>
{{.i18n.Tr "repo.settings.transfer_form_title"}}
<span class="text red">{{.Repository.Name}}</span>
</label>
</div>
<div class="required field">
<label for="repo_name">{{.i18n.Tr "repo.repo_name"}}</label>
<input id="repo_name" name="repo_name" required>
</div>
<div class="text right actions">
<div class="ui cancel button">{{.i18n.Tr "settings.cancel"}}</div>
<button class="ui red button">{{.i18n.Tr "repo.settings.confirm_delete"}}</button>
</div>
</form>
</div> </div>
</div>
<div class="ui small modal" id="delete-repo-modal">
<div class="header">
{{.i18n.Tr "repo.settings.delete"}}
</div>
<div class="content">
<div class="ui warning message text left">
{{.i18n.Tr "repo.settings.delete_notices_1" | Safe}} <br>
{{.i18n.Tr "repo.settings.delete_notices_2" | Safe}}
{{if .Repository.NumForks}}<br>
{{.i18n.Tr "repo.settings.delete_notices_fork_1" | Safe}} <br>
{{.i18n.Tr "repo.settings.delete_notices_fork_2" | Safe}} <br>
{{.i18n.Tr "repo.settings.delete_notices_fork_3" | Safe}}
{{end}}
</div>
<form class="ui form" action="{{.Link}}" method="post">
{{.CsrfTokenHtml}}
<input type="hidden" name="action" value="delete">
<div class="field">
<label>
{{.i18n.Tr "repo.settings.transfer_form_title"}}
<span class="text red">{{.Repository.Name}}</span>
</label>
</div>
<div class="required field">
<label for="repo_name">{{.i18n.Tr "repo.repo_name"}}</label>
<input id="repo_name" name="repo_name" required>
</div>
<div class="text right actions">
<div class="ui cancel button">{{.i18n.Tr "settings.cancel"}}</div>
<button class="ui red button">{{.i18n.Tr "repo.settings.confirm_delete"}}</button>
</div>
</form>
</div>
</div>
{{if .Repository.EnableWiki}}
<div class="ui small modal" id="delete-wiki-modal">
<div class="header">
{{.i18n.Tr "repo.settings.wiki-delete"}}
</div>
<div class="content">
<div class="ui warning message text left">
{{.i18n.Tr "repo.settings.delete_notices_1" | Safe}}<br>
{{.i18n.Tr "repo.settings.wiki_delete_notices_1" .Repository.Name | Safe}}
</div>
<form class="ui form" action="{{.Link}}" method="post">
{{.CsrfTokenHtml}}
<input type="hidden" name="action" value="delete-wiki">
<div class="field">
<label>
{{.i18n.Tr "repo.settings.transfer_form_title"}}
<span class="text red">{{.Repository.Name}}</span>
</label>
</div>
<div class="required field">
<label for="repo_name">{{.i18n.Tr "repo.repo_name"}}</label>
<input id="repo_name" name="repo_name" required>
</div>
<div class="text right actions">
<div class="ui cancel button">{{.i18n.Tr "settings.cancel"}}</div>
<button class="ui red button">{{.i18n.Tr "repo.settings.confirm_delete"}}</button>
</div>
</form>
</div>
</div>
{{end}}
{{end}} {{end}}
{{template "base/footer" .}} {{template "base/footer" .}}

View File

@ -6,7 +6,7 @@
<span class="mega-octicon octicon-book"></span> <span class="mega-octicon octicon-book"></span>
<h2>{{.i18n.Tr "repo.wiki.welcome"}}</h2> <h2>{{.i18n.Tr "repo.wiki.welcome"}}</h2>
<p>{{.i18n.Tr "repo.wiki.welcome_desc"}}</p> <p>{{.i18n.Tr "repo.wiki.welcome_desc"}}</p>
{{if .IsRepositoryPusher}} {{if .IsRepositoryWriter}}
<a class="ui green button" href="{{.RepoLink}}/wiki/_new">{{.i18n.Tr "repo.wiki.create_first_page"}}</a> <a class="ui green button" href="{{.RepoLink}}/wiki/_new">{{.i18n.Tr "repo.wiki.create_first_page"}}</a>
{{end}} {{end}}
</div> </div>

View File

@ -46,7 +46,7 @@
</div> </div>
<div class="ui dividing header"> <div class="ui dividing header">
{{.title}} {{.title}}
{{if .IsRepositoryPusher}} {{if .IsRepositoryWriter}}
<div class="ui right"> <div class="ui right">
<a class="ui small button" href="{{.RepoLink}}/wiki/{{.PageURL}}/_edit">{{.i18n.Tr "repo.wiki.edit_page_button"}}</a> <a class="ui small button" href="{{.RepoLink}}/wiki/{{.PageURL}}/_edit">{{.i18n.Tr "repo.wiki.edit_page_button"}}</a>
<a class="ui green small button" href="{{.RepoLink}}/wiki/_new">{{.i18n.Tr "repo.wiki.new_page_button"}}</a> <a class="ui green small button" href="{{.RepoLink}}/wiki/_new">{{.i18n.Tr "repo.wiki.new_page_button"}}</a>