templates: make state changing routes to POST method (#5541)

- pkg/context: add ParamsUser to unify the injection process
pull/5340/head^2
Unknwon 2018-12-06 22:58:02 -05:00
parent 458aadbb10
commit f545faa06d
No known key found for this signature in database
GPG Key ID: 25B575AE3213B2B3
12 changed files with 190 additions and 166 deletions

View File

@ -257,7 +257,7 @@ func runWeb(c *cli.Context) error {
m.Get("/email2user", user.Email2User) m.Get("/email2user", user.Email2User)
m.Get("/forget_password", user.ForgotPasswd) m.Get("/forget_password", user.ForgotPasswd)
m.Post("/forget_password", user.ForgotPasswdPost) m.Post("/forget_password", user.ForgotPasswdPost)
m.Get("/logout", user.SignOut) m.Post("/logout", user.SignOut)
}) })
// ***** END: User ***** // ***** END: User *****
@ -308,7 +308,7 @@ func runWeb(c *cli.Context) error {
m.Get("/followers", user.Followers) m.Get("/followers", user.Followers)
m.Get("/following", user.Following) m.Get("/following", user.Following)
m.Get("/stars", user.Stars) m.Get("/stars", user.Stars)
}) }, context.InjectParamsUser())
m.Get("/attachments/:uuid", func(c *context.Context) { m.Get("/attachments/:uuid", func(c *context.Context) {
attach, err := models.GetAttachmentByUUID(c.Params(":uuid")) attach, err := models.GetAttachmentByUUID(c.Params(":uuid"))
@ -340,8 +340,8 @@ func runWeb(c *cli.Context) error {
}, ignSignIn) }, ignSignIn)
m.Group("/:username", func() { m.Group("/:username", func() {
m.Get("/action/:action", user.Action) m.Post("/action/:action", user.Action)
}, reqSignIn) }, reqSignIn, context.InjectParamsUser())
if macaron.Env == macaron.DEV { if macaron.Env == macaron.DEV {
m.Get("/template/*", dev.TemplatePreview) m.Get("/template/*", dev.TemplatePreview)
@ -484,7 +484,7 @@ func runWeb(c *cli.Context) error {
}) })
}, reqSignIn, context.RepoAssignment(), reqRepoAdmin, context.RepoRef()) }, reqSignIn, context.RepoAssignment(), reqRepoAdmin, context.RepoRef())
m.Get("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), repo.Action) m.Post("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), repo.Action)
m.Group("/:username/:reponame", func() { m.Group("/:username/:reponame", func() {
m.Get("/issues", repo.RetrieveLabels, repo.Issues) m.Get("/issues", repo.RetrieveLabels, repo.Issues)
m.Get("/issues/:index", repo.ViewIssue) m.Get("/issues/:index", repo.ViewIssue)

View File

@ -16,7 +16,7 @@ import (
"github.com/gogs/gogs/pkg/setting" "github.com/gogs/gogs/pkg/setting"
) )
const APP_VER = "0.11.76.1204" const APP_VER = "0.11.77.1206"
func init() { func init() {
setting.AppVer = APP_VER setting.AppVer = APP_VER

30
pkg/context/user.go Normal file
View File

@ -0,0 +1,30 @@
// Copyright 2018 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 context
import (
"gopkg.in/macaron.v1"
"github.com/gogs/gogs/models"
"github.com/gogs/gogs/models/errors"
)
// ParamsUser is the wrapper type of the target user defined by URL parameter, namely ':username'.
type ParamsUser struct {
*models.User
}
// InjectParamsUser returns a handler that retrieves target user based on URL parameter ':username',
// and injects it as *ParamsUser.
func InjectParamsUser() macaron.Handler {
return func(c *Context) {
user, err := models.GetUserByName(c.Params(":username"))
if err != nil {
c.NotFoundOrServerError("GetUserByName", errors.IsUserNotExist, err)
return
}
c.Map(&ParamsUser{user})
}
}

View File

@ -347,6 +347,9 @@ footer .ui.language .menu {
.hide { .hide {
display: none; display: none;
} }
.display.inline {
display: inline;
}
.center { .center {
text-align: center; text-align: center;
} }
@ -2934,6 +2937,9 @@ footer .ui.language .menu {
margin-top: 5px; margin-top: 5px;
margin-right: 8px; margin-right: 8px;
} }
.user.profile .ui.card .profile-avatar {
height: 287px;
}
.user.profile .ui.card .header { .user.profile .ui.card .header {
word-break: break-all; word-break: break-all;
} }

View File

@ -1336,6 +1336,10 @@ $(document).ready(function () {
window.location.href = $this.data('done-url'); window.location.href = $this.data('done-url');
}); });
}); });
// To make arbitrary form element to behave like a submit button
$('.submit-button').click(function () {
$($(this).data('form')).submit();
});
// Check or select on option to enable/disable target region // Check or select on option to enable/disable target region
$('.enable-system').change(function () { $('.enable-system').change(function () {

View File

@ -384,6 +384,11 @@ footer {
.hide { .hide {
display: none; display: none;
} }
.display {
&.inline {
display: inline;
}
}
.center { .center {
text-align: center; text-align: center;
} }

View File

@ -60,6 +60,9 @@
&.profile { &.profile {
.ui.card { .ui.card {
.profile-avatar {
height: 287px;
}
.header { .header {
word-break: break-all; word-break: break-all;
} }

View File

@ -6,13 +6,11 @@ package user
import ( import (
"fmt" "fmt"
"path"
"strings" "strings"
"github.com/Unknwon/paginater" "github.com/Unknwon/paginater"
"github.com/gogs/gogs/models" "github.com/gogs/gogs/models"
"github.com/gogs/gogs/models/errors"
"github.com/gogs/gogs/pkg/context" "github.com/gogs/gogs/pkg/context"
"github.com/gogs/gogs/pkg/setting" "github.com/gogs/gogs/pkg/setting"
"github.com/gogs/gogs/pkg/tool" "github.com/gogs/gogs/pkg/tool"
@ -24,59 +22,30 @@ const (
STARS = "user/meta/stars" STARS = "user/meta/stars"
) )
func GetUserByName(c *context.Context, name string) *models.User { func Profile(c *context.Context, puser *context.ParamsUser) {
user, err := models.GetUserByName(name)
if err != nil {
c.NotFoundOrServerError("GetUserByName", errors.IsUserNotExist, err)
return nil
}
return user
}
// GetUserByParams returns user whose name is presented in URL paramenter.
func GetUserByParams(c *context.Context) *models.User {
return GetUserByName(c, c.Params(":username"))
}
func Profile(c *context.Context) {
uname := c.Params(":username")
// Special handle for FireFox requests favicon.ico.
if uname == "favicon.ico" {
c.ServeFile(path.Join(setting.StaticRootPath, "public/img/favicon.png"))
return
} else if strings.HasSuffix(uname, ".png") {
c.Error(404)
return
}
isShowKeys := false isShowKeys := false
if strings.HasSuffix(uname, ".keys") { if strings.HasSuffix(c.Params(":username"), ".keys") {
isShowKeys = true isShowKeys = true
} }
ctxUser := GetUserByName(c, strings.TrimSuffix(uname, ".keys"))
if c.Written() {
return
}
// Show SSH keys. // Show SSH keys.
if isShowKeys { if isShowKeys {
ShowSSHKeys(c, ctxUser.ID) ShowSSHKeys(c, puser.ID)
return return
} }
if ctxUser.IsOrganization() { if puser.IsOrganization() {
showOrgProfile(c) showOrgProfile(c)
return return
} }
c.Data["Title"] = ctxUser.DisplayName() c.Title(puser.DisplayName())
c.Data["PageIsUserProfile"] = true c.PageIs("UserProfile")
c.Data["Owner"] = ctxUser c.Data["Owner"] = puser
orgs, err := models.GetOrgsByUserID(ctxUser.ID, c.IsLogged && (c.User.IsAdmin || c.User.ID == ctxUser.ID)) orgs, err := models.GetOrgsByUserID(puser.ID, c.IsLogged && (c.User.IsAdmin || c.User.ID == puser.ID))
if err != nil { if err != nil {
c.Handle(500, "GetOrgsByUserIDDesc", err) c.ServerError("GetOrgsByUserIDDesc", err)
return return
} }
@ -86,7 +55,7 @@ func Profile(c *context.Context) {
c.Data["TabName"] = tab c.Data["TabName"] = tab
switch tab { switch tab {
case "activity": case "activity":
retrieveFeeds(c, ctxUser, -1, true) retrieveFeeds(c, puser.User, -1, true)
if c.Written() { if c.Written() {
return return
} }
@ -96,65 +65,52 @@ func Profile(c *context.Context) {
page = 1 page = 1
} }
showPrivate := c.IsLogged && (ctxUser.ID == c.User.ID || c.User.IsAdmin) showPrivate := c.IsLogged && (puser.ID == c.User.ID || c.User.IsAdmin)
c.Data["Repos"], err = models.GetUserRepositories(&models.UserRepoOptions{ c.Data["Repos"], err = models.GetUserRepositories(&models.UserRepoOptions{
UserID: ctxUser.ID, UserID: puser.ID,
Private: showPrivate, Private: showPrivate,
Page: page, Page: page,
PageSize: setting.UI.User.RepoPagingNum, PageSize: setting.UI.User.RepoPagingNum,
}) })
if err != nil { if err != nil {
c.Handle(500, "GetRepositories", err) c.ServerError("GetRepositories", err)
return return
} }
count := models.CountUserRepositories(ctxUser.ID, showPrivate) count := models.CountUserRepositories(puser.ID, showPrivate)
c.Data["Page"] = paginater.New(int(count), setting.UI.User.RepoPagingNum, page, 5) c.Data["Page"] = paginater.New(int(count), setting.UI.User.RepoPagingNum, page, 5)
} }
c.HTML(200, PROFILE) c.Success(PROFILE)
} }
func Followers(c *context.Context) { func Followers(c *context.Context, puser *context.ParamsUser) {
u := GetUserByParams(c) c.Title(puser.DisplayName())
if c.Written() { c.PageIs("Followers")
return
}
c.Data["Title"] = u.DisplayName()
c.Data["CardsTitle"] = c.Tr("user.followers") c.Data["CardsTitle"] = c.Tr("user.followers")
c.Data["PageIsFollowers"] = true c.Data["Owner"] = puser
c.Data["Owner"] = u repo.RenderUserCards(c, puser.NumFollowers, puser.GetFollowers, FOLLOWERS)
repo.RenderUserCards(c, u.NumFollowers, u.GetFollowers, FOLLOWERS)
} }
func Following(c *context.Context) { func Following(c *context.Context, puser *context.ParamsUser) {
u := GetUserByParams(c) c.Title(puser.DisplayName())
if c.Written() { c.PageIs("Following")
return
}
c.Data["Title"] = u.DisplayName()
c.Data["CardsTitle"] = c.Tr("user.following") c.Data["CardsTitle"] = c.Tr("user.following")
c.Data["PageIsFollowing"] = true c.Data["Owner"] = puser
c.Data["Owner"] = u repo.RenderUserCards(c, puser.NumFollowing, puser.GetFollowing, FOLLOWERS)
repo.RenderUserCards(c, u.NumFollowing, u.GetFollowing, FOLLOWERS)
} }
func Stars(c *context.Context) { func Stars(c *context.Context) {
} }
func Action(c *context.Context) { func Action(c *context.Context, puser *context.ParamsUser) {
u := GetUserByParams(c)
if c.Written() {
return
}
var err error var err error
switch c.Params(":action") { switch c.Params(":action") {
case "follow": case "follow":
err = models.FollowUser(c.User.ID, u.ID) err = models.FollowUser(c.UserID(), puser.ID)
case "unfollow": case "unfollow":
err = models.UnfollowUser(c.User.ID, u.ID) err = models.UnfollowUser(c.UserID(), puser.ID)
} }
if err != nil { if err != nil {
@ -164,7 +120,7 @@ func Action(c *context.Context) {
redirectTo := c.Query("redirect_to") redirectTo := c.Query("redirect_to")
if !tool.IsSameSiteURLPath(redirectTo) { if !tool.IsSameSiteURLPath(redirectTo) {
redirectTo = u.HomeLink() redirectTo = puser.HomeLink()
} }
c.Redirect(redirectTo) c.Redirect(redirectTo)
} }

View File

@ -1 +1 @@
0.11.76.1204 0.11.77.1206

View File

@ -160,9 +160,13 @@
{{end}} {{end}}
<div class="divider"></div> <div class="divider"></div>
<a class="item" href="{{AppSubURL}}/user/logout">
<form id="logout-form" class="item" action="{{AppSubURL}}/user/logout" method="POST">
{{.CSRFTokenHTML}}
<div class="submit-button" data-form="#logout-form">
<i class="octicon octicon-sign-out"></i> {{.i18n.Tr "sign_out"}} <i class="octicon octicon-sign-out"></i> {{.i18n.Tr "sign_out"}}
</a> </div>
</form>
</div><!-- end content avatar menu --> </div><!-- end content avatar menu -->
</div><!-- end dropdown avatar menu --> </div><!-- end dropdown avatar menu -->
</div><!-- end signed user right menu --> </div><!-- end signed user right menu -->

View File

@ -20,22 +20,28 @@
{{if not $.IsGuest}} {{if not $.IsGuest}}
<div class="ui right"> <div class="ui right">
<form class="display inline" action="{{$.RepoLink}}/action/{{if $.IsWatchingRepo}}un{{end}}watch?redirect_to={{$.Link}}" method="POST">
{{$.CSRFTokenHTML}}
<div class="ui labeled button" tabindex="0"> <div class="ui labeled button" tabindex="0">
<a class="ui basic button" href="{{$.RepoLink}}/action/{{if $.IsWatchingRepo}}un{{end}}watch?redirect_to={{$.Link}}"> <button class="ui basic button">
<i class="eye{{if not $.IsWatchingRepo}} slash outline{{end}} icon"></i>{{if $.IsWatchingRepo}}{{$.i18n.Tr "repo.unwatch"}}{{else}}{{$.i18n.Tr "repo.watch"}}{{end}} <i class="eye{{if not $.IsWatchingRepo}} slash outline{{end}} icon"></i>{{if $.IsWatchingRepo}}{{$.i18n.Tr "repo.unwatch"}}{{else}}{{$.i18n.Tr "repo.watch"}}{{end}}
</a> </button>
<a class="ui basic label" href="{{.Link}}/watchers"> <a class="ui basic label" href="{{.Link}}/watchers">
{{.NumWatches}} {{.NumWatches}}
</a> </a>
</div> </div>
</form>
<form class="display inline" action="{{$.RepoLink}}/action/{{if $.IsStaringRepo}}un{{end}}star?redirect_to={{$.Link}}" method="POST">
{{$.CSRFTokenHTML}}
<div class="ui labeled button" tabindex="0"> <div class="ui labeled button" tabindex="0">
<a class="ui basic button" href="{{$.RepoLink}}/action/{{if $.IsStaringRepo}}un{{end}}star?redirect_to={{$.Link}}"> <button class="ui basic button">
<i class="star{{if not $.IsStaringRepo}} outline{{end}} icon"></i>{{if $.IsStaringRepo}}{{$.i18n.Tr "repo.unstar"}}{{else}}{{$.i18n.Tr "repo.star"}}{{end}} <i class="star{{if not $.IsStaringRepo}} outline{{end}} icon"></i>{{if $.IsStaringRepo}}{{$.i18n.Tr "repo.unstar"}}{{else}}{{$.i18n.Tr "repo.star"}}{{end}}
</a> </button>
<a class="ui basic label" href="{{.Link}}/stars"> <a class="ui basic label" href="{{.Link}}/stars">
{{.NumStars}} {{.NumStars}}
</a> </a>
</div> </div>
</form>
{{if .CanBeForked}} {{if .CanBeForked}}
<div class="ui labeled button" tabindex="0"> <div class="ui labeled button" tabindex="0">
<a class="ui basic button {{if eq .OwnerID $.LoggedUserID}}poping up{{end}}" href="{{AppSubURL}}/repo/fork/{{.ID}}"> <a class="ui basic button {{if eq .OwnerID $.LoggedUserID}}poping up{{end}}" href="{{AppSubURL}}/repo/fork/{{.ID}}">

View File

@ -5,12 +5,12 @@
<div class="ui five wide column"> <div class="ui five wide column">
<div class="ui card"> <div class="ui card">
{{if eq .LoggedUserName .Owner.Name}} {{if eq .LoggedUserName .Owner.Name}}
<a class="image poping up" href="{{AppSubURL}}/user/settings/avatar" id="profile-avatar" data-content="{{.i18n.Tr "user.change_avatar"}}" data-variation="inverted tiny" data-position="bottom center"> <a class="profile-avatar image poping up" href="{{AppSubURL}}/user/settings/avatar" id="profile-avatar" data-content="{{.i18n.Tr "user.change_avatar"}}" data-variation="inverted tiny" data-position="bottom center">
<img src="{{AppendAvatarSize .Owner.RelAvatarLink 290}}" title="{{.Owner.Name}}"/> <img src="{{AppendAvatarSize .Owner.RelAvatarLink 287}}" title="{{.Owner.Name}}"/>
</a> </a>
{{else}} {{else}}
<span class="image"> <span class="profile-avatar image">
<img src="{{AppendAvatarSize .Owner.RelAvatarLink 290}}" title="{{.Owner.Name}}"/> <img src="{{AppendAvatarSize .Owner.RelAvatarLink 287}}" title="{{.Owner.Name}}"/>
</span> </span>
{{end}} {{end}}
<div class="content"> <div class="content">
@ -63,9 +63,19 @@
{{if and .IsLogged (ne .LoggedUserName .Owner.Name)}} {{if and .IsLogged (ne .LoggedUserName .Owner.Name)}}
<li class="follow"> <li class="follow">
{{if .LoggedUser.IsFollowing .Owner.ID}} {{if .LoggedUser.IsFollowing .Owner.ID}}
<a class="ui basic red button" href="{{.Link}}/action/unfollow?redirect_to={{$.Link}}"><i class="octicon octicon-person"></i> {{.i18n.Tr "user.unfollow"}}</a> <form action="{{.Link}}/action/unfollow?redirect_to={{$.Link}}" method="POST">
{{.CSRFTokenHTML}}
<button class="ui basic red button">
<i class="octicon octicon-person"></i> {{.i18n.Tr "user.unfollow"}}
</button>
</form>
{{else}} {{else}}
<a class="ui basic green button" href="{{.Link}}/action/follow?redirect_to={{$.Link}}"><i class="octicon octicon-person"></i> {{.i18n.Tr "user.follow"}}</a> <form action="{{.Link}}/action/follow?redirect_to={{$.Link}}" method="POST">
{{.CSRFTokenHTML}}
<button class="ui basic green button">
<i class="octicon octicon-person"></i> {{.i18n.Tr "user.follow"}}
</button>
</form>
{{end}} {{end}}
</li> </li>
{{end}} {{end}}