aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gopmfile1
-rw-r--r--cmd/web.go10
-rw-r--r--conf/app.ini14
-rw-r--r--conf/locale/TRANSLATORS6
-rw-r--r--gogs.go2
-rw-r--r--modules/setting/setting.go6
-rw-r--r--modules/social/social.go292
-rw-r--r--routers/user/social.go50
-rw-r--r--templates/.VERSION2
-rw-r--r--templates/admin/repo/list.tmpl4
-rw-r--r--templates/ng/base/social.tmpl8
-rw-r--r--templates/repo/issue/list.tmpl2
-rw-r--r--templates/repo/issue/view.tmpl24
-rw-r--r--templates/repo/release/list.tmpl2
-rw-r--r--templates/user/auth/signin.tmpl4
-rw-r--r--templates/user/issues.tmpl2
-rw-r--r--templates/user/settings/profile.tmpl2
17 files changed, 183 insertions, 248 deletions
diff --git a/.gopmfile b/.gopmfile
index 2f9ebb96..a3af87e9 100644
--- a/.gopmfile
+++ b/.gopmfile
@@ -21,6 +21,7 @@ github.com/macaron-contrib/cache = commit:0bb9e6c9ef
github.com/macaron-contrib/captcha = commit:3567dc48b8
github.com/macaron-contrib/csrf = commit:422b79675c
github.com/macaron-contrib/i18n =
+github.com/macaron-contrib/oauth2 =
github.com/macaron-contrib/session = commit:f00d48fd4f
github.com/macaron-contrib/toolbox = commit:57127bcc89
github.com/mattn/go-sqlite3 = commit:a80c27ba33
diff --git a/cmd/web.go b/cmd/web.go
index f2a506bc..6875ddb1 100644
--- a/cmd/web.go
+++ b/cmd/web.go
@@ -21,6 +21,7 @@ import (
"github.com/macaron-contrib/captcha"
"github.com/macaron-contrib/csrf"
"github.com/macaron-contrib/i18n"
+ "github.com/macaron-contrib/oauth2"
"github.com/macaron-contrib/session"
"github.com/macaron-contrib/toolbox"
@@ -140,6 +141,11 @@ func newMacaron() *macaron.Macaron {
},
},
}))
+
+ // OAuth 2.
+ for _, info := range setting.OauthService.OauthInfos {
+ m.Use(oauth2.NewOAuth2Provider(info.Options, info.AuthUrl, info.TokenUrl))
+ }
m.Use(middleware.Contexter())
return m
}
@@ -213,7 +219,7 @@ func runWeb(*cli.Context) {
m.Group("/user", func() {
m.Get("/login", user.SignIn)
m.Post("/login", bindIgnErr(auth.SignInForm{}), user.SignInPost)
- m.Get("/login/:name", user.SocialSignIn)
+ m.Get("/info/:name", user.SocialSignIn)
m.Get("/sign_up", user.SignUp)
m.Post("/sign_up", bindIgnErr(auth.RegisterForm{}), user.SignUpPost)
m.Get("/reset_password", user.ResetPasswd)
@@ -406,7 +412,7 @@ func runWeb(*cli.Context) {
m.Get("/issues2/", repo.Issues2)
m.Get("/pulls2/", repo.PullRequest2)
m.Get("/labels2/", repo.Labels2)
- m.Get("/milestone2/",repo.Milestones2)
+ m.Get("/milestone2/", repo.Milestones2)
m.Group("", func() {
m.Get("/src/*", repo.Home)
diff --git a/conf/app.ini b/conf/app.ini
index e0620f31..dba75ed1 100644
--- a/conf/app.ini
+++ b/conf/app.ini
@@ -22,6 +22,11 @@ DISABLE_ROUTER_LOG = false
; Generate steps:
; $ cd path/to/gogs/custom/https
; $ ./gogs cert -ca=true -duration=8760h0m0s -host=myhost.example.com
+;
+; Or from a .pfx file exported from the Windows certificate store (do
+; not forget to export the private key):
+; $ openssl pkcs12 -in cert.pfx -out cert.pem -nokeys
+; $ openssl pkcs12 -in cert.pfx -out key.pem -nocerts -nodes
CERT_FILE = custom/https/cert.pem
KEY_FILE = custom/https/key.pem
; Upper level of template and static file path
@@ -120,13 +125,10 @@ TOKEN_URL = https://accounts.google.com/o/oauth2/token
ENABLED = false
CLIENT_ID =
CLIENT_SECRET =
-SCOPES = all
+SCOPES = get_user_info
; QQ 互联
-; AUTH_URL = https://graph.qq.com/oauth2.0/authorize
-; TOKEN_URL = https://graph.qq.com/oauth2.0/token
-; Tencent weibo
-AUTH_URL = https://open.t.qq.com/cgi-bin/oauth2/authorize
-TOKEN_URL = https://open.t.qq.com/cgi-bin/oauth2/access_token
+AUTH_URL = https://graph.qq.com/oauth2.0/authorize
+TOKEN_URL = https://graph.qq.com/oauth2.0/token
[oauth.weibo]
ENABLED = false
diff --git a/conf/locale/TRANSLATORS b/conf/locale/TRANSLATORS
index a07e7d5e..9899ea4e 100644
--- a/conf/locale/TRANSLATORS
+++ b/conf/locale/TRANSLATORS
@@ -1,3 +1,5 @@
-# This file lists all individuals having contributed content to the translation.
+# This file lists all PUBLIC individuals having contributed content to the translation.
+# Order of name is meaningless.
-Thomas Fanninger <gogs.thomas@fanninger.at> \ No newline at end of file
+Thomas Fanninger <gogs.thomas@fanninger.at>
+Łukasz Jan Niemier <lukasz@niemier.pl> \ No newline at end of file
diff --git a/gogs.go b/gogs.go
index 00ac2456..c555b56c 100644
--- a/gogs.go
+++ b/gogs.go
@@ -17,7 +17,7 @@ import (
"github.com/gogits/gogs/modules/setting"
)
-const APP_VER = "0.5.8.1125 Beta"
+const APP_VER = "0.5.8.1128 Beta"
func init() {
runtime.GOMAXPROCS(runtime.NumCPU())
diff --git a/modules/setting/setting.go b/modules/setting/setting.go
index a775847c..9737fa7c 100644
--- a/modules/setting/setting.go
+++ b/modules/setting/setting.go
@@ -17,6 +17,7 @@ import (
"github.com/Unknwon/com"
"github.com/Unknwon/goconfig"
+ "github.com/macaron-contrib/oauth2"
"github.com/macaron-contrib/session"
"github.com/gogits/gogs/modules/log"
@@ -434,9 +435,8 @@ type Mailer struct {
}
type OauthInfo struct {
- ClientId, ClientSecret string
- Scopes string
- AuthUrl, TokenUrl string
+ oauth2.Options
+ AuthUrl, TokenUrl string
}
// Oauther represents oauth service.
diff --git a/modules/social/social.go b/modules/social/social.go
index f4d85988..bdafae69 100644
--- a/modules/social/social.go
+++ b/modules/social/social.go
@@ -7,12 +7,12 @@ package social
import (
"encoding/json"
+ "io/ioutil"
"net/http"
"net/url"
"strconv"
- "strings"
- oauth "github.com/gogits/oauth2"
+ "github.com/macaron-contrib/oauth2"
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/log"
@@ -27,16 +27,11 @@ type BasicUserInfo struct {
type SocialConnector interface {
Type() int
- SetRedirectUrl(string)
- UserInfo(*oauth.Token, *url.URL) (*BasicUserInfo, error)
-
- AuthCodeURL(string) string
- Exchange(string) (*oauth.Token, error)
+ UserInfo(*oauth2.Token, *url.URL) (*BasicUserInfo, error)
}
var (
- SocialBaseUrl = "/user/login"
- SocialMap = make(map[string]SocialConnector)
+ SocialMap = make(map[string]SocialConnector)
)
func NewOauthService() {
@@ -44,27 +39,34 @@ func NewOauthService() {
return
}
+ oauth2.AppSubUrl = setting.AppSubUrl
+
setting.OauthService = &setting.Oauther{}
setting.OauthService.OauthInfos = make(map[string]*setting.OauthInfo)
- socialConfigs := make(map[string]*oauth.Config)
+ socialConfigs := make(map[string]*oauth2.Options)
allOauthes := []string{"github", "google", "qq", "twitter", "weibo"}
// Load all OAuth config data.
for _, name := range allOauthes {
+ if !setting.Cfg.MustBool("oauth."+name, "ENABLED") {
+ continue
+ }
setting.OauthService.OauthInfos[name] = &setting.OauthInfo{
- ClientId: setting.Cfg.MustValue("oauth."+name, "CLIENT_ID"),
- ClientSecret: setting.Cfg.MustValue("oauth."+name, "CLIENT_SECRET"),
- Scopes: setting.Cfg.MustValue("oauth."+name, "SCOPES"),
- AuthUrl: setting.Cfg.MustValue("oauth."+name, "AUTH_URL"),
- TokenUrl: setting.Cfg.MustValue("oauth."+name, "TOKEN_URL"),
+ Options: oauth2.Options{
+ ClientID: setting.Cfg.MustValue("oauth."+name, "CLIENT_ID"),
+ ClientSecret: setting.Cfg.MustValue("oauth."+name, "CLIENT_SECRET"),
+ Scopes: setting.Cfg.MustValueArray("oauth."+name, "SCOPES", " "),
+ PathLogin: "/user/login/oauth2/" + name,
+ PathCallback: setting.AppSubUrl + "/user/login/" + name,
+ RedirectURL: setting.AppUrl + "user/login/" + name,
+ },
+ AuthUrl: setting.Cfg.MustValue("oauth."+name, "AUTH_URL"),
+ TokenUrl: setting.Cfg.MustValue("oauth."+name, "TOKEN_URL"),
}
- socialConfigs[name] = &oauth.Config{
- ClientId: setting.OauthService.OauthInfos[name].ClientId,
+ socialConfigs[name] = &oauth2.Options{
+ ClientID: setting.OauthService.OauthInfos[name].ClientID,
ClientSecret: setting.OauthService.OauthInfos[name].ClientSecret,
- RedirectURL: strings.TrimSuffix(setting.AppUrl, "/") + SocialBaseUrl + name,
- Scope: setting.OauthService.OauthInfos[name].Scopes,
- AuthURL: setting.OauthService.OauthInfos[name].AuthUrl,
- TokenURL: setting.OauthService.OauthInfos[name].TokenUrl,
+ Scopes: setting.OauthService.OauthInfos[name].Scopes,
}
}
enabledOauths := make([]string, 0, 10)
@@ -91,11 +93,11 @@ func NewOauthService() {
}
// Twitter.
- if setting.Cfg.MustBool("oauth.twitter", "ENABLED") {
- setting.OauthService.Twitter = true
- newTwitterOauth(socialConfigs["twitter"])
- enabledOauths = append(enabledOauths, "Twitter")
- }
+ // if setting.Cfg.MustBool("oauth.twitter", "ENABLED") {
+ // setting.OauthService.Twitter = true
+ // newTwitterOauth(socialConfigs["twitter"])
+ // enabledOauths = append(enabledOauths, "Twitter")
+ // }
// Weibo.
if setting.Cfg.MustBool("oauth.weibo", "ENABLED") {
@@ -115,38 +117,25 @@ func NewOauthService() {
// \/ \/ \/
type SocialGithub struct {
- Token *oauth.Token
- *oauth.Transport
-}
-
-func (s *SocialGithub) Type() int {
- return int(models.GITHUB)
+ opts *oauth2.Options
}
-func newGitHubOauth(config *oauth.Config) {
- SocialMap["github"] = &SocialGithub{
- Transport: &oauth.Transport{
- Config: config,
- Transport: http.DefaultTransport,
- },
- }
+func newGitHubOauth(opts *oauth2.Options) {
+ SocialMap["github"] = &SocialGithub{opts}
}
-func (s *SocialGithub) SetRedirectUrl(url string) {
- s.Transport.Config.RedirectURL = url
+func (s *SocialGithub) Type() int {
+ return int(models.GITHUB)
}
-func (s *SocialGithub) UserInfo(token *oauth.Token, _ *url.URL) (*BasicUserInfo, error) {
- transport := &oauth.Transport{
- Token: token,
- }
+func (s *SocialGithub) UserInfo(token *oauth2.Token, _ *url.URL) (*BasicUserInfo, error) {
+ transport := s.opts.NewTransportFromToken(token)
var data struct {
Id int `json:"id"`
Name string `json:"login"`
Email string `json:"email"`
}
- var err error
- r, err := transport.Client().Get(s.Transport.Scope)
+ r, err := transport.Client().Get("https://api.github.com/user")
if err != nil {
return nil, err
}
@@ -169,38 +158,25 @@ func (s *SocialGithub) UserInfo(token *oauth.Token, _ *url.URL) (*BasicUserInfo,
// \/ /_____/ \/
type SocialGoogle struct {
- Token *oauth.Token
- *oauth.Transport
+ opts *oauth2.Options
}
func (s *SocialGoogle) Type() int {
return int(models.GOOGLE)
}
-func newGoogleOauth(config *oauth.Config) {
- SocialMap["google"] = &SocialGoogle{
- Transport: &oauth.Transport{
- Config: config,
- Transport: http.DefaultTransport,
- },
- }
-}
-
-func (s *SocialGoogle) SetRedirectUrl(url string) {
- s.Transport.Config.RedirectURL = url
+func newGoogleOauth(opts *oauth2.Options) {
+ SocialMap["google"] = &SocialGoogle{opts}
}
-func (s *SocialGoogle) UserInfo(token *oauth.Token, _ *url.URL) (*BasicUserInfo, error) {
- transport := &oauth.Transport{Token: token}
+func (s *SocialGoogle) UserInfo(token *oauth2.Token, _ *url.URL) (*BasicUserInfo, error) {
+ transport := s.opts.NewTransportFromToken(token)
var data struct {
Id string `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
- var err error
-
- reqUrl := "https://www.googleapis.com/oauth2/v1/userinfo"
- r, err := transport.Client().Get(reqUrl)
+ r, err := transport.Client().Get("https://www.googleapis.com/userinfo/v2/me")
if err != nil {
return nil, err
}
@@ -223,62 +199,35 @@ func (s *SocialGoogle) UserInfo(token *oauth.Token, _ *url.URL) (*BasicUserInfo,
// \__> \__>
type SocialTencent struct {
- Token *oauth.Token
- *oauth.Transport
- reqUrl string
+ opts *oauth2.Options
+}
+
+func newTencentOauth(opts *oauth2.Options) {
+ SocialMap["qq"] = &SocialTencent{opts}
}
func (s *SocialTencent) Type() int {
return int(models.QQ)
}
-func newTencentOauth(config *oauth.Config) {
- SocialMap["qq"] = &SocialTencent{
- reqUrl: "https://open.t.qq.com/api/user/info",
- Transport: &oauth.Transport{
- Config: config,
- Transport: http.DefaultTransport,
- },
+func (s *SocialTencent) UserInfo(token *oauth2.Token, URL *url.URL) (*BasicUserInfo, error) {
+ r, err := http.Get("https://graph.z.qq.com/moc2/me?access_token=" + url.QueryEscape(token.AccessToken))
+ if err != nil {
+ return nil, err
}
-}
-
-func (s *SocialTencent) SetRedirectUrl(url string) {
- s.Transport.Config.RedirectURL = url
-}
+ defer r.Body.Close()
-func (s *SocialTencent) UserInfo(token *oauth.Token, URL *url.URL) (*BasicUserInfo, error) {
- var data struct {
- Data struct {
- Id string `json:"openid"`
- Name string `json:"name"`
- Email string `json:"email"`
- } `json:"data"`
- }
- var err error
- // https://open.t.qq.com/api/user/info?
- //oauth_consumer_key=APP_KEY&
- //access_token=ACCESSTOKEN&openid=openid
- //clientip=CLIENTIP&oauth_version=2.a
- //scope=all
- var urls = url.Values{
- "oauth_consumer_key": {s.Transport.Config.ClientId},
- "access_token": {token.AccessToken},
- "openid": URL.Query()["openid"],
- "oauth_version": {"2.a"},
- "scope": {"all"},
- }
- r, err := http.Get(s.reqUrl + "?" + urls.Encode())
+ body, err := ioutil.ReadAll(r.Body)
if err != nil {
return nil, err
}
- defer r.Body.Close()
- if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
+ vals, err := url.ParseQuery(string(body))
+ if err != nil {
return nil, err
}
+
return &BasicUserInfo{
- Identity: data.Data.Id,
- Name: data.Data.Name,
- Email: data.Data.Email,
+ Identity: vals.Get("openid"),
}, nil
}
@@ -289,54 +238,54 @@ func (s *SocialTencent) UserInfo(token *oauth.Token, URL *url.URL) (*BasicUserIn
// |____| \/\_/ |__||__| |__| \___ >__|
// \/
-type SocialTwitter struct {
- Token *oauth.Token
- *oauth.Transport
-}
-
-func (s *SocialTwitter) Type() int {
- return int(models.TWITTER)
-}
-
-func newTwitterOauth(config *oauth.Config) {
- SocialMap["twitter"] = &SocialTwitter{
- Transport: &oauth.Transport{
- Config: config,
- Transport: http.DefaultTransport,
- },
- }
-}
-
-func (s *SocialTwitter) SetRedirectUrl(url string) {
- s.Transport.Config.RedirectURL = url
-}
-
-//https://github.com/mrjones/oauth
-func (s *SocialTwitter) UserInfo(token *oauth.Token, _ *url.URL) (*BasicUserInfo, error) {
- // transport := &oauth.Transport{Token: token}
- // var data struct {
- // Id string `json:"id"`
- // Name string `json:"name"`
- // Email string `json:"email"`
- // }
- // var err error
-
- // reqUrl := "https://www.googleapis.com/oauth2/v1/userinfo"
- // r, err := transport.Client().Get(reqUrl)
- // if err != nil {
- // return nil, err
- // }
- // defer r.Body.Close()
- // if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
- // return nil, err
- // }
- // return &BasicUserInfo{
- // Identity: data.Id,
- // Name: data.Name,
- // Email: data.Email,
- // }, nil
- return nil, nil
-}
+// type SocialTwitter struct {
+// Token *oauth2.Token
+// *oauth2.Transport
+// }
+
+// func (s *SocialTwitter) Type() int {
+// return int(models.TWITTER)
+// }
+
+// func newTwitterOauth(config *oauth2.Config) {
+// SocialMap["twitter"] = &SocialTwitter{
+// Transport: &oauth.Transport{
+// Config: config,
+// Transport: http.DefaultTransport,
+// },
+// }
+// }
+
+// func (s *SocialTwitter) SetRedirectUrl(url string) {
+// s.Transport.Config.RedirectURL = url
+// }
+
+// //https://github.com/mrjones/oauth
+// func (s *SocialTwitter) UserInfo(token *oauth2.Token, _ *url.URL) (*BasicUserInfo, error) {
+// // transport := &oauth.Transport{Token: token}
+// // var data struct {
+// // Id string `json:"id"`
+// // Name string `json:"name"`
+// // Email string `json:"email"`
+// // }
+// // var err error
+
+// // reqUrl := "https://www.googleapis.com/oauth2/v1/userinfo"
+// // r, err := transport.Client().Get(reqUrl)
+// // if err != nil {
+// // return nil, err
+// // }
+// // defer r.Body.Close()
+// // if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
+// // return nil, err
+// // }
+// // return &BasicUserInfo{
+// // Identity: data.Id,
+// // Name: data.Name,
+// // Email: data.Email,
+// // }, nil
+// return nil, nil
+// }
// __ __ ._____.
// / \ / \ ____ |__\_ |__ ____
@@ -346,37 +295,25 @@ func (s *SocialTwitter) UserInfo(token *oauth.Token, _ *url.URL) (*BasicUserInfo
// \/ \/ \/
type SocialWeibo struct {
- Token *oauth.Token
- *oauth.Transport
-}
-
-func (s *SocialWeibo) Type() int {
- return int(models.WEIBO)
+ opts *oauth2.Options
}
-func newWeiboOauth(config *oauth.Config) {
- SocialMap["weibo"] = &SocialWeibo{
- Transport: &oauth.Transport{
- Config: config,
- Transport: http.DefaultTransport,
- },
- }
+func newWeiboOauth(opts *oauth2.Options) {
+ SocialMap["weibo"] = &SocialWeibo{opts}
}
-func (s *SocialWeibo) SetRedirectUrl(url string) {
- s.Transport.Config.RedirectURL = url
+func (s *SocialWeibo) Type() int {
+ return int(models.WEIBO)
}
-func (s *SocialWeibo) UserInfo(token *oauth.Token, _ *url.URL) (*BasicUserInfo, error) {
- transport := &oauth.Transport{Token: token}
+func (s *SocialWeibo) UserInfo(token *oauth2.Token, _ *url.URL) (*BasicUserInfo, error) {
+ transport := s.opts.NewTransportFromToken(token)
var data struct {
Name string `json:"name"`
}
- var err error
-
var urls = url.Values{
"access_token": {token.AccessToken},
- "uid": {token.Extra["id_token"]},
+ "uid": {token.Extra("uid")},
}
reqUrl := "https://api.weibo.com/2/users/show.json"
r, err := transport.Client().Get(reqUrl + "?" + urls.Encode())
@@ -384,11 +321,12 @@ func (s *SocialWeibo) UserInfo(token *oauth.Token, _ *url.URL) (*BasicUserInfo,
return nil, err
}
defer r.Body.Close()
+
if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
return nil, err
}
return &BasicUserInfo{
- Identity: token.Extra["id_token"],
+ Identity: token.Extra("uid"),
Name: data.Name,
}, nil
}
diff --git a/routers/user/social.go b/routers/user/social.go
index 0bc1fa59..913fc094 100644
--- a/routers/user/social.go
+++ b/routers/user/social.go
@@ -8,10 +8,11 @@ import (
"encoding/json"
"errors"
"fmt"
- "net/url"
- "strings"
+ // "strings"
"time"
+ "github.com/macaron-contrib/oauth2"
+
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/log"
"github.com/gogits/gogs/modules/middleware"
@@ -19,52 +20,39 @@ import (
"github.com/gogits/gogs/modules/social"
)
-func extractPath(next string) string {
- n, err := url.Parse(next)
- if err != nil {
- return setting.AppSubUrl + "/"
- }
- return n.Path
-}
-
func SocialSignIn(ctx *middleware.Context) {
if setting.OauthService == nil {
- ctx.Handle(404, "social.SocialSignIn(oauth service not enabled)", nil)
+ ctx.Handle(404, "OAuth2 service not enabled", nil)
+ return
+ }
+
+ next := setting.AppSubUrl + "/user/login"
+ info := ctx.Session.Get(oauth2.KEY_TOKEN)
+ if info == nil {
+ ctx.Redirect(next)
return
}
- next := extractPath(ctx.Query("next"))
name := ctx.Params(":name")
connect, ok := social.SocialMap[name]
if !ok {
- ctx.Handle(404, "social.SocialSignIn(social login not enabled)", errors.New(name))
+ ctx.Handle(404, "social login not enabled", errors.New(name))
return
}
- appUrl := strings.TrimSuffix(setting.AppUrl, "/")
- if name == "weibo" {
- appUrl = strings.Replace(appUrl, "localhost", "127.0.0.1", 1)
- }
- code := ctx.Query("code")
- if code == "" {
- // redirect to social login page
- connect.SetRedirectUrl(appUrl + ctx.Req.URL.Path)
- ctx.Redirect(connect.AuthCodeURL(next))
+ tk := new(oauth2.Token)
+ if err := json.Unmarshal(info.([]byte), tk); err != nil {
+ ctx.Handle(500, "Unmarshal token", err)
return
}
- // handle call back
- tk, err := connect.Exchange(code)
+ ui, err := connect.UserInfo(tk, ctx.Req.URL)
if err != nil {
- ctx.Handle(500, "social.SocialSignIn(Exchange)", err)
+ ctx.Handle(500, fmt.Sprintf("UserInfo(%s)", name), err)
return
}
- next = extractPath(ctx.Query("state"))
- log.Trace("social.SocialSignIn(Got token)")
-
- ui, err := connect.UserInfo(tk, ctx.Req.URL)
- if err != nil {
- ctx.Handle(500, fmt.Sprintf("social.SocialSignIn(get info from %s)", name), err)
+ if len(ui.Identity) == 0 {
+ ctx.Handle(404, "no identity is presented", errors.New(name))
return
}
log.Info("social.SocialSignIn(social login): %s", ui)
diff --git a/templates/.VERSION b/templates/.VERSION
index d244b039..c4127c31 100644
--- a/templates/.VERSION
+++ b/templates/.VERSION
@@ -1 +1 @@
-0.5.8.1125 Beta \ No newline at end of file
+0.5.8.1128 Beta \ No newline at end of file
diff --git a/templates/admin/repo/list.tmpl b/templates/admin/repo/list.tmpl
index 276fdff8..3a201fea 100644
--- a/templates/admin/repo/list.tmpl
+++ b/templates/admin/repo/list.tmpl
@@ -35,8 +35,8 @@
<td><a href="{{AppSubUrl}}/{{.Owner.Name}}/{{.Name}}">{{.Name}}</a></td>
<td><i class="fa fa{{if .IsPrivate}}-check{{end}}-square-o"></i></td>
<td>{{.NumWatches}}</td>
- <td>{{.NumIssues}}</td>
<td>{{.NumStars}}</td>
+ <td>{{.NumIssues}}</td>
<td>{{DateFormat .Created "M d, Y"}}</td>
</tr>
{{end}}
@@ -57,4 +57,4 @@
</div>
</div>
</div>
-{{template "ng/base/footer" .}} \ No newline at end of file
+{{template "ng/base/footer" .}}
diff --git a/templates/ng/base/social.tmpl b/templates/ng/base/social.tmpl
index 2d4acd28..277b54fc 100644
--- a/templates/ng/base/social.tmpl
+++ b/templates/ng/base/social.tmpl
@@ -1,4 +1,4 @@
-{{if .OauthService.GitHub}}<a class="btn github" href="{{AppSubUrl}}/user/login/github?next=/user/sign_up"><i class="fa fa-github"></i>GitHub</a>{{end}}
-{{if .OauthService.Google}}<a class="btn google" href="{{AppSubUrl}}/user/login/google?next=/user/sign_up"><i class="fa fa-google"></i>Google +</a>{{end}}
-{{if .OauthService.Weibo}}<a class="btn weibo" href="{{AppSubUrl}}/user/login/weibo?next=/user/sign_up"><i class="fa fa-weibo"></i>新浪微博</a>{{end}}
-{{if .OauthService.Tencent}}<a class="btn qq" href="{{AppSubUrl}}/user/login/qq?next=/user/sign_up"><i class="fa fa-qq"></i>腾讯 QQ&nbsp;</a>{{end}} \ No newline at end of file
+{{if .OauthService.GitHub}}<a class="btn github" href="{{AppSubUrl}}/user/login/oauth2/github?next={{AppSubUrl}}/user/info/github"><i class="fa fa-github"></i>GitHub</a>{{end}}
+{{if .OauthService.Google}}<a class="btn google" href="{{AppSubUrl}}/user/login/oauth2/google?next={{AppSubUrl}}/user/info/google"><i class="fa fa-google"></i>Google +</a>{{end}}
+{{if .OauthService.Weibo}}<a class="btn weibo" href="{{AppSubUrl}}/user/login/oauth2/weibo?next={{AppSubUrl}}/user/info/weibo"><i class="fa fa-weibo"></i>新浪微博</a>{{end}}
+{{if .OauthService.Tencent}}<a class="btn qq" href="{{AppSubUrl}}/user/login/oauth2/qq?next={{AppSubUrl}}/user/info/qq"><i class="fa fa-qq"></i>腾讯 QQ&nbsp;</a>{{end}} \ No newline at end of file
diff --git a/templates/repo/issue/list.tmpl b/templates/repo/issue/list.tmpl
index 0f9daae9..db2d0752 100644
--- a/templates/repo/issue/list.tmpl
+++ b/templates/repo/issue/list.tmpl
@@ -85,7 +85,7 @@
</h5>
<p class="info">
<span class="author"><img class="avatar" src="{{.Poster.AvatarLink}}" alt="" width="20"/>
- <a href="{{AppSubUrl}}/user/{{.Poster.Name}}">{{.Poster.Name}}</a></span>
+ <a href="{{AppSubUrl}}/{{.Poster.Name}}">{{.Poster.Name}}</a></span>
<span class="time">{{TimeSince .Created $.Lang}}</span>
<span class="comment"><i class="fa fa-comments"></i> {{.NumComments}}</span>
</p>
diff --git a/templates/repo/issue/view.tmpl b/templates/repo/issue/view.tmpl
index 68bc047b..738e0c34 100644
--- a/templates/repo/issue/view.tmpl
+++ b/templates/repo/issue/view.tmpl
@@ -8,7 +8,7 @@
<div class="issue-wrap col-md-10">
<div class="issue-head clearfix">
<div class="number pull-right">#{{.Issue.Index}}</div>
- <a class="author pull-left" href="{{AppSubUrl}}/user/{{.Issue.Poster.Name}}"><img class="avatar" src="{{.Issue.Poster.AvatarLink}}" alt="" width="30"/></a>
+ <a class="author pull-left" href="{{AppSubUrl}}/{{.Issue.Poster.Name}}"><img class="avatar" src="{{.Issue.Poster.AvatarLink}}" alt="" width="30"/></a>
<h1 class="title pull-left">{{.Issue.Name}}</h1>
<input id="issue-edit-title" class="form-control input-lg pull-left hidden" type="text" value="{{.Issue.Name}}" data-ajax-rel="issue-edit-save" data-ajax-val="val" data-ajax-field="title"/>
<input type="hidden" value="{{.Issue.Id}}" data-ajax-rel="issue-edit-save" data-ajax-val="val" data-ajax-field="issue_id"/>
@@ -17,7 +17,7 @@
<a class="btn btn-danger pull-right issue-edit-cancel hidden" href="#">Cancel</a>
<a class="btn btn-primary pull-right issue-edit-save hidden" href="#" data-ajax="{{.RepoLink}}/issues/{{.Issue.Index}}" data-ajax-name="issue-edit-save" data-ajax-method="post">Save</a>{{end}}
<span class="status label label-{{if .Issue.IsClosed}}danger{{else}}success{{end}}">{{if .Issue.IsClosed}}Closed{{else}}Open{{end}}</span>
- <a href="{{AppSubUrl}}/user/{{.Issue.Poster.Name}}" class="author"><strong>{{.Issue.Poster.Name}}</strong></a> opened this issue
+ <a href="{{AppSubUrl}}/{{.Issue.Poster.Name}}" class="author"><strong>{{.Issue.Poster.Name}}</strong></a> opened this issue
<span class="time">{{TimeSince .Issue.Created $.Lang}}</span> · {{.Issue.NumComments}} comments
</p>
</div>
@@ -63,10 +63,10 @@
{{/* 0 = COMMENT, 1 = REOPEN, 2 = CLOSE, 3 = ISSUE, 4 = COMMIT, 5 = PULL */}}
{{if eq .Type 0}}
<div class="issue-child" id="issue-comment-{{.Id}}">
- <a class="user pull-left" href="{{AppSubUrl}}/user/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a>
+ <a class="user pull-left" href="{{AppSubUrl}}/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a>
<div class="issue-content panel panel-default">
<div class="panel-heading">
- <a href="{{AppSubUrl}}/user/{{.Poster.Name}}" class="user">{{.Poster.Name}}</a> commented <span class="time">{{TimeSince .Created $.Lang}}</span>
+ <a href="{{AppSubUrl}}/{{.Poster.Name}}" class="user">{{.Poster.Name}}</a> commented <span class="time">{{TimeSince .Created $.Lang}}</span>
<!-- <a class="issue-comment-del pull-right issue-action" href="#" title="Edit Comment"><i class="fa fa-times-circle"></i></a>
<a class="issue-comment-edit pull-right issue-action" href="#" title="Remove Comment" data-url="{remove-link}"><i class="fa fa-edit"></i></a> -->
<span class="role label label-default pull-right">Owner</span>
@@ -93,25 +93,25 @@
</div>
{{else if eq .Type 1}}
<div class="issue-child issue-opened">
- <a class="user pull-left" href="{{AppSubUrl}}/user/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt="" /></a>
+ <a class="user pull-left" href="{{AppSubUrl}}/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt="" /></a>
<div class="issue-content">
- <a class="user pull-left" href="{{AppSubUrl}}/user/{{.Poster.Name}}">{{.Poster.Name}}</a> <span class="label label-success">Reopened</span> this issue <span class="time">{{TimeSince .Created $.Lang}}</span>
+ <a class="user pull-left" href="{{AppSubUrl}}/{{.Poster.Name}}">{{.Poster.Name}}</a> <span class="label label-success">Reopened</span> this issue <span class="time">{{TimeSince .Created $.Lang}}</span>
</div>
</div>
{{else if eq .Type 2}}
<div class="issue-child issue-closed">
- <a class="user pull-left" href="{{AppSubUrl}}/user/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a>
+ <a class="user pull-left" href="{{AppSubUrl}}/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a>
<div class="issue-content">
- <a class="user pull-left" href="{{AppSubUrl}}/user/{{.Poster.Name}}">{{.Poster.Name}}</a> <span class="label label-danger">Closed</span> this issue <span class="time">{{TimeSince .Created $.Lang}}</span>
+ <a class="user pull-left" href="{{AppSubUrl}}/{{.Poster.Name}}">{{.Poster.Name}}</a> <span class="label label-danger">Closed</span> this issue <span class="time">{{TimeSince .Created $.Lang}}</span>
</div>
</div>
{{else if eq .Type 4}}
<div class="issue-child issue-reference issue-reference-commit">
- <a class="user pull-left" href="{{AppSubUrl}}/user/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a>
+ <a class="user pull-left" href="{{AppSubUrl}}/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a>
<div class="issue-content">
- <a class="user pull-left" href="{{AppSubUrl}}/user/{{.Poster.Name}}">{{.Poster.Name}}</a> <span class="label label-primary">Referenced</span> this issue <span class="time">{{TimeSince .Created $.Lang}}</span>
+ <a class="user pull-left" href="{{AppSubUrl}}/{{.Poster.Name}}">{{.Poster.Name}}</a> <span class="label label-primary">Referenced</span> this issue <span class="time">{{TimeSince .Created $.Lang}}</span>
<p>
- <a class="user pull-left" href="{{AppSubUrl}}/user/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a>
+ <a class="user pull-left" href="{{AppSubUrl}}/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a>
{{.ContentHtml}}
</p>
</div>
@@ -120,7 +120,7 @@
{{end}}
<hr class="issue-line"/>
{{if .SignedUser}}<div class="issue-child issue-reply">
- <a class="user pull-left" href="{{AppSubUrl}}/user/{{.SignedUser.Name}}"><img class="avatar" src="{{.SignedUser.AvatarLink}}" alt=""/></a>
+ <a class="user pull-left" href="{{AppSubUrl}}/{{.SignedUser.Name}}"><img class="avatar" src="{{.SignedUser.AvatarLink}}" alt=""/></a>
<form class="panel panel-default issue-content" action="{{.RepoLink}}/comment/new" method="post" enctype="multipart/form-data">
{{.CsrfTokenHtml}}
<div class="panel-body">
diff --git a/templates/repo/release/list.tmpl b/templates/repo/release/list.tmpl
index 1eb11fc5..b3e3db95 100644
--- a/templates/repo/release/list.tmpl
+++ b/templates/repo/release/list.tmpl
@@ -28,7 +28,7 @@
<h4 class="title"><a href="{{$.RepoLink}}/src/{{.TagName}}">{{.Title}}</a> <small>(<a href="{{$.RepoLink}}/releases/edit/{{.TagName}}" rel="nofollow">edit</a>)</small></h4>
<p class="info">
<span class="author"><img class="avatar" src="{{.Publisher.AvatarLink}}" alt="" width="20">&nbsp;&nbsp;
- <a href="{{AppSubUrl}}/user/{{.Publisher.Name}}">{{.Publisher.Name}}</a></span>
+ <a href="{{AppSubUrl}}/{{.Publisher.Name}}">{{.Publisher.Name}}</a></span>
{{if .Created}}<span class="time">{{TimeSince .Created $.Lang}}</span>{{end}}
<span class="ahead"><strong>{{.NumCommitsBehind}}</strong> commits to {{.Target}} since this release</span>
</p>
diff --git a/templates/user/auth/signin.tmpl b/templates/user/auth/signin.tmpl
index 54748077..78d6febb 100644
--- a/templates/user/auth/signin.tmpl
+++ b/templates/user/auth/signin.tmpl
@@ -26,18 +26,16 @@
<button class="btn btn-green btn-large btn-radius">{{.i18n.Tr "sign_in"}}</button>&nbsp;&nbsp;&nbsp;&nbsp;
{{if not .IsSocialLogin}}<a href="{{AppSubUrl}}/user/forget_password">{{.i18n.Tr "auth.forget_password"}}</a>{{end}}
</div>
- {{if not .IsSocialLogin}}
<div class="field">
<label></label>
<a href="{{AppSubUrl}}/user/sign_up">{{.i18n.Tr "auth.sign_up_now" | Str2html}}</a>
</div>
- {{if .OauthEnabled}}
+ {{if and (not .IsSocialLogin) .OauthEnabled}}
<hr/>
<div id="sign-social" class="text-center social-buttons">
{{template "ng/base/social" .}}
</div>
{{end}}
- {{end}}
</div>
</form>
</div>
diff --git a/templates/user/issues.tmpl b/templates/user/issues.tmpl
index 45492039..bb81d4fa 100644
--- a/templates/user/issues.tmpl
+++ b/templates/user/issues.tmpl
@@ -40,7 +40,7 @@
<h5 class="title"><a href="{{AppSubUrl}}/{{.Repo.Owner.Name}}/{{.Repo.Name}}/issues/{{.Index}}">{{.Name}}</a></h5>
<p class="info">
<span class="author"><img class="avatar" src="{{.Poster.AvatarLink}}" alt="" width="20"/>
- <a href="{{AppSubUrl}}/user/{{.Poster.Name}}">{{.Poster.Name}}</a></span>
+ <a href="{{AppSubUrl}}/{{.Poster.Name}}">{{.Poster.Name}}</a></span>
<span class="time">{{TimeSince .Created $.Lang}}</span>
<span class="comment"><i class="fa fa-comments"></i> {{.NumComments}}</span>
</p>
diff --git a/templates/user/settings/profile.tmpl b/templates/user/settings/profile.tmpl
index 827586fa..febf5237 100644
--- a/templates/user/settings/profile.tmpl
+++ b/templates/user/settings/profile.tmpl
@@ -47,7 +47,7 @@
<input class="ipt ipt-large ipt-radius {{if .Err_Location}}ipt-error{{end}}" id="location" name="location" type="text" value="{{.SignedUser.Location}}" />
</div>
<div class="field">
- <label for="gravatar-email">Gravatar {{.i18n.Tr "email"}}</label>
+ <label class="req" for="gravatar-email">Gravatar {{.i18n.Tr "email"}}</label>
<input class="ipt ipt-large ipt-radius {{if .Err_Avatar}}ipt-error{{end}}" id="gravatar-email" name="avatar" type="text" value="{{.SignedUser.AvatarEmail}}" />
</div>
<div class="field">