Merge branch 'master' of github.com:gogits/gogs into dev
Conflicts: web.go
This commit is contained in:
commit
94c7278194
44 changed files with 1084 additions and 413 deletions
|
@ -13,6 +13,6 @@ func Markdown(ctx *middleware.Context) {
|
|||
content := ctx.Query("content")
|
||||
ctx.Render.JSON(200, map[string]interface{}{
|
||||
"ok": true,
|
||||
"content": string(base.RenderMarkdown([]byte(content), "")),
|
||||
"content": string(base.RenderMarkdown([]byte(content), ctx.Query("repoLink"))),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -6,13 +6,13 @@ package routers
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/Unknwon/goconfig"
|
||||
"github.com/go-martini/martini"
|
||||
"github.com/lunny/xorm"
|
||||
qlog "github.com/qiniu/log"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/auth"
|
||||
|
@ -43,8 +43,7 @@ func GlobalInit() {
|
|||
|
||||
if base.InstallLock {
|
||||
if err := models.NewEngine(); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(2)
|
||||
qlog.Fatal(err)
|
||||
}
|
||||
|
||||
models.HasEngine = true
|
||||
|
@ -183,6 +182,7 @@ func Install(ctx *middleware.Context, form auth.InstallForm) {
|
|||
if _, err := models.RegisterUser(&models.User{Name: form.AdminName, Email: form.AdminEmail, Passwd: form.AdminPasswd,
|
||||
IsAdmin: true, IsActive: true}); err != nil {
|
||||
if err != models.ErrUserAlreadyExist {
|
||||
base.InstallLock = false
|
||||
ctx.RenderWithErr("Admin account setting is invalid: "+err.Error(), "install", &form)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -135,10 +135,11 @@ type route struct {
|
|||
}
|
||||
|
||||
type Config struct {
|
||||
ReposRoot string
|
||||
GitBinPath string
|
||||
UploadPack bool
|
||||
ReceivePack bool
|
||||
ReposRoot string
|
||||
GitBinPath string
|
||||
UploadPack bool
|
||||
ReceivePack bool
|
||||
OnPushSucceed func()
|
||||
}
|
||||
|
||||
type handler struct {
|
||||
|
@ -223,21 +224,26 @@ func serviceRpc(rpc string, hr handler) {
|
|||
in, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return
|
||||
}
|
||||
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return
|
||||
}
|
||||
|
||||
err = cmd.Start()
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return
|
||||
}
|
||||
|
||||
in.Write(input)
|
||||
io.Copy(w, stdout)
|
||||
cmd.Wait()
|
||||
|
||||
hr.Config.OnPushSucceed()
|
||||
}
|
||||
|
||||
func getInfoRefs(hr handler) {
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-martini/martini"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
|
@ -99,7 +100,7 @@ func CreateIssue(ctx *middleware.Context, params martini.Params, form auth.Creat
|
|||
issue, err := models.CreateIssue(ctx.User.Id, ctx.Repo.Repository.Id, form.MilestoneId, form.AssigneeId,
|
||||
ctx.Repo.Repository.NumIssues, form.IssueName, form.Labels, form.Content, false)
|
||||
if err != nil {
|
||||
ctx.Handle(200, "issue.CreateIssue", err)
|
||||
ctx.Handle(200, "issue.CreateIssue(CreateIssue)", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -107,14 +108,31 @@ func CreateIssue(ctx *middleware.Context, params martini.Params, form auth.Creat
|
|||
if err = models.NotifyWatchers(&models.Action{ActUserId: ctx.User.Id, ActUserName: ctx.User.Name, ActEmail: ctx.User.Email,
|
||||
OpType: models.OP_CREATE_ISSUE, Content: fmt.Sprintf("%d|%s", issue.Index, issue.Name),
|
||||
RepoId: ctx.Repo.Repository.Id, RepoName: ctx.Repo.Repository.Name, RefName: ""}); err != nil {
|
||||
ctx.Handle(200, "issue.CreateIssue", err)
|
||||
ctx.Handle(200, "issue.CreateIssue(NotifyWatchers)", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Mail watchers.
|
||||
// Mail watchers and mentions.
|
||||
if base.Service.NotifyMail {
|
||||
if err = mailer.SendNotifyMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue); err != nil {
|
||||
ctx.Handle(200, "issue.CreateIssue", err)
|
||||
tos, err := mailer.SendIssueNotifyMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository, issue)
|
||||
if err != nil {
|
||||
ctx.Handle(200, "issue.CreateIssue(SendIssueNotifyMail)", err)
|
||||
return
|
||||
}
|
||||
|
||||
tos = append(tos, ctx.User.LowerName)
|
||||
ms := base.MentionPattern.FindAllString(issue.Content, -1)
|
||||
newTos := make([]string, 0, len(ms))
|
||||
for _, m := range ms {
|
||||
if com.IsSliceContainsStr(tos, m[1:]) {
|
||||
continue
|
||||
}
|
||||
|
||||
newTos = append(newTos, m[1:])
|
||||
}
|
||||
if err = mailer.SendIssueMentionMail(ctx.User, ctx.Repo.Owner, ctx.Repo.Repository,
|
||||
issue, models.GetUserEmailsByNames(newTos)); err != nil {
|
||||
ctx.Handle(200, "issue.CreateIssue(SendIssueMentionMail)", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -147,7 +165,7 @@ func ViewIssue(ctx *middleware.Context, params martini.Params) {
|
|||
return
|
||||
}
|
||||
issue.Poster = u
|
||||
issue.RenderedContent = string(base.RenderMarkdown([]byte(issue.Content), ""))
|
||||
issue.RenderedContent = string(base.RenderMarkdown([]byte(issue.Content), ctx.Repo.RepoLink))
|
||||
|
||||
// Get comments.
|
||||
comments, err := models.GetIssueComments(issue.Id)
|
||||
|
@ -164,7 +182,7 @@ func ViewIssue(ctx *middleware.Context, params martini.Params) {
|
|||
return
|
||||
}
|
||||
comments[i].Poster = u
|
||||
comments[i].Content = string(base.RenderMarkdown([]byte(comments[i].Content), ""))
|
||||
comments[i].Content = string(base.RenderMarkdown([]byte(comments[i].Content), ctx.Repo.RepoLink))
|
||||
}
|
||||
|
||||
ctx.Data["Title"] = issue.Name
|
||||
|
@ -193,7 +211,7 @@ func UpdateIssue(ctx *middleware.Context, params martini.Params, form auth.Creat
|
|||
return
|
||||
}
|
||||
|
||||
if ctx.User.Id != issue.PosterId {
|
||||
if ctx.User.Id != issue.PosterId && !ctx.Repo.IsOwner {
|
||||
ctx.Handle(404, "issue.UpdateIssue", nil)
|
||||
return
|
||||
}
|
||||
|
@ -211,7 +229,7 @@ func UpdateIssue(ctx *middleware.Context, params martini.Params, form auth.Creat
|
|||
ctx.JSON(200, map[string]interface{}{
|
||||
"ok": true,
|
||||
"title": issue.Name,
|
||||
"content": string(base.RenderMarkdown([]byte(issue.Content), "")),
|
||||
"content": string(base.RenderMarkdown([]byte(issue.Content), ctx.Repo.RepoLink)),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
func Releases(ctx *middleware.Context) {
|
||||
ctx.Data["Title"] = "Releases"
|
||||
ctx.Data["IsRepoToolbarReleases"] = true
|
||||
ctx.Data["IsRepoReleaseNew"] = false
|
||||
tags, err := models.GetTags(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
|
||||
if err != nil {
|
||||
ctx.Handle(404, "repo.Releases(GetTags)", err)
|
||||
|
@ -20,3 +21,10 @@ func Releases(ctx *middleware.Context) {
|
|||
ctx.Data["Releases"] = tags
|
||||
ctx.HTML(200, "release/list")
|
||||
}
|
||||
|
||||
func ReleasesNew(ctx *middleware.Context) {
|
||||
ctx.Data["Title"] = "New Release"
|
||||
ctx.Data["IsRepoToolbarReleases"] = true
|
||||
ctx.Data["IsRepoReleaseNew"] = true
|
||||
ctx.HTML(200, "release/new")
|
||||
}
|
||||
|
|
|
@ -73,11 +73,7 @@ func SettingPassword(ctx *middleware.Context, form auth.UpdatePasswdForm) {
|
|||
|
||||
user := ctx.User
|
||||
newUser := &models.User{Passwd: form.NewPasswd}
|
||||
if err := newUser.EncodePasswd(); err != nil {
|
||||
ctx.Handle(200, "setting.SettingPassword", err)
|
||||
return
|
||||
}
|
||||
|
||||
newUser.EncodePasswd()
|
||||
if user.Passwd != newUser.Passwd {
|
||||
ctx.Data["HasError"] = true
|
||||
ctx.Data["ErrorMsg"] = "Old password is not correct"
|
||||
|
@ -85,6 +81,7 @@ func SettingPassword(ctx *middleware.Context, form auth.UpdatePasswdForm) {
|
|||
ctx.Data["HasError"] = true
|
||||
ctx.Data["ErrorMsg"] = "New password and re-type password are not same"
|
||||
} else {
|
||||
newUser.Salt = models.GetUserSalt()
|
||||
user.Passwd = newUser.Passwd
|
||||
if err := models.UpdateUser(user); err != nil {
|
||||
ctx.Handle(200, "setting.SettingPassword", err)
|
||||
|
|
|
@ -1,49 +1,122 @@
|
|||
// Copyright 2014 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 user
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
|
||||
"code.google.com/p/goauth2/oauth"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/middleware"
|
||||
"github.com/gogits/gogs/modules/oauth2"
|
||||
)
|
||||
|
||||
// github && google && ...
|
||||
func SocialSignIn(tokens oauth2.Tokens) {
|
||||
transport := &oauth.Transport{}
|
||||
transport.Token = &oauth.Token{
|
||||
AccessToken: tokens.Access(),
|
||||
RefreshToken: tokens.Refresh(),
|
||||
Expiry: tokens.ExpiryTime(),
|
||||
Extra: tokens.ExtraData(),
|
||||
}
|
||||
type SocialConnector interface {
|
||||
Identity() string
|
||||
Type() int
|
||||
Name() string
|
||||
Email() string
|
||||
Token() string
|
||||
}
|
||||
|
||||
// Github API refer: https://developer.github.com/v3/users/
|
||||
// FIXME: need to judge url
|
||||
type GithubUser struct {
|
||||
type SocialGithub struct {
|
||||
data struct {
|
||||
Id int `json:"id"`
|
||||
Name string `json:"login"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
WebToken *oauth.Token
|
||||
}
|
||||
|
||||
// Make the request.
|
||||
func (s *SocialGithub) Identity() string {
|
||||
return strconv.Itoa(s.data.Id)
|
||||
}
|
||||
|
||||
func (s *SocialGithub) Type() int {
|
||||
return models.OT_GITHUB
|
||||
}
|
||||
|
||||
func (s *SocialGithub) Name() string {
|
||||
return s.data.Name
|
||||
}
|
||||
|
||||
func (s *SocialGithub) Email() string {
|
||||
return s.data.Email
|
||||
}
|
||||
|
||||
func (s *SocialGithub) Token() string {
|
||||
data, _ := json.Marshal(s.WebToken)
|
||||
return string(data)
|
||||
}
|
||||
|
||||
// Github API refer: https://developer.github.com/v3/users/
|
||||
func (s *SocialGithub) Update() error {
|
||||
scope := "https://api.github.com/user"
|
||||
transport := &oauth.Transport{
|
||||
Token: s.WebToken,
|
||||
}
|
||||
log.Debug("update github info")
|
||||
r, err := transport.Client().Get(scope)
|
||||
if err != nil {
|
||||
log.Error("connect with github error: %s", err)
|
||||
// FIXME: handle error page
|
||||
return
|
||||
return err
|
||||
}
|
||||
defer r.Body.Close()
|
||||
|
||||
user := &GithubUser{}
|
||||
err = json.NewDecoder(r.Body).Decode(user)
|
||||
if err != nil {
|
||||
log.Error("Get: %s", err)
|
||||
}
|
||||
log.Info("login: %s", user.Name)
|
||||
// FIXME: login here, user email to check auth, if not registe, then generate a uniq username
|
||||
return json.NewDecoder(r.Body).Decode(&s.data)
|
||||
}
|
||||
|
||||
// github && google && ...
|
||||
func SocialSignIn(ctx *middleware.Context, tokens oauth2.Tokens) {
|
||||
gh := &SocialGithub{
|
||||
WebToken: &oauth.Token{
|
||||
AccessToken: tokens.Access(),
|
||||
RefreshToken: tokens.Refresh(),
|
||||
Expiry: tokens.ExpiryTime(),
|
||||
Extra: tokens.ExtraData(),
|
||||
},
|
||||
}
|
||||
if len(tokens.Access()) == 0 {
|
||||
log.Error("empty access")
|
||||
return
|
||||
}
|
||||
var err error
|
||||
var u *models.User
|
||||
if err = gh.Update(); err != nil {
|
||||
// FIXME: handle error page
|
||||
log.Error("connect with github error: %s", err)
|
||||
return
|
||||
}
|
||||
var soc SocialConnector = gh
|
||||
log.Info("login: %s", soc.Name())
|
||||
// FIXME: login here, user email to check auth, if not registe, then generate a uniq username
|
||||
if u, err = models.GetOauth2User(soc.Identity()); err != nil {
|
||||
u = &models.User{
|
||||
Name: soc.Name(),
|
||||
Email: soc.Email(),
|
||||
Passwd: "123456",
|
||||
IsActive: !base.Service.RegisterEmailConfirm,
|
||||
}
|
||||
if u, err = models.RegisterUser(u); err != nil {
|
||||
log.Error("register user: %v", err)
|
||||
return
|
||||
}
|
||||
oa := &models.Oauth2{}
|
||||
oa.Uid = u.Id
|
||||
oa.Type = soc.Type()
|
||||
oa.Token = soc.Token()
|
||||
oa.Identity = soc.Identity()
|
||||
log.Info("oa: %v", oa)
|
||||
if err = models.AddOauth2(oa); err != nil {
|
||||
log.Error("add oauth2 %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
ctx.Session.Set("userId", u.Id)
|
||||
ctx.Session.Set("userName", u.Name)
|
||||
ctx.Redirect("/")
|
||||
}
|
||||
|
|
|
@ -78,6 +78,11 @@ func SignIn(ctx *middleware.Context, form auth.LogInForm) {
|
|||
ctx.Data["Title"] = "Log In"
|
||||
|
||||
if ctx.Req.Method == "GET" {
|
||||
if base.OauthService != nil {
|
||||
ctx.Data["OauthEnabled"] = true
|
||||
ctx.Data["OauthGitHubEnabled"] = base.OauthService.GitHub.Enabled
|
||||
}
|
||||
|
||||
// Check auto-login.
|
||||
userName := ctx.GetCookie(base.CookieUserName)
|
||||
if len(userName) == 0 {
|
||||
|
@ -403,9 +408,12 @@ func Activate(ctx *middleware.Context) {
|
|||
if user := models.VerifyUserActiveCode(code); user != nil {
|
||||
user.IsActive = true
|
||||
user.Rands = models.GetUserSalt()
|
||||
models.UpdateUser(user)
|
||||
if err := models.UpdateUser(user); err != nil {
|
||||
ctx.Handle(404, "user.Activate", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Trace("%s User activated: %s", ctx.Req.RequestURI, user.LowerName)
|
||||
log.Trace("%s User activated: %s", ctx.Req.RequestURI, user.Name)
|
||||
|
||||
ctx.Session.Set("userId", user.Id)
|
||||
ctx.Session.Set("userName", user.Name)
|
||||
|
@ -416,3 +424,77 @@ func Activate(ctx *middleware.Context) {
|
|||
ctx.Data["IsActivateFailed"] = true
|
||||
ctx.HTML(200, "user/active")
|
||||
}
|
||||
|
||||
func ForgotPasswd(ctx *middleware.Context) {
|
||||
ctx.Data["Title"] = "Forgot Password"
|
||||
|
||||
if base.MailService == nil {
|
||||
ctx.Data["IsResetDisable"] = true
|
||||
ctx.HTML(200, "user/forgot_passwd")
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["IsResetRequest"] = true
|
||||
if ctx.Req.Method == "GET" {
|
||||
ctx.HTML(200, "user/forgot_passwd")
|
||||
return
|
||||
}
|
||||
|
||||
email := ctx.Query("email")
|
||||
u, err := models.GetUserByEmail(email)
|
||||
if err != nil {
|
||||
if err == models.ErrUserNotExist {
|
||||
ctx.RenderWithErr("This e-mail address does not associate to any account.", "user/forgot_passwd", nil)
|
||||
} else {
|
||||
ctx.Handle(404, "user.ResetPasswd(check existence)", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
mailer.SendResetPasswdMail(ctx.Render, u)
|
||||
ctx.Data["Email"] = email
|
||||
ctx.Data["Hours"] = base.Service.ActiveCodeLives / 60
|
||||
ctx.Data["IsResetSent"] = true
|
||||
ctx.HTML(200, "user/forgot_passwd")
|
||||
}
|
||||
|
||||
func ResetPasswd(ctx *middleware.Context) {
|
||||
code := ctx.Query("code")
|
||||
if len(code) == 0 {
|
||||
ctx.Error(404)
|
||||
return
|
||||
}
|
||||
ctx.Data["Code"] = code
|
||||
|
||||
if ctx.Req.Method == "GET" {
|
||||
ctx.Data["IsResetForm"] = true
|
||||
ctx.HTML(200, "user/reset_passwd")
|
||||
return
|
||||
}
|
||||
|
||||
if u := models.VerifyUserActiveCode(code); u != nil {
|
||||
// Validate password length.
|
||||
passwd := ctx.Query("passwd")
|
||||
if len(passwd) < 6 || len(passwd) > 30 {
|
||||
ctx.Data["IsResetForm"] = true
|
||||
ctx.RenderWithErr("Password length should be in 6 and 30.", "user/reset_passwd", nil)
|
||||
return
|
||||
}
|
||||
|
||||
u.Passwd = passwd
|
||||
u.Rands = models.GetUserSalt()
|
||||
u.Salt = models.GetUserSalt()
|
||||
u.EncodePasswd()
|
||||
if err := models.UpdateUser(u); err != nil {
|
||||
ctx.Handle(404, "user.ResetPasswd(UpdateUser)", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Trace("%s User password reset: %s", ctx.Req.RequestURI, u.Name)
|
||||
ctx.Redirect("/user/login")
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["IsResetFailed"] = true
|
||||
ctx.HTML(200, "user/reset_passwd")
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue