Skip to content

Commit d4e35b9

Browse files
wULLSnpAXbWZGYDYyhWTKKspEQoaYxXyhoisqHfzeripathtechknowlogick
authored
Hide 'New Project board' button for users that are not signed in (#12547)
* hide: 'New Project board' button * there is no reason to show the button for users that are not signed in * update template: specifies the condition together with another one as per lafriks' suggestion in the comment * chore: add proper user authorization check * chore: also hide button if repo is archived * chore: show project board edit/delete menu to authorized users only * chore: drop the redundant IsSigned check * CanWriteIssues and CanWritePulls implies (and requires) signed in user * Add CanWriteProjects and properly assert permissions Signed-off-by: Andrew Thornton <[email protected]> Co-authored-by: Andrew Thornton <[email protected]> Co-authored-by: techknowlogick <[email protected]>
1 parent a048489 commit d4e35b9

File tree

5 files changed

+112
-106
lines changed

5 files changed

+112
-106
lines changed

routers/repo/projects.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ func Projects(ctx *context.Context) {
9595
pager.AddParam(ctx, "state", "State")
9696
ctx.Data["Page"] = pager
9797

98+
ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(models.UnitTypeProjects)
9899
ctx.Data["IsShowClosed"] = isShowClosed
99100
ctx.Data["IsProjectsPage"] = true
100101
ctx.Data["SortType"] = sortType
@@ -106,16 +107,17 @@ func Projects(ctx *context.Context) {
106107
func NewProject(ctx *context.Context) {
107108
ctx.Data["Title"] = ctx.Tr("repo.projects.new")
108109
ctx.Data["ProjectTypes"] = models.GetProjectsConfig()
109-
110+
ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(models.UnitTypeProjects)
110111
ctx.HTML(200, tplProjectsNew)
111112
}
112113

113-
// NewRepoProjectPost creates a new project
114-
func NewRepoProjectPost(ctx *context.Context, form auth.CreateProjectForm) {
115-
114+
// NewProjectPost creates a new project
115+
func NewProjectPost(ctx *context.Context, form auth.CreateProjectForm) {
116116
ctx.Data["Title"] = ctx.Tr("repo.projects.new")
117117

118118
if ctx.HasError() {
119+
ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(models.UnitTypeProjects)
120+
ctx.Data["ProjectTypes"] = models.GetProjectsConfig()
119121
ctx.HTML(200, tplProjectsNew)
120122
return
121123
}
@@ -192,6 +194,7 @@ func EditProject(ctx *context.Context) {
192194
ctx.Data["Title"] = ctx.Tr("repo.projects.edit")
193195
ctx.Data["PageIsProjects"] = true
194196
ctx.Data["PageIsEditProjects"] = true
197+
ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(models.UnitTypeProjects)
195198

196199
p, err := models.GetProjectByID(ctx.ParamsInt64(":id"))
197200
if err != nil {
@@ -218,9 +221,10 @@ func EditProjectPost(ctx *context.Context, form auth.CreateProjectForm) {
218221
ctx.Data["Title"] = ctx.Tr("repo.projects.edit")
219222
ctx.Data["PageIsProjects"] = true
220223
ctx.Data["PageIsEditProjects"] = true
224+
ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(models.UnitTypeProjects)
221225

222226
if ctx.HasError() {
223-
ctx.HTML(200, tplMilestoneNew)
227+
ctx.HTML(200, tplProjectsNew)
224228
return
225229
}
226230

@@ -287,6 +291,7 @@ func ViewProject(ctx *context.Context) {
287291
return
288292
}
289293

294+
ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(models.UnitTypeProjects)
290295
ctx.Data["Project"] = project
291296
ctx.Data["Boards"] = allBoards
292297
ctx.Data["PageIsProjects"] = true
@@ -551,6 +556,7 @@ func MoveIssueAcrossBoards(ctx *context.Context) {
551556
func CreateProject(ctx *context.Context) {
552557
ctx.Data["Title"] = ctx.Tr("repo.projects.new")
553558
ctx.Data["ProjectTypes"] = models.GetProjectsConfig()
559+
ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(models.UnitTypeProjects)
554560

555561
ctx.HTML(200, tplGenericProjectsNew)
556562
}
@@ -566,6 +572,7 @@ func CreateProjectPost(ctx *context.Context, form auth.UserCreateProjectForm) {
566572
ctx.Data["ContextUser"] = user
567573

568574
if ctx.HasError() {
575+
ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(models.UnitTypeProjects)
569576
ctx.HTML(200, tplGenericProjectsNew)
570577
return
571578
}

routers/routes/routes.go

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,7 @@ func RegisterRoutes(m *macaron.Macaron) {
535535
reqRepoIssuesOrPullsWriter := context.RequireRepoWriterOr(models.UnitTypeIssues, models.UnitTypePullRequests)
536536
reqRepoIssuesOrPullsReader := context.RequireRepoReaderOr(models.UnitTypeIssues, models.UnitTypePullRequests)
537537
reqRepoProjectsReader := context.RequireRepoReader(models.UnitTypeProjects)
538+
reqRepoProjectsWriter := context.RequireRepoWriter(models.UnitTypeProjects)
538539

539540
// ***** START: Organization *****
540541
m.Group("/org", func() {
@@ -858,24 +859,26 @@ func RegisterRoutes(m *macaron.Macaron) {
858859

859860
m.Group("/projects", func() {
860861
m.Get("", repo.Projects)
861-
m.Get("/new", repo.NewProject)
862-
m.Post("/new", bindIgnErr(auth.CreateProjectForm{}), repo.NewRepoProjectPost)
863-
m.Group("/:id", func() {
864-
m.Get("", repo.ViewProject)
865-
m.Post("", bindIgnErr(auth.EditProjectBoardTitleForm{}), repo.AddBoardToProjectPost)
866-
m.Post("/delete", repo.DeleteProject)
867-
868-
m.Get("/edit", repo.EditProject)
869-
m.Post("/edit", bindIgnErr(auth.CreateProjectForm{}), repo.EditProjectPost)
870-
m.Post("/^:action(open|close)$", repo.ChangeProjectStatus)
871-
872-
m.Group("/:boardID", func() {
873-
m.Put("", bindIgnErr(auth.EditProjectBoardTitleForm{}), repo.EditProjectBoardTitle)
874-
m.Delete("", repo.DeleteProjectBoard)
875-
876-
m.Post("/:index", repo.MoveIssueAcrossBoards)
862+
m.Get("/:id", repo.ViewProject)
863+
m.Group("", func() {
864+
m.Get("/new", repo.NewProject)
865+
m.Post("/new", bindIgnErr(auth.CreateProjectForm{}), repo.NewProjectPost)
866+
m.Group("/:id", func() {
867+
m.Post("", bindIgnErr(auth.EditProjectBoardTitleForm{}), repo.AddBoardToProjectPost)
868+
m.Post("/delete", repo.DeleteProject)
869+
870+
m.Get("/edit", repo.EditProject)
871+
m.Post("/edit", bindIgnErr(auth.CreateProjectForm{}), repo.EditProjectPost)
872+
m.Post("/^:action(open|close)$", repo.ChangeProjectStatus)
873+
874+
m.Group("/:boardID", func() {
875+
m.Put("", bindIgnErr(auth.EditProjectBoardTitleForm{}), repo.EditProjectBoardTitle)
876+
m.Delete("", repo.DeleteProjectBoard)
877+
878+
m.Post("/:index", repo.MoveIssueAcrossBoards)
879+
})
877880
})
878-
})
881+
}, reqRepoProjectsWriter, context.RepoMustNotBeArchived())
879882
}, reqRepoProjectsReader, repo.MustEnableProjects)
880883

881884
m.Group("/wiki", func() {

templates/repo/projects/list.tmpl

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
<div class="ui container">
55
<div class="navbar">
66
{{template "repo/issue/navbar" .}}
7-
{{if and (or .CanWriteIssues .CanWritePulls) (not .Repository.IsArchived)}}
8-
<div class="ui right">
9-
<a class="ui green button" href="{{$.Link}}/new">{{.i18n.Tr "repo.projects.new"}}</a>
10-
</div>
7+
{{if and .CanWriteProjects (not .Repository.IsArchived)}}
8+
<div class="ui right">
9+
<a class="ui green button" href="{{$.Link}}/new">{{.i18n.Tr "repo.projects.new"}}</a>
10+
</div>
1111
{{end}}
1212
</div>
1313
<div class="ui divider"></div>
@@ -39,35 +39,35 @@
3939
</div>
4040
<div class="milestone list">
4141
{{range .Projects}}
42-
<li class="item">
43-
{{svg "octicon-project" 16}} <a href="{{$.RepoLink}}/projects/{{.ID}}">{{.Title}}</a>
44-
<div class="meta">
45-
{{ $closedDate:= TimeSinceUnix .ClosedDateUnix $.Lang }}
46-
{{if .IsClosed }}
47-
{{svg "octicon-clock" 16}} {{$.i18n.Tr "repo.milestones.closed" $closedDate|Str2html}}
42+
<li class="item">
43+
{{svg "octicon-project" 16}} <a href="{{$.RepoLink}}/projects/{{.ID}}">{{.Title}}</a>
44+
<div class="meta">
45+
{{ $closedDate:= TimeSinceUnix .ClosedDateUnix $.Lang }}
46+
{{if .IsClosed }}
47+
{{svg "octicon-clock" 16}} {{$.i18n.Tr "repo.milestones.closed" $closedDate|Str2html}}
48+
{{end}}
49+
<span class="issue-stats">
50+
{{svg "octicon-issue-opened" 16}} {{$.i18n.Tr "repo.issues.open_tab" .NumOpenIssues}}
51+
{{svg "octicon-issue-closed" 16}} {{$.i18n.Tr "repo.issues.close_tab" .NumClosedIssues}}
52+
</span>
53+
</div>
54+
{{if and (or $.CanWriteIssues $.CanWritePulls) (not $.Repository.IsArchived)}}
55+
<div class="ui right operate">
56+
<a href="{{$.Link}}/{{.ID}}/edit" data-id={{.ID}} data-title={{.Title}}>{{svg "octicon-pencil" 16}} {{$.i18n.Tr "repo.issues.label_edit"}}</a>
57+
{{if .IsClosed}}
58+
<a class="link-action" href data-url="{{$.Link}}/{{.ID}}/open">{{svg "octicon-check" 16}} {{$.i18n.Tr "repo.projects.open"}}</a>
59+
{{else}}
60+
<a class="link-action" href data-url="{{$.Link}}/{{.ID}}/close">{{svg "octicon-x" 16}} {{$.i18n.Tr "repo.projects.close"}}</a>
61+
{{end}}
62+
<a class="delete-button" href="#" data-url="{{$.RepoLink}}/projects/{{.ID}}/delete" data-id="{{.ID}}">{{svg "octicon-trashcan" 16}} {{$.i18n.Tr "repo.issues.label_delete"}}</a>
63+
</div>
4864
{{end}}
49-
<span class="issue-stats">
50-
{{svg "octicon-issue-opened" 16}} {{$.i18n.Tr "repo.issues.open_tab" .NumOpenIssues}}
51-
{{svg "octicon-issue-closed" 16}} {{$.i18n.Tr "repo.issues.close_tab" .NumClosedIssues}}
52-
</span>
53-
</div>
54-
{{if and (or $.CanWriteIssues $.CanWritePulls) (not $.Repository.IsArchived)}}
55-
<div class="ui right operate">
56-
<a href="{{$.Link}}/{{.ID}}/edit" data-id={{.ID}} data-title={{.Title}}>{{svg "octicon-pencil" 16}} {{$.i18n.Tr "repo.issues.label_edit"}}</a>
57-
{{if .IsClosed}}
58-
<a class="link-action" href data-url="{{$.Link}}/{{.ID}}/open">{{svg "octicon-check" 16}} {{$.i18n.Tr "repo.projects.open"}}</a>
59-
{{else}}
60-
<a class="link-action" href data-url="{{$.Link}}/{{.ID}}/close">{{svg "octicon-x" 16}} {{$.i18n.Tr "repo.projects.close"}}</a>
65+
{{if .Description}}
66+
<div class="content">
67+
{{.RenderedContent|Str2html}}
68+
</div>
6169
{{end}}
62-
<a class="delete-button" href="#" data-url="{{$.RepoLink}}/projects/{{.ID}}/delete" data-id="{{.ID}}">{{svg "octicon-trashcan" 16}} {{$.i18n.Tr "repo.issues.label_delete"}}</a>
63-
</div>
64-
{{end}}
65-
{{if .Description}}
66-
<div class="content">
67-
{{.RenderedContent|Str2html}}
68-
</div>
69-
{{end}}
70-
</li>
70+
</li>
7171
{{end}}
7272

7373
{{template "base/paginate" .}}

templates/repo/projects/new.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<div class="ui container">
55
<div class="navbar">
66
{{template "repo/issue/navbar" .}}
7-
{{if and (or .CanWriteIssues .CanWritePulls) .PageIsEditProject}}
7+
{{if and .CanWriteProjects .PageIsEditProject}}
88
<div class="ui right floated secondary menu">
99
<a class="ui green button" href="{{$.RepoLink}}/projects/new">{{.i18n.Tr "repo.milestones.new"}}</a>
1010
</div>

templates/repo/projects/view.tmpl

Lines changed: 48 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,9 @@
1010
{{template "repo/issue/search" .}}
1111
</div>
1212
<div class="column right aligned">
13-
{{if .PageIsProjects}}
14-
<a class="ui green button show-modal item" data-modal="#new-board-item">{{.i18n.Tr "new_project_board"}}</a>
13+
{{if and .CanWriteProjects (not .Repository.IsArchived) .PageIsProjects}}
14+
<a class="ui green button show-modal item" data-modal="#new-board-item">{{.i18n.Tr "new_project_board"}}</a>
1515
{{end}}
16-
1716
<div class="ui small modal" id="new-board-item">
1817
<div class="header">
1918
{{$.i18n.Tr "repo.projects.board.new"}}
@@ -45,65 +44,62 @@
4544
<div class="ui segment board-column">
4645
<div class="board-column-header">
4746
<div class="ui large label board-label">{{.Title}}</div>
48-
49-
{{ if $.IsSigned }}
50-
{{ if not (eq .ID 0) }}
51-
<div class="ui dropdown jump item poping up right" data-variation="tiny inverted">
52-
<span class="ui text">
53-
<img class="ui tiny avatar image" width="24" height="24">
54-
<span class="fitted not-mobile" tabindex="-1">{{svg "octicon-kebab-horizontal" 24}}</span>
55-
</span>
56-
<div class="menu user-menu" tabindex="-1">
57-
<a class="item show-modal button" data-modal="#edit-project-board-modal-{{.ID}}">
58-
{{svg "octicon-pencil" 16}}
59-
{{$.i18n.Tr "repo.projects.board.edit"}}
60-
</a>
61-
<a class="item show-modal button" data-modal="#delete-board-modal-{{.ID}}">
62-
{{svg "octicon-trashcan" 16}}
63-
{{$.i18n.Tr "repo.projects.board.delete"}}
64-
</a>
65-
66-
<div class="ui small modal edit-project-board" id="edit-project-board-modal-{{.ID}}">
67-
<div class="header">
47+
{{if and $.CanWriteProjects (not $.Repository.IsArchived) $.PageIsProjects (ne .ID 0)}}
48+
<div class="ui dropdown jump item poping up right" data-variation="tiny inverted">
49+
<span class="ui text">
50+
<img class="ui tiny avatar image" width="24" height="24">
51+
<span class="fitted not-mobile" tabindex="-1">{{svg "octicon-kebab-horizontal" 24}}</span>
52+
</span>
53+
<div class="menu user-menu" tabindex="-1">
54+
<a class="item show-modal button" data-modal="#edit-project-board-modal-{{.ID}}">
55+
{{svg "octicon-pencil" 16}}
6856
{{$.i18n.Tr "repo.projects.board.edit"}}
57+
</a>
58+
<a class="item show-modal button" data-modal="#delete-board-modal-{{.ID}}">
59+
{{svg "octicon-trashcan" 16}}
60+
{{$.i18n.Tr "repo.projects.board.delete"}}
61+
</a>
62+
63+
<div class="ui small modal edit-project-board" id="edit-project-board-modal-{{.ID}}">
64+
<div class="header">
65+
{{$.i18n.Tr "repo.projects.board.edit"}}
66+
</div>
67+
<div class="content">
68+
<form class="ui form">
69+
<div class="required field">
70+
<label for="new_board_title">{{$.i18n.Tr "repo.projects.board.edit_title"}}</label>
71+
<input class="project-board-title" id="new_board_title" name="title" value="{{.Title}}" required>
72+
</div>
73+
74+
<div class="text right actions">
75+
<div class="ui cancel button">{{$.i18n.Tr "settings.cancel"}}</div>
76+
<button data-url="{{$.RepoLink}}/projects/{{$.Project.ID}}/{{.ID}}" class="ui red button">{{$.i18n.Tr "repo.projects.board.edit"}}</button>
77+
</div>
78+
</form>
79+
</div>
6980
</div>
70-
<div class="content">
71-
<form class="ui form">
72-
<div class="required field">
73-
<label for="new_board_title">{{$.i18n.Tr "repo.projects.board.edit_title"}}</label>
74-
<input class="project-board-title" id="new_board_title" name="title" value="{{.Title}}" required>
75-
</div>
7681

82+
<div class="ui basic modal" id="delete-board-modal-{{.ID}}">
83+
<div class="ui icon header">
84+
{{$.i18n.Tr "repo.projects.board.delete"}}
85+
</div>
86+
<div class="content center">
87+
<input type="hidden" name="action" value="delete">
88+
<div class="field">
89+
<label>
90+
{{$.i18n.Tr "repo.projects.board.deletion_desc"}}
91+
</label>
92+
</div>
93+
</div>
94+
<form class="ui form" method="post">
7795
<div class="text right actions">
7896
<div class="ui cancel button">{{$.i18n.Tr "settings.cancel"}}</div>
79-
<button data-url="{{$.RepoLink}}/projects/{{$.Project.ID}}/{{.ID}}" class="ui red button">{{$.i18n.Tr "repo.projects.board.edit"}}</button>
97+
<button class="ui red button delete-project-board" data-url="{{$.RepoLink}}/projects/{{$.Project.ID}}/{{.ID}}">{{$.i18n.Tr "repo.projects.board.delete"}}</button>
8098
</div>
8199
</form>
82100
</div>
83101
</div>
84-
85-
<div class="ui basic modal" id="delete-board-modal-{{.ID}}">
86-
<div class="ui icon header">
87-
{{$.i18n.Tr "repo.projects.board.delete"}}
88-
</div>
89-
<div class="content center">
90-
<input type="hidden" name="action" value="delete">
91-
<div class="field">
92-
<label>
93-
{{$.i18n.Tr "repo.projects.board.deletion_desc"}}
94-
</label>
95-
</div>
96-
</div>
97-
<form class="ui form" method="post">
98-
<div class="text right actions">
99-
<div class="ui cancel button">{{$.i18n.Tr "settings.cancel"}}</div>
100-
<button class="ui red button delete-project-board" data-url="{{$.RepoLink}}/projects/{{$.Project.ID}}/{{.ID}}">{{$.i18n.Tr "repo.projects.board.delete"}}</button>
101-
</div>
102-
</form>
103-
</div>
104102
</div>
105-
</div>
106-
{{ end }}
107103
{{ end }}
108104
</div>
109105
<div class="ui divider"></div>

0 commit comments

Comments
 (0)