Merge branch 'master' of https://github.com/gogits/gogs
This commit is contained in:
		
						commit
						78097a2c5a
					
				
					 41 changed files with 867 additions and 193 deletions
				
			
		
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							|  | @ -5,4 +5,4 @@ gogs | |||
| *.db | ||||
| *.log | ||||
| custom/ | ||||
| .vendor/ | ||||
| .vendor/ | ||||
							
								
								
									
										7
									
								
								.gobuild.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								.gobuild.yml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,7 @@ | |||
| filesets: | ||||
|     includes: | ||||
|         - templates | ||||
|         - public | ||||
|         - conf | ||||
|         - LICENSE | ||||
|         - README.md | ||||
|  | @ -15,6 +15,7 @@ There are some very good products in this category such as [gitlab](http://gitla | |||
| 
 | ||||
| - Please see [Wiki](https://github.com/gogits/gogs/wiki) for project design, develop specification, change log and road map. | ||||
| - See [Trello Broad](https://trello.com/b/uxAoeLUl/gogs-go-git-service) to follow the develop team. | ||||
| - Try it before anything? Go down to **Installation -> Install from binary** section!. | ||||
| 
 | ||||
| ## Features | ||||
| 
 | ||||
|  | @ -33,11 +34,12 @@ Make sure you install [Prerequirements](https://github.com/gogits/gogs/wiki/Prer | |||
| 
 | ||||
| There are two ways to install Gogs: | ||||
| 
 | ||||
| - [Install from binary](https://github.com/gogits/gogs/wiki/Install-from-binary) | ||||
| - [Install from binary](https://github.com/gogits/gogs/wiki/Install-from-binary): **STRONGLY RECOMMENDED** for just try and deployment! | ||||
| - [Install from source](https://github.com/gogits/gogs/wiki/Install-from-source) | ||||
| 
 | ||||
| ## Acknowledgments | ||||
| 
 | ||||
| - Mail service is based on [WeTalk](https://github.com/beego/wetalk). | ||||
| - Logo inspired by [martini](https://github.com/martini-contrib). | ||||
| 
 | ||||
| ## Contributors | ||||
|  |  | |||
							
								
								
									
										93
									
								
								conf/app.ini
									
									
									
									
									
								
							
							
						
						
									
										93
									
								
								conf/app.ini
									
									
									
									
									
								
							|  | @ -1,28 +1,103 @@ | |||
| # App name that shows on every page title | ||||
| ; App name that shows on every page title | ||||
| APP_NAME = Gogs: Go Git Service | ||||
| # !!MUST CHANGE TO YOUR USER NAME!! | ||||
| APP_LOGO = img/favicon.png | ||||
| ; !!MUST CHANGE TO YOUR USER NAME!! | ||||
| RUN_USER = lunny | ||||
| ; Either "dev", "prod" or "test", default is "dev" | ||||
| RUN_MODE = dev | ||||
| 
 | ||||
| [repository] | ||||
| ROOT = /Users/%(RUN_USER)s/git/gogs-repositories | ||||
| LANG_IGNS=Google Go|C|Python|Ruby|C Sharp | ||||
| LICENSES=Apache v2 License|GPL v2|MIT License|Affero GPL|BSD (3-Clause) License | ||||
| LANG_IGNS = Google Go|C|Python|Ruby|C Sharp | ||||
| LICENSES = Apache v2 License|GPL v2|MIT License|Affero GPL|BSD (3-Clause) License | ||||
| 
 | ||||
| [server] | ||||
| DOMAIN = gogits.org | ||||
| DOMAIN = localhost | ||||
| ROOT_URL = http://%(DOMAIN)s:%(HTTP_PORT)s/ | ||||
| HTTP_ADDR =  | ||||
| HTTP_PORT = 3000 | ||||
| 
 | ||||
| [database] | ||||
| # Either "mysql" or "postgres", it's your choice | ||||
| ; Either "mysql" or "postgres", it's your choice | ||||
| DB_TYPE = mysql | ||||
| HOST =  | ||||
| NAME = gogs | ||||
| USER = root | ||||
| PASSWD = | ||||
| # For "postgres" only, either "disable" or "verify-full" | ||||
| ; For "postgres" only, either "disable", "require" or "verify-full" | ||||
| SSL_MODE = disable | ||||
| 
 | ||||
| [security] | ||||
| # !!CHANGE THIS TO KEEP YOUR USER DATA SAFE!! | ||||
| USER_PASSWD_SALT = !#@FDEWREWR&*( | ||||
| ; !!CHANGE THIS TO KEEP YOUR USER DATA SAFE!! | ||||
| SECRET_KEY = !#@FDEWREWR&*( | ||||
| 
 | ||||
| [service] | ||||
| ACTIVE_CODE_LIVE_MINUTES = 180 | ||||
| RESET_PASSWD_CODE_LIVE_MINUTES = 180 | ||||
| ; User need to confirm e-mail for registration | ||||
| REGISTER_EMAIL_CONFIRM = false | ||||
| 
 | ||||
| [mailer] | ||||
| ENABLED = false | ||||
| ; Name displayed in mail title | ||||
| SUBJECT = %(APP_NAME)s | ||||
| ; Mail server | ||||
| ; Gmail: smtp.gmail.com:587 | ||||
| HOST =  | ||||
| ; Mail from address | ||||
| FROM =  | ||||
| ; Mailer user name and password | ||||
| USER =  | ||||
| PASSWD =  | ||||
| 
 | ||||
| [log] | ||||
| ; Either "console", "file", "conn" or "smtp", default is "console" | ||||
| MODE = console | ||||
| ; Buffer length of channel, keep it as it is if you don't know what it is. | ||||
| BUFFER_LEN = 10000 | ||||
| ; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace" | ||||
| LEVEL = Trace | ||||
| 
 | ||||
| ; For "console" mode only | ||||
| [log.console] | ||||
| LEVEL =  | ||||
| 
 | ||||
| ; For "file" mode only | ||||
| [log.file] | ||||
| LEVEL =  | ||||
| FILE_NAME = log/gogs.log | ||||
| ; This enables automated log rotate(switch of following options), default is true | ||||
| LOG_ROTATE = true | ||||
| ; Max line number of single file, default is 1000000 | ||||
| MAX_LINES = 1000000 | ||||
| ; Max size shift of single file, default is 28 means 1 << 28, 256MB | ||||
| MAX_SIZE_SHIFT = 28 | ||||
| ; Segment log daily, default is true | ||||
| DAILY_ROTATE = true | ||||
| ; Expired days of log file(delete after max days), default is 7 | ||||
| MAX_DAYS = 7 | ||||
| 
 | ||||
| ; For "conn" mode only | ||||
| [log.conn] | ||||
| LEVEL =  | ||||
| ; Reconnect host for every single message, default is false | ||||
| RECONNECT_ON_MSG = false | ||||
| ; Try to reconnect when connection is lost, default is false | ||||
| RECONNECT = false | ||||
| ; Either "tcp", "unix" or "udp", default is "tcp" | ||||
| PROTOCOL = tcp | ||||
| ; Host address | ||||
| ADDR =  | ||||
| 
 | ||||
| ; For "smtp" mode only | ||||
| [log.smtp] | ||||
| LEVEL =  | ||||
| ; Name displayed in mail title, default is "Diagnostic message from serve" | ||||
| SUBJECT = Diagnostic message from serve | ||||
| ; Mail server | ||||
| HOST =  | ||||
| ; Mailer user name and password | ||||
| USER =  | ||||
| PASSWD = | ||||
| ; Receivers, can be one or more, e.g. ["1@example.com","2@example.com"] | ||||
| RECEIVERS =  | ||||
							
								
								
									
										2
									
								
								gogs.go
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								gogs.go
									
									
									
									
									
								
							|  | @ -20,7 +20,7 @@ import ( | |||
| // Test that go1.1 tag above is included in builds. main.go refers to this definition.
 | ||||
| const go11tag = true | ||||
| 
 | ||||
| const APP_VER = "0.1.0.0318.1" | ||||
| const APP_VER = "0.1.0.0319.1" | ||||
| 
 | ||||
| func init() { | ||||
| 	base.AppVer = APP_VER | ||||
|  |  | |||
|  | @ -22,8 +22,8 @@ const ( | |||
| // Action represents user operation type and information to the repository.
 | ||||
| type Action struct { | ||||
| 	Id          int64 | ||||
| 	UserId      int64 // Receiver user id.
 | ||||
| 	OpType      int | ||||
| 	UserId      int64  // Receiver user id.
 | ||||
| 	OpType      int    // Operations: CREATE DELETE STAR ...
 | ||||
| 	ActUserId   int64  // Action user id.
 | ||||
| 	ActUserName string // Action user name.
 | ||||
| 	RepoId      int64 | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ | |||
| package models | ||||
| 
 | ||||
| import ( | ||||
| 	"container/list" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
|  | @ -144,10 +145,7 @@ func CreateRepository(user *User, repoName, desc, repoLang, license string, priv | |||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	rawSql := "UPDATE user SET num_repos = num_repos + 1 WHERE id = ?" | ||||
| 	if base.Cfg.MustValue("database", "DB_TYPE") == "postgres" { | ||||
| 		rawSql = "UPDATE \"user\" SET num_repos = num_repos + 1 WHERE id = ?" | ||||
| 	} | ||||
| 	rawSql := "UPDATE `user` SET num_repos = num_repos + 1 WHERE id = ?" | ||||
| 	if _, err = session.Exec(rawSql, user.Id); err != nil { | ||||
| 		session.Rollback() | ||||
| 		if err2 := os.RemoveAll(repoPath); err2 != nil { | ||||
|  | @ -448,7 +446,7 @@ func GetReposFiles(userName, reposName, branchName, commitId, rpath string) ([]* | |||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	commit, err := GetCommit(userName, reposName, branchName, commitId) | ||||
| 	commit, err := repo.GetCommit(branchName, commitId) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | @ -464,8 +462,10 @@ func GetReposFiles(userName, reposName, branchName, commitId, rpath string) ([]* | |||
| 			} | ||||
| 
 | ||||
| 			var cm = commit | ||||
| 
 | ||||
| 			var i int | ||||
| 			for { | ||||
| 				i = i + 1 | ||||
| 				//fmt.Println(".....", i, cm.Id(), cm.ParentCount())
 | ||||
| 				if cm.ParentCount() == 0 { | ||||
| 					break | ||||
| 				} else if cm.ParentCount() == 1 { | ||||
|  | @ -482,7 +482,10 @@ func GetReposFiles(userName, reposName, branchName, commitId, rpath string) ([]* | |||
| 				} else { | ||||
| 					var emptyCnt = 0 | ||||
| 					var sameIdcnt = 0 | ||||
| 					var lastSameCm *git.Commit | ||||
| 					//fmt.Println(".....", cm.ParentCount())
 | ||||
| 					for i := 0; i < cm.ParentCount(); i++ { | ||||
| 						//fmt.Println("parent", i, cm.Parent(i).Id())
 | ||||
| 						p := cm.Parent(i) | ||||
| 						pt, _ := repo.SubTree(p.Tree, dirname) | ||||
| 						var pEntry *git.TreeEntry | ||||
|  | @ -490,23 +493,31 @@ func GetReposFiles(userName, reposName, branchName, commitId, rpath string) ([]* | |||
| 							pEntry = pt.EntryByName(entry.Name) | ||||
| 						} | ||||
| 
 | ||||
| 						//fmt.Println("pEntry", pEntry)
 | ||||
| 
 | ||||
| 						if pEntry == nil { | ||||
| 							if emptyCnt == cm.ParentCount()-1 { | ||||
| 								goto loop | ||||
| 							} else { | ||||
| 								emptyCnt = emptyCnt + 1 | ||||
| 								continue | ||||
| 							emptyCnt = emptyCnt + 1 | ||||
| 							if emptyCnt+sameIdcnt == cm.ParentCount() { | ||||
| 								if lastSameCm == nil { | ||||
| 									goto loop | ||||
| 								} else { | ||||
| 									cm = lastSameCm | ||||
| 									break | ||||
| 								} | ||||
| 							} | ||||
| 						} else { | ||||
| 							//fmt.Println(i, "pEntry", pEntry.Id, "entry", entry.Id)
 | ||||
| 							if !pEntry.Id.Equal(entry.Id) { | ||||
| 								goto loop | ||||
| 							} else { | ||||
| 								if sameIdcnt == cm.ParentCount()-1 { | ||||
| 								lastSameCm = cm.Parent(i) | ||||
| 								sameIdcnt = sameIdcnt + 1 | ||||
| 								if emptyCnt+sameIdcnt == cm.ParentCount() { | ||||
| 									// TODO: now follow the first parent commit?
 | ||||
| 									cm = cm.Parent(0) | ||||
| 									cm = lastSameCm | ||||
| 									//fmt.Println("sameId...")
 | ||||
| 									break | ||||
| 								} | ||||
| 								sameIdcnt = sameIdcnt + 1 | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
|  | @ -541,26 +552,11 @@ func GetCommit(userName, repoName, branchname, commitid string) (*git.Commit, er | |||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if commitid != "" { | ||||
| 		oid, err := git.NewOidFromString(commitid) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		return repo.LookupCommit(oid) | ||||
| 	} | ||||
| 	if branchname == "" { | ||||
| 		return nil, errors.New("no branch name and no commit id") | ||||
| 	} | ||||
| 
 | ||||
| 	r, err := repo.LookupReference(fmt.Sprintf("refs/heads/%s", branchname)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return r.LastCommit() | ||||
| 	return repo.GetCommit(branchname, commitid) | ||||
| } | ||||
| 
 | ||||
| // GetCommits returns all commits of given branch of repository.
 | ||||
| func GetCommits(userName, reposName, branchname string) ([]*git.Commit, error) { | ||||
| func GetCommits(userName, reposName, branchname string) (*list.List, error) { | ||||
| 	repo, err := git.OpenRepository(RepoPath(userName, reposName)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
|  |  | |||
|  | @ -19,14 +19,6 @@ import ( | |||
| 	"github.com/gogits/gogs/modules/base" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	UserPasswdSalt string | ||||
| ) | ||||
| 
 | ||||
| func init() { | ||||
| 	UserPasswdSalt = base.Cfg.MustValue("security", "USER_PASSWD_SALT") | ||||
| } | ||||
| 
 | ||||
| // User types.
 | ||||
| const ( | ||||
| 	UT_INDIVIDUAL = iota + 1 | ||||
|  | @ -56,6 +48,9 @@ type User struct { | |||
| 	AvatarEmail   string `xorm:"not null"` | ||||
| 	Location      string | ||||
| 	Website       string | ||||
| 	IsActive      bool | ||||
| 	Rands         string `xorm:"VARCHAR(10)"` | ||||
| 	Expired       time.Time | ||||
| 	Created       time.Time `xorm:"created"` | ||||
| 	Updated       time.Time `xorm:"updated"` | ||||
| } | ||||
|  | @ -104,37 +99,44 @@ func (user *User) NewGitSig() *git.Signature { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| // return a user salt token
 | ||||
| func GetUserSalt() string { | ||||
| 	return base.GetRandomString(10) | ||||
| } | ||||
| 
 | ||||
| // RegisterUser creates record of a new user.
 | ||||
| func RegisterUser(user *User) (err error) { | ||||
| func RegisterUser(user *User) (*User, error) { | ||||
| 	isExist, err := IsUserExist(user.Name) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 		return nil, err | ||||
| 	} else if isExist { | ||||
| 		return ErrUserAlreadyExist | ||||
| 		return nil, ErrUserAlreadyExist | ||||
| 	} | ||||
| 
 | ||||
| 	isExist, err = IsEmailUsed(user.Email) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 		return nil, err | ||||
| 	} else if isExist { | ||||
| 		return ErrEmailAlreadyUsed | ||||
| 		return nil, ErrEmailAlreadyUsed | ||||
| 	} | ||||
| 
 | ||||
| 	user.LowerName = strings.ToLower(user.Name) | ||||
| 	user.Avatar = base.EncodeMd5(user.Email) | ||||
| 	user.AvatarEmail = user.Email | ||||
| 	user.Expired = time.Now().Add(3 * 24 * time.Hour) | ||||
| 	user.Rands = GetUserSalt() | ||||
| 	if err = user.EncodePasswd(); err != nil { | ||||
| 		return err | ||||
| 		return nil, err | ||||
| 	} else if _, err = orm.Insert(user); err != nil { | ||||
| 		return err | ||||
| 		return nil, err | ||||
| 	} else if err = os.MkdirAll(UserPath(user.Name), os.ModePerm); err != nil { | ||||
| 		if _, err := orm.Id(user.Id).Delete(&User{}); err != nil { | ||||
| 			return errors.New(fmt.Sprintf( | ||||
| 			return nil, errors.New(fmt.Sprintf( | ||||
| 				"both create userpath %s and delete table record faild: %v", user.Name, err)) | ||||
| 		} | ||||
| 		return err | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return nil | ||||
| 	return user, nil | ||||
| } | ||||
| 
 | ||||
| // UpdateUser updates user's information.
 | ||||
|  | @ -183,7 +185,7 @@ func DeleteUser(user *User) error { | |||
| 
 | ||||
| // EncodePasswd encodes password to safe format.
 | ||||
| func (user *User) EncodePasswd() error { | ||||
| 	newPasswd, err := scrypt.Key([]byte(user.Passwd), []byte(UserPasswdSalt), 16384, 8, 1, 64) | ||||
| 	newPasswd, err := scrypt.Key([]byte(user.Passwd), []byte(base.SecretKey), 16384, 8, 1, 64) | ||||
| 	user.Passwd = fmt.Sprintf("%x", newPasswd) | ||||
| 	return err | ||||
| } | ||||
|  | @ -252,7 +254,7 @@ func LoginUserPlain(name, passwd string) (*User, error) { | |||
| 	} else if !has { | ||||
| 		err = ErrUserNotExist | ||||
| 	} | ||||
| 	return &user, nil | ||||
| 	return &user, err | ||||
| } | ||||
| 
 | ||||
| // FollowUser marks someone be another's follower.
 | ||||
|  |  | |||
							
								
								
									
										41
									
								
								modules/auth/mail.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								modules/auth/mail.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,41 @@ | |||
| // 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 auth | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/hex" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/gogits/gogs/models" | ||||
| 	"github.com/gogits/gogs/modules/base" | ||||
| 	"github.com/gogits/gogs/modules/mailer" | ||||
| ) | ||||
| 
 | ||||
| // create a time limit code for user active
 | ||||
| func CreateUserActiveCode(user *models.User, startInf interface{}) string { | ||||
| 	hours := base.Service.ActiveCodeLives / 60 | ||||
| 	data := base.ToStr(user.Id) + user.Email + user.LowerName + user.Passwd + user.Rands | ||||
| 	code := base.CreateTimeLimitCode(data, hours, startInf) | ||||
| 
 | ||||
| 	// add tail hex username
 | ||||
| 	code += hex.EncodeToString([]byte(user.LowerName)) | ||||
| 	return code | ||||
| } | ||||
| 
 | ||||
| // Send user register mail with active code
 | ||||
| func SendRegisterMail(user *models.User) { | ||||
| 	code := CreateUserActiveCode(user, nil) | ||||
| 	subject := "Register success, Welcome" | ||||
| 
 | ||||
| 	data := mailer.GetMailTmplData(user) | ||||
| 	data["Code"] = code | ||||
| 	body := base.RenderTemplate("mail/auth/register_success.html", data) | ||||
| 
 | ||||
| 	msg := mailer.NewMailMessage([]string{user.Email}, subject, body) | ||||
| 	msg.Info = fmt.Sprintf("UID: %d, send register mail", user.Id) | ||||
| 
 | ||||
| 	// async send mail
 | ||||
| 	mailer.SendAsync(msg) | ||||
| } | ||||
|  | @ -10,18 +10,38 @@ import ( | |||
| 	"os/exec" | ||||
| 	"path" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/Unknwon/com" | ||||
| 	"github.com/Unknwon/goconfig" | ||||
| 
 | ||||
| 	"github.com/gogits/gogs/modules/log" | ||||
| ) | ||||
| 
 | ||||
| // Mailer represents a mail service.
 | ||||
| type Mailer struct { | ||||
| 	Name         string | ||||
| 	Host         string | ||||
| 	User, Passwd string | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	AppVer  string | ||||
| 	AppName string | ||||
| 	Domain  string | ||||
| 	Cfg     *goconfig.ConfigFile | ||||
| 	AppVer      string | ||||
| 	AppName     string | ||||
| 	AppLogo     string | ||||
| 	AppUrl      string | ||||
| 	Domain      string | ||||
| 	SecretKey   string | ||||
| 	Cfg         *goconfig.ConfigFile | ||||
| 	MailService *Mailer | ||||
| ) | ||||
| 
 | ||||
| var Service struct { | ||||
| 	RegisterEmailConfirm bool | ||||
| 	ActiveCodeLives      int | ||||
| 	ResetPwdCodeLives    int | ||||
| } | ||||
| 
 | ||||
| func exeDir() (string, error) { | ||||
| 	file, err := exec.LookPath(os.Args[0]) | ||||
| 	if err != nil { | ||||
|  | @ -34,6 +54,94 @@ func exeDir() (string, error) { | |||
| 	return path.Dir(p), nil | ||||
| } | ||||
| 
 | ||||
| var logLevels = map[string]string{ | ||||
| 	"Trace":    "0", | ||||
| 	"Debug":    "1", | ||||
| 	"Info":     "2", | ||||
| 	"Warn":     "3", | ||||
| 	"Error":    "4", | ||||
| 	"Critical": "5", | ||||
| } | ||||
| 
 | ||||
| func newService() { | ||||
| 	Service.ActiveCodeLives = Cfg.MustInt("service", "ACTIVE_CODE_LIVE_MINUTES", 180) | ||||
| 	Service.ResetPwdCodeLives = Cfg.MustInt("service", "RESET_PASSWD_CODE_LIVE_MINUTES", 180) | ||||
| } | ||||
| 
 | ||||
| func newLogService() { | ||||
| 	// Get and check log mode.
 | ||||
| 	mode := Cfg.MustValue("log", "MODE", "console") | ||||
| 	modeSec := "log." + mode | ||||
| 	if _, err := Cfg.GetSection(modeSec); err != nil { | ||||
| 		fmt.Printf("Unknown log mode: %s\n", mode) | ||||
| 		os.Exit(2) | ||||
| 	} | ||||
| 
 | ||||
| 	// Log level.
 | ||||
| 	levelName := Cfg.MustValue("log."+mode, "LEVEL", "Trace") | ||||
| 	level, ok := logLevels[levelName] | ||||
| 	if !ok { | ||||
| 		fmt.Printf("Unknown log level: %s\n", levelName) | ||||
| 		os.Exit(2) | ||||
| 	} | ||||
| 
 | ||||
| 	// Generate log configuration.
 | ||||
| 	var config string | ||||
| 	switch mode { | ||||
| 	case "console": | ||||
| 		config = fmt.Sprintf(`{"level":%s}`, level) | ||||
| 	case "file": | ||||
| 		config = fmt.Sprintf( | ||||
| 			`{"level":%s,"filename":%s,"rotate":%v,"maxlines":%d,"maxsize",%d,"daily":%v,"maxdays":%d}`, level, | ||||
| 			Cfg.MustValue(modeSec, "FILE_NAME", "log/gogs.log"), | ||||
| 			Cfg.MustBool(modeSec, "LOG_ROTATE", true), | ||||
| 			Cfg.MustInt(modeSec, "MAX_LINES", 1000000), | ||||
| 			1<<uint(Cfg.MustInt(modeSec, "MAX_SIZE_SHIFT", 28)), | ||||
| 			Cfg.MustBool(modeSec, "DAILY_ROTATE", true), | ||||
| 			Cfg.MustInt(modeSec, "MAX_DAYS", 7)) | ||||
| 	case "conn": | ||||
| 		config = fmt.Sprintf(`{"level":%s,"reconnectOnMsg":%v,"reconnect":%v,"net":%s,"addr":%s}`, level, | ||||
| 			Cfg.MustBool(modeSec, "RECONNECT_ON_MSG", false), | ||||
| 			Cfg.MustBool(modeSec, "RECONNECT", false), | ||||
| 			Cfg.MustValue(modeSec, "PROTOCOL", "tcp"), | ||||
| 			Cfg.MustValue(modeSec, "ADDR", ":7020")) | ||||
| 	case "smtp": | ||||
| 		config = fmt.Sprintf(`{"level":%s,"username":%s,"password":%s,"host":%s,"sendTos":%s,"subject":%s}`, level, | ||||
| 			Cfg.MustValue(modeSec, "USER", "example@example.com"), | ||||
| 			Cfg.MustValue(modeSec, "PASSWD", "******"), | ||||
| 			Cfg.MustValue(modeSec, "HOST", "127.0.0.1:25"), | ||||
| 			Cfg.MustValue(modeSec, "RECEIVERS", "[]"), | ||||
| 			Cfg.MustValue(modeSec, "SUBJECT", "Diagnostic message from serve")) | ||||
| 	} | ||||
| 
 | ||||
| 	log.NewLogger(Cfg.MustInt64("log", "BUFFER_LEN", 10000), mode, config) | ||||
| 	log.Info("Log Mode: %s(%s)", strings.Title(mode), levelName) | ||||
| } | ||||
| 
 | ||||
| func newMailService() { | ||||
| 	// Check mailer setting.
 | ||||
| 	if Cfg.MustBool("mailer", "ENABLED") { | ||||
| 		MailService = &Mailer{ | ||||
| 			Name:   Cfg.MustValue("mailer", "NAME", AppName), | ||||
| 			Host:   Cfg.MustValue("mailer", "HOST", "127.0.0.1:25"), | ||||
| 			User:   Cfg.MustValue("mailer", "USER", "example@example.com"), | ||||
| 			Passwd: Cfg.MustValue("mailer", "PASSWD", "******"), | ||||
| 		} | ||||
| 		log.Info("Mail Service Enabled") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func newRegisterService() { | ||||
| 	if !Cfg.MustBool("service", "REGISTER_EMAIL_CONFIRM") { | ||||
| 		return | ||||
| 	} else if MailService == nil { | ||||
| 		log.Warn("Register Service: Mail Service is not enabled") | ||||
| 		return | ||||
| 	} | ||||
| 	Service.RegisterEmailConfirm = true | ||||
| 	log.Info("Register Service Enabled") | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	var err error | ||||
| 	workDir, err := exeDir() | ||||
|  | @ -59,6 +167,14 @@ func init() { | |||
| 	} | ||||
| 	Cfg.BlockMode = false | ||||
| 
 | ||||
| 	AppName = Cfg.MustValue("", "APP_NAME") | ||||
| 	AppName = Cfg.MustValue("", "APP_NAME", "Gogs: Go Git Service") | ||||
| 	AppLogo = Cfg.MustValue("", "APP_LOGO", "img/favicon.png") | ||||
| 	AppUrl = Cfg.MustValue("server", "ROOT_URL") | ||||
| 	Domain = Cfg.MustValue("server", "DOMAIN") | ||||
| 	SecretKey = Cfg.MustValue("security", "SECRET_KEY") | ||||
| 
 | ||||
| 	// Extensions.
 | ||||
| 	newLogService() | ||||
| 	newMailService() | ||||
| 	newRegisterService() | ||||
| } | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ | |||
| package base | ||||
| 
 | ||||
| import ( | ||||
| 	"container/list" | ||||
| 	"html/template" | ||||
| ) | ||||
| 
 | ||||
|  | @ -12,6 +13,23 @@ func Str2html(raw string) template.HTML { | |||
| 	return template.HTML(raw) | ||||
| } | ||||
| 
 | ||||
| func Range(l int) []int { | ||||
| 	return make([]int, l) | ||||
| } | ||||
| 
 | ||||
| func List(l *list.List) chan interface{} { | ||||
| 	e := l.Front() | ||||
| 	c := make(chan interface{}) | ||||
| 	go func() { | ||||
| 		for e != nil { | ||||
| 			c <- e.Value | ||||
| 			e = e.Next() | ||||
| 		} | ||||
| 		close(c) | ||||
| 	}() | ||||
| 	return c | ||||
| } | ||||
| 
 | ||||
| var TemplateFuncs template.FuncMap = map[string]interface{}{ | ||||
| 	"AppName": func() string { | ||||
| 		return AppName | ||||
|  | @ -30,4 +48,5 @@ var TemplateFuncs template.FuncMap = map[string]interface{}{ | |||
| 	"ActionIcon": ActionIcon, | ||||
| 	"ActionDesc": ActionDesc, | ||||
| 	"DateFormat": DateFormat, | ||||
| 	"List":       List, | ||||
| } | ||||
|  |  | |||
|  | @ -7,10 +7,13 @@ package base | |||
| import ( | ||||
| 	"bytes" | ||||
| 	"crypto/md5" | ||||
| 	"crypto/rand" | ||||
| 	"crypto/sha1" | ||||
| 	"encoding/hex" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"math" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| ) | ||||
|  | @ -22,6 +25,67 @@ func EncodeMd5(str string) string { | |||
| 	return hex.EncodeToString(m.Sum(nil)) | ||||
| } | ||||
| 
 | ||||
| // Random generate string
 | ||||
| func GetRandomString(n int) string { | ||||
| 	const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" | ||||
| 	var bytes = make([]byte, n) | ||||
| 	rand.Read(bytes) | ||||
| 	for i, b := range bytes { | ||||
| 		bytes[i] = alphanum[b%byte(len(alphanum))] | ||||
| 	} | ||||
| 	return string(bytes) | ||||
| } | ||||
| 
 | ||||
| // create a time limit code
 | ||||
| // code format: 12 length date time string + 6 minutes string + 40 sha1 encoded string
 | ||||
| func CreateTimeLimitCode(data string, minutes int, startInf interface{}) string { | ||||
| 	format := "YmdHi" | ||||
| 
 | ||||
| 	var start, end time.Time | ||||
| 	var startStr, endStr string | ||||
| 
 | ||||
| 	if startInf == nil { | ||||
| 		// Use now time create code
 | ||||
| 		start = time.Now() | ||||
| 		startStr = DateFormat(start, format) | ||||
| 	} else { | ||||
| 		// use start string create code
 | ||||
| 		startStr = startInf.(string) | ||||
| 		start, _ = DateParse(startStr, format) | ||||
| 		startStr = DateFormat(start, format) | ||||
| 	} | ||||
| 
 | ||||
| 	end = start.Add(time.Minute * time.Duration(minutes)) | ||||
| 	endStr = DateFormat(end, format) | ||||
| 
 | ||||
| 	// create sha1 encode string
 | ||||
| 	sh := sha1.New() | ||||
| 	sh.Write([]byte(data + SecretKey + startStr + endStr + ToStr(minutes))) | ||||
| 	encoded := hex.EncodeToString(sh.Sum(nil)) | ||||
| 
 | ||||
| 	code := fmt.Sprintf("%s%06d%s", startStr, minutes, encoded) | ||||
| 	return code | ||||
| } | ||||
| 
 | ||||
| // TODO:
 | ||||
| func RenderTemplate(TplNames string, Data map[interface{}]interface{}) string { | ||||
| 	// if beego.RunMode == "dev" {
 | ||||
| 	// 	beego.BuildTemplate(beego.ViewsPath)
 | ||||
| 	// }
 | ||||
| 
 | ||||
| 	// ibytes := bytes.NewBufferString("")
 | ||||
| 	// if _, ok := beego.BeeTemplates[TplNames]; !ok {
 | ||||
| 	// 	panic("can't find templatefile in the path:" + TplNames)
 | ||||
| 	// }
 | ||||
| 	// err := beego.BeeTemplates[TplNames].ExecuteTemplate(ibytes, TplNames, Data)
 | ||||
| 	// if err != nil {
 | ||||
| 	// 	beego.Trace("template Execute err:", err)
 | ||||
| 	// }
 | ||||
| 	// icontent, _ := ioutil.ReadAll(ibytes)
 | ||||
| 	// return string(icontent)
 | ||||
| 	return "not implement yet" | ||||
| } | ||||
| 
 | ||||
| // AvatarLink returns avatar link by given e-mail.
 | ||||
| func AvatarLink(email string) string { | ||||
| 	return "http://1.gravatar.com/avatar/" + EncodeMd5(email) | ||||
|  | @ -238,6 +302,57 @@ func DateFormat(t time.Time, format string) string { | |||
| 	return t.Format(format) | ||||
| } | ||||
| 
 | ||||
| type argInt []int | ||||
| 
 | ||||
| func (a argInt) Get(i int, args ...int) (r int) { | ||||
| 	if i >= 0 && i < len(a) { | ||||
| 		r = a[i] | ||||
| 	} | ||||
| 	if len(args) > 0 { | ||||
| 		r = args[0] | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // convert any type to string
 | ||||
| func ToStr(value interface{}, args ...int) (s string) { | ||||
| 	switch v := value.(type) { | ||||
| 	case bool: | ||||
| 		s = strconv.FormatBool(v) | ||||
| 	case float32: | ||||
| 		s = strconv.FormatFloat(float64(v), 'f', argInt(args).Get(0, -1), argInt(args).Get(1, 32)) | ||||
| 	case float64: | ||||
| 		s = strconv.FormatFloat(v, 'f', argInt(args).Get(0, -1), argInt(args).Get(1, 64)) | ||||
| 	case int: | ||||
| 		s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10)) | ||||
| 	case int8: | ||||
| 		s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10)) | ||||
| 	case int16: | ||||
| 		s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10)) | ||||
| 	case int32: | ||||
| 		s = strconv.FormatInt(int64(v), argInt(args).Get(0, 10)) | ||||
| 	case int64: | ||||
| 		s = strconv.FormatInt(v, argInt(args).Get(0, 10)) | ||||
| 	case uint: | ||||
| 		s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10)) | ||||
| 	case uint8: | ||||
| 		s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10)) | ||||
| 	case uint16: | ||||
| 		s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10)) | ||||
| 	case uint32: | ||||
| 		s = strconv.FormatUint(uint64(v), argInt(args).Get(0, 10)) | ||||
| 	case uint64: | ||||
| 		s = strconv.FormatUint(v, argInt(args).Get(0, 10)) | ||||
| 	case string: | ||||
| 		s = v | ||||
| 	case []byte: | ||||
| 		s = string(v) | ||||
| 	default: | ||||
| 		s = fmt.Sprintf("%v", v) | ||||
| 	} | ||||
| 	return s | ||||
| } | ||||
| 
 | ||||
| type Actioner interface { | ||||
| 	GetOpType() int | ||||
| 	GetActUserName() string | ||||
|  |  | |||
|  | @ -11,9 +11,9 @@ import ( | |||
| 
 | ||||
| var logger *logs.BeeLogger | ||||
| 
 | ||||
| func init() { | ||||
| 	logger = logs.NewLogger(10000) | ||||
| 	logger.SetLogger("console", "") | ||||
| func NewLogger(bufLen int64, mode, config string) { | ||||
| 	logger = logs.NewLogger(bufLen) | ||||
| 	logger.SetLogger(mode, config) | ||||
| } | ||||
| 
 | ||||
| func Trace(format string, v ...interface{}) { | ||||
|  |  | |||
							
								
								
									
										31
									
								
								modules/mailer/mail.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								modules/mailer/mail.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,31 @@ | |||
| // 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 mailer | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/gogits/gogs/models" | ||||
| 	"github.com/gogits/gogs/modules/base" | ||||
| ) | ||||
| 
 | ||||
| // Create New mail message use MailFrom and MailUser
 | ||||
| func NewMailMessage(To []string, subject, body string) Message { | ||||
| 	msg := NewHtmlMessage(To, base.MailService.User, subject, body) | ||||
| 	msg.User = base.MailService.User | ||||
| 	return msg | ||||
| } | ||||
| 
 | ||||
| func GetMailTmplData(user *models.User) map[interface{}]interface{} { | ||||
| 	data := make(map[interface{}]interface{}, 10) | ||||
| 	data["AppName"] = base.AppName | ||||
| 	data["AppVer"] = base.AppVer | ||||
| 	data["AppUrl"] = base.AppUrl | ||||
| 	data["AppLogo"] = base.AppLogo | ||||
| 	data["ActiveCodeLives"] = base.Service.ActiveCodeLives | ||||
| 	data["ResetPwdCodeLives"] = base.Service.ResetPwdCodeLives | ||||
| 	if user != nil { | ||||
| 		data["User"] = user | ||||
| 	} | ||||
| 	return data | ||||
| } | ||||
							
								
								
									
										112
									
								
								modules/mailer/mailer.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								modules/mailer/mailer.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,112 @@ | |||
| // 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 mailer | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"net/smtp" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/gogits/gogs/modules/base" | ||||
| 	"github.com/gogits/gogs/modules/log" | ||||
| ) | ||||
| 
 | ||||
| type Message struct { | ||||
| 	To      []string | ||||
| 	From    string | ||||
| 	Subject string | ||||
| 	Body    string | ||||
| 	User    string | ||||
| 	Type    string | ||||
| 	Massive bool | ||||
| 	Info    string | ||||
| } | ||||
| 
 | ||||
| // create mail content
 | ||||
| func (m Message) Content() string { | ||||
| 	// set mail type
 | ||||
| 	contentType := "text/plain; charset=UTF-8" | ||||
| 	if m.Type == "html" { | ||||
| 		contentType = "text/html; charset=UTF-8" | ||||
| 	} | ||||
| 
 | ||||
| 	// create mail content
 | ||||
| 	content := "From: " + m.User + "<" + m.From + | ||||
| 		">\r\nSubject: " + m.Subject + "\r\nContent-Type: " + contentType + "\r\n\r\n" + m.Body | ||||
| 	return content | ||||
| } | ||||
| 
 | ||||
| // Direct Send mail message
 | ||||
| func Send(msg Message) (int, error) { | ||||
| 	log.Trace("Sending mails to: %s", strings.Join(msg.To, "; ")) | ||||
| 	host := strings.Split(base.MailService.Host, ":") | ||||
| 
 | ||||
| 	// get message body
 | ||||
| 	content := msg.Content() | ||||
| 
 | ||||
| 	auth := smtp.PlainAuth("", base.MailService.User, base.MailService.Passwd, host[0]) | ||||
| 
 | ||||
| 	if len(msg.To) == 0 { | ||||
| 		return 0, fmt.Errorf("empty receive emails") | ||||
| 	} | ||||
| 
 | ||||
| 	if len(msg.Body) == 0 { | ||||
| 		return 0, fmt.Errorf("empty email body") | ||||
| 	} | ||||
| 
 | ||||
| 	if msg.Massive { | ||||
| 		// send mail to multiple emails one by one
 | ||||
| 		num := 0 | ||||
| 		for _, to := range msg.To { | ||||
| 			body := []byte("To: " + to + "\r\n" + content) | ||||
| 			err := smtp.SendMail(base.MailService.Host, auth, msg.From, []string{to}, body) | ||||
| 			if err != nil { | ||||
| 				return num, err | ||||
| 			} | ||||
| 			num++ | ||||
| 		} | ||||
| 		return num, nil | ||||
| 	} else { | ||||
| 		body := []byte("To: " + strings.Join(msg.To, ";") + "\r\n" + content) | ||||
| 
 | ||||
| 		// send to multiple emails in one message
 | ||||
| 		err := smtp.SendMail(base.MailService.Host, auth, msg.From, msg.To, body) | ||||
| 		if err != nil { | ||||
| 			return 0, err | ||||
| 		} else { | ||||
| 			return 1, nil | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Async Send mail message
 | ||||
| func SendAsync(msg Message) { | ||||
| 	// TODO may be need pools limit concurrent nums
 | ||||
| 	go func() { | ||||
| 		num, err := Send(msg) | ||||
| 		tos := strings.Join(msg.To, "; ") | ||||
| 		info := "" | ||||
| 		if err != nil { | ||||
| 			if len(msg.Info) > 0 { | ||||
| 				info = ", info: " + msg.Info | ||||
| 			} | ||||
| 			// log failed
 | ||||
| 			log.Error(fmt.Sprintf("Async sent email %d succeed, not send emails: %s%s err: %s", num, tos, info, err)) | ||||
| 			return | ||||
| 		} | ||||
| 		log.Trace(fmt.Sprintf("Async sent email %d succeed, sent emails: %s%s", num, tos, info)) | ||||
| 	}() | ||||
| } | ||||
| 
 | ||||
| // Create html mail message
 | ||||
| func NewHtmlMessage(To []string, From, Subject, Body string) Message { | ||||
| 	return Message{ | ||||
| 		To:      To, | ||||
| 		From:    From, | ||||
| 		Subject: Subject, | ||||
| 		Body:    Body, | ||||
| 		Type:    "html", | ||||
| 	} | ||||
| } | ||||
|  | @ -67,8 +67,13 @@ func (ctx *Context) RenderWithErr(msg, tpl string, form auth.Form) { | |||
| 
 | ||||
| // Handle handles and logs error by given status.
 | ||||
| func (ctx *Context) Handle(status int, title string, err error) { | ||||
| 	ctx.Data["ErrorMsg"] = err | ||||
| 	log.Error("%s: %v", title, err) | ||||
| 	if martini.Dev == martini.Prod { | ||||
| 		ctx.Render.HTML(500, "status/500", ctx.Data) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	ctx.Data["ErrorMsg"] = err | ||||
| 	ctx.Render.HTML(status, fmt.Sprintf("status/%d", status), ctx.Data) | ||||
| } | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										46
									
								
								modules/middleware/logger.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								modules/middleware/logger.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,46 @@ | |||
| // 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 middleware | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"net/http" | ||||
| 	"runtime" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/codegangsta/martini" | ||||
| ) | ||||
| 
 | ||||
| var isWindows bool | ||||
| 
 | ||||
| func init() { | ||||
| 	isWindows = runtime.GOOS == "windows" | ||||
| } | ||||
| 
 | ||||
| func Logger() martini.Handler { | ||||
| 	return func(res http.ResponseWriter, req *http.Request, ctx martini.Context, log *log.Logger) { | ||||
| 		start := time.Now() | ||||
| 		log.Printf("Started %s %s", req.Method, req.URL.Path) | ||||
| 
 | ||||
| 		rw := res.(martini.ResponseWriter) | ||||
| 		ctx.Next() | ||||
| 
 | ||||
| 		content := fmt.Sprintf("Completed %v %s in %v", rw.Status(), http.StatusText(rw.Status()), time.Since(start)) | ||||
| 		if !isWindows { | ||||
| 			switch rw.Status() { | ||||
| 			case 200: | ||||
| 				content = fmt.Sprintf("\033[1;32m%s\033[0m", content) | ||||
| 			case 304: | ||||
| 				content = fmt.Sprintf("\033[1;33m%s\033[0m", content) | ||||
| 			case 404: | ||||
| 				content = fmt.Sprintf("\033[1;31m%s\033[0m", content) | ||||
| 			case 500: | ||||
| 				content = fmt.Sprintf("\033[1;36m%s\033[0m", content) | ||||
| 			} | ||||
| 		} | ||||
| 		log.Println(content) | ||||
| 	} | ||||
| } | ||||
|  | @ -575,6 +575,15 @@ html, body { | |||
|     padding: 9px 20px; | ||||
| } | ||||
| 
 | ||||
| .info-box .info-head { | ||||
|     font-weight: normal; | ||||
| } | ||||
| 
 | ||||
| .info-box .info-content  a, | ||||
| .info-box .info-head a { | ||||
|     color: #666; | ||||
| } | ||||
| 
 | ||||
| .file-list { | ||||
|     background-color: #fafafa; | ||||
| } | ||||
|  |  | |||
|  | @ -105,7 +105,7 @@ | |||
| .markdown > pre { | ||||
|   line-height: 1.6; | ||||
|   overflow: auto; | ||||
|   background: #fff; | ||||
|   background: #f8f8f8; | ||||
|   padding: 6px 10px; | ||||
|   border: 1px solid #ddd; | ||||
| } | ||||
|  |  | |||
|  | @ -18,6 +18,7 @@ func Home(ctx *middleware.Context) { | |||
| 	ctx.Render.HTML(200, "home", ctx.Data) | ||||
| } | ||||
| 
 | ||||
| func Help(ctx *middleware.Context) string { | ||||
| 	return "This is help page" | ||||
| func Help(ctx *middleware.Context) { | ||||
| 	ctx.Data["PageIsHelp"] = true | ||||
| 	ctx.Render.HTML(200, "help", ctx.Data) | ||||
| } | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ package repo | |||
| import ( | ||||
| 	"github.com/gogits/gogs/models" | ||||
| 	"github.com/gogits/gogs/modules/auth" | ||||
| 	"github.com/gogits/gogs/modules/log" | ||||
| 	"github.com/gogits/gogs/modules/middleware" | ||||
| ) | ||||
| 
 | ||||
|  | @ -23,6 +24,7 @@ func Create(ctx *middleware.Context, form auth.CreateRepoForm) { | |||
| 	_, err := models.CreateRepository(ctx.User, form.RepoName, form.Description, | ||||
| 		form.Language, form.License, form.Visibility == "private", form.InitReadme == "on") | ||||
| 	if err == nil { | ||||
| 		log.Trace("%s Repository created: %s/%s", ctx.Req.RequestURI, ctx.User.LowerName, form.RepoName) | ||||
| 		ctx.Render.Redirect("/"+ctx.User.Name+"/"+form.RepoName, 302) | ||||
| 		return | ||||
| 	} else if err == models.ErrRepoAlreadyExist { | ||||
|  | @ -52,5 +54,6 @@ func SettingPost(ctx *middleware.Context) { | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	log.Trace("%s Repository deleted: %s/%s", ctx.Req.RequestURI, ctx.User.LowerName, ctx.Repo.Repository.LowerName) | ||||
| 	ctx.Render.Redirect("/", 302) | ||||
| } | ||||
|  |  | |||
|  | @ -182,10 +182,12 @@ func Commits(ctx *middleware.Context, params martini.Params) { | |||
| 	ctx.Render.HTML(200, "repo/commits", ctx.Data) | ||||
| } | ||||
| 
 | ||||
| func Issues(ctx *middleware.Context) string { | ||||
| 	return "This is issues page" | ||||
| func Issues(ctx *middleware.Context) { | ||||
| 	ctx.Data["IsRepoToolbarIssues"] = true | ||||
| 	ctx.Render.HTML(200, "repo/issues", ctx.Data) | ||||
| } | ||||
| 
 | ||||
| func Pulls(ctx *middleware.Context) string { | ||||
| 	return "This is pulls page" | ||||
| func Pulls(ctx *middleware.Context) { | ||||
| 	ctx.Data["IsRepoToolbarPulls"] = true | ||||
| 	ctx.Render.HTML(200, "repo/pulls", ctx.Data) | ||||
| } | ||||
|  |  | |||
|  | @ -14,9 +14,11 @@ import ( | |||
| 	"github.com/gogits/gogs/modules/middleware" | ||||
| ) | ||||
| 
 | ||||
| // Render user setting page (email, website modify)
 | ||||
| func Setting(ctx *middleware.Context, form auth.UpdateProfileForm) { | ||||
| 	ctx.Data["Title"] = "Setting" | ||||
| 	ctx.Data["PageIsUserSetting"] = true | ||||
| 	ctx.Data["PageIsUserSetting"] = true // For navbar arrow.
 | ||||
| 	ctx.Data["IsUserPageSetting"] = true // For setting nav highlight.
 | ||||
| 
 | ||||
| 	user := ctx.User | ||||
| 	ctx.Data["Owner"] = user | ||||
|  | @ -26,6 +28,7 @@ func Setting(ctx *middleware.Context, form auth.UpdateProfileForm) { | |||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// below is for POST requests
 | ||||
| 	if hasErr, ok := ctx.Data["HasError"]; ok && hasErr.(bool) { | ||||
| 		ctx.Render.HTML(200, "user/setting", ctx.Data) | ||||
| 		return | ||||
|  | @ -43,11 +46,13 @@ func Setting(ctx *middleware.Context, form auth.UpdateProfileForm) { | |||
| 
 | ||||
| 	ctx.Data["IsSuccess"] = true | ||||
| 	ctx.Render.HTML(200, "user/setting", ctx.Data) | ||||
| 	log.Trace("%s User setting updated: %s", ctx.Req.RequestURI, ctx.User.LowerName) | ||||
| } | ||||
| 
 | ||||
| func SettingPassword(ctx *middleware.Context, form auth.UpdatePasswdForm) { | ||||
| 	ctx.Data["Title"] = "Password" | ||||
| 	ctx.Data["PageIsUserSetting"] = true | ||||
| 	ctx.Data["IsUserPageSettingPasswd"] = true | ||||
| 
 | ||||
| 	if ctx.Req.Method == "GET" { | ||||
| 		ctx.Render.HTML(200, "user/password", ctx.Data) | ||||
|  | @ -78,6 +83,7 @@ func SettingPassword(ctx *middleware.Context, form auth.UpdatePasswdForm) { | |||
| 
 | ||||
| 	ctx.Data["Owner"] = user | ||||
| 	ctx.Render.HTML(200, "user/password", ctx.Data) | ||||
| 	log.Trace("%s User password updated: %s", ctx.Req.RequestURI, ctx.User.LowerName) | ||||
| } | ||||
| 
 | ||||
| func SettingSSHKeys(ctx *middleware.Context, form auth.AddSSHKeyForm) { | ||||
|  | @ -108,6 +114,7 @@ func SettingSSHKeys(ctx *middleware.Context, form auth.AddSSHKeyForm) { | |||
| 				"err": err.Error(), | ||||
| 			}) | ||||
| 		} else { | ||||
| 			log.Trace("%s User SSH key deleted: %s", ctx.Req.RequestURI, ctx.User.LowerName) | ||||
| 			ctx.Render.JSON(200, map[string]interface{}{ | ||||
| 				"ok": true, | ||||
| 			}) | ||||
|  | @ -133,6 +140,7 @@ func SettingSSHKeys(ctx *middleware.Context, form auth.AddSSHKeyForm) { | |||
| 				return | ||||
| 			} | ||||
| 			ctx.Handle(200, "ssh.AddPublicKey", err) | ||||
| 			log.Trace("%s User SSH key added: %s", ctx.Req.RequestURI, ctx.User.LowerName) | ||||
| 			return | ||||
| 		} else { | ||||
| 			ctx.Data["AddSSHKeySuccess"] = true | ||||
|  | @ -147,20 +155,23 @@ func SettingSSHKeys(ctx *middleware.Context, form auth.AddSSHKeyForm) { | |||
| 	} | ||||
| 
 | ||||
| 	ctx.Data["PageIsUserSetting"] = true | ||||
| 	ctx.Data["IsUserPageSettingSSH"] = true | ||||
| 	ctx.Data["Keys"] = keys | ||||
| 	ctx.Render.HTML(200, "user/publickey", ctx.Data) | ||||
| } | ||||
| 
 | ||||
| func SettingNotification(ctx *middleware.Context) { | ||||
| 	// todo user setting notification
 | ||||
| 	// TODO: user setting notification
 | ||||
| 	ctx.Data["Title"] = "Notification" | ||||
| 	ctx.Data["PageIsUserSetting"] = true | ||||
| 	ctx.Data["IsUserPageSettingNotify"] = true | ||||
| 	ctx.Render.HTML(200, "user/notification", ctx.Data) | ||||
| } | ||||
| 
 | ||||
| func SettingSecurity(ctx *middleware.Context) { | ||||
| 	// todo user setting security
 | ||||
| 	// TODO: user setting security
 | ||||
| 	ctx.Data["Title"] = "Security" | ||||
| 	ctx.Data["PageIsUserSetting"] = true | ||||
| 	ctx.Data["IsUserPageSettingSecurity"] = true | ||||
| 	ctx.Render.HTML(200, "user/security", ctx.Data) | ||||
| } | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ package user | |||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/codegangsta/martini" | ||||
| 	"github.com/martini-contrib/render" | ||||
|  | @ -14,6 +15,7 @@ import ( | |||
| 	"github.com/gogits/gogs/models" | ||||
| 	"github.com/gogits/gogs/modules/auth" | ||||
| 	"github.com/gogits/gogs/modules/base" | ||||
| 	"github.com/gogits/gogs/modules/log" | ||||
| 	"github.com/gogits/gogs/modules/middleware" | ||||
| ) | ||||
| 
 | ||||
|  | @ -129,12 +131,14 @@ func SignUp(ctx *middleware.Context, form auth.RegisterForm) { | |||
| 	} | ||||
| 
 | ||||
| 	u := &models.User{ | ||||
| 		Name:   form.UserName, | ||||
| 		Email:  form.Email, | ||||
| 		Passwd: form.Password, | ||||
| 		Name:     form.UserName, | ||||
| 		Email:    form.Email, | ||||
| 		Passwd:   form.Password, | ||||
| 		IsActive: !base.Service.RegisterEmailConfirm, | ||||
| 	} | ||||
| 
 | ||||
| 	if err := models.RegisterUser(u); err != nil { | ||||
| 	var err error | ||||
| 	if u, err = models.RegisterUser(u); err != nil { | ||||
| 		switch err.Error() { | ||||
| 		case models.ErrUserAlreadyExist.Error(): | ||||
| 			ctx.RenderWithErr("Username has been already taken", "user/signup", &form) | ||||
|  | @ -146,11 +150,19 @@ func SignUp(ctx *middleware.Context, form auth.RegisterForm) { | |||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	log.Trace("%s User created: %s", ctx.Req.RequestURI, strings.ToLower(form.UserName)) | ||||
| 
 | ||||
| 	// Send confirmation e-mail.
 | ||||
| 	if base.Service.RegisterEmailConfirm { | ||||
| 		auth.SendRegisterMail(u) | ||||
| 	} | ||||
| 	ctx.Render.Redirect("/user/login") | ||||
| } | ||||
| 
 | ||||
| func Delete(ctx *middleware.Context) { | ||||
| 	ctx.Data["Title"] = "Delete Account" | ||||
| 	ctx.Data["PageIsUserSetting"] = true | ||||
| 	ctx.Data["IsUserPageSettingDelete"] = true | ||||
| 
 | ||||
| 	if ctx.Req.Method == "GET" { | ||||
| 		ctx.Render.HTML(200, "user/delete", ctx.Data) | ||||
|  | @ -182,7 +194,7 @@ func Delete(ctx *middleware.Context) { | |||
| } | ||||
| 
 | ||||
| const ( | ||||
| 	feedTpl = `<i class="icon fa fa-%s"></i> | ||||
| 	TPL_FEED = `<i class="icon fa fa-%s"></i> | ||||
|                         <div class="info"><span class="meta">%s</span><br>%s</div>` | ||||
| ) | ||||
| 
 | ||||
|  | @ -194,20 +206,20 @@ func Feeds(ctx *middleware.Context, form auth.FeedsForm) { | |||
| 
 | ||||
| 	feeds := make([]string, len(actions)) | ||||
| 	for i := range actions { | ||||
| 		feeds[i] = fmt.Sprintf(feedTpl, base.ActionIcon(actions[i].OpType), | ||||
| 		feeds[i] = fmt.Sprintf(TPL_FEED, base.ActionIcon(actions[i].OpType), | ||||
| 			base.TimeSince(actions[i].Created), base.ActionDesc(actions[i], ctx.User.AvatarLink())) | ||||
| 	} | ||||
| 	ctx.Render.JSON(200, &feeds) | ||||
| } | ||||
| 
 | ||||
| func Issues(ctx *middleware.Context) string { | ||||
| 	return "This is issues page" | ||||
| func Issues(ctx *middleware.Context) { | ||||
| 	ctx.Render.HTML(200, "user/issues", ctx.Data) | ||||
| } | ||||
| 
 | ||||
| func Pulls(ctx *middleware.Context) string { | ||||
| 	return "This is pulls page" | ||||
| func Pulls(ctx *middleware.Context) { | ||||
| 	ctx.Render.HTML(200, "user/pulls", ctx.Data) | ||||
| } | ||||
| 
 | ||||
| func Stars(ctx *middleware.Context) string { | ||||
| 	return "This is stars page" | ||||
| func Stars(ctx *middleware.Context) { | ||||
| 	ctx.Render.HTML(200, "user/stars", ctx.Data) | ||||
| } | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ | |||
|         <nav class="gogs-nav"> | ||||
|             <a id="gogs-nav-logo" class="gogs-nav-item{{if .PageIsHome}} active{{end}}" href="/"><img src="/img/favicon.png" alt="Gogs Logo" id="gogs-logo"></a> | ||||
|             <a class="gogs-nav-item{{if .PageIsUserDashboard}} active{{end}}" href="/">Dashboard</a> | ||||
|             <a class="gogs-nav-item" href="/help">Help</a>{{if .IsSigned}} | ||||
|             <a class="gogs-nav-item{{if .PageIsHelp}} active{{end}}" href="/help">Help</a>{{if .IsSigned}} | ||||
|             <a id="gogs-nav-out" class="gogs-nav-item navbar-right navbar-btn btn btn-danger" href="/user/logout/"><i class="fa fa-power-off fa-lg"></i></a> | ||||
|             <a id="gogs-nav-avatar" class="gogs-nav-item navbar-right" href="{{.SignedUser.HomeLink}}" data-toggle="tooltip" data-placement="bottom" title="{{.SignedUserName}}"> | ||||
|                 <img src="{{.SignedUser.AvatarLink}}?s=28" alt="user-avatar" title="username"/> | ||||
|  |  | |||
							
								
								
									
										11
									
								
								templates/help.tmpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								templates/help.tmpl
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | |||
| {{template "base/head" .}} | ||||
| {{template "base/navbar" .}} | ||||
| <div id="gogs-body-nav"> | ||||
|     <div class="container"> | ||||
|         <h3>Help</h3> | ||||
|     </div> | ||||
| </div> | ||||
| <div id="gogs-body" class="container" data-page="user"> | ||||
|     {{if .HasInfo}}<div class="alert alert-info">{{.InfoMsg}}</div>{{end}} | ||||
| </div> | ||||
| {{template "base/footer" .}} | ||||
|  | @ -1,6 +1,6 @@ | |||
| {{template "base/head" .}} | ||||
| {{template "base/navbar" .}} | ||||
| <div id="gogs-body" class="container"> | ||||
| 	Website is still in the progress of building...please come back later! | ||||
| 	Welcome to the land of Gogs! There will be some indroduction! | ||||
| </div> | ||||
| {{template "base/footer" .}} | ||||
|  | @ -5,8 +5,9 @@ | |||
| <div id="gogs-body" class="container"> | ||||
|     <div id="gogs-commits"> | ||||
|     <ul> | ||||
|     {{range .Commits}} | ||||
|     <li>{{.Committer.Name}} - {{.Id}} - {{.Message}} - {{.Committer.When}}</li> | ||||
|     {{$r := List .Commits}} | ||||
|     {{range $r}} | ||||
| 		    <li>{{.Committer.Name}} - {{.Id}} - {{.Message}} - {{.Committer.When}}</li> | ||||
|     {{end}} | ||||
|     </ul> | ||||
|     </div> | ||||
|  |  | |||
							
								
								
									
										9
									
								
								templates/repo/issues.tmpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								templates/repo/issues.tmpl
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | |||
| {{template "base/head" .}} | ||||
| {{template "base/navbar" .}} | ||||
| {{template "repo/nav" .}} | ||||
| {{template "repo/toolbar" .}} | ||||
| <div id="gogs-body" class="container"> | ||||
|     <div id="gogs-source"> | ||||
|     </div> | ||||
| </div> | ||||
| {{template "base/footer" .}} | ||||
							
								
								
									
										9
									
								
								templates/repo/pulls.tmpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								templates/repo/pulls.tmpl
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | |||
| {{template "base/head" .}} | ||||
| {{template "base/navbar" .}} | ||||
| {{template "repo/nav" .}} | ||||
| {{template "repo/toolbar" .}} | ||||
| <div id="gogs-body" class="container"> | ||||
|     <div id="gogs-source"> | ||||
|     </div> | ||||
| </div> | ||||
| {{template "base/footer" .}} | ||||
							
								
								
									
										17
									
								
								templates/user/issues.tmpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								templates/user/issues.tmpl
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | |||
| {{template "base/head" .}} | ||||
| {{template "base/navbar" .}} | ||||
| <div id="gogs-body-nav"> | ||||
|     <div class="container"> | ||||
|         <ul class="nav nav-pills pull-right"> | ||||
|             <li><a href="/">Feed</a></li> | ||||
|             <li class="active"><a href="/issues">Issues</a></li> | ||||
|             <li><a href="/pulls">Pull Requests</a></li> | ||||
|             <li><a href="/stars">Stars</a></li> | ||||
|         </ul> | ||||
|         <h3>Issues</h3> | ||||
|     </div> | ||||
| </div> | ||||
| <div id="gogs-body" class="container" data-page="user"> | ||||
|     {{if .HasInfo}}<div class="alert alert-info">{{.InfoMsg}}</div>{{end}} | ||||
| </div> | ||||
| {{template "base/footer" .}} | ||||
|  | @ -1,17 +1,7 @@ | |||
| {{template "base/head" .}} | ||||
| {{template "base/navbar" .}} | ||||
| <div id="gogs-body" class="container" data-page="user"> | ||||
|     <div id="gogs-user-setting-nav" class="col-md-3"> | ||||
|         <h4>Account Setting</h4> | ||||
|         <ul class="list-group"> | ||||
|             <li class="list-group-item"><a href="/user/setting">Account Profile</a></li> | ||||
|             <li class="list-group-item"><a href="/user/setting/password">Password</a></li> | ||||
|             <li class="list-group-item list-group-item-success"><a href="/user/setting/notification">Notifications</a></li> | ||||
|             <li class="list-group-item"><a href="/user/setting/ssh/">SSH Keys</a></li> | ||||
|             <li class="list-group-item"><a href="/user/setting/security">Security</a></li> | ||||
|             <li class="list-group-item"><a href="/user/delete">Delete Account</a></li> | ||||
|         </ul> | ||||
|     </div> | ||||
|     {{template "user/setting_nav" .}} | ||||
|     <div id="gogs-user-setting-container" class="col-md-9"> | ||||
|         <h4>Notification</h4> | ||||
|     </div> | ||||
|  |  | |||
|  | @ -1,45 +1,35 @@ | |||
| {{template "base/head" .}} | ||||
| {{template "base/navbar" .}} | ||||
| <div id="gogs-body" class="container" data-page="user"> | ||||
|     <div id="gogs-user-setting-nav" class="col-md-3"> | ||||
|         <h4>Account Setting</h4> | ||||
|         <ul class="list-group"> | ||||
|             <li class="list-group-item"><a href="/user/setting">Account Profile</a></li> | ||||
|             <li class="list-group-item list-group-item-success"><a href="/user/setting/password">Password</a></li> | ||||
|             <li class="list-group-item"><a href="/user/setting/notification">Notifications</a></li> | ||||
|             <li class="list-group-item"><a href="/user/setting/ssh/">SSH Keys</a></li> | ||||
|             <li class="list-group-item"><a href="/user/setting/security">Security</a></li> | ||||
|             <li class="list-group-item"><a href="/user/delete">Delete Account</a></li> | ||||
|         </ul> | ||||
|     </div> | ||||
|     {{template "user/setting_nav" .}} | ||||
|     <div id="gogs-user-setting-container" class="col-md-9"> | ||||
|         <div id="gogs-setting-pwd"> | ||||
|             <h4>Password</h4> | ||||
|             <form class="form-horizontal" id="gogs-password-form" method="post" action="/user/setting/password">{{if .IsSuccess}} | ||||
|                 <p class="alert alert-success">Password is changed successfully. You can now sign in via new password.</p>{{else if .HasError}}<p class="alert alert-danger form-error">{{.ErrorMsg}}</p>{{end}} | ||||
|                 <div class="form-group"> | ||||
|                     <label class="col-md-2 control-label">Old Password<strong class="text-danger">*</strong></label> | ||||
|                     <div class="col-md-8"> | ||||
|                     <label class="col-md-3 control-label">Old Password<strong class="text-danger">*</strong></label> | ||||
|                     <div class="col-md-7"> | ||||
|                         <input type="password" name="oldpasswd" class="form-control" placeholder="Type your current password" required="required"> | ||||
|                     </div> | ||||
|                 </div> | ||||
| 
 | ||||
|                 <div class="form-group"> | ||||
|                     <label class="col-md-2 control-label">New Password<strong class="text-danger">*</strong></label> | ||||
|                     <div class="col-md-8"> | ||||
|                     <label class="col-md-3 control-label">New Password<strong class="text-danger">*</strong></label> | ||||
|                     <div class="col-md-7"> | ||||
|                         <input type="password" name="newpasswd" class="form-control" placeholder="Type your new password" required="required"> | ||||
|                     </div> | ||||
|                 </div> | ||||
| 
 | ||||
|                 <div class="form-group"> | ||||
|                     <label class="col-md-2 control-label">Re-Type<strong class="text-danger">*</strong></label> | ||||
|                     <div class="col-md-8"> | ||||
|                     <label class="col-md-3 control-label">Re-Type<strong class="text-danger">*</strong></label> | ||||
|                     <div class="col-md-7"> | ||||
|                         <input type="password" name="retypepasswd" class="form-control" placeholder="Re-type your new password" required="required"> | ||||
|                     </div> | ||||
|                 </div> | ||||
| 
 | ||||
|                 <div class="form-group"> | ||||
|                     <div class="col-md-offset-2 col-md-8"> | ||||
|                     <div class="col-md-offset-3 col-md-7"> | ||||
|                         <button type="submit" class="btn btn-primary">Change Password</button>   | ||||
|                         <a href="/forget-password/">Forgot your password?</a> | ||||
|                     </div> | ||||
|  |  | |||
|  | @ -1,18 +1,7 @@ | |||
| {{template "base/head" .}} | ||||
| {{template "base/navbar" .}} | ||||
| <div id="gogs-body" class="container" data-page="user"> | ||||
|     <div id="gogs-user-setting-nav" class="col-md-3"> | ||||
|         <h4>Account Setting</h4> | ||||
|         <ul class="list-group"> | ||||
|             <li class="list-group-item"><a href="/user/setting">Account Profile</a></li> | ||||
|             <li class="list-group-item"><a href="/user/setting/password">Password</a></li> | ||||
|             <li class="list-group-item"><a href="/user/setting/notification">Notifications</a></li> | ||||
|             <li class="list-group-item list-group-item-success"><a href="/user/setting/ssh/">SSH Keys</a></li> | ||||
|             <li class="list-group-item"><a href="/user/setting/security">Security</a></li> | ||||
|             <li class="list-group-item"><a href="/user/delete">Delete Account</a></li> | ||||
|         </ul> | ||||
|     </div> | ||||
| 
 | ||||
|     {{template "user/setting_nav" .}} | ||||
|     <div id="gogs-user-setting-container" class="col-md-9"> | ||||
|         <div id="gogs-ssh-keys"> | ||||
|             <h4>SSH Keys</h4>{{if .AddSSHKeySuccess}} | ||||
|  |  | |||
							
								
								
									
										17
									
								
								templates/user/pulls.tmpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								templates/user/pulls.tmpl
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | |||
| {{template "base/head" .}} | ||||
| {{template "base/navbar" .}} | ||||
| <div id="gogs-body-nav"> | ||||
|     <div class="container"> | ||||
|         <ul class="nav nav-pills pull-right"> | ||||
|             <li><a href="/">Feed</a></li> | ||||
|             <li><a href="/issues">Issues</a></li> | ||||
|             <li class="active"><a href="/pulls">Pull Requests</a></li> | ||||
|             <li><a href="/stars">Stars</a></li> | ||||
|         </ul> | ||||
|         <h3>Pull Requests</h3> | ||||
|     </div> | ||||
| </div> | ||||
| <div id="gogs-body" class="container" data-page="user"> | ||||
|     {{if .HasInfo}}<div class="alert alert-info">{{.InfoMsg}}</div>{{end}} | ||||
| </div> | ||||
| {{template "base/footer" .}} | ||||
|  | @ -1,17 +1,7 @@ | |||
| {{template "base/head" .}} | ||||
| {{template "base/navbar" .}} | ||||
| <div id="gogs-body" class="container" data-page="user"> | ||||
|     <div id="gogs-user-setting-nav" class="col-md-3"> | ||||
|         <h4>Account Setting</h4> | ||||
|         <ul class="list-group"> | ||||
|             <li class="list-group-item"><a href="/user/setting">Account Profile</a></li> | ||||
|             <li class="list-group-item"><a href="/user/setting/password">Password</a></li> | ||||
|             <li class="list-group-item"><a href="/user/setting/notification">Notifications</a></li> | ||||
|             <li class="list-group-item"><a href="/user/setting/ssh/">SSH Keys</a></li> | ||||
|             <li class="list-group-item list-group-item-success"><a href="/user/setting/security">Security</a></li> | ||||
|             <li class="list-group-item"><a href="/user/delete">Delete Account</a></li> | ||||
|         </ul> | ||||
|     </div> | ||||
|     {{template "user/setting_nav" .}} | ||||
|     <div id="gogs-user-setting-container" class="col-md-9"> | ||||
|         <h4>Security</h4> | ||||
|     </div> | ||||
|  |  | |||
|  | @ -1,17 +1,7 @@ | |||
| {{template "base/head" .}} | ||||
| {{template "base/navbar" .}} | ||||
| <div id="gogs-body" class="container" data-page="user"> | ||||
|     <div id="gogs-user-setting-nav" class="col-md-3"> | ||||
|         <h4>Account Setting</h4> | ||||
|         <ul class="list-group"> | ||||
|             <li class="list-group-item list-group-item-success"><a href="/user/setting">Account Profile</a></li> | ||||
|             <li class="list-group-item"><a href="/user/setting/password">Password</a></li> | ||||
|             <li class="list-group-item"><a href="/user/setting/notification">Notifications</a></li> | ||||
|             <li class="list-group-item"><a href="/user/setting/ssh/">SSH Keys</a></li> | ||||
|             <li class="list-group-item"><a href="/user/setting/security">Security</a></li> | ||||
|             <li class="list-group-item"><a href="/user/delete">Delete Account</a></li> | ||||
|         </ul> | ||||
|     </div> | ||||
|     {{template "user/setting_nav" .}} | ||||
|     <div id="gogs-user-setting-container" class="col-md-9"> | ||||
|         <div id="gogs-setting-pwd"> | ||||
|             <h4>Account Profile</h4> | ||||
|  |  | |||
							
								
								
									
										11
									
								
								templates/user/setting_nav.tmpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								templates/user/setting_nav.tmpl
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | |||
| <div id="gogs-user-setting-nav" class="col-md-3"> | ||||
|     <h4>Account Setting</h4> | ||||
|     <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 .IsUserPageSettingPasswd}} list-group-item-success{{end}}"><a href="/user/setting/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 .IsUserPageSettingSSH}} list-group-item-success{{end}}"><a href="/user/setting/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 .IsUserPageSettingDelete}} list-group-item-success{{end}}"><a href="/user/delete">Delete Account</a></li> | ||||
|     </ul> | ||||
| </div> | ||||
							
								
								
									
										17
									
								
								templates/user/stars.tmpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								templates/user/stars.tmpl
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | |||
| {{template "base/head" .}} | ||||
| {{template "base/navbar" .}} | ||||
| <div id="gogs-body-nav"> | ||||
|     <div class="container"> | ||||
|         <ul class="nav nav-pills pull-right"> | ||||
|             <li><a href="/">Feed</a></li> | ||||
|             <li><a href="/issues">Issues</a></li> | ||||
|             <li><a href="/pulls">Pull Requests</a></li> | ||||
|             <li class="active"><a href="/stars">Stars</a></li> | ||||
|         </ul> | ||||
|         <h3>Stars</h3> | ||||
|     </div> | ||||
| </div> | ||||
| <div id="gogs-body" class="container" data-page="user"> | ||||
|     {{if .HasInfo}}<div class="alert alert-info">{{.InfoMsg}}</div>{{end}} | ||||
| </div> | ||||
| {{template "base/footer" .}} | ||||
|  | @ -10,8 +10,7 @@ import ( | |||
| 
 | ||||
| 	"github.com/codegangsta/cli" | ||||
| 
 | ||||
| 	git "github.com/gogits/git" | ||||
| 
 | ||||
| 	"github.com/gogits/git" | ||||
| 	"github.com/gogits/gogs/models" | ||||
| 	"github.com/gogits/gogs/modules/log" | ||||
| ) | ||||
|  | @ -25,6 +24,7 @@ gogs serv provide access auth for repositories`, | |||
| 	Flags:  []cli.Flag{}, | ||||
| } | ||||
| 
 | ||||
| // for command: ./gogs update
 | ||||
| func runUpdate(*cli.Context) { | ||||
| 	userName := os.Getenv("userName") | ||||
| 	userId := os.Getenv("userId") | ||||
|  |  | |||
							
								
								
									
										84
									
								
								web.go
									
									
									
									
									
								
							
							
						
						
									
										84
									
								
								web.go
									
									
									
									
									
								
							|  | @ -8,6 +8,7 @@ import ( | |||
| 	"fmt" | ||||
| 	"html/template" | ||||
| 	"net/http" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/codegangsta/cli" | ||||
| 	"github.com/codegangsta/martini" | ||||
|  | @ -34,10 +35,33 @@ gogs web`, | |||
| 	Flags:  []cli.Flag{}, | ||||
| } | ||||
| 
 | ||||
| // Check run mode(Default of martini is Dev).
 | ||||
| func checkRunMode() { | ||||
| 	switch base.Cfg.MustValue("", "RUN_MODE") { | ||||
| 	case "prod": | ||||
| 		martini.Env = martini.Prod | ||||
| 	case "test": | ||||
| 		martini.Env = martini.Test | ||||
| 	} | ||||
| 	log.Info("Run Mode: %s", strings.Title(martini.Env)) | ||||
| } | ||||
| 
 | ||||
| func newMartini() *martini.ClassicMartini { | ||||
| 	r := martini.NewRouter() | ||||
| 	m := martini.New() | ||||
| 	m.Use(middleware.Logger()) | ||||
| 	m.Use(martini.Recovery()) | ||||
| 	m.Use(martini.Static("public")) | ||||
| 	m.MapTo(r, (*martini.Routes)(nil)) | ||||
| 	m.Action(r.Handle) | ||||
| 	return &martini.ClassicMartini{m, r} | ||||
| } | ||||
| 
 | ||||
| func runWeb(*cli.Context) { | ||||
| 	checkRunMode() | ||||
| 	log.Info("%s %s", base.AppName, base.AppVer) | ||||
| 
 | ||||
| 	m := martini.Classic() | ||||
| 	m := newMartini() | ||||
| 
 | ||||
| 	// Middlewares.
 | ||||
| 	m.Use(render.Renderer(render.Options{Funcs: []template.FuncMap{base.TemplateFuncs}})) | ||||
|  | @ -48,48 +72,52 @@ func runWeb(*cli.Context) { | |||
| 
 | ||||
| 	m.Use(middleware.InitContext()) | ||||
| 
 | ||||
| 	ignSignIn := middleware.SignInRequire(false) | ||||
| 	reqSignIn, reqSignOut := middleware.SignInRequire(true), middleware.SignOutRequire() | ||||
| 	// Routers.
 | ||||
| 	m.Get("/", middleware.SignInRequire(false), routers.Home) | ||||
| 	m.Get("/issues", middleware.SignInRequire(true), user.Issues) | ||||
| 	m.Get("/pulls", middleware.SignInRequire(true), user.Pulls) | ||||
| 	m.Get("/stars", middleware.SignInRequire(true), user.Stars) | ||||
| 	m.Any("/user/login", middleware.SignOutRequire(), binding.BindIgnErr(auth.LogInForm{}), user.SignIn) | ||||
| 	m.Any("/user/logout", middleware.SignInRequire(true), user.SignOut) | ||||
| 	m.Any("/user/sign_up", middleware.SignOutRequire(), binding.BindIgnErr(auth.RegisterForm{}), user.SignUp) | ||||
| 	m.Any("/user/delete", middleware.SignInRequire(true), user.Delete) | ||||
| 	m.Get("/", ignSignIn, routers.Home) | ||||
| 	m.Get("/issues", reqSignIn, user.Issues) | ||||
| 	m.Get("/pulls", reqSignIn, user.Pulls) | ||||
| 	m.Get("/stars", reqSignIn, user.Stars) | ||||
| 	m.Any("/user/login", reqSignOut, binding.BindIgnErr(auth.LogInForm{}), user.SignIn) | ||||
| 	m.Any("/user/logout", reqSignIn, user.SignOut) | ||||
| 	m.Any("/user/sign_up", reqSignOut, binding.BindIgnErr(auth.RegisterForm{}), user.SignUp) | ||||
| 	m.Any("/user/delete", reqSignIn, user.Delete) | ||||
| 	m.Get("/user/feeds", binding.Bind(auth.FeedsForm{}), user.Feeds) | ||||
| 
 | ||||
| 	m.Any("/user/setting", middleware.SignInRequire(true), binding.BindIgnErr(auth.UpdateProfileForm{}), user.Setting) | ||||
| 	m.Any("/user/setting/password", middleware.SignInRequire(true), binding.BindIgnErr(auth.UpdatePasswdForm{}), user.SettingPassword) | ||||
| 	m.Any("/user/setting/ssh", middleware.SignInRequire(true), binding.BindIgnErr(auth.AddSSHKeyForm{}), user.SettingSSHKeys) | ||||
| 	m.Any("/user/setting/notification", middleware.SignInRequire(true), user.SettingNotification) | ||||
| 	m.Any("/user/setting/security", middleware.SignInRequire(true), user.SettingSecurity) | ||||
| 	m.Any("/user/setting", reqSignIn, binding.BindIgnErr(auth.UpdateProfileForm{}), user.Setting) | ||||
| 	m.Any("/user/setting/password", reqSignIn, binding.BindIgnErr(auth.UpdatePasswdForm{}), user.SettingPassword) | ||||
| 	m.Any("/user/setting/ssh", reqSignIn, binding.BindIgnErr(auth.AddSSHKeyForm{}), user.SettingSSHKeys) | ||||
| 	m.Any("/user/setting/notification", reqSignIn, user.SettingNotification) | ||||
| 	m.Any("/user/setting/security", reqSignIn, user.SettingSecurity) | ||||
| 
 | ||||
| 	m.Get("/user/:username", middleware.SignInRequire(false), user.Profile) | ||||
| 	m.Get("/user/:username", ignSignIn, user.Profile) | ||||
| 
 | ||||
| 	m.Any("/repo/create", middleware.SignInRequire(true), binding.BindIgnErr(auth.CreateRepoForm{}), repo.Create) | ||||
| 	m.Any("/repo/create", reqSignIn, binding.BindIgnErr(auth.CreateRepoForm{}), repo.Create) | ||||
| 
 | ||||
| 	m.Get("/help", routers.Help) | ||||
| 
 | ||||
| 	m.Post("/:username/:reponame/settings", middleware.SignInRequire(true), middleware.RepoAssignment(true), repo.SettingPost) | ||||
| 	m.Get("/:username/:reponame/settings", middleware.SignInRequire(true), middleware.RepoAssignment(true), repo.Setting) | ||||
| 	m.Post("/:username/:reponame/settings", reqSignIn, middleware.RepoAssignment(true), repo.SettingPost) | ||||
| 	m.Get("/:username/:reponame/settings", reqSignIn, middleware.RepoAssignment(true), repo.Setting) | ||||
| 
 | ||||
| 	m.Get("/:username/:reponame/commits/:branchname", middleware.SignInRequire(false), middleware.RepoAssignment(true), repo.Commits) | ||||
| 	m.Get("/:username/:reponame/issues", middleware.SignInRequire(false), middleware.RepoAssignment(true), repo.Issues) | ||||
| 	m.Get("/:username/:reponame/pulls", middleware.SignInRequire(false), middleware.RepoAssignment(true), repo.Pulls) | ||||
| 	m.Get("/:username/:reponame/branches", middleware.SignInRequire(false), middleware.RepoAssignment(true), repo.Branches) | ||||
| 	m.Get("/:username/:reponame/commits/:branchname", ignSignIn, middleware.RepoAssignment(true), repo.Commits) | ||||
| 	m.Get("/:username/:reponame/issues", ignSignIn, middleware.RepoAssignment(true), repo.Issues) | ||||
| 	m.Get("/:username/:reponame/pulls", ignSignIn, middleware.RepoAssignment(true), repo.Pulls) | ||||
| 	m.Get("/:username/:reponame/branches", ignSignIn, middleware.RepoAssignment(true), repo.Branches) | ||||
| 	m.Get("/:username/:reponame/tree/:branchname/**", | ||||
| 		middleware.SignInRequire(false), middleware.RepoAssignment(true), repo.Single) | ||||
| 		ignSignIn, middleware.RepoAssignment(true), repo.Single) | ||||
| 	m.Get("/:username/:reponame/tree/:branchname", | ||||
| 		middleware.SignInRequire(false), middleware.RepoAssignment(true), repo.Single) | ||||
| 	m.Get("/:username/:reponame/commit/:commitid/**", middleware.SignInRequire(false), middleware.RepoAssignment(true), repo.Single) | ||||
| 	m.Get("/:username/:reponame/commit/:commitid", middleware.SignInRequire(false), middleware.RepoAssignment(true), repo.Single) | ||||
| 		ignSignIn, middleware.RepoAssignment(true), repo.Single) | ||||
| 	m.Get("/:username/:reponame/commit/:commitid/**", ignSignIn, middleware.RepoAssignment(true), repo.Single) | ||||
| 	m.Get("/:username/:reponame/commit/:commitid", ignSignIn, middleware.RepoAssignment(true), repo.Single) | ||||
| 
 | ||||
| 	m.Get("/:username/:reponame", middleware.SignInRequire(false), middleware.RepoAssignment(true), repo.Single) | ||||
| 	m.Get("/:username/:reponame", ignSignIn, middleware.RepoAssignment(true), repo.Single) | ||||
| 
 | ||||
| 	listenAddr := fmt.Sprintf("%s:%s", | ||||
| 		base.Cfg.MustValue("server", "HTTP_ADDR"), | ||||
| 		base.Cfg.MustValue("server", "HTTP_PORT", "3000")) | ||||
| 	log.Info("Listen: %s", listenAddr) | ||||
| 	http.ListenAndServe(listenAddr, m) | ||||
| 	if err := http.ListenAndServe(listenAddr, m); err != nil { | ||||
| 		log.Critical(err.Error()) | ||||
| 	} | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue