* Change action GETs to POST * submite = submit + smite * No more # href * Fix test * Match other tests * Explicit csrf Signed-off-by: jolheiser <john.olheiser@gmail.com> Co-authored-by: guillep2k <18600385+guillep2k@users.noreply.github.com>tags/v1.21.12.1
| @@ -20,7 +20,7 @@ func createNewRelease(t *testing.T, session *TestSession, repoURL, tag, title st | |||||
| resp := session.MakeRequest(t, req, http.StatusOK) | resp := session.MakeRequest(t, req, http.StatusOK) | ||||
| htmlDoc := NewHTMLParser(t, resp.Body) | htmlDoc := NewHTMLParser(t, resp.Body) | ||||
| link, exists := htmlDoc.doc.Find("form").Attr("action") | |||||
| link, exists := htmlDoc.doc.Find("form.ui.form").Attr("action") | |||||
| assert.True(t, exists, "The template has changed") | assert.True(t, exists, "The template has changed") | ||||
| postData := map[string]string{ | postData := map[string]string{ | ||||
| @@ -502,7 +502,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| }, reqSignIn) | }, reqSignIn) | ||||
| m.Group("/:username", func() { | m.Group("/:username", func() { | ||||
| m.Get("/action/:action", user.Action) | |||||
| m.Post("/action/:action", user.Action) | |||||
| }, reqSignIn) | }, reqSignIn) | ||||
| if macaron.Env == macaron.DEV { | if macaron.Env == macaron.DEV { | ||||
| @@ -534,7 +534,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| m.Get("/^:type(issues|pulls)$", user.Issues) | m.Get("/^:type(issues|pulls)$", user.Issues) | ||||
| m.Get("/milestones", reqMilestonesDashboardPageEnabled, user.Milestones) | m.Get("/milestones", reqMilestonesDashboardPageEnabled, user.Milestones) | ||||
| m.Get("/members", org.Members) | m.Get("/members", org.Members) | ||||
| m.Get("/members/action/:action", org.MembersAction) | |||||
| m.Post("/members/action/:action", org.MembersAction) | |||||
| m.Get("/teams", org.Teams) | m.Get("/teams", org.Teams) | ||||
| }, context.OrgAssignment(true)) | }, context.OrgAssignment(true)) | ||||
| @@ -542,8 +542,8 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| m.Group("/:org", func() { | m.Group("/:org", func() { | ||||
| m.Get("/teams/:team", org.TeamMembers) | m.Get("/teams/:team", org.TeamMembers) | ||||
| m.Get("/teams/:team/repositories", org.TeamRepositories) | m.Get("/teams/:team/repositories", org.TeamRepositories) | ||||
| m.Route("/teams/:team/action/:action", "GET,POST", org.TeamsAction) | |||||
| m.Route("/teams/:team/action/repo/:action", "GET,POST", org.TeamsRepoAction) | |||||
| m.Post("/teams/:team/action/:action", org.TeamsAction) | |||||
| m.Post("/teams/:team/action/repo/:action", org.TeamsRepoAction) | |||||
| }, context.OrgAssignment(true, false, true)) | }, context.OrgAssignment(true, false, true)) | ||||
| m.Group("/:org", func() { | m.Group("/:org", func() { | ||||
| @@ -681,7 +681,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| }) | }) | ||||
| }, reqSignIn, context.RepoAssignment(), context.UnitTypes(), reqRepoAdmin, context.RepoRef()) | }, reqSignIn, context.RepoAssignment(), context.UnitTypes(), reqRepoAdmin, context.RepoRef()) | ||||
| m.Get("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), context.UnitTypes(), repo.Action) | |||||
| m.Post("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), context.UnitTypes(), repo.Action) | |||||
| m.Group("/:username/:reponame", func() { | m.Group("/:username/:reponame", func() { | ||||
| m.Group("/issues", func() { | m.Group("/issues", func() { | ||||
| @@ -735,7 +735,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| Post(bindIgnErr(auth.CreateMilestoneForm{}), repo.NewMilestonePost) | Post(bindIgnErr(auth.CreateMilestoneForm{}), repo.NewMilestonePost) | ||||
| m.Get("/:id/edit", repo.EditMilestone) | m.Get("/:id/edit", repo.EditMilestone) | ||||
| 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.Post("/:id/:action", repo.ChangeMilestonStatus) | |||||
| m.Post("/delete", repo.DeleteMilestone) | m.Post("/delete", repo.DeleteMilestone) | ||||
| }, context.RepoMustNotBeArchived(), reqRepoIssuesOrPullsWriter, context.RepoRef()) | }, context.RepoMustNotBeArchived(), reqRepoIssuesOrPullsWriter, context.RepoRef()) | ||||
| m.Group("/milestone", func() { | m.Group("/milestone", func() { | ||||
| @@ -22,10 +22,10 @@ | |||||
| {{ $isPublic := index $.MembersIsPublicMember .ID}} | {{ $isPublic := index $.MembersIsPublicMember .ID}} | ||||
| {{if $isPublic}} | {{if $isPublic}} | ||||
| <strong>{{$.i18n.Tr "org.members.public"}}</strong> | <strong>{{$.i18n.Tr "org.members.public"}}</strong> | ||||
| {{if or (eq $.SignedUser.ID .ID) $.IsOrganizationOwner}}(<a href="{{$.OrgLink}}/members/action/private?uid={{.ID}}">{{$.i18n.Tr "org.members.public_helper"}}</a>){{end}} | |||||
| {{if or (eq $.SignedUser.ID .ID) $.IsOrganizationOwner}}(<a class="link-action" href data-url="{{$.OrgLink}}/members/action/private?uid={{.ID}}">{{$.i18n.Tr "org.members.public_helper"}}</a>){{end}} | |||||
| {{else}} | {{else}} | ||||
| <strong>{{$.i18n.Tr "org.members.private"}}</strong> | <strong>{{$.i18n.Tr "org.members.private"}}</strong> | ||||
| {{if or (eq $.SignedUser.ID .ID) $.IsOrganizationOwner}}(<a href="{{$.OrgLink}}/members/action/public?uid={{.ID}}">{{$.i18n.Tr "org.members.private_helper"}}</a>){{end}} | |||||
| {{if or (eq $.SignedUser.ID .ID) $.IsOrganizationOwner}}(<a class="link-action" href data-url="{{$.OrgLink}}/members/action/public?uid={{.ID}}">{{$.i18n.Tr "org.members.private_helper"}}</a>){{end}} | |||||
| {{end}} | {{end}} | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| @@ -27,7 +27,10 @@ | |||||
| {{range .Team.Members}} | {{range .Team.Members}} | ||||
| <div class="item"> | <div class="item"> | ||||
| {{if $.IsOrganizationOwner}} | {{if $.IsOrganizationOwner}} | ||||
| <a class="ui red small button right" href="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/action/remove?uid={{.ID}}">{{$.i18n.Tr "org.members.remove"}}</a> | |||||
| <form method="post" action="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/action/remove?uid={{.ID}}"> | |||||
| {{$.CsrfTokenHtml}} | |||||
| <button type="submit" class="ui red small button right" >{{$.i18n.Tr "org.members.remove"}}</button> | |||||
| </form> | |||||
| {{end}} | {{end}} | ||||
| <a href="{{.HomeLink}}"> | <a href="{{.HomeLink}}"> | ||||
| <img class="ui avatar image" src="{{.RelAvatarLink}}"> | <img class="ui avatar image" src="{{.RelAvatarLink}}"> | ||||
| @@ -35,7 +35,10 @@ | |||||
| {{range .Team.Repos}} | {{range .Team.Repos}} | ||||
| <div class="item"> | <div class="item"> | ||||
| {{if $canAddRemove}} | {{if $canAddRemove}} | ||||
| <a class="ui red small button right" href="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/action/repo/remove?repoid={{.ID}}">{{$.i18n.Tr "remove"}}</a> | |||||
| <form method="post" action="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/action/repo/remove?repoid={{.ID}}"> | |||||
| {{$.CsrfTokenHtml}} | |||||
| <button type="submit" class="ui red small button right">{{$.i18n.Tr "remove"}}</button> | |||||
| </form> | |||||
| {{end}} | {{end}} | ||||
| <a class="member" href="{{AppSubUrl}}/{{$.Org.Name}}/{{.Name}}"> | <a class="member" href="{{AppSubUrl}}/{{$.Org.Name}}/{{.Name}}"> | ||||
| {{if .IsPrivate}} | {{if .IsPrivate}} | ||||
| @@ -3,9 +3,15 @@ | |||||
| <strong>{{.Team.Name}}</strong> | <strong>{{.Team.Name}}</strong> | ||||
| <div class="ui right"> | <div class="ui right"> | ||||
| {{if .Team.IsMember $.SignedUser.ID}} | {{if .Team.IsMember $.SignedUser.ID}} | ||||
| <a class="ui red tiny button" href="{{.OrgLink}}/teams/{{.Team.LowerName}}/action/leave?uid={{$.SignedUser.ID}}&page=home">{{$.i18n.Tr "org.teams.leave"}}</a> | |||||
| <form method="post" action="{{.OrgLink}}/teams/{{.Team.LowerName}}/action/leave?uid={{$.SignedUser.ID}}&page=home"> | |||||
| {{$.CsrfTokenHtml}} | |||||
| <button type="submit" class="ui red tiny button">{{$.i18n.Tr "org.teams.leave"}}</button> | |||||
| </form> | |||||
| {{else if .IsOrganizationOwner}} | {{else if .IsOrganizationOwner}} | ||||
| <a class="ui blue tiny button" href="{{.OrgLink}}/teams/{{.Team.LowerName}}/action/join?uid={{$.SignedUser.ID}}&page=team">{{$.i18n.Tr "org.teams.join"}}</a> | |||||
| <form method="post" action="{{.OrgLink}}/teams/{{.Team.LowerName}}/action/join?uid={{$.SignedUser.ID}}&page=team"> | |||||
| {{$.CsrfTokenHtml}} | |||||
| <button type="submit" class="ui blue tiny button">{{$.i18n.Tr "org.teams.join"}}</button> | |||||
| </form> | |||||
| {{end}} | {{end}} | ||||
| </div> | </div> | ||||
| </h4> | </h4> | ||||
| @@ -17,9 +17,15 @@ | |||||
| <a class="text black" href="{{$.OrgLink}}/teams/{{.LowerName}}"><strong>{{.Name}}</strong></a> | <a class="text black" href="{{$.OrgLink}}/teams/{{.LowerName}}"><strong>{{.Name}}</strong></a> | ||||
| <div class="ui right"> | <div class="ui right"> | ||||
| {{if .IsMember $.SignedUser.ID}} | {{if .IsMember $.SignedUser.ID}} | ||||
| <a class="ui red small button" href="{{$.OrgLink}}/teams/{{.LowerName}}/action/leave?uid={{$.SignedUser.ID}}">{{$.i18n.Tr "org.teams.leave"}}</a> | |||||
| <form method="post" action="{{$.OrgLink}}/teams/{{.LowerName}}/action/leave?uid={{$.SignedUser.ID}}"> | |||||
| {{$.CsrfTokenHtml}} | |||||
| <button type="submit" class="ui red small button">{{$.i18n.Tr "org.teams.leave"}}</button> | |||||
| </form> | |||||
| {{else if $.IsOrganizationOwner}} | {{else if $.IsOrganizationOwner}} | ||||
| <a class="ui blue small button" href="{{$.OrgLink}}/teams/{{.LowerName}}/action/join?uid={{$.SignedUser.ID}}">{{$.i18n.Tr "org.teams.join"}}</a> | |||||
| <form method="post" action="{{$.OrgLink}}/teams/{{.LowerName}}/action/join?uid={{$.SignedUser.ID}}"> | |||||
| {{$.CsrfTokenHtml}} | |||||
| <button type="submit" class="ui blue small button">{{$.i18n.Tr "org.teams.join"}}</button> | |||||
| </form> | |||||
| {{end}} | {{end}} | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| @@ -51,22 +51,28 @@ | |||||
| </div> | </div> | ||||
| {{if not .IsBeingCreated}} | {{if not .IsBeingCreated}} | ||||
| <div class="repo-buttons"> | <div class="repo-buttons"> | ||||
| <div class="ui labeled button" tabindex="0"> | |||||
| <a class="ui compact basic button" href="{{$.RepoLink}}/action/{{if $.IsWatchingRepo}}un{{end}}watch?redirect_to={{$.Link}}"> | |||||
| <i class="icon fa-eye{{if not $.IsWatchingRepo}}-slash{{end}}"></i>{{if $.IsWatchingRepo}}{{$.i18n.Tr "repo.unwatch"}}{{else}}{{$.i18n.Tr "repo.watch"}}{{end}} | |||||
| </a> | |||||
| <a class="ui basic label" href="{{.Link}}/watchers"> | |||||
| {{.NumWatches}} | |||||
| </a> | |||||
| </div> | |||||
| <div class="ui labeled button" tabindex="0"> | |||||
| <a class="ui compact basic button" href="{{$.RepoLink}}/action/{{if $.IsStaringRepo}}un{{end}}star?redirect_to={{$.Link}}"> | |||||
| <i class="icon star{{if not $.IsStaringRepo}} outline{{end}}"></i>{{if $.IsStaringRepo}}{{$.i18n.Tr "repo.unstar"}}{{else}}{{$.i18n.Tr "repo.star"}}{{end}} | |||||
| </a> | |||||
| <a class="ui basic label" href="{{.Link}}/stars"> | |||||
| {{.NumStars}} | |||||
| </a> | |||||
| </div> | |||||
| <form method="post" action="{{$.RepoLink}}/action/{{if $.IsWatchingRepo}}un{{end}}watch?redirect_to={{$.Link}}"> | |||||
| {{$.CsrfTokenHtml}} | |||||
| <div class="ui labeled button" tabindex="0"> | |||||
| <button type="submit" class="ui compact basic button"> | |||||
| <i class="icon fa-eye{{if not $.IsWatchingRepo}}-slash{{end}}"></i>{{if $.IsWatchingRepo}}{{$.i18n.Tr "repo.unwatch"}}{{else}}{{$.i18n.Tr "repo.watch"}}{{end}} | |||||
| </button> | |||||
| <a class="ui basic label" href="{{.Link}}/watchers"> | |||||
| {{.NumWatches}} | |||||
| </a> | |||||
| </div> | |||||
| </form> | |||||
| <form method="post" action="{{$.RepoLink}}/action/{{if $.IsStaringRepo}}un{{end}}star?redirect_to={{$.Link}}"> | |||||
| {{$.CsrfTokenHtml}} | |||||
| <div class="ui labeled button" tabindex="0"> | |||||
| <button type="submit" class="ui compact basic button"> | |||||
| <i class="icon star{{if not $.IsStaringRepo}} outline{{end}}"></i>{{if $.IsStaringRepo}}{{$.i18n.Tr "repo.unstar"}}{{else}}{{$.i18n.Tr "repo.star"}}{{end}} | |||||
| </button> | |||||
| <a class="ui basic label" href="{{.Link}}/stars"> | |||||
| {{.NumStars}} | |||||
| </a> | |||||
| </div> | |||||
| </form> | |||||
| {{if and (not .IsEmpty) ($.Permission.CanRead $.UnitTypeCode)}} | {{if and (not .IsEmpty) ($.Permission.CanRead $.UnitTypeCode)}} | ||||
| <div class="ui labeled button {{if and ($.IsSigned) (not $.CanSignedUserFork)}}disabled-repo-button{{end}}" tabindex="0"> | <div class="ui labeled button {{if and ($.IsSigned) (not $.CanSignedUserFork)}}disabled-repo-button{{end}}" tabindex="0"> | ||||
| <a class="ui compact basic button {{if or (not $.IsSigned) (not $.CanSignedUserFork)}}poping up{{end}}" {{if $.CanSignedUserFork}}href="{{AppSubUrl}}/repo/fork/{{.ID}}"{{else if $.IsSigned}} data-content="{{$.i18n.Tr "repo.fork_from_self"}}" {{ else }} data-content="{{$.i18n.Tr "repo.fork_guest_user" }}" rel="nofollow" href="{{AppSubUrl}}/user/login?redirect_to={{AppSubUrl}}/repo/fork/{{.ID}}" {{end}} data-position="top center" data-variation="tiny"> | <a class="ui compact basic button {{if or (not $.IsSigned) (not $.CanSignedUserFork)}}poping up{{end}}" {{if $.CanSignedUserFork}}href="{{AppSubUrl}}/repo/fork/{{.ID}}"{{else if $.IsSigned}} data-content="{{$.i18n.Tr "repo.fork_from_self"}}" {{ else }} data-content="{{$.i18n.Tr "repo.fork_guest_user" }}" rel="nofollow" href="{{AppSubUrl}}/user/login?redirect_to={{AppSubUrl}}/repo/fork/{{.ID}}" {{end}} data-position="top center" data-variation="tiny"> | ||||
| @@ -71,9 +71,9 @@ | |||||
| <div class="ui right operate"> | <div class="ui right operate"> | ||||
| <a href="{{$.Link}}/{{.ID}}/edit" data-id={{.ID}} data-title={{.Name}}>{{svg "octicon-pencil" 16}} {{$.i18n.Tr "repo.issues.label_edit"}}</a> | <a href="{{$.Link}}/{{.ID}}/edit" data-id={{.ID}} data-title={{.Name}}>{{svg "octicon-pencil" 16}} {{$.i18n.Tr "repo.issues.label_edit"}}</a> | ||||
| {{if .IsClosed}} | {{if .IsClosed}} | ||||
| <a href="{{$.Link}}/{{.ID}}/open" data-id={{.ID}} data-title={{.Name}}>{{svg "octicon-check" 16}} {{$.i18n.Tr "repo.milestones.open"}}</a> | |||||
| <a class="link-action" href data-url="{{$.Link}}/{{.ID}}/open">{{svg "octicon-check" 16}} {{$.i18n.Tr "repo.milestones.open"}}</a> | |||||
| {{else}} | {{else}} | ||||
| <a href="{{$.Link}}/{{.ID}}/close" data-id={{.ID}} data-title={{.Name}}>{{svg "octicon-x" 16}} {{$.i18n.Tr "repo.milestones.close"}}</a> | |||||
| <a class="link-action" href data-url="{{$.Link}}/{{.ID}}/close">{{svg "octicon-x" 16}} {{$.i18n.Tr "repo.milestones.close"}}</a> | |||||
| {{end}} | {{end}} | ||||
| <a class="delete-button" href="#" data-url="{{$.RepoLink}}/milestones/delete" data-id="{{.ID}}">{{svg "octicon-trashcan" 16}} {{$.i18n.Tr "repo.issues.label_delete"}}</a> | <a class="delete-button" href="#" data-url="{{$.RepoLink}}/milestones/delete" data-id="{{.ID}}">{{svg "octicon-trashcan" 16}} {{$.i18n.Tr "repo.issues.label_delete"}}</a> | ||||
| </div> | </div> | ||||
| @@ -65,9 +65,15 @@ | |||||
| {{if and .IsSigned (ne .SignedUserName .Owner.Name)}} | {{if and .IsSigned (ne .SignedUserName .Owner.Name)}} | ||||
| <li class="follow"> | <li class="follow"> | ||||
| {{if .SignedUser.IsFollowing .Owner.ID}} | {{if .SignedUser.IsFollowing .Owner.ID}} | ||||
| <a class="ui basic red button" href="{{.Link}}/action/unfollow?redirect_to={{$.Link}}">{{svg "octicon-person" 16}} {{.i18n.Tr "user.unfollow"}}</a> | |||||
| <form method="post" action="{{.Link}}/action/unfollow?redirect_to={{$.Link}}"> | |||||
| {{$.CsrfTokenHtml}} | |||||
| <button type="submit" class="ui basic red button">{{svg "octicon-person" 16}} {{.i18n.Tr "user.unfollow"}}</button> | |||||
| </form> | |||||
| {{else}} | {{else}} | ||||
| <a class="ui basic green button" href="{{.Link}}/action/follow?redirect_to={{$.Link}}">{{svg "octicon-person" 16}} {{.i18n.Tr "user.follow"}}</a> | |||||
| <form method="post" action="{{.Link}}/action/follow?redirect_to={{$.Link}}"> | |||||
| {{$.CsrfTokenHtml}} | |||||
| <button type="submit" class="ui basic green button">{{svg "octicon-person" 16}} {{.i18n.Tr "user.follow"}}</button> | |||||
| </form> | |||||
| {{end}} | {{end}} | ||||
| </li> | </li> | ||||
| {{end}} | {{end}} | ||||
| @@ -2469,6 +2469,7 @@ $(document).ready(async () => { | |||||
| // Helpers. | // Helpers. | ||||
| $('.delete-button').click(showDeletePopup); | $('.delete-button').click(showDeletePopup); | ||||
| $('.add-all-button').click(showAddAllPopup); | $('.add-all-button').click(showAddAllPopup); | ||||
| $('.link-action').click(linkAction); | |||||
| $('.delete-branch-button').click(showDeletePopup); | $('.delete-branch-button').click(showDeletePopup); | ||||
| @@ -2735,6 +2736,19 @@ function showAddAllPopup() { | |||||
| return false; | return false; | ||||
| } | } | ||||
| function linkAction() { | |||||
| const $this = $(this); | |||||
| $.post($this.data('url'), { | |||||
| _csrf: csrf | |||||
| }).done((data) => { | |||||
| if (data.redirect) { | |||||
| window.location.href = data.redirect; | |||||
| } else { | |||||
| window.location.reload(); | |||||
| } | |||||
| }); | |||||
| } | |||||
| function initVueComponents() { | function initVueComponents() { | ||||
| const vueDelimeters = ['${', '}']; | const vueDelimeters = ['${', '}']; | ||||