Browse Source

Merge remote-tracking branch 'upstream/master'

pull/146/head
Meaglith Ma 11 years ago
parent
commit
aff9d9039c
  1. 1
      .gitignore
  2. 1
      .gopmfile
  3. 2
      CONTRIBUTING.md
  4. 7
      README.md
  5. 8
      README_ZH.md
  6. 2
      conf/app.ini
  7. 26
      doc/install_gogs_from_binary_on_ubuntu.md
  8. 48
      doc/install_gogs_from_source_on_ubuntu.md
  9. 2
      dockerfiles/README.md
  10. 2
      dockerfiles/images/gogits/Dockerfile
  11. 3
      dockerfiles/images/postgres/Dockerfile
  12. 2
      dockerfiles/images/redis/Dockerfile
  13. 2
      gogs.go
  14. 4
      models/issue.go
  15. 38
      models/ldap.go
  16. 14
      models/publickey.go
  17. 43
      models/repo.go
  18. 8
      models/update.go
  19. 19
      models/user.go
  20. 2
      modules/auth/auth.go
  21. 43
      modules/auth/ldap/README.md
  22. 86
      modules/auth/ldap/ldap.go
  23. 1
      modules/base/base_redis.go
  24. 67
      modules/base/conf.go
  25. 10
      modules/base/template.go
  26. 7
      modules/middleware/repo.go
  27. BIN
      public/img/favicon.bak.png
  28. BIN
      public/img/favicon.png
  29. 4
      public/js/app.js
  30. 2
      routers/admin/admin.go
  31. 18
      routers/install.go
  32. 15
      routers/repo/commit.go
  33. 1
      routers/repo/release.go
  34. 1
      routers/repo/repo.go
  35. 9
      routers/user/setting.go
  36. 34
      routers/user/user.go
  37. 3
      serve.go
  38. 4
      templates/admin/config.tmpl
  39. 5
      templates/base/footer.tmpl
  40. 2
      templates/base/head.tmpl
  41. 8
      templates/base/navbar.tmpl
  42. 13
      templates/install.tmpl
  43. 2
      templates/issue/user.tmpl
  44. 36
      templates/release/list.tmpl
  45. 6
      templates/repo/commits.tmpl
  46. 7
      templates/repo/diff.tmpl
  47. 4
      templates/repo/nav.tmpl
  48. 47
      templates/repo/single_file.tmpl
  49. 4
      templates/repo/single_list.tmpl
  50. 2
      templates/user/password.tmpl
  51. 6
      templates/user/profile.tmpl
  52. 2
      templates/user/publickey.tmpl
  53. 4
      templates/user/setting.tmpl
  54. 10
      templates/user/setting_nav.tmpl
  55. 2
      templates/user/signin.tmpl
  56. 9
      tests/.travel.yml
  57. 13
      tests/README.md
  58. 17
      tests/default_test.go
  59. 2
      update.go
  60. 6
      web.go

1
.gitignore vendored

@ -12,6 +12,7 @@ public/img/avatar/
*.o *.o
*.a *.a
*.so *.so
dev
# Folders # Folders
_obj _obj

1
.gopmfile

@ -19,6 +19,7 @@ github.com/lib/pq =
github.com/nfnt/resize = github.com/nfnt/resize =
github.com/qiniu/log = github.com/qiniu/log =
github.com/robfig/cron = github.com/robfig/cron =
github.com/juju2013/goldap =
[res] [res]
include = templates|public|conf include = templates|public|conf

2
CONTRIBUTING.md

@ -10,6 +10,8 @@ Want to hack on Gogs? Awesome! Here are instructions to get you started. They ar
### Pull requests are always welcome ### Pull requests are always welcome
**ALL PULL REQUESTS MUST SEND TO `DEV` BRANCH**
We are always thrilled to receive pull requests, and do our best to process them as fast as possible. Not sure if that typo is worth a pull request? Do it! We will appreciate it. We are always thrilled to receive pull requests, and do our best to process them as fast as possible. Not sure if that typo is worth a pull request? Do it! We will appreciate it.
If your pull request is not accepted on the first try, don't be discouraged! If there's a problem with the implementation, hopefully you received feedback on what to improve. If your pull request is not accepted on the first try, don't be discouraged! If there's a problem with the implementation, hopefully you received feedback on what to improve.

7
README.md

@ -5,7 +5,7 @@ Gogs(Go Git Service) is a Self Hosted Git Service in the Go Programming Language
![Demo](http://gowalker.org/public/gogs_demo.gif) ![Demo](http://gowalker.org/public/gogs_demo.gif)
##### Current version: 0.3.0 Alpha ##### Current version: 0.3.1 Alpha
### NOTICES ### NOTICES
@ -42,6 +42,11 @@ More importantly, Gogs only needs one binary to setup your own project hosting o
- Supports MySQL, PostgreSQL and SQLite3. - Supports MySQL, PostgreSQL and SQLite3.
- Social account login(GitHub, Google, QQ, Weibo) - Social account login(GitHub, Google, QQ, Weibo)
## System Requirements
- A cheap Raspberry Pi is powerful enough to match the minimal requirement.
- 4 CPU Cores and 1GB RAM would be the baseline for teamwork.
## Installation ## Installation
Make sure you install [Prerequirements](https://github.com/gogits/gogs/wiki/Prerequirements) first. Make sure you install [Prerequirements](https://github.com/gogits/gogs/wiki/Prerequirements) first.

8
README_ZH.md

@ -5,7 +5,7 @@ Gogs(Go Git Service) 是一个由 Go 语言编写的自助 Git 托管服务。
![Demo](http://gowalker.org/public/gogs_demo.gif) ![Demo](http://gowalker.org/public/gogs_demo.gif)
##### 当前版本:0.3.0 Alpha ##### 当前版本:0.3.1 Alpha
## 开发目的 ## 开发目的
@ -33,6 +33,12 @@ Gogs 完全使用 Go 语言来实现对 Git 数据的操作,实现 **零** 依
- 支持 MySQL、PostgreSQL 以及 SQLite3 数据库 - 支持 MySQL、PostgreSQL 以及 SQLite3 数据库
- 社交帐号登录(GitHub、Google、QQ、微博) - 社交帐号登录(GitHub、Google、QQ、微博)
## 系统要求
- 最低的系统硬件要求为一个廉价的树莓派
- 如果用于团队项目,建议使用 4 核 CPU 及 1GB 内存
## 安装部署 ## 安装部署
在安装 Gogs 之前,您需要先安装 [基本环境](https://github.com/gogits/gogs/wiki/Prerequirements)。 在安装 Gogs 之前,您需要先安装 [基本环境](https://github.com/gogits/gogs/wiki/Prerequirements)。

2
conf/app.ini

@ -16,6 +16,8 @@ LICENSES = Apache v2 License|GPL v2|MIT License|Affero GPL|Artistic License 2.0|
PROTOCOL = http PROTOCOL = http
DOMAIN = localhost DOMAIN = localhost
ROOT_URL = %(PROTOCOL)s://%(DOMAIN)s:%(HTTP_PORT)s/ ROOT_URL = %(PROTOCOL)s://%(DOMAIN)s:%(HTTP_PORT)s/
; Disable CDN even in "prod" mode
OFFLINE_MODE = false
HTTP_ADDR = HTTP_ADDR =
HTTP_PORT = 3000 HTTP_PORT = 3000
; Generate steps: ; Generate steps:

26
doc/install_gogs_from_binary_on_ubuntu.md

@ -0,0 +1,26 @@
### Binary install gogs on ubuntu 14.04 LTS
### create user and install denpendency
- sudo adduser git
- sudo apt-get update
- sudo apt-get upgrade
- sudo apt-get install git
- sudo apt-get install mysql-server
### create the database
- $mysql -u root -p
- mysql> SET GLOBAL storage_engine = 'InnoDB';
- mysql> CREATE DATABASE gogs CHARACTER SET utf8 COLLATE utf8_bin;
- mysql> GRANT ALL PRIVILEGES ON gogs.* TO 'root'@'localhost' IDENTIFIED BY 'password';
- mysql> FLUSH PRIVILEGES;
- mysql> QUIT
### install the gogs
- mkdir gogs
- cd gogs
- curl -L http://gobuild.io/github.com/gogits/gogs/v0.3.0/linux/amd64 -o v0.3.0.zip
- unzip v0.3.0.zip
- ./start.sh
> The up-to-date binary could be found at
> http://gobuild.io/download/github.com/gogits/gogs

48
doc/install_gogs_from_source_on_ubuntu.md

@ -0,0 +1,48 @@
##Install gogs under ubuntu 14.04 LTS 32bit from source code
###Requirements
- Go Programming Language: Version >= 1.2
- git(bash): Version >= 1.6.6(both server and client)
- MySQL: Version >= 5.1 or PostgreSQL or NOTHING.
### Create the user which will run git
- sudo adduser git
- su git
### Install git and Mysql-server
- sudo apt-get install git
- sudo apt-get install mysql-server
### Create database
- $ mysql -u root -p
- mysql> SET GLOBAL storage_engine = 'InnoDB';
- mysql> CREATE DATABASE gogs CHARACTER SET utf8 COLLATE utf8_bin;
- mysql> GRANT ALL PRIVILEGES ON gogs.* TO 'root'@'localhost' IDENTIFIED BY 'pasword';
- mysql> FLUSH PRIVILEGES;
- mysql> QUIT
### install go from source
- sudo apt-get install build-essential
- sudo apt-get install mercurial
- hg clone -r release https://go.googlecode.com/hg/ /home/git/golang/
- echo export GOROOT=/home/git/golang >>.bashrc
- echo export GOARCH=386 >>.bashrc
- echo export GOOS=linux >>.bashrc
- echo export GOBIN= /home/git/golang/bin >>.bashrc
- echo export GOPATH=$HOME/app/Go >>.bashrc
- echo PATH=${PATH}: /$HOME/golang/bin >>.bashrc
- cd $GOROOT/src
- ./make.bash
### Download and install dependencies
- $ go get -u github.com/gogits/gogs
### Build main program
- $ cd $GOPATH/src/github.com/gogits/gogs
- $ go build
- $ ./start.sh
### At present, you could access gogs from http://localhost:3000

2
dockerfiles/README.md

@ -1,6 +1,6 @@
### Install Gogs With Docker ### Install Gogs With Docker
Deplying gogs in [Docker](http://www.docker.io/) is just as easy as eating a pie, what you do is just open the `dockerfiles/build.sh` file, replace the confis: Deploying gogs in [Docker](http://www.docker.io/) is just as easy as eating a pie, what you do is just open the `dockerfiles/build.sh` file, replace the configs:
``` ```
DB_TYPE="YOUR_DB_TYPE" # type of database, support 'mysql' and 'postgres' DB_TYPE="YOUR_DB_TYPE" # type of database, support 'mysql' and 'postgres'

2
dockerfiles/images/gogits/Dockerfile

@ -13,7 +13,7 @@ ENV GOROOT /usr/local/go
ENV GOPATH /go ENV GOPATH /go
RUN apt-get update && apt-get install --yes --force-yes curl git mercurial zip wget ca-certificates build-essential RUN apt-get update && apt-get install --yes --force-yes curl git mercurial zip wget ca-certificates build-essential
RUN apt-get install -yq vim RUN apt-get install -yq vim sudo
RUN curl -s http://docker.u.qiniudn.com/go1.2.1.src.tar.gz | tar -v -C /usr/local -xz RUN curl -s http://docker.u.qiniudn.com/go1.2.1.src.tar.gz | tar -v -C /usr/local -xz
RUN cd /usr/local/go/src && ./make.bash --no-clean 2>&1 RUN cd /usr/local/go/src && ./make.bash --no-clean 2>&1

3
dockerfiles/images/postgres/Dockerfile

@ -9,7 +9,8 @@ RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys B97B0AFCAA
# Add PostgreSQL's repository. It contains the most recent stable release # Add PostgreSQL's repository. It contains the most recent stable release
# of PostgreSQL, ``9.3``. # of PostgreSQL, ``9.3``.
RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ precise-pgdg main" > /etc/apt/sources.list.d/pgdg.list # See http://apt.postgresql.org/pub/repos/apt/README
RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list
# Update the Ubuntu and PostgreSQL repository indexes # Update the Ubuntu and PostgreSQL repository indexes
RUN apt-get update RUN apt-get update

2
dockerfiles/images/redis/Dockerfile

@ -1,8 +1,6 @@
FROM ubuntu FROM ubuntu
MAINTAINER Meaglith Ma <genedna@gmail.com> (@genedna), Lance Ju <juzhenatpku@gmail.com> (@crystaldust) MAINTAINER Meaglith Ma <genedna@gmail.com> (@genedna), Lance Ju <juzhenatpku@gmail.com> (@crystaldust)
ENV DEBIAN_FRONTEND noninteractive
ENV DEBIAN_FRONTEND noninteractive ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update && apt-get install -y redis-server RUN apt-get update && apt-get install -y redis-server

2
gogs.go

@ -19,7 +19,7 @@ import (
// Test that go1.2 tag above is included in builds. main.go refers to this definition. // Test that go1.2 tag above is included in builds. main.go refers to this definition.
const go12tag = true const go12tag = true
const APP_VER = "0.3.0.0421 Alpha" const APP_VER = "0.3.1.0427 Alpha"
func init() { func init() {
base.AppVer = APP_VER base.AppVer = APP_VER

4
models/issue.go

@ -71,7 +71,7 @@ func CreateIssue(userId, repoId, milestoneId, assigneeId int64, issueCount int,
} }
if err = sess.Commit(); err != nil { if err = sess.Commit(); err != nil {
sess.Rollback() //sess.Rollback()
return nil, err return nil, err
} }
@ -196,7 +196,7 @@ func CreateComment(userId, repoId, issueId, commitId, line int64, cmtType int, c
defer sess.Close() defer sess.Close()
sess.Begin() sess.Begin()
if _, err := orm.Insert(&Comment{PosterId: userId, Type: cmtType, IssueId: issueId, if _, err := sess.Insert(&Comment{PosterId: userId, Type: cmtType, IssueId: issueId,
CommitId: commitId, Line: line, Content: content}); err != nil { CommitId: commitId, Line: line, Content: content}); err != nil {
sess.Rollback() sess.Rollback()
return err return err

38
models/ldap.go

@ -0,0 +1,38 @@
// Copyright github.com/juju2013. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package models
import (
"strings"
"github.com/gogits/gogs/modules/auth/ldap"
"github.com/gogits/gogs/modules/log"
)
// Query if name/passwd can login against the LDAP direcotry pool
// Create a local user if success
// Return the same LoginUserPlain semantic
func LoginUserLdap(name, passwd string) (*User, error) {
mail, logged := ldap.LoginUser(name, passwd)
if !logged {
// user not in LDAP, do nothing
return nil, ErrUserNotExist
}
// fake a local user creation
user := User{
LowerName: strings.ToLower(name),
Name: strings.ToLower(name),
LoginType: 389,
IsActive: true,
Passwd: passwd,
Email: mail}
_, err := RegisterUser(&user)
if err != nil {
log.Debug("LDAP local user %s fond (%s) ", name, err)
}
// simulate local user login
localUser, err2 := GetUserByName(user.Name)
return localUser, err2
}

14
models/publickey.go

@ -77,12 +77,12 @@ func init() {
// PublicKey represents a SSH key of user. // PublicKey represents a SSH key of user.
type PublicKey struct { type PublicKey struct {
Id int64 Id int64
OwnerId int64 `xorm:"unique(s) index not null"` OwnerId int64 `xorm:"UNIQUE(s) INDEX NOT NULL"`
Name string `xorm:"unique(s) not null"` Name string `xorm:"UNIQUE(s) NOT NULL"`
Fingerprint string Fingerprint string
Content string `xorm:"TEXT not null"` Content string `xorm:"TEXT NOT NULL"`
Created time.Time `xorm:"created"` Created time.Time `xorm:"CREATED"`
Updated time.Time `xorm:"updated"` Updated time.Time `xorm:"UPDATED"`
} }
// GenAuthorizedKey returns formatted public key string. // GenAuthorizedKey returns formatted public key string.
@ -107,9 +107,9 @@ func AddPublicKey(key *PublicKey) (err error) {
if err = ioutil.WriteFile(tmpPath, []byte(key.Content), os.ModePerm); err != nil { if err = ioutil.WriteFile(tmpPath, []byte(key.Content), os.ModePerm); err != nil {
return err return err
} }
stdout, _, err := com.ExecCmd("ssh-keygen", "-l", "-f", tmpPath) stdout, stderr, err := com.ExecCmd("ssh-keygen", "-l", "-f", tmpPath)
if err != nil { if err != nil {
return err return errors.New("ssh-keygen -l -f: " + stderr)
} else if len(stdout) < 2 { } else if len(stdout) < 2 {
return errors.New("Not enough output for calculating fingerprint") return errors.New("Not enough output for calculating fingerprint")
} }

43
models/repo.go

@ -47,16 +47,16 @@ func NewRepoContext() {
zip.Verbose = false zip.Verbose = false
// Check if server has basic git setting. // Check if server has basic git setting.
stdout, _, err := com.ExecCmd("git", "config", "--get", "user.name") stdout, stderr, err := com.ExecCmd("git", "config", "--get", "user.name")
if err != nil { if strings.Contains(stderr, "fatal:") {
fmt.Printf("repo.init(fail to get git user.name): %v", err) fmt.Printf("repo.NewRepoContext(fail to get git user.name): %s", stderr)
os.Exit(2) os.Exit(2)
} else if len(stdout) == 0 { } else if err != nil || len(strings.TrimSpace(stdout)) == 0 {
if _, _, err = com.ExecCmd("git", "config", "--global", "user.email", "gogitservice@gmail.com"); err != nil { if _, stderr, err = com.ExecCmd("git", "config", "--global", "user.email", "gogitservice@gmail.com"); err != nil {
fmt.Printf("repo.init(fail to set git user.email): %v", err) fmt.Printf("repo.NewRepoContext(fail to set git user.email): %s", stderr)
os.Exit(2) os.Exit(2)
} else if _, _, err = com.ExecCmd("git", "config", "--global", "user.name", "Gogs"); err != nil { } else if _, stderr, err = com.ExecCmd("git", "config", "--global", "user.name", "Gogs"); err != nil {
fmt.Printf("repo.init(fail to set git user.name): %v", err) fmt.Printf("repo.NewRepoContext(fail to set git user.name): %s", stderr)
os.Exit(2) os.Exit(2)
} }
} }
@ -159,9 +159,7 @@ func MirrorUpdate() {
repoPath := filepath.Join(base.RepoRootPath, m.RepoName+".git") repoPath := filepath.Join(base.RepoRootPath, m.RepoName+".git")
_, stderr, err := com.ExecCmdDir(repoPath, "git", "remote", "update") _, stderr, err := com.ExecCmdDir(repoPath, "git", "remote", "update")
if err != nil { if err != nil {
return err return errors.New("git remote update: " + stderr)
} else if strings.Contains(stderr, "fatal:") {
return errors.New(stderr)
} else if err = git.UnpackRefs(repoPath); err != nil { } else if err = git.UnpackRefs(repoPath); err != nil {
return err return err
} }
@ -177,9 +175,7 @@ func MirrorUpdate() {
func MirrorRepository(repoId int64, userName, repoName, repoPath, url string) error { func MirrorRepository(repoId int64, userName, repoName, repoPath, url string) error {
_, stderr, err := com.ExecCmd("git", "clone", "--mirror", url, repoPath) _, stderr, err := com.ExecCmd("git", "clone", "--mirror", url, repoPath)
if err != nil { if err != nil {
return err return errors.New("git clone --mirror: " + stderr)
} else if strings.Contains(stderr, "fatal:") {
return errors.New(stderr)
} }
if _, err = orm.InsertOne(&Mirror{ if _, err = orm.InsertOne(&Mirror{
@ -219,23 +215,17 @@ func MigrateRepository(user *User, name, desc string, private, mirror bool, url
// Clone from local repository. // Clone from local repository.
_, stderr, err := com.ExecCmd("git", "clone", repoPath, tmpDir) _, stderr, err := com.ExecCmd("git", "clone", repoPath, tmpDir)
if err != nil { if err != nil {
return repo, err
} else if strings.Contains(stderr, "fatal:") {
return repo, errors.New("git clone: " + stderr) return repo, errors.New("git clone: " + stderr)
} }
// Pull data from source. // Pull data from source.
_, stderr, err = com.ExecCmdDir(tmpDir, "git", "pull", url) _, stderr, err = com.ExecCmdDir(tmpDir, "git", "pull", url)
if err != nil { if err != nil {
return repo, err
} else if strings.Contains(stderr, "fatal:") {
return repo, errors.New("git pull: " + stderr) return repo, errors.New("git pull: " + stderr)
} }
// Push data to local repository. // Push data to local repository.
if _, stderr, err = com.ExecCmdDir(tmpDir, "git", "push", "origin", "master"); err != nil { if _, stderr, err = com.ExecCmdDir(tmpDir, "git", "push", "origin", "master"); err != nil {
return repo, err
} else if strings.Contains(stderr, "fatal:") {
return repo, errors.New("git push: " + stderr) return repo, errors.New("git push: " + stderr)
} }
@ -352,7 +342,6 @@ func CreateRepository(user *User, name, desc, lang, license string, private, mir
func extractGitBareZip(repoPath string) error { func extractGitBareZip(repoPath string) error {
z, err := zip.Open("conf/content/git-bare.zip") z, err := zip.Open("conf/content/git-bare.zip")
if err != nil { if err != nil {
fmt.Println("shi?")
return err return err
} }
defer z.Close() defer z.Close()
@ -364,21 +353,14 @@ func extractGitBareZip(repoPath string) error {
func initRepoCommit(tmpPath string, sig *git.Signature) (err error) { func initRepoCommit(tmpPath string, sig *git.Signature) (err error) {
var stderr string var stderr string
if _, stderr, err = com.ExecCmdDir(tmpPath, "git", "add", "--all"); err != nil { if _, stderr, err = com.ExecCmdDir(tmpPath, "git", "add", "--all"); err != nil {
return err
} else if strings.Contains(stderr, "fatal:") {
return errors.New("git add: " + stderr) return errors.New("git add: " + stderr)
} }
if _, stderr, err = com.ExecCmdDir(tmpPath, "git", "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), if _, stderr, err = com.ExecCmdDir(tmpPath, "git", "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email),
"-m", "Init commit"); err != nil { "-m", "Init commit"); err != nil {
return err
} else if strings.Contains(stderr, "fatal:") {
return errors.New("git commit: " + stderr) return errors.New("git commit: " + stderr)
} }
if _, stderr, err = com.ExecCmdDir(tmpPath, "git", "push", "origin", "master"); err != nil { if _, stderr, err = com.ExecCmdDir(tmpPath, "git", "push", "origin", "master"); err != nil {
return err
} else if strings.Contains(stderr, "fatal:") {
return errors.New("git push: " + stderr) return errors.New("git push: " + stderr)
} }
return nil return nil
@ -411,10 +393,11 @@ func initRepository(f string, user *User, repo *Repository, initReadme bool, rep
return err return err
} }
rp := strings.NewReplacer("\\", "/", " ", "\\ ")
// hook/post-update // hook/post-update
if err := createHookUpdate(filepath.Join(repoPath, "hooks", "update"), if err := createHookUpdate(filepath.Join(repoPath, "hooks", "update"),
fmt.Sprintf("#!/usr/bin/env %s\n%s update $1 $2 $3\n", base.ScriptType, fmt.Sprintf("#!/usr/bin/env %s\n%s update $1 $2 $3\n", base.ScriptType,
strings.Replace(appPath, "\\", "/", -1))); err != nil { rp.Replace(appPath))); err != nil {
return err return err
} }
@ -436,8 +419,6 @@ func initRepository(f string, user *User, repo *Repository, initReadme bool, rep
_, stderr, err := com.ExecCmd("git", "clone", repoPath, tmpDir) _, stderr, err := com.ExecCmd("git", "clone", repoPath, tmpDir)
if err != nil { if err != nil {
return err
} else if strings.Contains(stderr, "fatal:") {
return errors.New("git clone: " + stderr) return errors.New("git clone: " + stderr)
} }

8
models/update.go

@ -1,3 +1,7 @@
// 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 models package models
import ( import (
@ -5,9 +9,11 @@ import (
"os/exec" "os/exec"
"strings" "strings"
qlog "github.com/qiniu/log"
"github.com/gogits/git" "github.com/gogits/git"
"github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/base"
qlog "github.com/qiniu/log"
) )
func Update(refName, oldCommitId, newCommitId, userName, repoName string, userId int64) { func Update(refName, oldCommitId, newCommitId, userName, repoName string, userId int64) {

19
models/user.go

@ -125,6 +125,7 @@ func GetUserSalt() string {
// RegisterUser creates record of a new user. // RegisterUser creates record of a new user.
func RegisterUser(user *User) (*User, error) { func RegisterUser(user *User) (*User, error) {
if !IsLegalName(user.Name) { if !IsLegalName(user.Name) {
return nil, ErrUserNameIllegal return nil, ErrUserNameIllegal
} }
@ -409,21 +410,27 @@ func GetUserByEmail(email string) (*User, error) {
} }
// LoginUserPlain validates user by raw user name and password. // LoginUserPlain validates user by raw user name and password.
func LoginUserPlain(name, passwd string) (*User, error) { func LoginUserPlain(uname, passwd string) (*User, error) {
user := User{LowerName: strings.ToLower(name)} var u *User
has, err := orm.Get(&user) if strings.Contains(uname, "@") {
u = &User{Email: uname}
} else {
u = &User{LowerName: strings.ToLower(uname)}
}
has, err := orm.Get(u)
if err != nil { if err != nil {
return nil, err return nil, err
} else if !has { } else if !has {
return nil, ErrUserNotExist return nil, ErrUserNotExist
} }
newUser := &User{Passwd: passwd, Salt: user.Salt} newUser := &User{Passwd: passwd, Salt: u.Salt}
newUser.EncodePasswd() newUser.EncodePasswd()
if user.Passwd != newUser.Passwd { if u.Passwd != newUser.Passwd {
return nil, ErrUserNotExist return nil, ErrUserNotExist
} }
return &user, nil return u, nil
} }
// Follow is connection request for receiving user notifycation. // Follow is connection request for receiving user notifycation.

2
modules/auth/auth.go

@ -57,7 +57,7 @@ func (f *RegisterForm) Validate(errors *base.BindingErrors, req *http.Request, c
} }
type LogInForm struct { type LogInForm struct {
UserName string `form:"username" binding:"Required;AlphaDash;MaxSize(30)"` UserName string `form:"username" binding:"Required;MaxSize(35)"`
Password string `form:"passwd" binding:"Required;MinSize(6);MaxSize(30)"` Password string `form:"passwd" binding:"Required;MinSize(6);MaxSize(30)"`
Remember string `form:"remember"` Remember string `form:"remember"`
} }

43
modules/auth/ldap/README.md

@ -0,0 +1,43 @@
LDAP authentication
===================
## Goal
Authenticat user against LDAP directories
It will bind with the user's login/pasword and query attributs ("mail" for instance) in a pool of directory servers
The first OK wins.
If there's connection error, the server will be disabled and won't be checked again
## Usage
In the [security] section, set
> LDAP_AUTH = true
then for each LDAP source, set
> [LdapSource-someuniquename]
> name=canonicalName
> host=hostname-or-ip
> port=3268 # or regular LDAP port
> # the following settings depend highly how you've configured your AD
> basedn=dc=ACME,dc=COM
> MSADSAFORMAT=%s@ACME.COM
> filter=(&(objectClass=user)(sAMAccountName=%s))
### Limitation
Only tested on an MS 2008R2 DC, using global catalog (TCP/3268)
This MSAD is a mess.
The way how one checks the directory (CN, DN etc...) may be highly depending local custom configuration
### Todo
* Define a timeout per server
* Check servers marked as "Disabled" when they'll come back online
* Find a more flexible way to define filter/MSADSAFORMAT/Attributes etc... maybe text/template ?
* Check OpenLDAP server
* SSL support ?

86
modules/auth/ldap/ldap.go

@ -0,0 +1,86 @@
// Copyright github.com/juju2013. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
// package ldap provide functions & structure to query a LDAP ldap directory
// For now, it's mainly tested again an MS Active Directory service, see README.md for more information
package ldap
import (
"fmt"
"github.com/gogits/gogs/modules/log"
goldap "github.com/juju2013/goldap"
)
// Basic LDAP authentication service
type ldapsource struct {
Name string // canonical name (ie. corporate.ad)
Host string // LDAP host
Port int // port number
BaseDN string // Base DN
Attributes string // Attribut to search
Filter string // Query filter to validate entry
MsAdSAFormat string // in the case of MS AD Simple Authen, the format to use (see: http://msdn.microsoft.com/en-us/library/cc223499.aspx)
Enabled bool // if this source is disabled
}
//Global LDAP directory pool
var (
Authensource []ldapsource
)
// Add a new source (LDAP directory) to the global pool
func AddSource(name string, host string, port int, basedn string, attributes string, filter string, msadsaformat string) {
ldaphost := ldapsource{name, host, port, basedn, attributes, filter, msadsaformat, true}
Authensource = append(Authensource, ldaphost)
}
//LoginUser : try to login an user to LDAP sources, return requested (attribut,true) if ok, ("",false) other wise
//First match wins
//Returns first attribute if exists
func LoginUser(name, passwd string) (a string, r bool) {
r = false
for _, ls := range Authensource {
a, r = ls.searchEntry(name, passwd)
if r {
return
}
}
return
}
// searchEntry : search an LDAP source if an entry (name, passwd) is valide and in the specific filter
func (ls ldapsource) searchEntry(name, passwd string) (string, bool) {
l, err := goldap.Dial("tcp", fmt.Sprintf("%s:%d", ls.Host, ls.Port))
if err != nil {
log.Debug("LDAP Connect error, disabled source %s", ls.Host)
ls.Enabled = false
return "", false
}
defer l.Close()
nx := fmt.Sprintf(ls.MsAdSAFormat, name)
err = l.Bind(nx, passwd)
if err != nil {
log.Debug("LDAP Authan failed for %s, reason: %s", nx, err.Error())
return "", false
}
search := goldap.NewSearchRequest(
ls.BaseDN,
goldap.ScopeWholeSubtree, goldap.NeverDerefAliases, 0, 0, false,
fmt.Sprintf(ls.Filter, name),
[]string{ls.Attributes},
nil)
sr, err := l.Search(search)
if err != nil {
log.Debug("LDAP Authen OK but not in filter %s", name)
return "", false
}
log.Debug("LDAP Authen OK: %s", name)
if len(sr.Entries) > 0 {
r := sr.Entries[0].GetAttributeValue(ls.Attributes)
return r, true
}
return "", true
}

1
modules/base/base_redis.go

@ -4,6 +4,7 @@ package base
import ( import (
_ "github.com/gogits/cache/redis" _ "github.com/gogits/cache/redis"
_ "github.com/gogits/session/redis"
) )
func init() { func init() {

67
modules/base/conf.go

@ -10,6 +10,7 @@ import (
"os/exec" "os/exec"
"path" "path"
"path/filepath" "path/filepath"
"regexp"
"strings" "strings"
"github.com/Unknwon/com" "github.com/Unknwon/com"
@ -19,6 +20,7 @@ import (
"github.com/gogits/cache" "github.com/gogits/cache"
"github.com/gogits/session" "github.com/gogits/session"
"github.com/gogits/gogs/modules/auth/ldap"
"github.com/gogits/gogs/modules/log" "github.com/gogits/gogs/modules/log"
) )
@ -43,14 +45,15 @@ type Oauther struct {
} }
var ( var (
AppVer string AppVer string
AppName string AppName string
AppLogo string AppLogo string
AppUrl string AppUrl string
IsProdMode bool OfflineMode bool
Domain string ProdMode bool
SecretKey string Domain string
RunUser string SecretKey string
RunUser string
RepoRootPath string RepoRootPath string
ScriptType string ScriptType string
@ -83,13 +86,14 @@ var (
) )
var Service struct { var Service struct {
RegisterEmailConfirm bool RegisterEmailConfirm bool
DisableRegistration bool DisableRegistration bool
RequireSignInView bool RequireSignInView bool
EnableCacheAvatar bool EnableCacheAvatar bool
NotifyMail bool NotifyMail bool
ActiveCodeLives int ActiveCodeLives int
ResetPwdCodeLives int ResetPwdCodeLives int
LdapAuth bool
} }
func ExecDir() (string, error) { func ExecDir() (string, error) {
@ -175,6 +179,36 @@ func newLogService() {
log.Info("Log Mode: %s(%s)", strings.Title(LogMode), levelName) log.Info("Log Mode: %s(%s)", strings.Title(LogMode), levelName)
} }
func newLdapService() {
Service.LdapAuth = Cfg.MustBool("security", "LDAP_AUTH", false)
if !Service.LdapAuth {
return
}
nbsrc := 0
for _, v := range Cfg.GetSectionList() {
if matched, _ := regexp.MatchString("(?i)^LDAPSOURCE.*", v); matched {
ldapname := Cfg.MustValue(v, "name", v)
ldaphost := Cfg.MustValue(v, "host")
ldapport := Cfg.MustInt(v, "port", 389)
ldapbasedn := Cfg.MustValue(v, "basedn", "dc=*,dc=*")
ldapattribute := Cfg.MustValue(v, "attribute", "mail")
ldapfilter := Cfg.MustValue(v, "filter", "(*)")
ldapmsadsaformat := Cfg.MustValue(v, "MSADSAFORMAT", "%s")
ldap.AddSource(ldapname, ldaphost, ldapport, ldapbasedn, ldapattribute, ldapfilter, ldapmsadsaformat)
nbsrc++
log.Debug("%s added as LDAP source", ldapname)
}
}
if nbsrc == 0 {
log.Warn("No valide LDAP found, LDAP Authentication NOT enabled")
Service.LdapAuth = false
return
}
log.Info("LDAP Authentication Enabled")
}
func newCacheService() { func newCacheService() {
CacheAdapter = Cfg.MustValue("cache", "ADAPTER", "memory") CacheAdapter = Cfg.MustValue("cache", "ADAPTER", "memory")
if EnableRedis { if EnableRedis {
@ -292,6 +326,7 @@ func NewConfigContext() {
AppLogo = Cfg.MustValue("", "APP_LOGO", "img/favicon.png") AppLogo = Cfg.MustValue("", "APP_LOGO", "img/favicon.png")
AppUrl = Cfg.MustValue("server", "ROOT_URL") AppUrl = Cfg.MustValue("server", "ROOT_URL")
Domain = Cfg.MustValue("server", "DOMAIN") Domain = Cfg.MustValue("server", "DOMAIN")
OfflineMode = Cfg.MustBool("server", "OFFLINE_MODE", false)
SecretKey = Cfg.MustValue("security", "SECRET_KEY") SecretKey = Cfg.MustValue("security", "SECRET_KEY")
InstallLock = Cfg.MustBool("security", "INSTALL_LOCK", false) InstallLock = Cfg.MustBool("security", "INSTALL_LOCK", false)
@ -309,7 +344,6 @@ func NewConfigContext() {
LogInRememberDays = Cfg.MustInt("security", "LOGIN_REMEMBER_DAYS") LogInRememberDays = Cfg.MustInt("security", "LOGIN_REMEMBER_DAYS")
CookieUserName = Cfg.MustValue("security", "COOKIE_USERNAME") CookieUserName = Cfg.MustValue("security", "COOKIE_USERNAME")
CookieRememberName = Cfg.MustValue("security", "COOKIE_REMEMBER_NAME") CookieRememberName = Cfg.MustValue("security", "COOKIE_REMEMBER_NAME")
PictureService = Cfg.MustValue("picture", "SERVICE") PictureService = Cfg.MustValue("picture", "SERVICE")
// Determine and create root git reposiroty path. // Determine and create root git reposiroty path.
@ -327,6 +361,7 @@ func NewConfigContext() {
func NewBaseServices() { func NewBaseServices() {
newService() newService()
newLogService() newLogService()
newLdapService()
newCacheService() newCacheService()
newSessionService() newSessionService()
newMailService() newMailService()

10
modules/base/template.go

@ -56,8 +56,8 @@ var TemplateFuncs template.FuncMap = map[string]interface{}{
"AppDomain": func() string { "AppDomain": func() string {
return Domain return Domain
}, },
"IsProdMode": func() bool { "CdnMode": func() bool {
return IsProdMode return ProdMode && !OfflineMode
}, },
"LoadTimes": func(startTime time.Time) string { "LoadTimes": func(startTime time.Time) string {
return fmt.Sprint(time.Since(startTime).Nanoseconds()/1e6) + "ms" return fmt.Sprint(time.Since(startTime).Nanoseconds()/1e6) + "ms"
@ -124,11 +124,11 @@ func ActionIcon(opType int) string {
const ( const (
TPL_CREATE_REPO = `<a href="/user/%s">%s</a> created repository <a href="/%s">%s</a>` TPL_CREATE_REPO = `<a href="/user/%s">%s</a> created repository <a href="/%s">%s</a>`
TPL_COMMIT_REPO = `<a href="/user/%s">%s</a> pushed to <a href="/%s/src/%s">%s</a> at <a href="/%s">%s</a>%s` TPL_COMMIT_REPO = `<a href="/user/%s">%s</a> pushed to <a href="/%s/src/%s">%s</a> at <a href="/%s">%s</a>%s`
TPL_COMMIT_REPO_LI = `<div><img src="%s?s=16" alt="user-avatar"/> <a href="/%s/commit/%s">%s</a> %s</div>` TPL_COMMIT_REPO_LI = `<div><img src="%s?s=16" alt="user-avatar"/> <a href="/%s/commit/%s" rel="nofollow">%s</a> %s</div>`
TPL_CREATE_ISSUE = `<a href="/user/%s">%s</a> opened issue <a href="/%s/issues/%s">%s#%s</a> TPL_CREATE_ISSUE = `<a href="/user/%s">%s</a> opened issue <a href="/%s/issues/%s">%s#%s</a>
<div><img src="%s?s=16" alt="user-avatar"/> %s</div>` <div><img src="%s?s=16" alt="user-avatar"/> %s</div>`
TPL_TRANSFER_REPO = `<a href="/user/%s">%s</a> transfered repository <code>%s</code> to <a href="/%s">%s</a>` TPL_TRANSFER_REPO = `<a href="/user/%s">%s</a> transfered repository <code>%s</code> to <a href="/%s">%s</a>`
TPL_PUSH_TAG = `<a href="/user/%s">%s</a> pushed tag <a href="/%s/src/%s">%s</a> at <a href="/%s">%s</a>` TPL_PUSH_TAG = `<a href="/user/%s">%s</a> pushed tag <a href="/%s/src/%s" rel="nofollow">%s</a> at <a href="/%s">%s</a>`
) )
type PushCommit struct { type PushCommit struct {
@ -165,7 +165,7 @@ func ActionDesc(act Actioner) string {
buf.WriteString(fmt.Sprintf(TPL_COMMIT_REPO_LI, AvatarLink(commit.AuthorEmail), repoLink, commit.Sha1, commit.Sha1[:7], commit.Message) + "\n") buf.WriteString(fmt.Sprintf(TPL_COMMIT_REPO_LI, AvatarLink(commit.AuthorEmail), repoLink, commit.Sha1, commit.Sha1[:7], commit.Message) + "\n")
} }
if push.Len > 3 { if push.Len > 3 {
buf.WriteString(fmt.Sprintf(`<div><a href="/%s/%s/commits/%s">%d other commits >></a></div>`, actUserName, repoName, branch, push.Len)) buf.WriteString(fmt.Sprintf(`<div><a href="/%s/%s/commits/%s" rel="nofollow">%d other commits >></a></div>`, actUserName, repoName, branch, push.Len))
} }
return fmt.Sprintf(TPL_COMMIT_REPO, actUserName, actUserName, repoLink, branch, branch, repoLink, repoLink, return fmt.Sprintf(TPL_COMMIT_REPO, actUserName, actUserName, repoLink, branch, branch, repoLink, repoLink,
buf.String()) buf.String())

7
modules/middleware/repo.go

@ -26,11 +26,14 @@ func RepoAssignment(redirect bool, args ...bool) martini.Handler {
var displayBare bool var displayBare bool
if len(args) >= 1 { if len(args) >= 1 {
validBranch = args[0] // Note: argument has wrong value in Go1.3 martini.
// validBranch = args[0]
validBranch = true
} }
if len(args) >= 2 { if len(args) >= 2 {
displayBare = args[1] // displayBare = args[1]
displayBare = true
} }
var ( var (

BIN
public/img/favicon.bak.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
public/img/favicon.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 11 KiB

4
public/js/app.js

@ -470,10 +470,10 @@ function initInstall() {
(function () { (function () {
$('#install-database').on("change", function () { $('#install-database').on("change", function () {
var val = $(this).val(); var val = $(this).val();
if (val != "sqlite") { if (val != "SQLite3") {
$('.server-sql').show(); $('.server-sql').show();
$('.sqlite-setting').addClass("hide"); $('.sqlite-setting').addClass("hide");
if (val == "pgsql") { if (val == "PostgreSQL") {
$('.pgsql-setting').removeClass("hide"); $('.pgsql-setting').removeClass("hide");
} else { } else {
$('.pgsql-setting').addClass("hide"); $('.pgsql-setting').addClass("hide");

2
routers/admin/admin.go

@ -139,9 +139,11 @@ func Config(ctx *middleware.Context) {
ctx.Data["AppUrl"] = base.AppUrl ctx.Data["AppUrl"] = base.AppUrl
ctx.Data["Domain"] = base.Domain ctx.Data["Domain"] = base.Domain
ctx.Data["OfflineMode"] = base.OfflineMode
ctx.Data["RunUser"] = base.RunUser ctx.Data["RunUser"] = base.RunUser
ctx.Data["RunMode"] = strings.Title(martini.Env) ctx.Data["RunMode"] = strings.Title(martini.Env)
ctx.Data["RepoRootPath"] = base.RepoRootPath ctx.Data["RepoRootPath"] = base.RepoRootPath
ctx.Data["ScriptType"] = base.ScriptType
ctx.Data["Service"] = base.Service ctx.Data["Service"] = base.Service

18
routers/install.go

@ -30,7 +30,7 @@ func checkRunMode() {
switch base.Cfg.MustValue("", "RUN_MODE") { switch base.Cfg.MustValue("", "RUN_MODE") {
case "prod": case "prod":
martini.Env = martini.Prod martini.Env = martini.Prod
base.IsProdMode = true base.ProdMode = true
case "test": case "test":
martini.Env = martini.Test martini.Env = martini.Test
} }
@ -65,6 +65,10 @@ func GlobalInit() {
checkRunMode() checkRunMode()
} }
func renderDbOption(ctx *middleware.Context) {
ctx.Data["DbOptions"] = []string{"MySQL", "PostgreSQL", "SQLite3"}
}
func Install(ctx *middleware.Context, form auth.InstallForm) { func Install(ctx *middleware.Context, form auth.InstallForm) {
if base.InstallLock { if base.InstallLock {
ctx.Handle(404, "install.Install", errors.New("Installation is prohibited")) ctx.Handle(404, "install.Install", errors.New("Installation is prohibited"))
@ -104,6 +108,13 @@ func Install(ctx *middleware.Context, form auth.InstallForm) {
form.AppUrl = base.AppUrl form.AppUrl = base.AppUrl
} }
renderDbOption(ctx)
curDbValue := ""
if models.EnableSQLite3 {
curDbValue = "SQLite3" // Default when enabled.
}
ctx.Data["CurDbValue"] = curDbValue
auth.AssignForm(form, ctx.Data) auth.AssignForm(form, ctx.Data)
ctx.HTML(200, "install") ctx.HTML(200, "install")
} }
@ -117,6 +128,9 @@ func InstallPost(ctx *middleware.Context, form auth.InstallForm) {
ctx.Data["Title"] = "Install" ctx.Data["Title"] = "Install"
ctx.Data["PageIsInstall"] = true ctx.Data["PageIsInstall"] = true
renderDbOption(ctx)
ctx.Data["CurDbValue"] = form.Database
if ctx.HasError() { if ctx.HasError() {
ctx.HTML(200, "install") ctx.HTML(200, "install")
return return
@ -129,7 +143,7 @@ func InstallPost(ctx *middleware.Context, form auth.InstallForm) {
// Pass basic check, now test configuration. // Pass basic check, now test configuration.
// Test database setting. // Test database setting.
dbTypes := map[string]string{"mysql": "mysql", "pgsql": "postgres", "sqlite": "sqlite3"} dbTypes := map[string]string{"MySQL": "mysql", "PostgreSQL": "postgres", "SQLite3": "sqlite3"}
models.DbCfg.Type = dbTypes[form.Database] models.DbCfg.Type = dbTypes[form.Database]
models.DbCfg.Host = form.Host models.DbCfg.Host = form.Host
models.DbCfg.User = form.User models.DbCfg.User = form.User

15
routers/repo/commit.go

@ -91,10 +91,23 @@ func Diff(ctx *middleware.Context, params martini.Params) {
return isImage return isImage
} }
parents := make([]string, commit.ParentCount())
for i := 0; i < commit.ParentCount(); i++ {
sha, err := commit.ParentId(i)
parents[i] = sha.String()
if err != nil {
ctx.Handle(404, "repo.Diff", err)
return
}
}
ctx.Data["Username"] = userName
ctx.Data["Reponame"] = repoName
ctx.Data["IsImageFile"] = isImageFile ctx.Data["IsImageFile"] = isImageFile
ctx.Data["Title"] = commit.Message() + " · " + base.ShortSha(commitId) ctx.Data["Title"] = commit.Summary() + " · " + base.ShortSha(commitId)
ctx.Data["Commit"] = commit ctx.Data["Commit"] = commit
ctx.Data["Diff"] = diff ctx.Data["Diff"] = diff
ctx.Data["Parents"] = parents
ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0 ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0
ctx.Data["IsRepoToolbarCommits"] = true ctx.Data["IsRepoToolbarCommits"] = true
ctx.Data["SourcePath"] = "/" + path.Join(userName, repoName, "src", commitId) ctx.Data["SourcePath"] = "/" + path.Join(userName, repoName, "src", commitId)

1
routers/repo/release.go

@ -87,7 +87,6 @@ func Releases(ctx *middleware.Context) {
return return
} }
tags.rels[i].NumCommitsBehind = commitsCount - tags.rels[i].NumCommits tags.rels[i].NumCommitsBehind = commitsCount - tags.rels[i].NumCommits
tags.rels[i].Created = commit.Author.When
} }
} }

1
routers/repo/repo.go

@ -134,7 +134,6 @@ func Single(ctx *middleware.Context, params martini.Params) {
} }
entry, err := ctx.Repo.Commit.GetTreeEntryByPath(treename) entry, err := ctx.Repo.Commit.GetTreeEntryByPath(treename)
if err != nil && err != git.ErrNotExist { if err != nil && err != git.ErrNotExist {
ctx.Handle(404, "repo.Single(GetTreeEntryByPath)", err) ctx.Handle(404, "repo.Single(GetTreeEntryByPath)", err)
return return

9
routers/user/setting.go

@ -66,7 +66,7 @@ func SettingPost(ctx *middleware.Context, form auth.UpdateProfileForm) {
log.Trace("%s User setting updated: %s", ctx.Req.RequestURI, ctx.User.LowerName) log.Trace("%s User setting updated: %s", ctx.Req.RequestURI, ctx.User.LowerName)
ctx.Flash.Success("Your profile has been successfully updated.") ctx.Flash.Success("Your profile has been successfully updated.")
ctx.Redirect("/user/setting") ctx.Redirect("/user/settings")
} }
func SettingSocial(ctx *middleware.Context) { func SettingSocial(ctx *middleware.Context) {
@ -122,7 +122,7 @@ func SettingPasswordPost(ctx *middleware.Context, form auth.UpdatePasswdForm) {
ctx.Flash.Success("Password is changed successfully. You can now sign in via new password.") ctx.Flash.Success("Password is changed successfully. You can now sign in via new password.")
} }
ctx.Redirect("/user/setting/password") ctx.Redirect("/user/settings/password")
} }
func SettingSSHKeys(ctx *middleware.Context, form auth.AddSSHKeyForm) { func SettingSSHKeys(ctx *middleware.Context, form auth.AddSSHKeyForm) {
@ -166,7 +166,8 @@ func SettingSSHKeys(ctx *middleware.Context, form auth.AddSSHKeyForm) {
return return
} }
k := &models.PublicKey{OwnerId: ctx.User.Id, k := &models.PublicKey{
OwnerId: ctx.User.Id,
Name: form.KeyName, Name: form.KeyName,
Content: form.KeyContent, Content: form.KeyContent,
} }
@ -181,7 +182,7 @@ func SettingSSHKeys(ctx *middleware.Context, form auth.AddSSHKeyForm) {
} else { } else {
log.Trace("%s User SSH key added: %s", ctx.Req.RequestURI, ctx.User.LowerName) log.Trace("%s User SSH key added: %s", ctx.Req.RequestURI, ctx.User.LowerName)
ctx.Flash.Success("New SSH Key has been added!") ctx.Flash.Success("New SSH Key has been added!")
ctx.Redirect("/user/setting/ssh") ctx.Redirect("/user/settings/ssh")
return return
} }
} }

34
routers/user/user.go

@ -89,7 +89,18 @@ func SignInPost(ctx *middleware.Context, form auth.LogInForm) {
return return
} }
user, err := models.LoginUserPlain(form.UserName, form.Password) var user *models.User
var err error
if base.Service.LdapAuth {
user, err = models.LoginUserLdap(form.UserName, form.Password)
if err != nil {
log.Error("Fail to login through LDAP: %v", err)
}
}
// try local if not LDAP or it's failed
if !base.Service.LdapAuth || err != nil {
user, err = models.LoginUserPlain(form.UserName, form.Password)
}
if err != nil { if err != nil {
if err == models.ErrUserNotExist { if err == models.ErrUserNotExist {
log.Trace("%s Log in failed: %s/%s", ctx.Req.RequestURI, form.UserName, form.Password) log.Trace("%s Log in failed: %s/%s", ctx.Req.RequestURI, form.UserName, form.Password)
@ -133,27 +144,6 @@ func SignInPost(ctx *middleware.Context, form auth.LogInForm) {
ctx.Redirect("/") ctx.Redirect("/")
} }
func oauthSignInPost(ctx *middleware.Context, sid int64) {
ctx.Data["Title"] = "OAuth Sign Up"
ctx.Data["PageIsSignUp"] = true
if _, err := models.GetOauth2ById(sid); err != nil {
if err == models.ErrOauth2RecordNotExist {
ctx.Handle(404, "user.oauthSignUp(GetOauth2ById)", err)
} else {
ctx.Handle(500, "user.oauthSignUp(GetOauth2ById)", err)
}
return
}
ctx.Data["IsSocialLogin"] = true
ctx.Data["username"] = ctx.Session.Get("socialName")
ctx.Data["email"] = ctx.Session.Get("socialEmail")
log.Trace("user.oauthSignUp(social ID): %v", ctx.Session.Get("socialId"))
ctx.HTML(200, "user/signup")
}
func SignOut(ctx *middleware.Context) { func SignOut(ctx *middleware.Context) {
ctx.Session.Delete("userId") ctx.Session.Delete("userId")
ctx.Session.Delete("userName") ctx.Session.Delete("userName")

3
serve.go

@ -53,6 +53,7 @@ func newLogger(execDir string) {
} }
qlog.SetOutput(f) qlog.SetOutput(f)
//qlog.SetOutputLevel(qlog.Ldebug)
qlog.Info("Start logging serv...") qlog.Info("Start logging serv...")
} }
@ -159,7 +160,7 @@ func runServ(k *cli.Context) {
qlog.Fatal(err) qlog.Fatal(err)
} }
if !has { if !has {
has, err = models.HasAccess(user.Name, repoPath, models.AU_WRITABLE) has, err = models.HasAccess(user.Name, path.Join(repoUserName, repoName), models.AU_WRITABLE)
if err != nil { if err != nil {
println("Internal error") println("Internal error")
qlog.Fatal(err) qlog.Fatal(err)

4
templates/admin/config.tmpl

@ -18,6 +18,8 @@
<dd>{{.AppUrl}}</dd> <dd>{{.AppUrl}}</dd>
<dt>Domain</dt> <dt>Domain</dt>
<dd>{{.Domain}}</dd> <dd>{{.Domain}}</dd>
<dt>Offline Mode</dt>
<dd><i class="fa fa{{if .OfflineMode}}-check{{end}}-square-o"></i></dd>
<hr/> <hr/>
<dt>Run User</dt> <dt>Run User</dt>
<dd>{{.RunUser}}</dd> <dd>{{.RunUser}}</dd>
@ -26,6 +28,8 @@
<hr/> <hr/>
<dt>Repository Root Path</dt> <dt>Repository Root Path</dt>
<dd>{{.RepoRootPath}}</dd> <dd>{{.RepoRootPath}}</dd>
<dt>Script Type</dt>
<dd>{{.ScriptType}}</dd>
</dl> </dl>
</div> </div>
</div> </div>

5
templates/base/footer.tmpl

@ -13,7 +13,10 @@
<div class="col-md-1" style="margin: -5px;"> <div class="col-md-1" style="margin: -5px;">
<a target="_blank" href="https://github.com/gogits/gogs"><i class="fa fa-github fa-2x"></i></a> <a target="_blank" href="https://github.com/gogits/gogs"><i class="fa fa-github fa-2x"></i></a>
</div> </div>
<p class="desc"></p>
<div class="col-md-5">
<p class="desc"></p>
</div>
</div> </div>
</div> </div>
</footer> </footer>

2
templates/base/head.tmpl

@ -12,7 +12,7 @@
{{if .Repository.IsGoget}}<meta name="go-import" content="{{.GoGetImport}} git {{.CloneLink.HTTPS}}">{{end}} {{if .Repository.IsGoget}}<meta name="go-import" content="{{.GoGetImport}} git {{.CloneLink.HTTPS}}">{{end}}
<!-- Stylesheets --> <!-- Stylesheets -->
{{if IsProdMode}} {{if CdnMode}}
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css"> <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet"> <link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">

8
templates/base/navbar.tmpl

@ -3,7 +3,7 @@
<nav class="nav"> <nav class="nav">
<a id="nav-logo" class="nav-item pull-left{{if .PageIsHome}} active{{end}}" href="/"><img src="/img/favicon.png" alt="Gogs Logo" id="logo"></a> <a id="nav-logo" class="nav-item pull-left{{if .PageIsHome}} active{{end}}" href="/"><img src="/img/favicon.png" alt="Gogs Logo" id="logo"></a>
<a class="nav-item pull-left{{if .PageIsUserDashboard}} active{{end}}" href="/">Dashboard</a> <a class="nav-item pull-left{{if .PageIsUserDashboard}} active{{end}}" href="/">Dashboard</a>
<a class="nav-item pull-left{{if .PageIsHelp}} active{{end}}" href="https://github.com/gogits/gogs/wiki">Help</a>{{if .IsSigned}} <a class="nav-item pull-left{{if .PageIsHelp}} active{{end}}" target="_blank" href="https://github.com/gogits/gogs/wiki">Help</a>{{if .IsSigned}}
{{if .HasAccess}}<!-- <form class="nav-item pull-left{{if .PageIsNewRepo}} active{{end}}" id="nav-search-form"> {{if .HasAccess}}<!-- <form class="nav-item pull-left{{if .PageIsNewRepo}} active{{end}}" id="nav-search-form">
<div class="input-group"> <div class="input-group">
<div class="input-group-btn"> <div class="input-group-btn">
@ -21,7 +21,7 @@
<a id="nav-avatar" class="nav-item navbar-right{{if .PageIsUserProfile}} active{{end}}" href="{{.SignedUser.HomeLink}}" data-toggle="tooltip" data-placement="bottom" title="{{.SignedUserName}}"> <a id="nav-avatar" class="nav-item navbar-right{{if .PageIsUserProfile}} active{{end}}" href="{{.SignedUser.HomeLink}}" data-toggle="tooltip" data-placement="bottom" title="{{.SignedUserName}}">
<img src="{{.SignedUser.AvatarLink}}?s=28" alt="user-avatar" title="username"/> <img src="{{.SignedUser.AvatarLink}}?s=28" alt="user-avatar" title="username"/>
</a> </a>
<a class="navbar-right nav-item{{if .PageIsUserSetting}} active{{end}}" href="/user/setting" data-toggle="tooltip" data-placement="bottom" title="Setting"><i class="fa fa-cogs fa-lg"></i></a> <a class="navbar-right nav-item{{if .PageIsUserSetting}} active{{end}}" href="/user/settings" data-toggle="tooltip" data-placement="bottom" title="Settings"><i class="fa fa-cogs fa-lg"></i></a>
{{if .IsAdmin}}<a class="navbar-right nav-item{{if .PageIsAdmin}} active{{end}}" href="/admin" data-toggle="tooltip" data-placement="bottom" title="Admin"><i class="fa fa-gear fa-lg"></i></a>{{end}} {{if .IsAdmin}}<a class="navbar-right nav-item{{if .PageIsAdmin}} active{{end}}" href="/admin" data-toggle="tooltip" data-placement="bottom" title="Admin"><i class="fa fa-gear fa-lg"></i></a>{{end}}
<div class="navbar-right nav-item pull-right{{if .PageIsNewRepo}} active{{end}}" id="nav-repo-new" data-toggle="tooltip" data-placement="bottom" title="New Repo"> <div class="navbar-right nav-item pull-right{{if .PageIsNewRepo}} active{{end}}" id="nav-repo-new" data-toggle="tooltip" data-placement="bottom" title="New Repo">
<button type="button" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-plus-square fa-lg"></i></button> <button type="button" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-plus-square fa-lg"></i></button>
@ -33,8 +33,8 @@
</ul> </ul>
</div> </div>
</div> </div>
{{else}}<a id="nav-signin" class="nav-item navbar-right navbar-btn btn btn-danger" href="/user/login/">Sign In</a> {{else}}<a id="nav-signin" class="nav-item navbar-right navbar-btn btn btn-danger" href="/user/login/" rel="nofollow">Sign In</a>
<a id="nav-signup" class="nav-item navbar-right" href="/user/sign_up/">Sign Up</a>{{end}} <a id="nav-signup" class="nav-item navbar-right" href="/user/sign_up/" rel="nofollow">Sign Up</a>{{end}}
</nav> </nav>
</div> </div>
</div> </div>

13
templates/install.tmpl

@ -9,14 +9,15 @@
<label class="col-md-3 control-label">Database Type: </label> <label class="col-md-3 control-label">Database Type: </label>
<div class="col-md-8"> <div class="col-md-8">
<select name="database" id="install-database" class="form-control"> <select name="database" id="install-database" class="form-control">
<option value="mysql">MySQL</option> {{if .CurDbValue}}<option value="{{.CurDbValue}}">{{.CurDbValue}}</option>{{end}}
<option value="pgsql">PostgreSQL</option> {{range .DbOptions}}
<option value="sqlite">SQLite3</option> {{if not (eq $.CurDbValue .)}}<option value="{{.}}">{{.}}</option>{{end}}
{{end}}
</select> </select>
</div> </div>
</div> </div>
<div class="server-sql"> <div class="server-sql {{if eq .CurDbValue "SQLite3"}}hide{{end}}">
<div class="form-group"> <div class="form-group">
<label class="col-md-3 control-label">Host: </label> <label class="col-md-3 control-label">Host: </label>
<div class="col-md-8"> <div class="col-md-8">
@ -49,7 +50,7 @@
</div> </div>
</div> </div>
<div class="form-group pgsql-setting hide"> <div class="form-group pgsql-setting {{if not (eq .CurDbValue "PostgreSQL")}}hide{{end}}">
<label class="col-md-3 control-label">SSL Mode: </label> <label class="col-md-3 control-label">SSL Mode: </label>
<div class="col-md-8"> <div class="col-md-8">
<select name="ssl_mode" class="form-control"> <select name="ssl_mode" class="form-control">
@ -61,7 +62,7 @@
</div> </div>
</div> </div>
<div class="sqlite-setting hide"> <div class="sqlite-setting {{if not (eq .CurDbValue "SQLite3")}}hide{{end}}">
<div class="form-group"> <div class="form-group">
<label class="col-md-3 control-label">Path: </label> <label class="col-md-3 control-label">Path: </label>

2
templates/issue/user.tmpl

@ -29,7 +29,7 @@
<div class="filter-option"> <div class="filter-option">
<div class="btn-group"> <div class="btn-group">
<a class="btn btn-default issue-open{{if not .IsShowClosed}} active{{end}}" href="/issues?type={{.ViewType}}&repoid={{.RepoId}}">{{.OpenIssueCount}} Open</a> <a class="btn btn-default issue-open{{if not .IsShowClosed}} active{{end}}" href="/issues?type={{.ViewType}}&repoid={{.RepoId}}">{{.OpenIssueCount}} Open</a>
<a class="btn btn-default issue-close{{if .IsShowClosed}} active{{end}}" href="/issues?state=closed&type={{.ViewType}}&repoid={{.RepoId}}">{{.ClosedIssueCount}} Close</a> <a class="btn btn-default issue-close{{if .IsShowClosed}} active{{end}}" href="/issues?state=closed&type={{.ViewType}}&repoid={{.RepoId}}">{{.ClosedIssueCount}} Closed</a>
</div> </div>
</div> </div>
<div class="issues list-group"> <div class="issues list-group">

36
templates/release/list.tmpl

@ -15,8 +15,8 @@
{{if .PublisherId}} {{if .PublisherId}}
<div class="col-md-2 text-right"> <div class="col-md-2 text-right">
{{if .IsPrerelease}}<span class="btn btn-warning status pre-release">Pre-Release</span>{{else}}<span class="btn btn-success status stable">Stable</span>{{end}} {{if .IsPrerelease}}<span class="btn btn-warning status pre-release">Pre-Release</span>{{else}}<span class="btn btn-success status stable">Stable</span>{{end}}
<a class="tag" href="{{$.RepoLink}}/src/{{.TagName}}"><i class="fa fa-tag"></i>{{.TagName}}</a> <a class="tag" href="{{$.RepoLink}}/src/{{.TagName}}" rel="nofollow"><i class="fa fa-tag"></i>{{.TagName}}</a>
<a class="commit" href="{{$.RepoLink}}/src/{{.SHA1}}"><i class="fa fa-code"></i>{{ShortSha .SHA1}}</a> <a class="commit" href="{{$.RepoLink}}/src/{{.SHA1}}" rel="nofollow"><i class="fa fa-code"></i>{{ShortSha .SHA1}}</a>
</div> </div>
<div class="col-md-10"> <div class="col-md-10">
<h4 class="title"><a href="{{$.RepoLink}}/src/{{.TagName}}">{{.Title}}</a></h4> <h4 class="title"><a href="{{$.RepoLink}}/src/{{.TagName}}">{{.Title}}</a></h4>
@ -30,19 +30,19 @@
{{str2html .Note}} {{str2html .Note}}
</div> </div>
<p class="download"> <p class="download">
<a class="btn btn-default" href="{{$.RepoLink}}/archive/{{.TagName}}/{{$.Repository.Name}}.zip"><i class="fa fa-download"></i>Source Code (ZIP)</a> <a class="btn btn-default" href="{{$.RepoLink}}/archive/{{.TagName}}/{{$.Repository.Name}}.zip" rel="nofollow"><i class="fa fa-download"></i>Source Code (ZIP)</a>
<!-- <a class="btn btn-default" href="{release_download_link}"><i class="fa fa-download"></i>Source Code (TAR.GZ)</a> --> <!-- <a class="btn btn-default" href="{release_download_link}"><i class="fa fa-download"></i>Source Code (TAR.GZ)</a> -->
</p> </p>
<span class="dot">&nbsp;</span> <span class="dot">&nbsp;</span>
</div> </div>
{{else}} {{else}}
<div class="col-md-2 text-right"> <div class="col-md-2 text-right">
<a class="commit" href="{{$.RepoLink}}/src/{{.SHA1}}"><i class="fa fa-code"></i>{{ShortSha .SHA1}}</a> <a class="commit" href="{{$.RepoLink}}/src/{{.SHA1}}" rel="nofollow"><i class="fa fa-code"></i>{{ShortSha .SHA1}}</a>
</div> </div>
<div class="col-md-10"> <div class="col-md-10">
<h5 class="title"><a href="{{$.RepoLink}}/src/{{.TagName}}">{{.TagName}}</a><i class="fa fa-tag"></i></h5> <h5 class="title"><a href="{{$.RepoLink}}/src/{{.TagName}}" rel="nofollow">{{.TagName}}</a><i class="fa fa-tag"></i></h5>
<p class="download"> <p class="download">
<a class="download-link" href="{{$.RepoLink}}/archive/{{.TagName}}/{{$.Repository.Name}}.zip"><i class="fa fa-download"></i>zip</a> <a class="download-link" href="{{$.RepoLink}}/archive/{{.TagName}}/{{$.Repository.Name}}.zip" rel="nofollow"><i class="fa fa-download"></i>zip</a>
<!-- <a class="download-link" href="{release_download_link}"><i class="fa fa-download"></i>tar.gz</a> --> <!-- <a class="download-link" href="{release_download_link}"><i class="fa fa-download"></i>tar.gz</a> -->
</p> </p>
<span class="dot">&nbsp;</span> <span class="dot">&nbsp;</span>
@ -50,30 +50,6 @@
{{end}} {{end}}
</li> </li>
{{end}} {{end}}
<!-- <li class="release-item clearfix" id="release-{release_id}">
<div class="col-md-2 text-right">
<span class="btn btn-warning status pre-release">Pre-Release</span>
<a class="tag" href="{commit_link}"><i class="fa fa-tag"></i>release tag</a>
<a class="commit" href="{commit_link}"><i class="fa fa-code"></i>commit-sha</a>
</div>
<div class="col-md-10">
<h4 class="title"><a href="{release_single_link}">Release Title</a></h4>
<p class="info">
<span class="author"><img class="avatar" src="http://1.gravatar.com/avatar/f72f7454ce9d710baa506394f68f4132" alt="" width="20">&nbsp;&nbsp;
<a href="/user/fuxiaohei">fuxiaohei</a></span>
<span class="time">1 week ago</span>
<span class="ahead"><strong>0</strong> commits since this tag</span>
</p>
<div class="markdown desc">
release descriptions, support markdown content
</div>
<p class="download">
<a class="btn btn-default" href="{release_download_link}"><i class="fa fa-download"></i>Source Code (ZIP)</a>
<a class="btn btn-default" href="{release_download_link}"><i class="fa fa-download"></i>Source Code (TAR.GZ)</a>
</p>
<span class="dot">&nbsp;</span>
</div>
</li> -->
</ul> </ul>
</div> </div>
</div> </div>

6
templates/repo/commits.tmpl

@ -33,7 +33,7 @@
<tr> <tr>
<td class="author"><img class="avatar" src="{{AvatarLink .Author.Email}}" alt=""/><a href="/user/email2user?email={{.Author.Email}}">{{.Author.Name}}</a></td> <td class="author"><img class="avatar" src="{{AvatarLink .Author.Email}}" alt=""/><a href="/user/email2user?email={{.Author.Email}}">{{.Author.Name}}</a></td>
<td class="sha"><a rel="nofollow" class="label label-success" href="/{{$username}}/{{$reponame}}/commit/{{.Id}} ">{{SubStr .Id.String 0 10}} </a></td> <td class="sha"><a rel="nofollow" class="label label-success" href="/{{$username}}/{{$reponame}}/commit/{{.Id}} ">{{SubStr .Id.String 0 10}} </a></td>
<td class="message">{{.Message}} </td> <td class="message">{{.Summary}} </td>
<td class="date">{{TimeSince .Author.When}}</td> <td class="date">{{TimeSince .Author.When}}</td>
</tr> </tr>
{{end}} {{end}}
@ -41,8 +41,8 @@
</table> </table>
</div> </div>
{{if not .IsSearchPage}}<ul class="pagination" id="commits-pager"> {{if not .IsSearchPage}}<ul class="pagination" id="commits-pager">
{{if .LastPageNum}}<li><a href="{{.RepoLink}}/commits/{{.BranchName}}?p={{.LastPageNum}}">&laquo; Newer</a></li>{{end}} {{if .LastPageNum}}<li><a href="{{.RepoLink}}/commits/{{.BranchName}}?p={{.LastPageNum}}" rel="nofollow">&laquo; Newer</a></li>{{end}}
{{if .NextPageNum}}<li><a href="{{.RepoLink}}/commits/{{.BranchName}}?p={{.NextPageNum}}">&raquo; Older</a></li>{{end}} {{if .NextPageNum}}<li><a href="{{.RepoLink}}/commits/{{.BranchName}}?p={{.NextPageNum}}" rel="nofollow">&raquo; Older</a></li>{{end}}
</ul>{{end}} </ul>{{end}}
</div> </div>
</div> </div>

7
templates/repo/diff.tmpl

@ -10,7 +10,12 @@
</div> </div>
<div class="panel-body"> <div class="panel-body">
<span class="pull-right"> <span class="pull-right">
commit <span class="label label-default sha">{{ShortSha .CommitId}}</span> <ul class="list-unstyled">
{{range .Parents}}
<li>parent <a href="{{$.RepoLink}}/commit/{{.}}"><span class="label label-default sha">{{ShortSha .}}</span></a></li>
{{end}}
<li>commit <span class="label label-default sha">{{ShortSha .CommitId}}</span></li>
</ul>
</span> </span>
<p class="author"> <p class="author">
<img class="avatar" src="{{AvatarLink .Commit.Author.Email}}" alt=""/> <img class="avatar" src="{{AvatarLink .Commit.Author.Email}}" alt=""/>

4
templates/repo/nav.tmpl

@ -23,10 +23,10 @@
<button class="btn btn-default" type="button" data-toggle="tooltip" title="copy to clipboard" data-placement="top" data-init="copy" data-copy-val="val" data-copy-from="#repo-clone-ipt"><i class="fa fa-copy"></i></button> <button class="btn btn-default" type="button" data-toggle="tooltip" title="copy to clipboard" data-placement="top" data-init="copy" data-copy-val="val" data-copy-from="#repo-clone-ipt"><i class="fa fa-copy"></i></button>
</span> </span>
</div> </div>
<p class="help-block text-center">Need help cloning? Visit <a href="#">Help</a>!</p> <p class="help-block text-center">Need help cloning? Visit <a target="_blank" href="https://help.github.com/articles/fork-a-repo">Help</a>!</p>
<hr/> <hr/>
<div class="clone-zip text-center"> <div class="clone-zip text-center">
<a class="btn btn-success btn-lg" href="{{.RepoLink}}/archive/{{.BranchName}}/{{.Repository.Name}}.zip"><i class="fa fa-suitcase"></i>Download ZIP</a> <a class="btn btn-success btn-lg" href="{{.RepoLink}}/archive/{{.BranchName}}/{{.Repository.Name}}.zip" rel="nofollow"><i class="fa fa-suitcase"></i>Download ZIP</a>
</div> </div>
</div> </div>
</div> </div>

47
templates/repo/single_file.tmpl

@ -14,37 +14,38 @@
{{if not .ReadmeInSingle}} {{if not .ReadmeInSingle}}
<div class="btn-group pull-right"> <div class="btn-group pull-right">
<a class="btn btn-default hidden" href="#">Edit</a> <a class="btn btn-default hidden" href="#">Edit</a>
<a class="btn btn-default" href="{{.FileLink}}">Raw</a> <a class="btn btn-default" href="{{.FileLink}}" rel="nofollow">Raw</a>
<a class="btn btn-default hidden" href="#">Blame</a> <a class="btn btn-default hidden" href="#">Blame</a>
<a class="btn btn-default hidden" href="#">History</a> <a class="btn btn-default hidden" href="#">History</a>
<a class="btn btn-danger hidden" href="#">Delete</a> <a class="btn btn-danger hidden" href="#">Delete</a>
</div> </div>
{{end}} {{end}}
</div> </div>
{{if not .FileIsText}} {{if not .FileIsText}}
<div class="panel-footer text-center"> <div class="panel-body file-body file-code code-view">
{{if .IsImageFile}} {{if .IsImageFile}}
<img src="{{.FileLink}}"> <img src="{{.FileLink}}">
{{else}}
<a href="{{.FileLink}}" class="btn btn-default">View Raw</a>
{{end}}
</div>
{{else}}
{{if .ReadmeExist}}
<div class="panel-body file-body markdown">
{{.FileContent|str2html}}
</div>
{{else}} {{else}}
<div class="panel-body file-body file-code code-view"> <a href="{{.FileLink}}" rel="nofollow" class="btn btn-default">View Raw</a>
<table>
<tbody>
<tr>
<td class="lines-num"></td>
<td class="lines-code markdown"><pre class="prettyprint linenums{{if .FileExt}} lang-{{.FileExt}}{{end}}">{{.FileContent}}</pre></td>
</tr>
</tbody>
</table>
</div>
{{end}} {{end}}
</div>
{{else}}
{{if .ReadmeExist}}
<div class="panel-body file-body markdown">
{{.FileContent|str2html}}
</div>
{{else}}
<div class="panel-body file-body file-code code-view">
<table>
<tbody>
<tr>
<td class="lines-num"></td>
<td class="lines-code markdown"><pre class="prettyprint linenums{{if .FileExt}} lang-{{.FileExt}}{{end}}">{{.FileContent}}</pre></td>
</tr>
</tbody>
</table>
</div>
{{end}}
{{end}} {{end}}
</div> </div>

4
templates/repo/single_list.tmpl

@ -1,6 +1,6 @@
<div class="panel panel-default info-box"> <div class="panel panel-default info-box">
<div class="panel-heading info-head"> <div class="panel-heading info-head">
<a href="/{{.Username}}/{{.Reponame}}/commit/{{.LastCommit.Id}}">{{.LastCommit.Message}}</a> <a href="/{{.Username}}/{{.Reponame}}/commit/{{.LastCommit.Id}}" rel="nofollow">{{.LastCommit.Summary}}</a>
</div> </div>
<div class="panel-body info-content"> <div class="panel-body info-content">
<a href="/user/{{.LastCommit.Author.Name}}">{{.LastCommit.Author.Name}}</a> <span class="text-muted">{{TimeSince .LastCommit.Author.When}}</span> <a href="/user/{{.LastCommit.Author.Name}}">{{.LastCommit.Author.Name}}</a> <span class="text-muted">{{TimeSince .LastCommit.Author.When}}</span>
@ -36,7 +36,7 @@
</span> </span>
</td> </td>
<td class="text"> <td class="text">
<span class="wrap"><a rel="nofollow" href="/{{$.Username}}/{{$.Reponame}}/commit/{{$commit.Id}}">{{$commit.Message}}</a></span> <span class="wrap"><a rel="nofollow" href="/{{$.Username}}/{{$.Reponame}}/commit/{{$commit.Id}}">{{$commit.Summary}}</a></span>
</td> </td>
<td class="date"> <td class="date">
<span class="wrap">{{TimeSince $commit.Committer.When}}</span> <span class="wrap">{{TimeSince $commit.Committer.When}}</span>

2
templates/user/password.tmpl

@ -5,7 +5,7 @@
<div id="user-setting-container" class="col-md-9"> <div id="user-setting-container" class="col-md-9">
<div id="setting-pwd"> <div id="setting-pwd">
<h4>Password</h4> <h4>Password</h4>
<form class="form-horizontal" id="password-form" method="post" action="/user/setting/password"> <form class="form-horizontal" id="password-form" method="post" action="/user/settings/password">
{{.CsrfTokenHtml}} {{.CsrfTokenHtml}}
{{template "base/alert" .}} {{template "base/alert" .}}
<div class="form-group"> <div class="form-group">

6
templates/user/profile.tmpl

@ -11,13 +11,13 @@
<div class="profile-info"> <div class="profile-info">
<ul class="list-group"> <ul class="list-group">
{{if .Owner.Location}} {{if .Owner.Location}}
<li class="list-group-item"><i class="fa fa-thumb-tack"></i>{{.Owner.Location}}</li> <li class="list-group-item"><i class="fa fa-thumb-tack"></i>{{.Owner.Location}}</li>
{{end}} {{end}}
{{if .Owner.Email}} {{if .Owner.Email}}
<li class="list-group-item"><i class="fa fa-envelope"></i><a href="mailto:{{.Owner.Email}}">{{.Owner.Email}}</a></li> <li class="list-group-item"><i class="fa fa-envelope"></i><a href="mailto:{{.Owner.Email}}" rel="nofollow">{{.Owner.Email}}</a></li>
{{end}} {{end}}
{{if .Owner.Website}} {{if .Owner.Website}}
<li class="list-group-item"><i class="fa fa-link"></i><a target="_blank" href="{{.Owner.Website}}">{{.Owner.Website}}</a></li> <li class="list-group-item"><i class="fa fa-link"></i><a target="_blank" href="{{.Owner.Website}}">{{.Owner.Website}}</a></li>
{{end}} {{end}}
<li class="list-group-item"><i class="fa fa-clock-o"></i>Joined on {{DateFormat .Owner.Created "M d, Y"}}</li> <li class="list-group-item"><i class="fa fa-clock-o"></i>Joined on {{DateFormat .Owner.Created "M d, Y"}}</li>
<!-- <hr> --> <!-- <hr> -->

2
templates/user/publickey.tmpl

@ -21,7 +21,7 @@
</ul> </ul>
<div class="modal fade" id="ssh-add-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> <div class="modal fade" id="ssh-add-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog"> <div class="modal-dialog">
<form class="modal-content form-horizontal" id="ssh-form" method="post" action="/user/setting/ssh/"> <form class="modal-content form-horizontal" id="ssh-form" method="post" action="/user/settings/ssh/">
{{.CsrfTokenHtml}} {{.CsrfTokenHtml}}
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>

4
templates/user/setting.tmpl

@ -5,7 +5,7 @@
<div id="user-setting-container" class="col-md-9"> <div id="user-setting-container" class="col-md-9">
<div id="setting-pwd"> <div id="setting-pwd">
<h4>Account Profile</h4> <h4>Account Profile</h4>
<form class="form-horizontal" id="password-form" method="post" action="/user/setting"> <form class="form-horizontal" id="password-form" method="post" action="/user/settings">
{{.CsrfTokenHtml}} {{.CsrfTokenHtml}}
{{template "base/alert" .}} {{template "base/alert" .}}
<p>Your Email address is public and will be used for any account related notifications, and any web based operations made via the site.</p> <p>Your Email address is public and will be used for any account related notifications, and any web based operations made via the site.</p>
@ -13,7 +13,7 @@
<label class="col-md-2 control-label" for="user-setting-username">Username<strong class="text-danger">*</strong></label> <label class="col-md-2 control-label" for="user-setting-username">Username<strong class="text-danger">*</strong></label>
<div class="col-md-8"> <div class="col-md-8">
<input name="username" class="form-control" placeholder="Type your user name" required="required" value="{{.SignedUser.Name}}" title="{{.SignedUser.Name}}" id="user-setting-username"> <input name="username" class="form-control" placeholder="Type your user name" required="required" value="{{.SignedUser.Name}}" title="{{.SignedUser.Name}}" id="user-setting-username">
<p class="help-block hidden"><span class="text-danger">Cautious : </span>your username is changing !</p> <p class="help-block hidden"><span class="text-danger">Caution : </span>your username is changing !</p>
</div> </div>
</div> </div>

10
templates/user/setting_nav.tmpl

@ -1,11 +1,11 @@
<div id="user-setting-nav" class="col-md-3"> <div id="user-setting-nav" class="col-md-3">
<h4>Account Setting</h4> <h4>Account Settings</h4>
<ul class="list-group"> <ul class="list-group">
<li class="list-group-item{{if .IsUserPageSetting}} list-group-item-success{{end}}"><a href="/user/setting">Account Profile</a></li> <li class="list-group-item{{if .IsUserPageSetting}} list-group-item-success{{end}}"><a href="/user/settings">Account Profile</a></li>
<li class="list-group-item{{if .IsUserPageSettingSocial}} list-group-item-success{{end}}"><a href="/user/setting/social">Social Account</a></li> <li class="list-group-item{{if .IsUserPageSettingSocial}} list-group-item-success{{end}}"><a href="/user/settings/social">Social Account</a></li>
<li class="list-group-item{{if .IsUserPageSettingPasswd}} list-group-item-success{{end}}"><a href="/user/setting/password">Password</a></li> <li class="list-group-item{{if .IsUserPageSettingPasswd}} list-group-item-success{{end}}"><a href="/user/settings/password">Password</a></li>
<!-- <li class="list-group-item{{if .IsUserPageSettingNotify}} list-group-item-success{{end}}"><a href="/user/setting/notification">Notifications</a></li> --> <!-- <li class="list-group-item{{if .IsUserPageSettingNotify}} list-group-item-success{{end}}"><a href="/user/setting/notification">Notifications</a></li> -->
<li class="list-group-item{{if .IsUserPageSettingSSH}} list-group-item-success{{end}}"><a href="/user/setting/ssh/">SSH Keys</a></li> <li class="list-group-item{{if .IsUserPageSettingSSH}} list-group-item-success{{end}}"><a href="/user/settings/ssh/">SSH Keys</a></li>
<!-- <li class="list-group-item{{if .IsUserPageSettingSecurity}} list-group-item-success{{end}}"><a href="/user/setting/security">Security</a></li> --> <!-- <li class="list-group-item{{if .IsUserPageSettingSecurity}} list-group-item-success{{end}}"><a href="/user/setting/security">Security</a></li> -->
<li class="list-group-item{{if .IsUserPageSettingDelete}} list-group-item-success{{end}}"><a href="/user/delete">Delete Account</a></li> <li class="list-group-item{{if .IsUserPageSettingDelete}} list-group-item-success{{end}}"><a href="/user/delete">Delete Account</a></li>
</ul> </ul>

2
templates/user/signin.tmpl

@ -10,7 +10,7 @@
{{end}} {{end}}
{{template "base/alert" .}} {{template "base/alert" .}}
<div class="form-group {{if .Err_UserName}}has-error has-feedback{{end}}"> <div class="form-group {{if .Err_UserName}}has-error has-feedback{{end}}">
<label class="col-md-4 control-label">Username: </label> <label class="col-md-4 control-label">Username or e-mail: </label>
<div class="col-md-6"> <div class="col-md-6">
<input name="username" class="form-control" placeholder="Type your username" value="{{.username}}" required="required"> <input name="username" class="form-control" placeholder="Type your username" value="{{.username}}" required="required">
</div> </div>

9
tests/.travel.yml

@ -1,9 +0,0 @@
command: go test -v {}
include: ^.+_test\.go$
path: ./
depth: 1
verbose: true
timeout: 1m
reload: false
html: test.html
notify: []

13
tests/README.md

@ -1,13 +0,0 @@
## Gogs Test
This is for developers.
## Prepare Environment
go get -u github.com/shxsun/travelexec
# start gogs server
gogs web
## Start Testing
travelexec

17
tests/default_test.go

@ -1,17 +0,0 @@
package test
import (
"net/http"
"testing"
)
func TestMain(t *testing.T) {
r, err := http.Get("http://localhost:3000/")
if err != nil {
t.Fatal(err)
}
defer r.Body.Close()
if r.StatusCode != http.StatusOK {
t.Error(r.StatusCode)
}
}

2
update.go

@ -20,7 +20,7 @@ var CmdUpdate = cli.Command{
Name: "update", Name: "update",
Usage: "This command just should be called by ssh shell", Usage: "This command just should be called by ssh shell",
Description: ` Description: `
gogs serv provide access auth for repositories`, gogs update get pushed info and insert into database`,
Action: runUpdate, Action: runUpdate,
Flags: []cli.Flag{}, Flags: []cli.Flag{},
} }

6
web.go

@ -94,8 +94,8 @@ func runWeb(*cli.Context) {
m.Group("/user", func(r martini.Router) { m.Group("/user", func(r martini.Router) {
r.Get("/delete", user.Delete) r.Get("/delete", user.Delete)
r.Post("/delete", user.DeletePost) r.Post("/delete", user.DeletePost)
r.Get("/setting", user.Setting) r.Get("/settings", user.Setting)
r.Post("/setting", bindIgnErr(auth.UpdateProfileForm{}), user.SettingPost) r.Post("/settings", bindIgnErr(auth.UpdateProfileForm{}), user.SettingPost)
}, reqSignIn) }, reqSignIn)
m.Group("/user", func(r martini.Router) { m.Group("/user", func(r martini.Router) {
r.Get("/feeds", middleware.Bind(auth.FeedsForm{}), user.Feeds) r.Get("/feeds", middleware.Bind(auth.FeedsForm{}), user.Feeds)
@ -105,7 +105,7 @@ func runWeb(*cli.Context) {
r.Post("/forget_password", user.ForgotPasswdPost) r.Post("/forget_password", user.ForgotPasswdPost)
r.Get("/logout", user.SignOut) r.Get("/logout", user.SignOut)
}) })
m.Group("/user/setting", func(r martini.Router) { m.Group("/user/settings", func(r martini.Router) {
r.Get("/social", user.SettingSocial) r.Get("/social", user.SettingSocial)
r.Get("/password", user.SettingPassword) r.Get("/password", user.SettingPassword)
r.Post("/password", bindIgnErr(auth.UpdatePasswdForm{}), user.SettingPasswordPost) r.Post("/password", bindIgnErr(auth.UpdatePasswdForm{}), user.SettingPasswordPost)

Loading…
Cancel
Save