merged
This commit is contained in:
		
						commit
						17da2fd2e3
					
				|  | @ -5,4 +5,6 @@ gogs | |||
| *.db | ||||
| *.log | ||||
| custom/ | ||||
| .vendor/ | ||||
| .vendor/ | ||||
| .idea/ | ||||
| *.iml | ||||
|  | @ -9,13 +9,12 @@ github.com/Unknwon/com= | |||
| github.com/Unknwon/cae= | ||||
| github.com/Unknwon/goconfig= | ||||
| github.com/dchest/scrypt= | ||||
| github.com/go-sql-driver/mysql= | ||||
| github.com/lib/pq= | ||||
| github.com/lunny/xorm= | ||||
| github.com/gogits/logs= | ||||
| github.com/gogits/binding= | ||||
| github.com/gogits/git= | ||||
| github.com/gogits/gfm= | ||||
| github.com/gogits/cache= | ||||
| 
 | ||||
| [res] | ||||
| include=templates|public|conf | ||||
|  |  | |||
|  | @ -0,0 +1,49 @@ | |||
| # Contributing to Gogs | ||||
| 
 | ||||
| Want to hack on Gogs? Awesome! Here are instructions to get you | ||||
| started. They are probably not perfect, please let us know if anything | ||||
| feels wrong or incomplete. | ||||
| 
 | ||||
| ## Contribution guidelines | ||||
| 
 | ||||
| ### Pull requests are always welcome | ||||
| 
 | ||||
| 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. | ||||
| 
 | ||||
| We're trying very hard to keep Gogs lean and focused. We don't want it | ||||
| to do everything for everybody. This means that we might decide against | ||||
| incorporating a new feature. | ||||
| 
 | ||||
| ### Discuss your design on the mailing list | ||||
| 
 | ||||
| We recommend discussing your plans [on the mailing | ||||
| list](https://groups.google.com/forum/#!forum/gogits) | ||||
| before starting to code - especially for more ambitious contributions. | ||||
| This gives other contributors a chance to point you in the right | ||||
| direction, give feedback on your design, and maybe point out if someone | ||||
| else is working on the same thing. | ||||
| 
 | ||||
| We may close your pull request if not first discussed on the mailing | ||||
| list. We aren't doing this to be jerks. We are doing this to prevent | ||||
| people from spending large amounts of time on changes that may need | ||||
| to be designed or architected in a specific way, or may not align with | ||||
| the vision of the project. | ||||
| 
 | ||||
| ### Create issues... | ||||
| 
 | ||||
| Any significant improvement should be documented as [a GitHub | ||||
| issue](https://github.com/gogits/gogs/issues) before anybody | ||||
| starts working on it. | ||||
| 
 | ||||
| ### ...but check for existing issues first! | ||||
| 
 | ||||
| Please take a moment to check that an issue doesn't already exist | ||||
| documenting your bug report or improvement proposal. If it does, it | ||||
| never hurts to add a quick "+1" or "I have this problem too". This will | ||||
| help prioritize the most common problems and requests. | ||||
|  | @ -5,7 +5,7 @@ Gogs(Go Git Service) is a GitHub-like clone in the Go Programming Language. | |||
| 
 | ||||
| Since we choose to use pure Go implementation of Git manipulation, Gogs certainly supports **ALL platforms**  that Go supports, including Linux, Max OS X, and Windows with **ZERO** dependency. | ||||
| 
 | ||||
| ##### Current version: 0.1.1 Alpha | ||||
| ##### Current version: 0.1.5 Alpha | ||||
| 
 | ||||
| ## Purpose | ||||
| 
 | ||||
|  | @ -15,7 +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!. | ||||
| - Try it before anything? Do it [online](http://try.gogits.org/Unknown/gogs) or go down to **Installation -> Install from binary** section! | ||||
| - Having troubles? Get help from [Troubleshooting](https://github.com/gogits/gogs/wiki/Troubleshooting). | ||||
| 
 | ||||
| ## Features | ||||
|  | @ -28,7 +28,8 @@ There are some very good products in this category such as [gitlab](http://gitla | |||
| - Repository viewer. | ||||
| - Gravatar support. | ||||
| - Mail service(register). | ||||
| - Supports MySQL and PostgreSQL. | ||||
| - Administration panel. | ||||
| - Supports MySQL, PostgreSQL and SQLite3(binary release only). | ||||
| 
 | ||||
| ## Installation | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										24
									
								
								conf/app.ini
								
								
								
								
							
							
						
						
									
										24
									
								
								conf/app.ini
								
								
								
								
							|  | @ -8,8 +8,8 @@ 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|C++|Python|Ruby|C Sharp | ||||
| LICENSES = Apache v2 License|GPL v2|MIT License|Affero GPL|Artistic License 2.0|BSD (3-Clause) License | ||||
| 
 | ||||
| [server] | ||||
| DOMAIN = localhost | ||||
|  | @ -18,7 +18,7 @@ HTTP_ADDR = | |||
| HTTP_PORT = 3000 | ||||
| 
 | ||||
| [database] | ||||
| ; Either "mysql" or "postgres", it's your choice | ||||
| ; Either "mysql", "postgres" or "sqlite3"(binary release only), it's your choice | ||||
| DB_TYPE = mysql | ||||
| HOST =  | ||||
| NAME = gogs | ||||
|  | @ -26,6 +26,10 @@ USER = root | |||
| PASSWD = | ||||
| ; For "postgres" only, either "disable", "require" or "verify-full" | ||||
| SSL_MODE = disable | ||||
| ; For "sqlite3" only | ||||
| PATH = data/gogs.db | ||||
| 
 | ||||
| [admin] | ||||
| 
 | ||||
| [security] | ||||
| ; !!CHANGE THIS TO KEEP YOUR USER DATA SAFE!! | ||||
|  | @ -36,6 +40,10 @@ ACTIVE_CODE_LIVE_MINUTES = 180 | |||
| RESET_PASSWD_CODE_LIVE_MINUTES = 180 | ||||
| ; User need to confirm e-mail for registration | ||||
| REGISTER_EMAIL_CONFIRM = false | ||||
| ; Does not allow register and admin create account only | ||||
| DISENABLE_REGISTERATION = false | ||||
| ; User must sign in to view anything. | ||||
| REQUIRE_SIGNIN_VIEW = false | ||||
| 
 | ||||
| [mailer] | ||||
| ENABLED = false | ||||
|  | @ -52,6 +60,16 @@ FROM = | |||
| USER =  | ||||
| PASSWD =  | ||||
| 
 | ||||
| [cache] | ||||
| ; Either "memory", "redis", or "memcache", default is "memory" | ||||
| ADAPTER = memory | ||||
| ; For "memory" only, GC interval in seconds, default is 60 | ||||
| INTERVAL = 60 | ||||
| ; For "redis" and "memcache", connection host address | ||||
| ; redis: ":6039" | ||||
| ; memcache: "127.0.0.1:11211" | ||||
| HOST = | ||||
| 
 | ||||
| [log] | ||||
| ; Either "console", "file", "conn" or "smtp", default is "console" | ||||
| MODE = console | ||||
|  |  | |||
|  | @ -0,0 +1,13 @@ | |||
| # Compiled Object files | ||||
| *.slo | ||||
| *.lo | ||||
| *.o | ||||
| 
 | ||||
| # Compiled Dynamic libraries | ||||
| *.so | ||||
| *.dylib | ||||
| 
 | ||||
| # Compiled Static libraries | ||||
| *.lai | ||||
| *.la | ||||
| *.a | ||||
|  | @ -0,0 +1,201 @@ | |||
| The Artistic License 2.0 | ||||
| 
 | ||||
|            Copyright (c) 2014 | ||||
| 
 | ||||
|      Everyone is permitted to copy and distribute verbatim copies | ||||
|       of this license document, but changing it is not allowed. | ||||
| 
 | ||||
| Preamble | ||||
| 
 | ||||
| This license establishes the terms under which a given free software | ||||
| Package may be copied, modified, distributed, and/or redistributed. | ||||
| The intent is that the Copyright Holder maintains some artistic | ||||
| control over the development of that Package while still keeping the | ||||
| Package available as open source and free software. | ||||
| 
 | ||||
| You are always permitted to make arrangements wholly outside of this | ||||
| license directly with the Copyright Holder of a given Package.  If the | ||||
| terms of this license do not permit the full use that you propose to | ||||
| make of the Package, you should contact the Copyright Holder and seek | ||||
| a different licensing arrangement. | ||||
| 
 | ||||
| Definitions | ||||
| 
 | ||||
|     "Copyright Holder" means the individual(s) or organization(s) | ||||
|     named in the copyright notice for the entire Package. | ||||
| 
 | ||||
|     "Contributor" means any party that has contributed code or other | ||||
|     material to the Package, in accordance with the Copyright Holder's | ||||
|     procedures. | ||||
| 
 | ||||
|     "You" and "your" means any person who would like to copy, | ||||
|     distribute, or modify the Package. | ||||
| 
 | ||||
|     "Package" means the collection of files distributed by the | ||||
|     Copyright Holder, and derivatives of that collection and/or of | ||||
|     those files. A given Package may consist of either the Standard | ||||
|     Version, or a Modified Version. | ||||
| 
 | ||||
|     "Distribute" means providing a copy of the Package or making it | ||||
|     accessible to anyone else, or in the case of a company or | ||||
|     organization, to others outside of your company or organization. | ||||
| 
 | ||||
|     "Distributor Fee" means any fee that you charge for Distributing | ||||
|     this Package or providing support for this Package to another | ||||
|     party.  It does not mean licensing fees. | ||||
| 
 | ||||
|     "Standard Version" refers to the Package if it has not been | ||||
|     modified, or has been modified only in ways explicitly requested | ||||
|     by the Copyright Holder. | ||||
| 
 | ||||
|     "Modified Version" means the Package, if it has been changed, and | ||||
|     such changes were not explicitly requested by the Copyright | ||||
|     Holder. | ||||
| 
 | ||||
|     "Original License" means this Artistic License as Distributed with | ||||
|     the Standard Version of the Package, in its current version or as | ||||
|     it may be modified by The Perl Foundation in the future. | ||||
| 
 | ||||
|     "Source" form means the source code, documentation source, and | ||||
|     configuration files for the Package. | ||||
| 
 | ||||
|     "Compiled" form means the compiled bytecode, object code, binary, | ||||
|     or any other form resulting from mechanical transformation or | ||||
|     translation of the Source form. | ||||
| 
 | ||||
| 
 | ||||
| Permission for Use and Modification Without Distribution | ||||
| 
 | ||||
| (1)  You are permitted to use the Standard Version and create and use | ||||
| Modified Versions for any purpose without restriction, provided that | ||||
| you do not Distribute the Modified Version. | ||||
| 
 | ||||
| 
 | ||||
| Permissions for Redistribution of the Standard Version | ||||
| 
 | ||||
| (2)  You may Distribute verbatim copies of the Source form of the | ||||
| Standard Version of this Package in any medium without restriction, | ||||
| either gratis or for a Distributor Fee, provided that you duplicate | ||||
| all of the original copyright notices and associated disclaimers.  At | ||||
| your discretion, such verbatim copies may or may not include a | ||||
| Compiled form of the Package. | ||||
| 
 | ||||
| (3)  You may apply any bug fixes, portability changes, and other | ||||
| modifications made available from the Copyright Holder.  The resulting | ||||
| Package will still be considered the Standard Version, and as such | ||||
| will be subject to the Original License. | ||||
| 
 | ||||
| 
 | ||||
| Distribution of Modified Versions of the Package as Source | ||||
| 
 | ||||
| (4)  You may Distribute your Modified Version as Source (either gratis | ||||
| or for a Distributor Fee, and with or without a Compiled form of the | ||||
| Modified Version) provided that you clearly document how it differs | ||||
| from the Standard Version, including, but not limited to, documenting | ||||
| any non-standard features, executables, or modules, and provided that | ||||
| you do at least ONE of the following: | ||||
| 
 | ||||
|     (a)  make the Modified Version available to the Copyright Holder | ||||
|     of the Standard Version, under the Original License, so that the | ||||
|     Copyright Holder may include your modifications in the Standard | ||||
|     Version. | ||||
| 
 | ||||
|     (b)  ensure that installation of your Modified Version does not | ||||
|     prevent the user installing or running the Standard Version. In | ||||
|     addition, the Modified Version must bear a name that is different | ||||
|     from the name of the Standard Version. | ||||
| 
 | ||||
|     (c)  allow anyone who receives a copy of the Modified Version to | ||||
|     make the Source form of the Modified Version available to others | ||||
|     under | ||||
| 
 | ||||
|     (i)  the Original License or | ||||
| 
 | ||||
|     (ii)  a license that permits the licensee to freely copy, | ||||
|     modify and redistribute the Modified Version using the same | ||||
|     licensing terms that apply to the copy that the licensee | ||||
|     received, and requires that the Source form of the Modified | ||||
|     Version, and of any works derived from it, be made freely | ||||
|     available in that license fees are prohibited but Distributor | ||||
|     Fees are allowed. | ||||
| 
 | ||||
| 
 | ||||
| Distribution of Compiled Forms of the Standard Version | ||||
| or Modified Versions without the Source | ||||
| 
 | ||||
| (5)  You may Distribute Compiled forms of the Standard Version without | ||||
| the Source, provided that you include complete instructions on how to | ||||
| get the Source of the Standard Version.  Such instructions must be | ||||
| valid at the time of your distribution.  If these instructions, at any | ||||
| time while you are carrying out such distribution, become invalid, you | ||||
| must provide new instructions on demand or cease further distribution. | ||||
| If you provide valid instructions or cease distribution within thirty | ||||
| days after you become aware that the instructions are invalid, then | ||||
| you do not forfeit any of your rights under this license. | ||||
| 
 | ||||
| (6)  You may Distribute a Modified Version in Compiled form without | ||||
| the Source, provided that you comply with Section 4 with respect to | ||||
| the Source of the Modified Version. | ||||
| 
 | ||||
| 
 | ||||
| Aggregating or Linking the Package | ||||
| 
 | ||||
| (7)  You may aggregate the Package (either the Standard Version or | ||||
| Modified Version) with other packages and Distribute the resulting | ||||
| aggregation provided that you do not charge a licensing fee for the | ||||
| Package.  Distributor Fees are permitted, and licensing fees for other | ||||
| components in the aggregation are permitted. The terms of this license | ||||
| apply to the use and Distribution of the Standard or Modified Versions | ||||
| as included in the aggregation. | ||||
| 
 | ||||
| (8) You are permitted to link Modified and Standard Versions with | ||||
| other works, to embed the Package in a larger work of your own, or to | ||||
| build stand-alone binary or bytecode versions of applications that | ||||
| include the Package, and Distribute the result without restriction, | ||||
| provided the result does not expose a direct interface to the Package. | ||||
| 
 | ||||
| 
 | ||||
| Items That are Not Considered Part of a Modified Version | ||||
| 
 | ||||
| (9) Works (including, but not limited to, modules and scripts) that | ||||
| merely extend or make use of the Package, do not, by themselves, cause | ||||
| the Package to be a Modified Version.  In addition, such works are not | ||||
| considered parts of the Package itself, and are not subject to the | ||||
| terms of this license. | ||||
| 
 | ||||
| 
 | ||||
| General Provisions | ||||
| 
 | ||||
| (10)  Any use, modification, and distribution of the Standard or | ||||
| Modified Versions is governed by this Artistic License. By using, | ||||
| modifying or distributing the Package, you accept this license. Do not | ||||
| use, modify, or distribute the Package, if you do not accept this | ||||
| license. | ||||
| 
 | ||||
| (11)  If your Modified Version has been derived from a Modified | ||||
| Version made by someone other than you, you are nevertheless required | ||||
| to ensure that your Modified Version complies with the requirements of | ||||
| this license. | ||||
| 
 | ||||
| (12)  This license does not grant you the right to use any trademark, | ||||
| service mark, tradename, or logo of the Copyright Holder. | ||||
| 
 | ||||
| (13)  This license includes the non-exclusive, worldwide, | ||||
| free-of-charge patent license to make, have made, use, offer to sell, | ||||
| sell, import and otherwise transfer the Package with respect to any | ||||
| patent claims licensable by the Copyright Holder that are necessarily | ||||
| infringed by the Package. If you institute patent litigation | ||||
| (including a cross-claim or counterclaim) against any party alleging | ||||
| that the Package constitutes direct or contributory patent | ||||
| infringement, then this Artistic License to you shall terminate on the | ||||
| date that such litigation is filed. | ||||
| 
 | ||||
| (14)  Disclaimer of Warranty: | ||||
| THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS | ||||
| IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED | ||||
| WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR | ||||
| NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL | ||||
| LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL | ||||
| BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL | ||||
| DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF | ||||
| ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
							
								
								
									
										8
									
								
								gogs.go
								
								
								
								
							
							
						
						
									
										8
									
								
								gogs.go
								
								
								
								
							|  | @ -15,12 +15,12 @@ import ( | |||
| 	"github.com/gogits/gogs/modules/base" | ||||
| ) | ||||
| 
 | ||||
| // +build go1.1
 | ||||
| // +build go1.2
 | ||||
| 
 | ||||
| // Test that go1.1 tag above is included in builds. main.go refers to this definition.
 | ||||
| const go11tag = true | ||||
| // Test that go1.2 tag above is included in builds. main.go refers to this definition.
 | ||||
| const go12tag = true | ||||
| 
 | ||||
| const APP_VER = "0.1.1.0320.1" | ||||
| const APP_VER = "0.1.5.0321" | ||||
| 
 | ||||
| func init() { | ||||
| 	base.AppVer = APP_VER | ||||
|  |  | |||
|  | @ -64,6 +64,10 @@ func CommitRepoAction(userId int64, userName string, | |||
| 	watches = append(watches, Watch{UserId: userId}) | ||||
| 
 | ||||
| 	for i := range watches { | ||||
| 		if userId == watches[i].UserId && i > 0 { | ||||
| 			continue // Do not add twice in case author watches his/her repository.
 | ||||
| 		} | ||||
| 
 | ||||
| 		_, err = orm.InsertOne(&Action{ | ||||
| 			UserId:      watches[i].UserId, | ||||
| 			ActUserId:   userId, | ||||
|  |  | |||
|  | @ -0,0 +1,19 @@ | |||
| // 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 | ||||
| 
 | ||||
| type Issue struct { | ||||
| 	Id       int64 | ||||
| 	RepoId   int64 `xorm:"index"` | ||||
| 	PosterId int64 | ||||
| } | ||||
| 
 | ||||
| type PullRequest struct { | ||||
| 	Id int64 | ||||
| } | ||||
| 
 | ||||
| type Comment struct { | ||||
| 	Id int64 | ||||
| } | ||||
|  | @ -7,6 +7,7 @@ package models | |||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"path" | ||||
| 
 | ||||
| 	_ "github.com/go-sql-driver/mysql" | ||||
| 	_ "github.com/lib/pq" | ||||
|  | @ -16,48 +17,37 @@ import ( | |||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	orm          *xorm.Engine | ||||
| 	RepoRootPath string | ||||
| 	orm *xorm.Engine | ||||
| 
 | ||||
| 	DbCfg struct { | ||||
| 		Type, Host, Name, User, Pwd, Path, SslMode string | ||||
| 	} | ||||
| ) | ||||
| 
 | ||||
| type Members struct { | ||||
| 	Id     int64 | ||||
| 	OrgId  int64 `xorm:"unique(s) index"` | ||||
| 	UserId int64 `xorm:"unique(s)"` | ||||
| } | ||||
| 
 | ||||
| type Issue struct { | ||||
| 	Id       int64 | ||||
| 	RepoId   int64 `xorm:"index"` | ||||
| 	PosterId int64 | ||||
| } | ||||
| 
 | ||||
| type PullRequest struct { | ||||
| 	Id int64 | ||||
| } | ||||
| 
 | ||||
| type Comment struct { | ||||
| 	Id int64 | ||||
| func LoadModelsConfig() { | ||||
| 	DbCfg.Type = base.Cfg.MustValue("database", "DB_TYPE") | ||||
| 	DbCfg.Host = base.Cfg.MustValue("database", "HOST") | ||||
| 	DbCfg.Name = base.Cfg.MustValue("database", "NAME") | ||||
| 	DbCfg.User = base.Cfg.MustValue("database", "USER") | ||||
| 	DbCfg.Pwd = base.Cfg.MustValue("database", "PASSWD") | ||||
| 	DbCfg.SslMode = base.Cfg.MustValue("database", "SSL_MODE") | ||||
| 	DbCfg.Path = base.Cfg.MustValue("database", "PATH", "data/gogs.db") | ||||
| } | ||||
| 
 | ||||
| func setEngine() { | ||||
| 	dbType := base.Cfg.MustValue("database", "DB_TYPE") | ||||
| 	dbHost := base.Cfg.MustValue("database", "HOST") | ||||
| 	dbName := base.Cfg.MustValue("database", "NAME") | ||||
| 	dbUser := base.Cfg.MustValue("database", "USER") | ||||
| 	dbPwd := base.Cfg.MustValue("database", "PASSWD") | ||||
| 	sslMode := base.Cfg.MustValue("database", "SSL_MODE") | ||||
| 
 | ||||
| 	var err error | ||||
| 	switch dbType { | ||||
| 	switch DbCfg.Type { | ||||
| 	case "mysql": | ||||
| 		orm, err = xorm.NewEngine("mysql", fmt.Sprintf("%s:%s@%s/%s?charset=utf8", | ||||
| 			dbUser, dbPwd, dbHost, dbName)) | ||||
| 			DbCfg.User, DbCfg.Pwd, DbCfg.Host, DbCfg.Name)) | ||||
| 	case "postgres": | ||||
| 		orm, err = xorm.NewEngine("postgres", fmt.Sprintf("user=%s password=%s dbname=%s sslmode=%s", | ||||
| 			dbUser, dbPwd, dbName, sslMode)) | ||||
| 			DbCfg.User, DbCfg.Pwd, DbCfg.Name, DbCfg.SslMode)) | ||||
| 	case "sqlite3": | ||||
| 		os.MkdirAll(path.Dir(DbCfg.Path), os.ModePerm) | ||||
| 		orm, err = xorm.NewEngine("sqlite3", DbCfg.Path) | ||||
| 	default: | ||||
| 		fmt.Printf("Unknown database type: %s\n", dbType) | ||||
| 		fmt.Printf("Unknown database type: %s\n", DbCfg.Type) | ||||
| 		os.Exit(2) | ||||
| 	} | ||||
| 	if err != nil { | ||||
|  | @ -65,8 +55,8 @@ func setEngine() { | |||
| 		os.Exit(2) | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO: for serv command, MUST remove the output to os.stdout, so
 | ||||
| 	// use log file to instead print to stdout
 | ||||
| 	// WARNNING: for serv command, MUST remove the output to os.stdout,
 | ||||
| 	// so use log file to instead print to stdout.
 | ||||
| 
 | ||||
| 	//x.ShowDebug = true
 | ||||
| 	//orm.ShowErr = true
 | ||||
|  | @ -77,20 +67,29 @@ func setEngine() { | |||
| 	} | ||||
| 	orm.Logger = f | ||||
| 	orm.ShowSQL = true | ||||
| 
 | ||||
| 	// Determine and create root git reposiroty path.
 | ||||
| 	RepoRootPath = base.Cfg.MustValue("repository", "ROOT") | ||||
| 	if err = os.MkdirAll(RepoRootPath, os.ModePerm); err != nil { | ||||
| 		fmt.Printf("models.init(fail to create RepoRootPath(%s)): %v\n", RepoRootPath, err) | ||||
| 		os.Exit(2) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| func NewEngine() { | ||||
| 	setEngine() | ||||
| 	if err := orm.Sync(new(User), new(PublicKey), new(Repository), new(Access), | ||||
| 		new(Action), new(Watch)); err != nil { | ||||
| 	if err := orm.Sync(new(User), new(PublicKey), new(Repository), new(Watch), | ||||
| 		new(Action), new(Access)); err != nil { | ||||
| 		fmt.Printf("sync database struct error: %v\n", err) | ||||
| 		os.Exit(2) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| type Statistic struct { | ||||
| 	Counter struct { | ||||
| 		User, PublicKey, Repo, Watch, Action, Access int64 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func GetStatistic() (stats Statistic) { | ||||
| 	stats.Counter.User, _ = orm.Count(new(User)) | ||||
| 	stats.Counter.PublicKey, _ = orm.Count(new(PublicKey)) | ||||
| 	stats.Counter.Repo, _ = orm.Count(new(Repository)) | ||||
| 	stats.Counter.Watch, _ = orm.Count(new(Watch)) | ||||
| 	stats.Counter.Action, _ = orm.Count(new(Action)) | ||||
| 	stats.Counter.Access, _ = orm.Count(new(Access)) | ||||
| 	return stats | ||||
| } | ||||
|  |  | |||
|  | @ -13,6 +13,9 @@ import ( | |||
| ) | ||||
| 
 | ||||
| func init() { | ||||
| 	LoadModelsConfig() | ||||
| 	NewEngine() | ||||
| 
 | ||||
| 	var err error | ||||
| 	orm, err = xorm.NewEngine("sqlite3", "./test.db") | ||||
| 	if err != nil { | ||||
|  |  | |||
|  | @ -27,8 +27,12 @@ const ( | |||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	sshOpLocker = sync.Mutex{} | ||||
| 	ErrKeyAlreadyExist = errors.New("Public key already exist") | ||||
| ) | ||||
| 
 | ||||
| var sshOpLocker = sync.Mutex{} | ||||
| 
 | ||||
| var ( | ||||
| 	sshPath string | ||||
| 	appPath string | ||||
| ) | ||||
|  | @ -79,10 +83,6 @@ type PublicKey struct { | |||
| 	Updated     time.Time `xorm:"updated"` | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	ErrKeyAlreadyExist = errors.New("Public key already exist") | ||||
| ) | ||||
| 
 | ||||
| // GenAuthorizedKey returns formatted public key string.
 | ||||
| func GenAuthorizedKey(keyId int64, key string) string { | ||||
| 	return fmt.Sprintf(TPL_PUBLICK_KEY+"\n", appPath, keyId, key) | ||||
|  |  | |||
							
								
								
									
										276
									
								
								models/repo.go
								
								
								
								
							
							
						
						
									
										276
									
								
								models/repo.go
								
								
								
								
							|  | @ -12,6 +12,7 @@ import ( | |||
| 	"os" | ||||
| 	"path" | ||||
| 	"path/filepath" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | @ -26,68 +27,26 @@ import ( | |||
| 	"github.com/gogits/gogs/modules/log" | ||||
| ) | ||||
| 
 | ||||
| // Repository represents a git repository.
 | ||||
| type Repository struct { | ||||
| 	Id          int64 | ||||
| 	OwnerId     int64 `xorm:"unique(s)"` | ||||
| 	ForkId      int64 | ||||
| 	LowerName   string `xorm:"unique(s) index not null"` | ||||
| 	Name        string `xorm:"index not null"` | ||||
| 	Description string | ||||
| 	Website     string | ||||
| 	Private     bool | ||||
| 	NumWatchs   int | ||||
| 	NumStars    int | ||||
| 	NumForks    int | ||||
| 	Created     time.Time `xorm:"created"` | ||||
| 	Updated     time.Time `xorm:"updated"` | ||||
| } | ||||
| var ( | ||||
| 	ErrRepoAlreadyExist  = errors.New("Repository already exist") | ||||
| 	ErrRepoNotExist      = errors.New("Repository does not exist") | ||||
| 	ErrRepoFileNotExist  = errors.New("Target Repo file does not exist") | ||||
| 	ErrRepoNameIllegal   = errors.New("Repository name contains illegal characters") | ||||
| 	ErrRepoFileNotLoaded = fmt.Errorf("repo file not loaded") | ||||
| ) | ||||
| 
 | ||||
| // Watch is connection request for receiving repository notifycation.
 | ||||
| type Watch struct { | ||||
| 	Id     int64 | ||||
| 	RepoId int64 `xorm:"UNIQUE(watch)"` | ||||
| 	UserId int64 `xorm:"UNIQUE(watch)"` | ||||
| } | ||||
| 
 | ||||
| // Watch or unwatch repository.
 | ||||
| func WatchRepo(userId, repoId int64, watch bool) (err error) { | ||||
| 	if watch { | ||||
| 		_, err = orm.Insert(&Watch{RepoId: repoId, UserId: userId}) | ||||
| 	} else { | ||||
| 		_, err = orm.Delete(&Watch{0, repoId, userId}) | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| // GetWatches returns all watches of given repository.
 | ||||
| func GetWatches(repoId int64) ([]Watch, error) { | ||||
| 	watches := make([]Watch, 0, 10) | ||||
| 	err := orm.Find(&watches, &Watch{RepoId: repoId}) | ||||
| 	return watches, err | ||||
| } | ||||
| 
 | ||||
| // IsWatching checks if user has watched given repository.
 | ||||
| func IsWatching(userId, repoId int64) bool { | ||||
| 	has, _ := orm.Get(&Watch{0, repoId, userId}) | ||||
| 	return has | ||||
| } | ||||
| var gitInitLocker = sync.Mutex{} | ||||
| 
 | ||||
| var ( | ||||
| 	gitInitLocker          = sync.Mutex{} | ||||
| 	LanguageIgns, Licenses []string | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	ErrRepoAlreadyExist = errors.New("Repository already exist") | ||||
| 	ErrRepoNotExist     = errors.New("Repository does not exist") | ||||
| 	ErrRepoFileNotExist = errors.New("Target Repo file does not exist") | ||||
| ) | ||||
| 
 | ||||
| func init() { | ||||
| func LoadRepoConfig() { | ||||
| 	LanguageIgns = strings.Split(base.Cfg.MustValue("repository", "LANG_IGNS"), "|") | ||||
| 	Licenses = strings.Split(base.Cfg.MustValue("repository", "LICENSES"), "|") | ||||
| } | ||||
| 
 | ||||
| func NewRepoContext() { | ||||
| 	zip.Verbose = false | ||||
| 
 | ||||
| 	// Check if server has basic git setting.
 | ||||
|  | @ -104,6 +63,32 @@ func init() { | |||
| 			os.Exit(2) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Initialize illegal patterns.
 | ||||
| 	for i := range illegalPatterns[1:] { | ||||
| 		pattern := "" | ||||
| 		for j := range illegalPatterns[i+1] { | ||||
| 			pattern += "[" + string(illegalPatterns[i+1][j]-32) + string(illegalPatterns[i+1][j]) + "]" | ||||
| 		} | ||||
| 		illegalPatterns[i+1] = pattern | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Repository represents a git repository.
 | ||||
| type Repository struct { | ||||
| 	Id          int64 | ||||
| 	OwnerId     int64 `xorm:"unique(s)"` | ||||
| 	ForkId      int64 | ||||
| 	LowerName   string `xorm:"unique(s) index not null"` | ||||
| 	Name        string `xorm:"index not null"` | ||||
| 	Description string | ||||
| 	Website     string | ||||
| 	Private     bool | ||||
| 	NumWatches  int | ||||
| 	NumStars    int | ||||
| 	NumForks    int | ||||
| 	Created     time.Time `xorm:"created"` | ||||
| 	Updated     time.Time `xorm:"updated"` | ||||
| } | ||||
| 
 | ||||
| // IsRepositoryExist returns true if the repository with given name under user has already existed.
 | ||||
|  | @ -120,8 +105,28 @@ func IsRepositoryExist(user *User, repoName string) (bool, error) { | |||
| 	return s.IsDir(), nil | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	// Define as all lower case!!
 | ||||
| 	illegalPatterns = []string{"[.][Gg][Ii][Tt]", "user", "help", "stars", "issues", "pulls", "commits", "admin", "repo", "template", "admin"} | ||||
| ) | ||||
| 
 | ||||
| // IsLegalName returns false if name contains illegal characters.
 | ||||
| func IsLegalName(repoName string) bool { | ||||
| 	for _, pattern := range illegalPatterns { | ||||
| 		has, _ := regexp.MatchString(pattern, repoName) | ||||
| 		if has { | ||||
| 			return false | ||||
| 		} | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| // CreateRepository creates a repository for given user or orgnaziation.
 | ||||
| func CreateRepository(user *User, repoName, desc, repoLang, license string, private bool, initReadme bool) (*Repository, error) { | ||||
| 	if !IsLegalName(repoName) { | ||||
| 		return nil, ErrRepoNameIllegal | ||||
| 	} | ||||
| 
 | ||||
| 	isExist, err := IsRepositoryExist(user, repoName) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
|  | @ -331,6 +336,82 @@ func initRepository(f string, user *User, repo *Repository, initReadme bool, rep | |||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // UserRepo reporesents a repository with user name.
 | ||||
| type UserRepo struct { | ||||
| 	*Repository | ||||
| 	UserName string | ||||
| } | ||||
| 
 | ||||
| // GetRepos returns given number of repository objects with offset.
 | ||||
| func GetRepos(num, offset int) ([]UserRepo, error) { | ||||
| 	repos := make([]Repository, 0, num) | ||||
| 	if err := orm.Limit(num, offset).Asc("id").Find(&repos); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	urepos := make([]UserRepo, len(repos)) | ||||
| 	for i := range repos { | ||||
| 		urepos[i].Repository = &repos[i] | ||||
| 		u := new(User) | ||||
| 		has, err := orm.Id(urepos[i].Repository.OwnerId).Get(u) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} else if !has { | ||||
| 			return nil, ErrUserNotExist | ||||
| 		} | ||||
| 		urepos[i].UserName = u.Name | ||||
| 	} | ||||
| 
 | ||||
| 	return urepos, nil | ||||
| } | ||||
| 
 | ||||
| func RepoPath(userName, repoName string) string { | ||||
| 	return filepath.Join(UserPath(userName), repoName+".git") | ||||
| } | ||||
| 
 | ||||
| // DeleteRepository deletes a repository for a user or orgnaztion.
 | ||||
| func DeleteRepository(userId, repoId int64, userName string) (err error) { | ||||
| 	repo := &Repository{Id: repoId, OwnerId: userId} | ||||
| 	has, err := orm.Get(repo) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} else if !has { | ||||
| 		return ErrRepoNotExist | ||||
| 	} | ||||
| 
 | ||||
| 	session := orm.NewSession() | ||||
| 	if err = session.Begin(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if _, err = session.Delete(&Repository{Id: repoId}); err != nil { | ||||
| 		session.Rollback() | ||||
| 		return err | ||||
| 	} | ||||
| 	if _, err := session.Delete(&Access{UserName: userName, RepoName: repo.Name}); err != nil { | ||||
| 		session.Rollback() | ||||
| 		return err | ||||
| 	} | ||||
| 	rawSql := "UPDATE `user` SET num_repos = num_repos - 1 WHERE id = ?" | ||||
| 	if _, err = session.Exec(rawSql, userId); err != nil { | ||||
| 		session.Rollback() | ||||
| 		return err | ||||
| 	} | ||||
| 	if _, err = session.Delete(&Watch{RepoId: repoId}); err != nil { | ||||
| 		session.Rollback() | ||||
| 		return err | ||||
| 	} | ||||
| 	if err = session.Commit(); err != nil { | ||||
| 		session.Rollback() | ||||
| 		return err | ||||
| 	} | ||||
| 	if err = os.RemoveAll(RepoPath(userName, repo.Name)); err != nil { | ||||
| 		// TODO: log and delete manully
 | ||||
| 		log.Error("delete repo %s/%s failed: %v", userName, repo.Name, err) | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // GetRepositoryByName returns the repository by given name under user if exists.
 | ||||
| func GetRepositoryByName(user *User, repoName string) (*Repository, error) { | ||||
| 	repo := &Repository{ | ||||
|  | @ -368,6 +449,45 @@ func GetRepositoryCount(user *User) (int64, error) { | |||
| 	return orm.Count(&Repository{OwnerId: user.Id}) | ||||
| } | ||||
| 
 | ||||
| // Watch is connection request for receiving repository notifycation.
 | ||||
| type Watch struct { | ||||
| 	Id     int64 | ||||
| 	RepoId int64 `xorm:"UNIQUE(watch)"` | ||||
| 	UserId int64 `xorm:"UNIQUE(watch)"` | ||||
| } | ||||
| 
 | ||||
| // Watch or unwatch repository.
 | ||||
| func WatchRepo(userId, repoId int64, watch bool) (err error) { | ||||
| 	if watch { | ||||
| 		if _, err = orm.Insert(&Watch{RepoId: repoId, UserId: userId}); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		rawSql := "UPDATE `repository` SET num_watches = num_watches + 1 WHERE id = ?" | ||||
| 		_, err = orm.Exec(rawSql, repoId) | ||||
| 	} else { | ||||
| 		if _, err = orm.Delete(&Watch{0, repoId, userId}); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		rawSql := "UPDATE `repository` SET num_watches = num_watches - 1 WHERE id = ?" | ||||
| 		_, err = orm.Exec(rawSql, repoId) | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| // GetWatches returns all watches of given repository.
 | ||||
| func GetWatches(repoId int64) ([]Watch, error) { | ||||
| 	watches := make([]Watch, 0, 10) | ||||
| 	err := orm.Find(&watches, &Watch{RepoId: repoId}) | ||||
| 	return watches, err | ||||
| } | ||||
| 
 | ||||
| // IsWatching checks if user has watched given repository.
 | ||||
| func IsWatching(userId, repoId int64) bool { | ||||
| 	has, _ := orm.Get(&Watch{0, repoId, userId}) | ||||
| 	return has | ||||
| } | ||||
| 
 | ||||
| func StarReposiory(user *User, repoName string) error { | ||||
| 	return nil | ||||
| } | ||||
|  | @ -388,56 +508,6 @@ func ForkRepository(reposName string, userId int64) { | |||
| 
 | ||||
| } | ||||
| 
 | ||||
| func RepoPath(userName, repoName string) string { | ||||
| 	return filepath.Join(UserPath(userName), repoName+".git") | ||||
| } | ||||
| 
 | ||||
| // DeleteRepository deletes a repository for a user or orgnaztion.
 | ||||
| func DeleteRepository(userId, repoId int64, userName string) (err error) { | ||||
| 	repo := &Repository{Id: repoId, OwnerId: userId} | ||||
| 	has, err := orm.Get(repo) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} else if !has { | ||||
| 		return ErrRepoNotExist | ||||
| 	} | ||||
| 
 | ||||
| 	session := orm.NewSession() | ||||
| 	if err = session.Begin(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if _, err = session.Delete(&Repository{Id: repoId}); err != nil { | ||||
| 		session.Rollback() | ||||
| 		return err | ||||
| 	} | ||||
| 	if _, err := session.Delete(&Access{UserName: userName, RepoName: repo.Name}); err != nil { | ||||
| 		session.Rollback() | ||||
| 		return 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 = ?" | ||||
| 	} | ||||
| 	if _, err = session.Exec(rawSql, userId); err != nil { | ||||
| 		session.Rollback() | ||||
| 		return err | ||||
| 	} | ||||
| 	if err = session.Commit(); err != nil { | ||||
| 		session.Rollback() | ||||
| 		return err | ||||
| 	} | ||||
| 	if err = os.RemoveAll(RepoPath(userName, repo.Name)); err != nil { | ||||
| 		// TODO: log and delete manully
 | ||||
| 		log.Error("delete repo %s/%s failed: %v", userName, repo.Name, err) | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	ErrRepoFileNotLoaded = fmt.Errorf("repo file not loaded") | ||||
| ) | ||||
| 
 | ||||
| // RepoFile represents a file object in git repository.
 | ||||
| type RepoFile struct { | ||||
| 	*git.TreeEntry | ||||
|  |  | |||
							
								
								
									
										105
									
								
								models/user.go
								
								
								
								
							
							
						
						
									
										105
									
								
								models/user.go
								
								
								
								
							|  | @ -33,6 +33,14 @@ const ( | |||
| 	LT_LDAP | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	ErrUserOwnRepos     = errors.New("User still have ownership of repositories") | ||||
| 	ErrUserAlreadyExist = errors.New("User already exist") | ||||
| 	ErrUserNotExist     = errors.New("User does not exist") | ||||
| 	ErrEmailAlreadyUsed = errors.New("E-mail already used") | ||||
| 	ErrUserNameIllegal  = errors.New("User name contains illegal characters") | ||||
| ) | ||||
| 
 | ||||
| // User represents the object of individual and member of organization.
 | ||||
| type User struct { | ||||
| 	Id            int64 | ||||
|  | @ -51,6 +59,7 @@ type User struct { | |||
| 	Location      string | ||||
| 	Website       string | ||||
| 	IsActive      bool | ||||
| 	IsAdmin       bool | ||||
| 	Rands         string    `xorm:"VARCHAR(10)"` | ||||
| 	Created       time.Time `xorm:"created"` | ||||
| 	Updated       time.Time `xorm:"updated"` | ||||
|  | @ -66,19 +75,28 @@ func (user *User) AvatarLink() string { | |||
| 	return "http://1.gravatar.com/avatar/" + user.Avatar | ||||
| } | ||||
| 
 | ||||
| type Follow struct { | ||||
| 	Id       int64 | ||||
| 	UserId   int64     `xorm:"unique(s)"` | ||||
| 	FollowId int64     `xorm:"unique(s)"` | ||||
| 	Created  time.Time `xorm:"created"` | ||||
| // NewGitSig generates and returns the signature of given user.
 | ||||
| func (user *User) NewGitSig() *git.Signature { | ||||
| 	return &git.Signature{ | ||||
| 		Name:  user.Name, | ||||
| 		Email: user.Email, | ||||
| 		When:  time.Now(), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	ErrUserOwnRepos     = errors.New("User still have ownership of repositories") | ||||
| 	ErrUserAlreadyExist = errors.New("User already exist") | ||||
| 	ErrUserNotExist     = errors.New("User does not exist") | ||||
| 	ErrEmailAlreadyUsed = errors.New("E-mail already used") | ||||
| ) | ||||
| // EncodePasswd encodes password to safe format.
 | ||||
| func (user *User) EncodePasswd() error { | ||||
| 	newPasswd, err := scrypt.Key([]byte(user.Passwd), []byte(base.SecretKey), 16384, 8, 1, 64) | ||||
| 	user.Passwd = fmt.Sprintf("%x", newPasswd) | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| // Member represents user is member of organization.
 | ||||
| type Member struct { | ||||
| 	Id     int64 | ||||
| 	OrgId  int64 `xorm:"unique(member) index"` | ||||
| 	UserId int64 `xorm:"unique(member)"` | ||||
| } | ||||
| 
 | ||||
| // IsUserExist checks if given user name exist,
 | ||||
| // the user name should be noncased unique.
 | ||||
|  | @ -91,15 +109,6 @@ func IsEmailUsed(email string) (bool, error) { | |||
| 	return orm.Get(&User{Email: email}) | ||||
| } | ||||
| 
 | ||||
| // NewGitSig generates and returns the signature of given user.
 | ||||
| func (user *User) NewGitSig() *git.Signature { | ||||
| 	return &git.Signature{ | ||||
| 		Name:  user.Name, | ||||
| 		Email: user.Email, | ||||
| 		When:  time.Now(), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // return a user salt token
 | ||||
| func GetUserSalt() string { | ||||
| 	return base.GetRandomString(10) | ||||
|  | @ -107,6 +116,10 @@ func GetUserSalt() string { | |||
| 
 | ||||
| // RegisterUser creates record of a new user.
 | ||||
| func RegisterUser(user *User) (*User, error) { | ||||
| 	if !IsLegalName(user.Name) { | ||||
| 		return nil, ErrUserNameIllegal | ||||
| 	} | ||||
| 
 | ||||
| 	isExist, err := IsUserExist(user.Name) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
|  | @ -136,7 +149,20 @@ func RegisterUser(user *User) (*User, error) { | |||
| 		} | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return user, nil | ||||
| 
 | ||||
| 	if user.Id == 1 { | ||||
| 		user.IsAdmin = true | ||||
| 		user.IsActive = true | ||||
| 		_, err = orm.Id(user.Id).UseBool().Update(user) | ||||
| 	} | ||||
| 	return user, err | ||||
| } | ||||
| 
 | ||||
| // GetUsers returns given number of user objects with offset.
 | ||||
| func GetUsers(num, offset int) ([]User, error) { | ||||
| 	users := make([]User, 0, num) | ||||
| 	err := orm.Limit(num, offset).Asc("id").Find(&users) | ||||
| 	return users, err | ||||
| } | ||||
| 
 | ||||
| // get user by erify code
 | ||||
|  | @ -217,22 +243,14 @@ func DeleteUser(user *User) error { | |||
| 	return err | ||||
| } | ||||
| 
 | ||||
| // EncodePasswd encodes password to safe format.
 | ||||
| func (user *User) EncodePasswd() error { | ||||
| 	newPasswd, err := scrypt.Key([]byte(user.Passwd), []byte(base.SecretKey), 16384, 8, 1, 64) | ||||
| 	user.Passwd = fmt.Sprintf("%x", newPasswd) | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| // UserPath returns the path absolute path of user repositories.
 | ||||
| func UserPath(userName string) string { | ||||
| 	return filepath.Join(RepoRootPath, strings.ToLower(userName)) | ||||
| 	return filepath.Join(base.RepoRootPath, strings.ToLower(userName)) | ||||
| } | ||||
| 
 | ||||
| func GetUserByKeyId(keyId int64) (*User, error) { | ||||
| 	user := new(User) | ||||
| 	rawSql := "SELECT a.* FROM `user` AS a, public_key AS b WHERE a.id = b.owner_id AND b.id=?" | ||||
| 
 | ||||
| 	has, err := orm.Sql(rawSql, keyId).Get(user) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
|  | @ -289,6 +307,13 @@ func LoginUserPlain(name, passwd string) (*User, error) { | |||
| 	return &user, err | ||||
| } | ||||
| 
 | ||||
| // Follow is connection request for receiving user notifycation.
 | ||||
| type Follow struct { | ||||
| 	Id       int64 | ||||
| 	UserId   int64 `xorm:"unique(follow)"` | ||||
| 	FollowId int64 `xorm:"unique(follow)"` | ||||
| } | ||||
| 
 | ||||
| // FollowUser marks someone be another's follower.
 | ||||
| func FollowUser(userId int64, followId int64) (err error) { | ||||
| 	session := orm.NewSession() | ||||
|  | @ -300,19 +325,13 @@ func FollowUser(userId int64, followId int64) (err error) { | |||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	rawSql := "UPDATE user SET num_followers = num_followers + 1 WHERE id = ?" | ||||
| 	if base.Cfg.MustValue("database", "DB_TYPE") == "postgres" { | ||||
| 		rawSql = "UPDATE \"user\" SET num_followers = num_followers + 1 WHERE id = ?" | ||||
| 	} | ||||
| 	rawSql := "UPDATE `user` SET num_followers = num_followers + 1 WHERE id = ?" | ||||
| 	if _, err = session.Exec(rawSql, followId); err != nil { | ||||
| 		session.Rollback() | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	rawSql = "UPDATE user SET num_followings = num_followings + 1 WHERE id = ?" | ||||
| 	if base.Cfg.MustValue("database", "DB_TYPE") == "postgres" { | ||||
| 		rawSql = "UPDATE \"user\" SET num_followings = num_followings + 1 WHERE id = ?" | ||||
| 	} | ||||
| 	rawSql = "UPDATE `user` SET num_followings = num_followings + 1 WHERE id = ?" | ||||
| 	if _, err = session.Exec(rawSql, userId); err != nil { | ||||
| 		session.Rollback() | ||||
| 		return err | ||||
|  | @ -331,19 +350,13 @@ func UnFollowUser(userId int64, unFollowId int64) (err error) { | |||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	rawSql := "UPDATE user SET num_followers = num_followers - 1 WHERE id = ?" | ||||
| 	if base.Cfg.MustValue("database", "DB_TYPE") == "postgres" { | ||||
| 		rawSql = "UPDATE \"user\" SET num_followers = num_followers - 1 WHERE id = ?" | ||||
| 	} | ||||
| 	rawSql := "UPDATE `user` SET num_followers = num_followers - 1 WHERE id = ?" | ||||
| 	if _, err = session.Exec(rawSql, unFollowId); err != nil { | ||||
| 		session.Rollback() | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	rawSql = "UPDATE user SET num_followings = num_followings - 1 WHERE id = ?" | ||||
| 	if base.Cfg.MustValue("database", "DB_TYPE") == "postgres" { | ||||
| 		rawSql = "UPDATE \"user\" SET num_followings = num_followings - 1 WHERE id = ?" | ||||
| 	} | ||||
| 	rawSql = "UPDATE `user` SET num_followings = num_followings - 1 WHERE id = ?" | ||||
| 	if _, err = session.Exec(rawSql, userId); err != nil { | ||||
| 		session.Rollback() | ||||
| 		return err | ||||
|  |  | |||
|  | @ -0,0 +1,55 @@ | |||
| // 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 ( | ||||
| 	"net/http" | ||||
| 	"reflect" | ||||
| 
 | ||||
| 	"github.com/codegangsta/martini" | ||||
| 
 | ||||
| 	"github.com/gogits/binding" | ||||
| 
 | ||||
| 	"github.com/gogits/gogs/modules/base" | ||||
| 	"github.com/gogits/gogs/modules/log" | ||||
| ) | ||||
| 
 | ||||
| type AdminEditUserForm struct { | ||||
| 	Email    string `form:"email" binding:"Required;Email;MaxSize(50)"` | ||||
| 	Website  string `form:"website" binding:"MaxSize(50)"` | ||||
| 	Location string `form:"location" binding:"MaxSize(50)"` | ||||
| 	Avatar   string `form:"avatar" binding:"Required;Email;MaxSize(50)"` | ||||
| 	Active   string `form:"active"` | ||||
| 	Admin    string `form:"admin"` | ||||
| } | ||||
| 
 | ||||
| func (f *AdminEditUserForm) Name(field string) string { | ||||
| 	names := map[string]string{ | ||||
| 		"Email":    "E-mail address", | ||||
| 		"Website":  "Website", | ||||
| 		"Location": "Location", | ||||
| 		"Avatar":   "Gravatar Email", | ||||
| 	} | ||||
| 	return names[field] | ||||
| } | ||||
| 
 | ||||
| func (f *AdminEditUserForm) Validate(errors *binding.Errors, req *http.Request, context martini.Context) { | ||||
| 	if req.Method == "GET" || errors.Count() == 0 { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) | ||||
| 	data["HasError"] = true | ||||
| 	AssignForm(f, data) | ||||
| 
 | ||||
| 	if len(errors.Overall) > 0 { | ||||
| 		for _, err := range errors.Overall { | ||||
| 			log.Error("AdminEditUserForm.Validate: %v", err) | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	validate(errors, data, f) | ||||
| } | ||||
|  | @ -79,7 +79,7 @@ type UpdateProfileForm struct { | |||
| 
 | ||||
| func (f *UpdateProfileForm) Name(field string) string { | ||||
| 	names := map[string]string{ | ||||
| 		"Email":    "Email address", | ||||
| 		"Email":    "E-mail address", | ||||
| 		"Website":  "Website", | ||||
| 		"Location": "Location", | ||||
| 		"Avatar":   "Gravatar Email", | ||||
|  |  | |||
|  | @ -15,6 +15,8 @@ import ( | |||
| 	"github.com/Unknwon/com" | ||||
| 	"github.com/Unknwon/goconfig" | ||||
| 
 | ||||
| 	"github.com/gogits/cache" | ||||
| 
 | ||||
| 	"github.com/gogits/gogs/modules/log" | ||||
| ) | ||||
| 
 | ||||
|  | @ -26,20 +28,32 @@ type Mailer struct { | |||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	AppVer      string | ||||
| 	AppName     string | ||||
| 	AppLogo     string | ||||
| 	AppUrl      string | ||||
| 	Domain      string | ||||
| 	SecretKey   string | ||||
| 	AppVer       string | ||||
| 	AppName      string | ||||
| 	AppLogo      string | ||||
| 	AppUrl       string | ||||
| 	Domain       string | ||||
| 	SecretKey    string | ||||
| 	RunUser      string | ||||
| 	RepoRootPath string | ||||
| 
 | ||||
| 	Cfg         *goconfig.ConfigFile | ||||
| 	MailService *Mailer | ||||
| 
 | ||||
| 	Cache        cache.Cache | ||||
| 	CacheAdapter string | ||||
| 	CacheConfig  string | ||||
| 
 | ||||
| 	LogMode   string | ||||
| 	LogConfig string | ||||
| ) | ||||
| 
 | ||||
| var Service struct { | ||||
| 	RegisterEmailConfirm bool | ||||
| 	ActiveCodeLives      int | ||||
| 	ResetPwdCodeLives    int | ||||
| 	RegisterEmailConfirm   bool | ||||
| 	DisenableRegisteration bool | ||||
| 	RequireSignInView      bool | ||||
| 	ActiveCodeLives        int | ||||
| 	ResetPwdCodeLives      int | ||||
| } | ||||
| 
 | ||||
| func exeDir() (string, error) { | ||||
|  | @ -66,19 +80,21 @@ var logLevels = map[string]string{ | |||
| func newService() { | ||||
| 	Service.ActiveCodeLives = Cfg.MustInt("service", "ACTIVE_CODE_LIVE_MINUTES", 180) | ||||
| 	Service.ResetPwdCodeLives = Cfg.MustInt("service", "RESET_PASSWD_CODE_LIVE_MINUTES", 180) | ||||
| 	Service.DisenableRegisteration = Cfg.MustBool("service", "DISENABLE_REGISTERATION", false) | ||||
| 	Service.RequireSignInView = Cfg.MustBool("service", "REQUIRE_SIGNIN_VIEW", false) | ||||
| } | ||||
| 
 | ||||
| func newLogService() { | ||||
| 	// Get and check log mode.
 | ||||
| 	mode := Cfg.MustValue("log", "MODE", "console") | ||||
| 	modeSec := "log." + mode | ||||
| 	LogMode = Cfg.MustValue("log", "MODE", "console") | ||||
| 	modeSec := "log." + LogMode | ||||
| 	if _, err := Cfg.GetSection(modeSec); err != nil { | ||||
| 		fmt.Printf("Unknown log mode: %s\n", mode) | ||||
| 		fmt.Printf("Unknown log mode: %s\n", LogMode) | ||||
| 		os.Exit(2) | ||||
| 	} | ||||
| 
 | ||||
| 	// Log level.
 | ||||
| 	levelName := Cfg.MustValue("log."+mode, "LEVEL", "Trace") | ||||
| 	levelName := Cfg.MustValue("log."+LogMode, "LEVEL", "Trace") | ||||
| 	level, ok := logLevels[levelName] | ||||
| 	if !ok { | ||||
| 		fmt.Printf("Unknown log level: %s\n", levelName) | ||||
|  | @ -86,14 +102,13 @@ func newLogService() { | |||
| 	} | ||||
| 
 | ||||
| 	// Generate log configuration.
 | ||||
| 	var config string | ||||
| 	switch mode { | ||||
| 	switch LogMode { | ||||
| 	case "console": | ||||
| 		config = fmt.Sprintf(`{"level":%s}`, level) | ||||
| 		LogConfig = fmt.Sprintf(`{"level":%s}`, level) | ||||
| 	case "file": | ||||
| 		logPath := Cfg.MustValue(modeSec, "FILE_NAME", "log/gogs.log") | ||||
| 		os.MkdirAll(path.Dir(logPath), os.ModePerm) | ||||
| 		config = fmt.Sprintf( | ||||
| 		LogConfig = fmt.Sprintf( | ||||
| 			`{"level":%s,"filename":%s,"rotate":%v,"maxlines":%d,"maxsize",%d,"daily":%v,"maxdays":%d}`, level, | ||||
| 			logPath, | ||||
| 			Cfg.MustBool(modeSec, "LOG_ROTATE", true), | ||||
|  | @ -102,13 +117,13 @@ func newLogService() { | |||
| 			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, | ||||
| 		LogConfig = 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, | ||||
| 		LogConfig = 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"), | ||||
|  | @ -116,8 +131,32 @@ func newLogService() { | |||
| 			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) | ||||
| 	log.NewLogger(Cfg.MustInt64("log", "BUFFER_LEN", 10000), LogMode, LogConfig) | ||||
| 	log.Info("Log Mode: %s(%s)", strings.Title(LogMode), levelName) | ||||
| } | ||||
| 
 | ||||
| func newCacheService() { | ||||
| 	CacheAdapter = Cfg.MustValue("cache", "ADAPTER", "memory") | ||||
| 
 | ||||
| 	switch CacheAdapter { | ||||
| 	case "memory": | ||||
| 		CacheConfig = fmt.Sprintf(`{"interval":%d}`, Cfg.MustInt("cache", "INTERVAL", 60)) | ||||
| 	case "redis", "memcache": | ||||
| 		CacheConfig = fmt.Sprintf(`{"conn":"%s"}`, Cfg.MustValue("cache", "HOST")) | ||||
| 	default: | ||||
| 		fmt.Printf("Unknown cache adapter: %s\n", CacheAdapter) | ||||
| 		os.Exit(2) | ||||
| 	} | ||||
| 
 | ||||
| 	var err error | ||||
| 	Cache, err = cache.NewCache(CacheAdapter, CacheConfig) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Init cache system failed, adapter: %s, config: %s, %v\n", | ||||
| 			CacheAdapter, CacheConfig, err) | ||||
| 		os.Exit(2) | ||||
| 	} | ||||
| 
 | ||||
| 	log.Info("Cache Service Enabled") | ||||
| } | ||||
| 
 | ||||
| func newMailService() { | ||||
|  | @ -144,7 +183,7 @@ func newRegisterMailService() { | |||
| 	log.Info("Register Mail Service Enabled") | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| func NewConfigContext() { | ||||
| 	var err error | ||||
| 	workDir, err := exeDir() | ||||
| 	if err != nil { | ||||
|  | @ -173,11 +212,20 @@ func init() { | |||
| 	AppUrl = Cfg.MustValue("server", "ROOT_URL") | ||||
| 	Domain = Cfg.MustValue("server", "DOMAIN") | ||||
| 	SecretKey = Cfg.MustValue("security", "SECRET_KEY") | ||||
| 	RunUser = Cfg.MustValue("", "RUN_USER") | ||||
| 
 | ||||
| 	// Determine and create root git reposiroty path.
 | ||||
| 	RepoRootPath = Cfg.MustValue("repository", "ROOT") | ||||
| 	if err = os.MkdirAll(RepoRootPath, os.ModePerm); err != nil { | ||||
| 		fmt.Printf("models.init(fail to create RepoRootPath(%s)): %v\n", RepoRootPath, err) | ||||
| 		os.Exit(2) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func NewServices() { | ||||
| 	newService() | ||||
| 	newLogService() | ||||
| 	newCacheService() | ||||
| 	newMailService() | ||||
| 	newRegisterMailService() | ||||
| } | ||||
|  |  | |||
|  | @ -36,7 +36,7 @@ func isLink(link []byte) bool { | |||
| func IsMarkdownFile(name string) bool { | ||||
| 	name = strings.ToLower(name) | ||||
| 	switch filepath.Ext(name) { | ||||
| 	case "md", "markdown": | ||||
| 	case ".md", ".markdown", ".mdown": | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
|  | @ -61,7 +61,7 @@ type CustomRender struct { | |||
| func (options *CustomRender) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) { | ||||
| 	if len(link) > 0 && !isLink(link) { | ||||
| 		if link[0] == '#' { | ||||
| 			link = append([]byte(options.urlPrefix), link...) | ||||
| 			// link = append([]byte(options.urlPrefix), link...)
 | ||||
| 		} else { | ||||
| 			link = []byte(path.Join(options.urlPrefix, string(link))) | ||||
| 		} | ||||
|  |  | |||
|  | @ -33,6 +33,10 @@ func List(l *list.List) chan interface{} { | |||
| 	return c | ||||
| } | ||||
| 
 | ||||
| var mailDomains = map[string]string{ | ||||
| 	"gmail.com": "gmail.com", | ||||
| } | ||||
| 
 | ||||
| var TemplateFuncs template.FuncMap = map[string]interface{}{ | ||||
| 	"AppName": func() string { | ||||
| 		return AppName | ||||
|  | @ -56,7 +60,12 @@ var TemplateFuncs template.FuncMap = map[string]interface{}{ | |||
| 	"DateFormat": DateFormat, | ||||
| 	"List":       List, | ||||
| 	"Mail2Domain": func(mail string) string { | ||||
| 		return "mail." + strings.Split(mail, "@")[1] | ||||
| 		suffix := strings.SplitN(mail, "@", 2)[1] | ||||
| 		domain, ok := mailDomains[suffix] | ||||
| 		if !ok { | ||||
| 			return "mail." + suffix | ||||
| 		} | ||||
| 		return domain | ||||
| 	}, | ||||
| 	"SubStr": func(str string, start, length int) string { | ||||
| 		return str[start : start+length] | ||||
|  |  | |||
|  | @ -40,7 +40,7 @@ func (m Message) Content() string { | |||
| 
 | ||||
| var mailQueue chan *Message | ||||
| 
 | ||||
| func init() { | ||||
| func NewMailerContext() { | ||||
| 	mailQueue = make(chan *Message, base.Cfg.MustInt("mailer", "SEND_BUFFER_LEN", 10)) | ||||
| 	go processMailQueue() | ||||
| } | ||||
|  |  | |||
|  | @ -15,12 +15,12 @@ func SignInRequire(redirect bool) martini.Handler { | |||
| 	return func(ctx *Context) { | ||||
| 		if !ctx.IsSigned { | ||||
| 			if redirect { | ||||
| 				ctx.Redirect("/") | ||||
| 				ctx.Redirect("/user/login") | ||||
| 			} | ||||
| 			return | ||||
| 		} else if !ctx.User.IsActive && base.Service.RegisterEmailConfirm { | ||||
| 			ctx.Data["Title"] = "Activate Your Account" | ||||
| 			ctx.Render.HTML(200, "user/active", ctx.Data) | ||||
| 			ctx.HTML(200, "user/active") | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
|  | @ -31,6 +31,18 @@ func SignOutRequire() martini.Handler { | |||
| 	return func(ctx *Context) { | ||||
| 		if ctx.IsSigned { | ||||
| 			ctx.Redirect("/") | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // AdminRequire requires user signed in as administor.
 | ||||
| func AdminRequire() martini.Handler { | ||||
| 	return func(ctx *Context) { | ||||
| 		if !ctx.User.IsAdmin { | ||||
| 			ctx.Error(403) | ||||
| 			return | ||||
| 		} | ||||
| 		ctx.Data["PageIsAdmin"] = true | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -12,8 +12,11 @@ import ( | |||
| 	"github.com/codegangsta/martini" | ||||
| 	"github.com/martini-contrib/sessions" | ||||
| 
 | ||||
| 	"github.com/gogits/cache" | ||||
| 
 | ||||
| 	"github.com/gogits/gogs/models" | ||||
| 	"github.com/gogits/gogs/modules/auth" | ||||
| 	"github.com/gogits/gogs/modules/base" | ||||
| 	"github.com/gogits/gogs/modules/log" | ||||
| ) | ||||
| 
 | ||||
|  | @ -25,6 +28,7 @@ type Context struct { | |||
| 	Req      *http.Request | ||||
| 	Res      http.ResponseWriter | ||||
| 	Session  sessions.Session | ||||
| 	Cache    cache.Cache | ||||
| 	User     *models.User | ||||
| 	IsSigned bool | ||||
| 
 | ||||
|  | @ -61,24 +65,29 @@ func (ctx *Context) HasError() bool { | |||
| 	return hasErr.(bool) | ||||
| } | ||||
| 
 | ||||
| // HTML calls render.HTML underlying but reduce one argument.
 | ||||
| func (ctx *Context) HTML(status int, name string, htmlOpt ...HTMLOptions) { | ||||
| 	ctx.Render.HTML(status, name, ctx.Data, htmlOpt...) | ||||
| } | ||||
| 
 | ||||
| // RenderWithErr used for page has form validation but need to prompt error to users.
 | ||||
| func (ctx *Context) RenderWithErr(msg, tpl string, form auth.Form) { | ||||
| 	ctx.Data["HasError"] = true | ||||
| 	ctx.Data["ErrorMsg"] = msg | ||||
| 	auth.AssignForm(form, ctx.Data) | ||||
| 	ctx.HTML(200, tpl, ctx.Data) | ||||
| 	ctx.HTML(200, tpl) | ||||
| } | ||||
| 
 | ||||
| // Handle handles and logs error by given status.
 | ||||
| func (ctx *Context) Handle(status int, title string, err error) { | ||||
| 	log.Error("%s: %v", title, err) | ||||
| 	if martini.Dev == martini.Prod { | ||||
| 		ctx.HTML(500, "status/500", ctx.Data) | ||||
| 		ctx.HTML(500, "status/500") | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	ctx.Data["ErrorMsg"] = err | ||||
| 	ctx.HTML(status, fmt.Sprintf("status/%d", status), ctx.Data) | ||||
| 	ctx.HTML(status, fmt.Sprintf("status/%d", status)) | ||||
| } | ||||
| 
 | ||||
| // InitContext initializes a classic context for a request.
 | ||||
|  | @ -92,6 +101,7 @@ func InitContext() martini.Handler { | |||
| 			Req:     r, | ||||
| 			Res:     res, | ||||
| 			Session: session, | ||||
| 			Cache:   base.Cache, | ||||
| 			Render:  rd, | ||||
| 		} | ||||
| 
 | ||||
|  | @ -106,6 +116,7 @@ func InitContext() martini.Handler { | |||
| 			ctx.Data["SignedUser"] = user | ||||
| 			ctx.Data["SignedUserId"] = user.Id | ||||
| 			ctx.Data["SignedUserName"] = user.LowerName | ||||
| 			ctx.Data["IsAdmin"] = ctx.User.IsAdmin | ||||
| 		} | ||||
| 
 | ||||
| 		ctx.Data["PageStartTime"] = time.Now() | ||||
|  |  | |||
|  | @ -70,6 +70,7 @@ func RepoAssignment(redirect bool) martini.Handler { | |||
| 		} | ||||
| 		ctx.Repo.Repository = repo | ||||
| 		ctx.Repo.CloneLink.SSH = fmt.Sprintf("git@%s:%s/%s.git", base.Domain, user.LowerName, repo.LowerName) | ||||
| 		ctx.Repo.CloneLink.HTTPS = fmt.Sprintf("https://%s/%s/%s.git", base.Domain, user.LowerName, repo.LowerName) | ||||
| 
 | ||||
| 		ctx.Data["IsRepositoryValid"] = true | ||||
| 		ctx.Data["Repository"] = repo | ||||
|  | @ -78,5 +79,6 @@ func RepoAssignment(redirect bool) martini.Handler { | |||
| 		ctx.Data["CloneLink"] = ctx.Repo.CloneLink | ||||
| 		ctx.Data["RepositoryLink"] = ctx.Data["Title"] | ||||
| 		ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner | ||||
| 		ctx.Data["IsRepositoryWatching"] = ctx.Repo.IsWatching | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -145,8 +145,9 @@ html, body { | |||
|     float: right; | ||||
| } | ||||
| 
 | ||||
| #gogs-nav-signin { | ||||
| #gogs-nav-signin, #gogs-nav-signup { | ||||
|     float: right; | ||||
|     margin-left: 1em; | ||||
| } | ||||
| 
 | ||||
| #gogs-nav-out .fa { | ||||
|  | @ -324,6 +325,27 @@ html, body { | |||
|     color: #444; | ||||
| } | ||||
| 
 | ||||
| .gogs-admin-nav { | ||||
|     background-color: #FFF; | ||||
|     padding-top: 10px; | ||||
|     padding-left: 0; | ||||
|     padding-right: 0; | ||||
|     border: 1px solid #D8D8D8; | ||||
| } | ||||
| 
 | ||||
| .gogs-admin-nav li { | ||||
|     margin-bottom: 8px; | ||||
|     border-left: 4px solid transparent; | ||||
| } | ||||
| 
 | ||||
| .gogs-admin-nav li:hover { | ||||
|     border-left-color: #EEE; | ||||
| } | ||||
| 
 | ||||
| .gogs-admin-nav li.active:hover { | ||||
|     border-left: 4px solid #DD4B39; | ||||
| } | ||||
| 
 | ||||
| /* gogits user ssh keys */ | ||||
| 
 | ||||
| #gogs-ssh-keys .list-group-item { | ||||
|  | @ -376,7 +398,7 @@ html, body { | |||
| } | ||||
| 
 | ||||
| #gogs-feed-right .repo-panel .list-group-item a { | ||||
|     display: inline-block; | ||||
|     display: block; | ||||
|     margin-left: 0; | ||||
|     background-color: transparent; | ||||
|     padding-left: 0; | ||||
|  | @ -406,7 +428,6 @@ html, body { | |||
| 
 | ||||
| #gogs-feed-right .repo-panel span.stars { | ||||
|     color: #666; | ||||
|     line-height: 44px; | ||||
|     margin-right: 1em; | ||||
| } | ||||
| 
 | ||||
|  | @ -445,7 +466,7 @@ html, body { | |||
|     padding: 0; | ||||
| } | ||||
| 
 | ||||
| #gogs-repo-watching .dropdown-menu .dropdown-item:hover .dropdown-header { | ||||
| #gogs-repo-watching .dropdown-menu .dropdown-item:hover .dropdown-header, #gogs-repo-watching .dropdown-item .dropdown-header.text-primary { | ||||
|     color: rgb(65, 131, 196); | ||||
|     cursor: pointer; | ||||
| } | ||||
|  | @ -501,8 +522,7 @@ html, body { | |||
| } | ||||
| 
 | ||||
| .activity-list .info { | ||||
|     float: left; | ||||
|     padding: 0 0 0 10px; | ||||
|     margin: 0 0 0 40px; | ||||
|     line-height: 1.7em; | ||||
| } | ||||
| 
 | ||||
|  | @ -555,6 +575,15 @@ html, body { | |||
|     min-width: 200px; | ||||
| } | ||||
| 
 | ||||
| #gogs-repo-clone .dropdown-menu{ | ||||
|     width: 400px; | ||||
|     padding: 20px; | ||||
| } | ||||
| 
 | ||||
| #gogs-repo-clone .input-group{ | ||||
|     margin-bottom: 15px; | ||||
| } | ||||
| 
 | ||||
| /* #gogs-source */ | ||||
| #gogs-source { | ||||
|     margin-top: -20px; | ||||
|  | @ -645,6 +674,62 @@ html, body { | |||
| 
 | ||||
| .file-content .file-body { | ||||
|     padding: 30px 30px 50px; | ||||
|     border: none; | ||||
|     background-color: #FFF; | ||||
|     overflow: auto; | ||||
|     overflow-x: auto; | ||||
|     overflow-y: hidden; | ||||
| } | ||||
| 
 | ||||
| .file-content .file-body.file-code pre { | ||||
|     background-color: #FFF; | ||||
|     border: none; | ||||
| } | ||||
| 
 | ||||
| .file-content .file-body.file-code { | ||||
|     padding: 0; | ||||
| } | ||||
| 
 | ||||
| .file-content .file-body.file-code .lines-code > pre { | ||||
|     border: none; | ||||
|     background: none; | ||||
|     border-left: 1px solid #ddd; | ||||
| } | ||||
| 
 | ||||
| .file-content .file-body.file-code .lines-code ol.linenums > .active { | ||||
|     background: #ffffdd; | ||||
| } | ||||
| 
 | ||||
| .file-content .file-body.file-code .lines-num { | ||||
|     text-align: right; | ||||
|     color: #999; | ||||
|     background: #fafafa; | ||||
|     width: 1%; | ||||
| } | ||||
| 
 | ||||
| .file-content .file-body.file-code .lines-num span { | ||||
|     font-family: Menlo, Monaco, Consolas, "Courier New", monospace; | ||||
|     line-height: 1.6; | ||||
|     padding: 0 8px 0 10px; | ||||
|     cursor: pointer; | ||||
|     display: block; | ||||
|     margin-top: 2px; | ||||
|     font-size: 90%; | ||||
| } | ||||
| 
 | ||||
| .file-content .file-body.file-code .lines-num span:first-child { | ||||
|     margin-top: 0; | ||||
| } | ||||
| 
 | ||||
| .file-content .file-body.file-code > table { | ||||
|     width: 100%; | ||||
| } | ||||
| 
 | ||||
| .file-content .file-body.file-code > table > tbody > tr, | ||||
| .file-content .file-body.file-code > table > tbody > tr > td, | ||||
| .file-content .file-body.file-code > table { | ||||
|     border: none; | ||||
|     background: none; | ||||
| } | ||||
| 
 | ||||
| .branch-list th, .commit-list th { | ||||
|  | @ -724,6 +809,28 @@ html, body { | |||
|     background-color: #FFF; | ||||
| } | ||||
| 
 | ||||
| .commit-list .date { | ||||
|     width: 120px; | ||||
| } | ||||
| 
 | ||||
| .commit-list .author { | ||||
|     min-width: 180px; | ||||
| } | ||||
| 
 | ||||
| .guide-box pre, .guide-box .input-group { | ||||
|     margin-top: 20px; | ||||
|     margin-bottom: 30px; | ||||
|     line-height: 24px; | ||||
| } | ||||
| 
 | ||||
| .guide-box input[readonly] { | ||||
|     background-color: #FFF; | ||||
| } | ||||
| 
 | ||||
| .guide-box { | ||||
|     margin-top: 20px; | ||||
| } | ||||
| 
 | ||||
| /* wrapper and footer */ | ||||
| 
 | ||||
| #wrapper { | ||||
|  |  | |||
|  | @ -15,7 +15,8 @@ | |||
|   line-height: 1.7; | ||||
|   padding: 15px 0 0; | ||||
|   margin: 0 0 15px; | ||||
|   color: #666; | ||||
|   color: #444; | ||||
|   font-weight: bold; | ||||
| } | ||||
| 
 | ||||
| .markdown h1, | ||||
|  | @ -86,6 +87,10 @@ | |||
|   margin-top: 6px; | ||||
| } | ||||
| 
 | ||||
| .markdown li:first-child { | ||||
|   margin-top: 0; | ||||
| } | ||||
| 
 | ||||
| .markdown dl dt { | ||||
|   font-style: italic; | ||||
|   margin-top: 9px; | ||||
|  | @ -106,8 +111,8 @@ | |||
|   line-height: 1.6; | ||||
|   overflow: auto; | ||||
|   background: #f8f8f8; | ||||
|   padding: 6px 10px; | ||||
|   border: 1px solid #ddd; | ||||
|   padding: 0; | ||||
| } | ||||
| 
 | ||||
| .markdown > pre.linenums { | ||||
|  | @ -115,6 +120,17 @@ | |||
| } | ||||
| 
 | ||||
| .markdown > pre > ol.linenums { | ||||
|   list-style: none; | ||||
|   padding: 0; | ||||
| } | ||||
| 
 | ||||
| .markdown > pre > ol.linenums > li { | ||||
|   margin-top: 2px; | ||||
| } | ||||
| 
 | ||||
| .markdown > pre.nums-style > ol.linenums { | ||||
|   list-style-type: decimal; | ||||
|   padding: 0 0 0 40px; | ||||
|   -webkit-box-shadow: inset 40px 0 0 #f5f5f5, inset 41px 0 0 #ccc; | ||||
|   box-shadow: inset 40px 0 0 #f5f5f5, inset 41px 0 0 #ccc; | ||||
| } | ||||
|  | @ -130,14 +146,14 @@ | |||
| } | ||||
| 
 | ||||
| .markdown > pre > ol.linenums > li:first-child { | ||||
|   padding-top: 6px; | ||||
|   padding-top: 12px; | ||||
| } | ||||
| 
 | ||||
| .markdown > pre > ol.linenums > li:last-child { | ||||
|   padding-bottom: 6px; | ||||
|   padding-bottom: 12px; | ||||
| } | ||||
| 
 | ||||
| .markdown > pre > ol.linenums > li { | ||||
| .markdown > pre.nums-style > ol.linenums > li { | ||||
|   border-left: 1px solid #ddd; | ||||
| } | ||||
| 
 | ||||
|  | @ -163,6 +179,54 @@ | |||
|   color: #fff; | ||||
| } | ||||
| 
 | ||||
| .markdown .anchor-wrap { | ||||
|   /*margin-top: -50px;*/ | ||||
|   /*padding-top: 50px;*/ | ||||
| } | ||||
| 
 | ||||
| .markdown h1 a, .markdown h2 a, .markdown h3 a { | ||||
|   text-decoration: none; | ||||
| } | ||||
| 
 | ||||
| .markdown h1 a.anchor, | ||||
| .markdown h2 a.anchor, | ||||
| .markdown h3 a.anchor, | ||||
| .markdown h4 a.anchor, | ||||
| .markdown h5 a.anchor, | ||||
| .markdown h6 a.anchor { | ||||
|   text-decoration:none; | ||||
|   line-height:1; | ||||
|   padding-left:0; | ||||
|   margin-left:5px; | ||||
|   top:15%; | ||||
| } | ||||
| .markdown a span.octicon { | ||||
|   font-size: 16px; | ||||
|   font-family: "FontAwesome"; | ||||
|   line-height: 1; | ||||
|   display: inline-block; | ||||
|   text-decoration: none; | ||||
|   -webkit-font-smoothing: antialiased; | ||||
| } | ||||
| 
 | ||||
| .markdown a span.octicon-link { | ||||
|   display: none; | ||||
|   color: #000; | ||||
| } | ||||
| 
 | ||||
| .markdown a span.octicon-link:before { | ||||
|   content: "\f0c1"; | ||||
| } | ||||
| 
 | ||||
| .markdown h1:hover .octicon-link, | ||||
| .markdown h2:hover .octicon-link, | ||||
| .markdown h3:hover .octicon-link, | ||||
| .markdown h4:hover .octicon-link, | ||||
| .markdown h5:hover .octicon-link, | ||||
| .markdown h6:hover .octicon-link { | ||||
|   display:inline-block | ||||
| } | ||||
| 
 | ||||
| /* Author: jmblog */ | ||||
| /* Project: https://github.com/jmblog/color-themes-for-google-code-prettify */ | ||||
| /* GitHub Theme */ | ||||
|  | @ -187,6 +251,7 @@ | |||
|   /* a comment */ | ||||
|   .com { | ||||
|     color: #999988; | ||||
|     font-style: italic; | ||||
|   } | ||||
| 
 | ||||
|   /* a type name */ | ||||
|  |  | |||
							
								
								
									
										116
									
								
								public/js/app.js
								
								
								
								
							
							
						
						
									
										116
									
								
								public/js/app.js
								
								
								
								
							|  | @ -41,15 +41,15 @@ var Gogits = { | |||
|         }); | ||||
|     }; | ||||
|     Gogits.initPopovers = function () { | ||||
|         var hideAllPopovers = function() { | ||||
|            $('[data-toggle=popover]').each(function() { | ||||
|         var hideAllPopovers = function () { | ||||
|             $('[data-toggle=popover]').each(function () { | ||||
|                 $(this).popover('hide'); | ||||
|             });   | ||||
|             }); | ||||
|         }; | ||||
| 
 | ||||
|         $(document).on('click', function(e) { | ||||
|         $(document).on('click', function (e) { | ||||
|             var $e = $(e.target); | ||||
|             if($e.data('toggle') == 'popover'||$e.parents("[data-toggle=popover], .popover").length > 0){ | ||||
|             if ($e.data('toggle') == 'popover' || $e.parents("[data-toggle=popover], .popover").length > 0) { | ||||
|                 return; | ||||
|             } | ||||
|             hideAllPopovers(); | ||||
|  | @ -63,12 +63,56 @@ var Gogits = { | |||
|         var $tabs = $('[data-init=tabs]'); | ||||
|         $tabs.find("li:eq(0) a").tab("show"); | ||||
|     }; | ||||
|     // fix dropdown inside click
 | ||||
|     Gogits.initDropDown = function(){ | ||||
|         $('.dropdown-menu').on('click','a,button,input,select',function(e){ | ||||
|             e.stopPropagation(); | ||||
|         }); | ||||
|     }; | ||||
| 
 | ||||
|     // render markdown
 | ||||
|     Gogits.renderMarkdown = function () { | ||||
|         var $pre = $('.markdown').find('pre > code').parent(); | ||||
|         $pre.addClass("prettyprint"); | ||||
|         var $md = $('.markdown'); | ||||
|         var $pre = $md.find('pre > code').parent(); | ||||
|         $pre.addClass('prettyprint linenums'); | ||||
|         prettyPrint(); | ||||
| 
 | ||||
|         var $lineNums = $pre.parent().siblings('.lines-num'); | ||||
|         if ($lineNums.length > 0) { | ||||
|             var nums = $pre.find('ol.linenums > li').length; | ||||
|             for (var i = 1; i <= nums; i++) { | ||||
|                 $lineNums.append('<span id="L' + i + '" rel=".L' + i + '">' + i + '</span>'); | ||||
|             } | ||||
| 
 | ||||
|             var last; | ||||
|             $(document).on('click', '.lines-num span', function () { | ||||
|                 var $e = $(this); | ||||
|                 if (last) { | ||||
|                     last.removeClass('active'); | ||||
|                 } | ||||
|                 last = $e.parent().siblings('.lines-code').find('ol.linenums > ' + $e.attr('rel')); | ||||
|                 last.addClass('active'); | ||||
|                 window.location.href = '#' + $e.attr('id'); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         // Set anchor.
 | ||||
|         var headers = {}; | ||||
|         $md.find('h1, h2, h3, h4, h5, h6').each(function () { | ||||
|             var node = $(this); | ||||
|             var val = encodeURIComponent(node.text().toLowerCase().replace(/[^\w\- ]/g, '').replace(/[ ]/g, '-')); | ||||
|             var name = val; | ||||
|             if (headers[val] > 0) { | ||||
|                 name = val + '-' + headers[val]; | ||||
|             } | ||||
|             if (headers[val] == undefined) { | ||||
|                 headers[val] = 1; | ||||
|             } else { | ||||
|                 headers[val] += 1; | ||||
|             } | ||||
|             node = node.wrap('<div id="' + name + '" class="anchor-wrap" ></div>'); | ||||
|             node.append('<a class="anchor" href="#' + name + '"><span class="octicon octicon-link"></span></a>'); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
| })(jQuery); | ||||
|  | @ -98,6 +142,7 @@ function initCore() { | |||
|     Gogits.initPopovers(); | ||||
|     Gogits.initTabs(); | ||||
|     Gogits.initModals(); | ||||
|     Gogits.initDropDown(); | ||||
|     Gogits.renderMarkdown(); | ||||
| } | ||||
| 
 | ||||
|  | @ -142,6 +187,60 @@ function initUserSetting() { | |||
|     }); | ||||
| } | ||||
| 
 | ||||
| function initRepository() { | ||||
|     // clone group button script
 | ||||
|     (function () { | ||||
|         var $clone = $('.clone-group-btn'); | ||||
|         if ($clone.length) { | ||||
|             var $url = $('.clone-group-url'); | ||||
|             $clone.find('button[data-link]').on("click",function (e) { | ||||
|                 var $this = $(this); | ||||
|                 if (!$this.hasClass('btn-primary')) { | ||||
|                     $clone.find('.btn-primary').removeClass('btn-primary').addClass("btn-default"); | ||||
|                     $(this).addClass('btn-primary').removeClass('btn-default'); | ||||
|                     $url.val($this.data("link")); | ||||
|                     $clone.find('span.clone-url').text($this.data('link')); | ||||
|                 } | ||||
|             }).eq(0).trigger("click"); | ||||
|             // todo copy to clipboard
 | ||||
|         } | ||||
|     })(); | ||||
| 
 | ||||
|     // watching script
 | ||||
|     (function () { | ||||
|         var $watch = $('#gogs-repo-watching'), | ||||
|             watchLink = $watch.data("watch"), | ||||
|             unwatchLink = $watch.data("unwatch"); | ||||
|         $watch.on('click', '.to-watch',function () { | ||||
|             if ($watch.hasClass("watching")) { | ||||
|                 return false; | ||||
|             } | ||||
|             $.get(watchLink, function (json) { | ||||
|                 if (json.ok) { | ||||
|                     $watch.find('.text-primary').removeClass('text-primary'); | ||||
|                     $watch.find('.to-watch h4').addClass('text-primary'); | ||||
|                     $watch.find('.fa-eye-slash').removeClass('fa-eye-slash').addClass('fa-eye'); | ||||
|                     $watch.removeClass("no-watching").addClass("watching"); | ||||
|                 } | ||||
|             }); | ||||
|             return false; | ||||
|         }).on('click', '.to-unwatch', function () { | ||||
|             if ($watch.hasClass("no-watching")) { | ||||
|                 return false; | ||||
|             } | ||||
|             $.get(unwatchLink, function (json) { | ||||
|                 if (json.ok) { | ||||
|                     $watch.find('.text-primary').removeClass('text-primary'); | ||||
|                     $watch.find('.to-unwatch h4').addClass('text-primary'); | ||||
|                     $watch.find('.fa-eye').removeClass('fa-eye').addClass('fa-eye-slash'); | ||||
|                     $watch.removeClass("watching").addClass("no-watching"); | ||||
|                 } | ||||
|             }); | ||||
|             return false; | ||||
|         }); | ||||
|     })(); | ||||
| } | ||||
| 
 | ||||
| (function ($) { | ||||
|     $(function () { | ||||
|         initCore(); | ||||
|  | @ -152,5 +251,8 @@ function initUserSetting() { | |||
|         if (body.data("page") == "user") { | ||||
|             initUserSetting(); | ||||
|         } | ||||
|         if ($('.gogs-repo-nav').length) { | ||||
|             initRepository(); | ||||
|         } | ||||
|     }); | ||||
| })(jQuery); | ||||
|  |  | |||
|  | @ -340,7 +340,7 @@ q,"'\"`"]):d.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(? | |||
| s+")*(?:\\x5D|$))+/")+")")])}(b=a.types)&&g.push(["typ",b]);b=(""+a.keywords).replace(/^ | $/g,"");b.length&&g.push(["kwd",RegExp("^(?:"+b.replace(/[\s,]+/g,"|")+")\\b"),q]);d.push(["pln",/^\s+/,q," \r\n\t\u00a0"]);b="^.[^\\s\\w.$@'\"`/\\\\]*";a.regexLiterals&&(b+="(?!s*/)");g.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/, | ||||
| q],["pun",RegExp(b),q]);return C(d,g)}function J(a,d,g){function b(a){var c=a.nodeType;if(c==1&&!x.test(a.className))if("br"===a.nodeName)s(a),a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)b(a);else if((c==3||c==4)&&g){var d=a.nodeValue,i=d.match(m);if(i)c=d.substring(0,i.index),a.nodeValue=c,(d=d.substring(i.index+i[0].length))&&a.parentNode.insertBefore(j.createTextNode(d),a.nextSibling),s(a),c||a.parentNode.removeChild(a)}}function s(a){function b(a,c){var d= | ||||
| c?a.cloneNode(!1):a,e=a.parentNode;if(e){var e=b(e,1),g=a.nextSibling;e.appendChild(d);for(var i=g;i;i=g)g=i.nextSibling,e.appendChild(i)}return d}for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),d;(d=a.parentNode)&&d.nodeType===1;)a=d;c.push(a)}for(var x=/(?:^|\s)nocode(?:\s|$)/,m=/\r\n?|\n/,j=a.ownerDocument,k=j.createElement("li");a.firstChild;)k.appendChild(a.firstChild);for(var c=[k],i=0;i<c.length;++i)b(c[i]);d===(d|0)&&c[0].setAttribute("value",d);var r=j.createElement("ol"); | ||||
| r.className="linenums";for(var d=Math.max(0,d-1|0)||0,i=0,n=c.length;i<n;++i)k=c[i],k.className="L"+(i+d)%10,k.firstChild||k.appendChild(j.createTextNode("\u00a0")),r.appendChild(k);a.appendChild(r)}function p(a,d){for(var g=d.length;--g>=0;){var b=d[g];F.hasOwnProperty(b)?D.console&&console.warn("cannot override language handler %s",b):F[b]=a}}function I(a,d){if(!a||!F.hasOwnProperty(a))a=/^\s*</.test(d)?"default-markup":"default-code";return F[a]}function K(a){var d=a.h;try{var g=T(a.c,a.i),b=g.a; | ||||
| r.className="linenums";for(var d=Math.max(0,d-1|0)||0,i=0,n=c.length;i<n;++i)k=c[i],k.className="L"+(i+d+1),k.firstChild||k.appendChild(j.createTextNode("\u00a0")),r.appendChild(k);a.appendChild(r)}function p(a,d){for(var g=d.length;--g>=0;){var b=d[g];F.hasOwnProperty(b)?D.console&&console.warn("cannot override language handler %s",b):F[b]=a}}function I(a,d){if(!a||!F.hasOwnProperty(a))a=/^\s*</.test(d)?"default-markup":"default-code";return F[a]}function K(a){var d=a.h;try{var g=T(a.c,a.i),b=g.a; | ||||
| a.a=b;a.d=g.d;a.e=0;I(d,b)(a);var s=/\bMSIE\s(\d+)/.exec(navigator.userAgent),s=s&&+s[1]<=8,d=/\n/g,x=a.a,m=x.length,g=0,j=a.d,k=j.length,b=0,c=a.g,i=c.length,r=0;c[i]=m;var n,e;for(e=n=0;e<i;)c[e]!==c[e+2]?(c[n++]=c[e++],c[n++]=c[e++]):e+=2;i=n;for(e=n=0;e<i;){for(var p=c[e],w=c[e+1],t=e+2;t+2<=i&&c[t+1]===w;)t+=2;c[n++]=p;c[n++]=w;e=t}c.length=n;var f=a.c,h;if(f)h=f.style.display,f.style.display="none";try{for(;b<k;){var l=j[b+2]||m,B=c[r+2]||m,t=Math.min(l,B),A=j[b+1],G;if(A.nodeType!==1&&(G=x.substring(g, | ||||
| t))){s&&(G=G.replace(d,"\r"));A.nodeValue=G;var L=A.ownerDocument,o=L.createElement("span");o.className=c[r+1];var v=A.parentNode;v.replaceChild(o,A);o.appendChild(A);g<l&&(j[b+1]=A=L.createTextNode(x.substring(t,l)),v.insertBefore(A,o.nextSibling))}g=t;g>=l&&(b+=2);g>=B&&(r+=2)}}finally{if(f)f.style.display=h}}catch(u){D.console&&console.log(u&&u.stack||u)}}var D=window,y=["break,continue,do,else,for,if,return,while"],E=[[y,"auto,case,char,const,default,double,enum,extern,float,goto,inline,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], | ||||
| "catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],M=[E,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,delegate,dynamic_cast,explicit,export,friend,generic,late_check,mutable,namespace,nullptr,property,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],N=[E,"abstract,assert,boolean,byte,extends,final,finally,implements,import,instanceof,interface,null,native,package,strictfp,super,synchronized,throws,transient"], | ||||
|  | @ -400,7 +400,7 @@ PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t-\r ]+/,null,"\t\n\u000 | |||
| ["kwd",/^-[_a-z]+/],["typ",/^[A-Z_]\w*/],["pun",/^[,.;]/]]),["erlang","erl"]); | ||||
| 
 | ||||
| // lang-go.js
 | ||||
| PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["pln",/^(?:"(?:[^"\\]|\\[\S\s])*(?:"|$)|'(?:[^'\\]|\\[\S\s])+(?:'|$)|`[^`]*(?:`|$))/,null,"\"'"]],[["com",/^(?:\/\/[^\n\r]*|\/\*[\S\s]*?\*\/)/],["pln",/^(?:[^"'/`]|\/(?![*/]))+/]]),["go"]); | ||||
| // PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["pln",/^(?:"(?:[^"\\]|\\[\S\s])*(?:"|$)|'(?:[^'\\]|\\[\S\s])+(?:'|$)|`[^`]*(?:`|$))/,null,"\"'"]],[["com",/^(?:\/\/[^\n\r]*|\/\*[\S\s]*?\*\/)/],["pln",/^(?:[^"'/`]|\/(?![*/]))+/]]),["go"]);
 | ||||
| 
 | ||||
| // lang-hs.js
 | ||||
| PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t-\r ]+/,null,"\t\n\u000b\u000c\r "],["str",/^"(?:[^\n\f\r"\\]|\\[\S\s])*(?:"|$)/,null,'"'],["str",/^'(?:[^\n\f\r'\\]|\\[^&])'?/,null,"'"],["lit",/^(?:0o[0-7]+|0x[\da-f]+|\d+(?:\.\d+)?(?:e[+-]?\d+)?)/i,null,"0123456789"]],[["com",/^(?:--+[^\n\f\r]*|{-(?:[^-]|-+[^}-])*-})/],["kwd",/^(?:case|class|data|default|deriving|do|else|if|import|in|infix|infixl|infixr|instance|let|module|newtype|of|then|type|where|_)(?=[^\d'A-Za-z]|$)/, | ||||
|  |  | |||
|  | @ -0,0 +1,77 @@ | |||
| // 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 admin | ||||
| 
 | ||||
| import ( | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/codegangsta/martini" | ||||
| 
 | ||||
| 	"github.com/gogits/gogs/models" | ||||
| 	"github.com/gogits/gogs/modules/base" | ||||
| 	"github.com/gogits/gogs/modules/middleware" | ||||
| ) | ||||
| 
 | ||||
| func Dashboard(ctx *middleware.Context) { | ||||
| 	ctx.Data["Title"] = "Admin Dashboard" | ||||
| 	ctx.Data["PageIsDashboard"] = true | ||||
| 	ctx.Data["Stats"] = models.GetStatistic() | ||||
| 	ctx.HTML(200, "admin/dashboard") | ||||
| } | ||||
| 
 | ||||
| func Users(ctx *middleware.Context) { | ||||
| 	ctx.Data["Title"] = "User Management" | ||||
| 	ctx.Data["PageIsUsers"] = true | ||||
| 
 | ||||
| 	var err error | ||||
| 	ctx.Data["Users"], err = models.GetUsers(100, 0) | ||||
| 	if err != nil { | ||||
| 		ctx.Handle(200, "admin.Users", err) | ||||
| 		return | ||||
| 	} | ||||
| 	ctx.HTML(200, "admin/users") | ||||
| } | ||||
| 
 | ||||
| func Repositories(ctx *middleware.Context) { | ||||
| 	ctx.Data["Title"] = "Repository Management" | ||||
| 	ctx.Data["PageIsRepos"] = true | ||||
| 
 | ||||
| 	var err error | ||||
| 	ctx.Data["Repos"], err = models.GetRepos(100, 0) | ||||
| 	if err != nil { | ||||
| 		ctx.Handle(200, "admin.Repositories", err) | ||||
| 		return | ||||
| 	} | ||||
| 	ctx.HTML(200, "admin/repos") | ||||
| } | ||||
| 
 | ||||
| func Config(ctx *middleware.Context) { | ||||
| 	ctx.Data["Title"] = "Server Configuration" | ||||
| 	ctx.Data["PageIsConfig"] = true | ||||
| 
 | ||||
| 	ctx.Data["AppUrl"] = base.AppUrl | ||||
| 	ctx.Data["Domain"] = base.Domain | ||||
| 	ctx.Data["RunUser"] = base.RunUser | ||||
| 	ctx.Data["RunMode"] = strings.Title(martini.Env) | ||||
| 	ctx.Data["RepoRootPath"] = base.RepoRootPath | ||||
| 
 | ||||
| 	ctx.Data["Service"] = base.Service | ||||
| 
 | ||||
| 	ctx.Data["DbCfg"] = models.DbCfg | ||||
| 
 | ||||
| 	ctx.Data["MailerEnabled"] = false | ||||
| 	if base.MailService != nil { | ||||
| 		ctx.Data["MailerEnabled"] = true | ||||
| 		ctx.Data["Mailer"] = base.MailService | ||||
| 	} | ||||
| 
 | ||||
| 	ctx.Data["CacheAdapter"] = base.CacheAdapter | ||||
| 	ctx.Data["CacheConfig"] = base.CacheConfig | ||||
| 
 | ||||
| 	ctx.Data["LogMode"] = base.LogMode | ||||
| 	ctx.Data["LogConfig"] = base.LogConfig | ||||
| 
 | ||||
| 	ctx.HTML(200, "admin/config") | ||||
| } | ||||
|  | @ -0,0 +1,109 @@ | |||
| // 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 admin | ||||
| 
 | ||||
| import ( | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/codegangsta/martini" | ||||
| 
 | ||||
| 	"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" | ||||
| ) | ||||
| 
 | ||||
| func NewUser(ctx *middleware.Context, form auth.RegisterForm) { | ||||
| 	ctx.Data["Title"] = "New Account" | ||||
| 	ctx.Data["PageIsUsers"] = true | ||||
| 
 | ||||
| 	if ctx.Req.Method == "GET" { | ||||
| 		ctx.HTML(200, "admin/users/new") | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if form.Password != form.RetypePasswd { | ||||
| 		ctx.Data["HasError"] = true | ||||
| 		ctx.Data["Err_Password"] = true | ||||
| 		ctx.Data["Err_RetypePasswd"] = true | ||||
| 		ctx.Data["ErrorMsg"] = "Password and re-type password are not same" | ||||
| 		auth.AssignForm(form, ctx.Data) | ||||
| 	} | ||||
| 
 | ||||
| 	if ctx.HasError() { | ||||
| 		ctx.HTML(200, "admin/users/new") | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	u := &models.User{ | ||||
| 		Name:     form.UserName, | ||||
| 		Email:    form.Email, | ||||
| 		Passwd:   form.Password, | ||||
| 		IsActive: true, | ||||
| 	} | ||||
| 
 | ||||
| 	var err error | ||||
| 	if u, err = models.RegisterUser(u); err != nil { | ||||
| 		switch err { | ||||
| 		case models.ErrUserAlreadyExist: | ||||
| 			ctx.RenderWithErr("Username has been already taken", "admin/users/new", &form) | ||||
| 		case models.ErrEmailAlreadyUsed: | ||||
| 			ctx.RenderWithErr("E-mail address has been already used", "admin/users/new", &form) | ||||
| 		case models.ErrUserNameIllegal: | ||||
| 			ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), "admin/users/new", &form) | ||||
| 		default: | ||||
| 			ctx.Handle(200, "admin.user.NewUser", err) | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	log.Trace("%s User created by admin(%s): %s", ctx.Req.RequestURI, | ||||
| 		ctx.User.LowerName, strings.ToLower(form.UserName)) | ||||
| 
 | ||||
| 	ctx.Redirect("/admin/users") | ||||
| } | ||||
| 
 | ||||
| func EditUser(ctx *middleware.Context, params martini.Params, form auth.AdminEditUserForm) { | ||||
| 	ctx.Data["Title"] = "Edit Account" | ||||
| 	ctx.Data["PageIsUsers"] = true | ||||
| 
 | ||||
| 	uid, err := base.StrTo(params["userid"]).Int() | ||||
| 	if err != nil { | ||||
| 		ctx.Handle(200, "admin.user.EditUser", err) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	u, err := models.GetUserById(int64(uid)) | ||||
| 	if err != nil { | ||||
| 		ctx.Handle(200, "admin.user.EditUser", err) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if ctx.Req.Method == "GET" { | ||||
| 		ctx.Data["User"] = u | ||||
| 		ctx.HTML(200, "admin/users/edit") | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	u.Email = form.Email | ||||
| 	u.Website = form.Website | ||||
| 	u.Location = form.Location | ||||
| 	u.Avatar = base.EncodeMd5(form.Avatar) | ||||
| 	u.AvatarEmail = form.Avatar | ||||
| 	u.IsActive = form.Active == "on" | ||||
| 	u.IsAdmin = form.Admin == "on" | ||||
| 	if err := models.UpdateUser(u); err != nil { | ||||
| 		ctx.Handle(200, "admin.user.EditUser", err) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	ctx.Data["IsSuccess"] = true | ||||
| 	ctx.Data["User"] = u | ||||
| 	ctx.HTML(200, "admin/users/edit") | ||||
| 
 | ||||
| 	log.Trace("%s User profile updated by admin(%s): %s", ctx.Req.RequestURI, | ||||
| 		ctx.User.LowerName, ctx.User.LowerName) | ||||
| } | ||||
|  | @ -15,10 +15,10 @@ func Home(ctx *middleware.Context) { | |||
| 		return | ||||
| 	} | ||||
| 	ctx.Data["PageIsHome"] = true | ||||
| 	ctx.HTML(200, "home", ctx.Data) | ||||
| 	ctx.HTML(200, "home") | ||||
| } | ||||
| 
 | ||||
| func Help(ctx *middleware.Context) { | ||||
| 	ctx.Data["PageIsHelp"] = true | ||||
| 	ctx.HTML(200, "help", ctx.Data) | ||||
| 	ctx.HTML(200, "help") | ||||
| } | ||||
|  |  | |||
|  | @ -21,5 +21,5 @@ func TemplatePreview(ctx *middleware.Context, params martini.Params) { | |||
| 	ctx.Data["Code"] = "2014031910370000009fff6782aadb2162b4a997acb69d4400888e0b9274657374" | ||||
| 	ctx.Data["ActiveCodeLives"] = base.Service.ActiveCodeLives / 60 | ||||
| 	ctx.Data["ResetPwdCodeLives"] = base.Service.ResetPwdCodeLives / 60 | ||||
| 	ctx.HTML(200, params["_1"], ctx.Data) | ||||
| 	ctx.HTML(200, params["_1"]) | ||||
| } | ||||
|  |  | |||
|  | @ -18,7 +18,7 @@ func Create(ctx *middleware.Context, form auth.CreateRepoForm) { | |||
| 	ctx.Data["Licenses"] = models.Licenses | ||||
| 
 | ||||
| 	if ctx.Req.Method == "GET" { | ||||
| 		ctx.HTML(200, "repo/create", ctx.Data) | ||||
| 		ctx.HTML(200, "repo/create") | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
|  | @ -31,6 +31,9 @@ func Create(ctx *middleware.Context, form auth.CreateRepoForm) { | |||
| 	} else if err == models.ErrRepoAlreadyExist { | ||||
| 		ctx.RenderWithErr("Repository name has already been used", "repo/create", &form) | ||||
| 		return | ||||
| 	} else if err == models.ErrRepoNameIllegal { | ||||
| 		ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), "repo/create", &form) | ||||
| 		return | ||||
| 	} | ||||
| 	ctx.Handle(200, "repo.Create", err) | ||||
| } | ||||
|  | @ -45,7 +48,7 @@ func SettingPost(ctx *middleware.Context) { | |||
| 	case "delete": | ||||
| 		if len(ctx.Repo.Repository.Name) == 0 || ctx.Repo.Repository.Name != ctx.Query("repository") { | ||||
| 			ctx.Data["ErrorMsg"] = "Please make sure you entered repository name is correct." | ||||
| 			ctx.HTML(200, "repo/setting", ctx.Data) | ||||
| 			ctx.HTML(200, "repo/setting") | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
|  |  | |||
|  | @ -40,7 +40,7 @@ func Branches(ctx *middleware.Context, params martini.Params) { | |||
| 	ctx.Data["Branches"] = brs | ||||
| 	ctx.Data["IsRepoToolbarBranches"] = true | ||||
| 
 | ||||
| 	ctx.HTML(200, "repo/branches", ctx.Data) | ||||
| 	ctx.HTML(200, "repo/branches") | ||||
| } | ||||
| 
 | ||||
| func Single(ctx *middleware.Context, params martini.Params) { | ||||
|  | @ -61,6 +61,8 @@ func Single(ctx *middleware.Context, params martini.Params) { | |||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	ctx.Data["IsRepoToolbarSource"] = true | ||||
| 
 | ||||
| 	// Branches.
 | ||||
| 	brs, err := models.GetBranches(params["username"], params["reponame"]) | ||||
| 	if err != nil { | ||||
|  | @ -69,7 +71,7 @@ func Single(ctx *middleware.Context, params martini.Params) { | |||
| 		return | ||||
| 	} else if len(brs) == 0 { | ||||
| 		ctx.Data["IsBareRepo"] = true | ||||
| 		ctx.HTML(200, "repo/single", ctx.Data) | ||||
| 		ctx.HTML(200, "repo/single") | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
|  | @ -86,6 +88,11 @@ func Single(ctx *middleware.Context, params martini.Params) { | |||
| 
 | ||||
| 	branchLink := "/" + ctx.Repo.Owner.LowerName + "/" + ctx.Repo.Repository.Name + "/src/" + params["branchname"] | ||||
| 
 | ||||
| 	if len(treename) != 0 && repoFile == nil { | ||||
| 		ctx.Error(404) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if repoFile != nil && repoFile.IsFile() { | ||||
| 		if repoFile.Size > 1024*1024 || repoFile.Filemode != git.FileModeBlob { | ||||
| 			ctx.Data["FileIsLarge"] = true | ||||
|  | @ -95,6 +102,11 @@ func Single(ctx *middleware.Context, params martini.Params) { | |||
| 		} else { | ||||
| 			ctx.Data["IsFile"] = true | ||||
| 			ctx.Data["FileName"] = repoFile.Name | ||||
| 			ext := path.Ext(repoFile.Name) | ||||
| 			if len(ext) > 0 { | ||||
| 				ext = ext[1:] | ||||
| 			} | ||||
| 			ctx.Data["FileExt"] = ext | ||||
| 
 | ||||
| 			readmeExist := base.IsMarkdownFile(repoFile.Name) || base.IsReadmeFile(repoFile.Name) | ||||
| 			ctx.Data["ReadmeExist"] = readmeExist | ||||
|  | @ -139,10 +151,9 @@ func Single(ctx *middleware.Context, params martini.Params) { | |||
| 				return | ||||
| 			} else { | ||||
| 				// current repo branch link
 | ||||
| 				urlPrefix := "http://" + base.Domain + branchLink | ||||
| 
 | ||||
| 				ctx.Data["FileName"] = readmeFile.Name | ||||
| 				ctx.Data["FileContent"] = string(base.RenderMarkdown(blob.Contents(), urlPrefix)) | ||||
| 				ctx.Data["FileContent"] = string(base.RenderMarkdown(blob.Contents(), branchLink)) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | @ -178,9 +189,8 @@ func Single(ctx *middleware.Context, params martini.Params) { | |||
| 
 | ||||
| 	ctx.Data["Paths"] = Paths | ||||
| 	ctx.Data["Treenames"] = treenames | ||||
| 	ctx.Data["IsRepoToolbarSource"] = true | ||||
| 	ctx.Data["BranchLink"] = branchLink | ||||
| 	ctx.HTML(200, "repo/single", ctx.Data) | ||||
| 	ctx.HTML(200, "repo/single") | ||||
| } | ||||
| 
 | ||||
| func Http(ctx *middleware.Context, params martini.Params) { | ||||
|  | @ -212,6 +222,8 @@ func Setting(ctx *middleware.Context, params martini.Params) { | |||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	ctx.Data["IsRepoToolbarSetting"] = true | ||||
| 
 | ||||
| 	// Branches.
 | ||||
| 	brs, err := models.GetBranches(params["username"], params["reponame"]) | ||||
| 	if err != nil { | ||||
|  | @ -220,7 +232,7 @@ func Setting(ctx *middleware.Context, params martini.Params) { | |||
| 		return | ||||
| 	} else if len(brs) == 0 { | ||||
| 		ctx.Data["IsBareRepo"] = true | ||||
| 		ctx.HTML(200, "repo/setting", ctx.Data) | ||||
| 		ctx.HTML(200, "repo/setting") | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
|  | @ -229,9 +241,13 @@ func Setting(ctx *middleware.Context, params martini.Params) { | |||
| 		title = t | ||||
| 	} | ||||
| 
 | ||||
| 	if len(params["branchname"]) == 0 { | ||||
| 		params["branchname"] = "master" | ||||
| 	} | ||||
| 
 | ||||
| 	ctx.Data["Branchname"] = params["branchname"] | ||||
| 	ctx.Data["Title"] = title + " - settings" | ||||
| 	ctx.Data["IsRepoToolbarSetting"] = true | ||||
| 	ctx.HTML(200, "repo/setting", ctx.Data) | ||||
| 	ctx.HTML(200, "repo/setting") | ||||
| } | ||||
| 
 | ||||
| func Commits(ctx *middleware.Context, params martini.Params) { | ||||
|  | @ -255,17 +271,17 @@ func Commits(ctx *middleware.Context, params martini.Params) { | |||
| 	ctx.Data["Reponame"] = params["reponame"] | ||||
| 	ctx.Data["CommitCount"] = commits.Len() | ||||
| 	ctx.Data["Commits"] = commits | ||||
| 	ctx.HTML(200, "repo/commits", ctx.Data) | ||||
| 	ctx.HTML(200, "repo/commits") | ||||
| } | ||||
| 
 | ||||
| func Issues(ctx *middleware.Context) { | ||||
| 	ctx.Data["IsRepoToolbarIssues"] = true | ||||
| 	ctx.HTML(200, "repo/issues", ctx.Data) | ||||
| 	ctx.HTML(200, "repo/issues") | ||||
| } | ||||
| 
 | ||||
| func Pulls(ctx *middleware.Context) { | ||||
| 	ctx.Data["IsRepoToolbarPulls"] = true | ||||
| 	ctx.HTML(200, "repo/pulls", ctx.Data) | ||||
| 	ctx.HTML(200, "repo/pulls") | ||||
| } | ||||
| 
 | ||||
| func Action(ctx *middleware.Context, params martini.Params) { | ||||
|  |  | |||
|  | @ -24,13 +24,13 @@ func Setting(ctx *middleware.Context, form auth.UpdateProfileForm) { | |||
| 	ctx.Data["Owner"] = user | ||||
| 
 | ||||
| 	if ctx.Req.Method == "GET" { | ||||
| 		ctx.HTML(200, "user/setting", ctx.Data) | ||||
| 		ctx.HTML(200, "user/setting") | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// below is for POST requests
 | ||||
| 	if hasErr, ok := ctx.Data["HasError"]; ok && hasErr.(bool) { | ||||
| 		ctx.HTML(200, "user/setting", ctx.Data) | ||||
| 		ctx.HTML(200, "user/setting") | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
|  | @ -45,7 +45,8 @@ func Setting(ctx *middleware.Context, form auth.UpdateProfileForm) { | |||
| 	} | ||||
| 
 | ||||
| 	ctx.Data["IsSuccess"] = true | ||||
| 	ctx.HTML(200, "user/setting", ctx.Data) | ||||
| 	ctx.HTML(200, "user/setting") | ||||
| 
 | ||||
| 	log.Trace("%s User setting updated: %s", ctx.Req.RequestURI, ctx.User.LowerName) | ||||
| } | ||||
| 
 | ||||
|  | @ -55,7 +56,7 @@ func SettingPassword(ctx *middleware.Context, form auth.UpdatePasswdForm) { | |||
| 	ctx.Data["IsUserPageSettingPasswd"] = true | ||||
| 
 | ||||
| 	if ctx.Req.Method == "GET" { | ||||
| 		ctx.HTML(200, "user/password", ctx.Data) | ||||
| 		ctx.HTML(200, "user/password") | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
|  | @ -82,7 +83,7 @@ func SettingPassword(ctx *middleware.Context, form auth.UpdatePasswdForm) { | |||
| 	} | ||||
| 
 | ||||
| 	ctx.Data["Owner"] = user | ||||
| 	ctx.HTML(200, "user/password", ctx.Data) | ||||
| 	ctx.HTML(200, "user/password") | ||||
| 	log.Trace("%s User password updated: %s", ctx.Req.RequestURI, ctx.User.LowerName) | ||||
| } | ||||
| 
 | ||||
|  | @ -123,7 +124,7 @@ func SettingSSHKeys(ctx *middleware.Context, form auth.AddSSHKeyForm) { | |||
| 	// Add new SSH key.
 | ||||
| 	if ctx.Req.Method == "POST" { | ||||
| 		if hasErr, ok := ctx.Data["HasError"]; ok && hasErr.(bool) { | ||||
| 			ctx.HTML(200, "user/publickey", ctx.Data) | ||||
| 			ctx.HTML(200, "user/publickey") | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
|  | @ -155,7 +156,7 @@ func SettingSSHKeys(ctx *middleware.Context, form auth.AddSSHKeyForm) { | |||
| 	ctx.Data["PageIsUserSetting"] = true | ||||
| 	ctx.Data["IsUserPageSettingSSH"] = true | ||||
| 	ctx.Data["Keys"] = keys | ||||
| 	ctx.HTML(200, "user/publickey", ctx.Data) | ||||
| 	ctx.HTML(200, "user/publickey") | ||||
| } | ||||
| 
 | ||||
| func SettingNotification(ctx *middleware.Context) { | ||||
|  | @ -163,7 +164,7 @@ func SettingNotification(ctx *middleware.Context) { | |||
| 	ctx.Data["Title"] = "Notification" | ||||
| 	ctx.Data["PageIsUserSetting"] = true | ||||
| 	ctx.Data["IsUserPageSettingNotify"] = true | ||||
| 	ctx.HTML(200, "user/notification", ctx.Data) | ||||
| 	ctx.HTML(200, "user/notification") | ||||
| } | ||||
| 
 | ||||
| func SettingSecurity(ctx *middleware.Context) { | ||||
|  | @ -171,5 +172,5 @@ func SettingSecurity(ctx *middleware.Context) { | |||
| 	ctx.Data["Title"] = "Security" | ||||
| 	ctx.Data["PageIsUserSetting"] = true | ||||
| 	ctx.Data["IsUserPageSettingSecurity"] = true | ||||
| 	ctx.HTML(200, "user/security", ctx.Data) | ||||
| 	ctx.HTML(200, "user/security") | ||||
| } | ||||
|  |  | |||
|  | @ -34,7 +34,7 @@ func Dashboard(ctx *middleware.Context) { | |||
| 		return | ||||
| 	} | ||||
| 	ctx.Data["Feeds"] = feeds | ||||
| 	ctx.HTML(200, "user/dashboard", ctx.Data) | ||||
| 	ctx.HTML(200, "user/dashboard") | ||||
| } | ||||
| 
 | ||||
| func Profile(ctx *middleware.Context, params martini.Params) { | ||||
|  | @ -70,19 +70,19 @@ func Profile(ctx *middleware.Context, params martini.Params) { | |||
| 	} | ||||
| 
 | ||||
| 	ctx.Data["PageIsUserProfile"] = true | ||||
| 	ctx.HTML(200, "user/profile", ctx.Data) | ||||
| 	ctx.HTML(200, "user/profile") | ||||
| } | ||||
| 
 | ||||
| func SignIn(ctx *middleware.Context, form auth.LogInForm) { | ||||
| 	ctx.Data["Title"] = "Log In" | ||||
| 
 | ||||
| 	if ctx.Req.Method == "GET" { | ||||
| 		ctx.HTML(200, "user/signin", ctx.Data) | ||||
| 		ctx.HTML(200, "user/signin") | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if hasErr, ok := ctx.Data["HasError"]; ok && hasErr.(bool) { | ||||
| 		ctx.HTML(200, "user/signin", ctx.Data) | ||||
| 		ctx.HTML(200, "user/signin") | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
|  | @ -112,8 +112,14 @@ func SignUp(ctx *middleware.Context, form auth.RegisterForm) { | |||
| 	ctx.Data["Title"] = "Sign Up" | ||||
| 	ctx.Data["PageIsSignUp"] = true | ||||
| 
 | ||||
| 	if base.Service.DisenableRegisteration { | ||||
| 		ctx.Data["DisenableRegisteration"] = true | ||||
| 		ctx.HTML(200, "user/signup") | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if ctx.Req.Method == "GET" { | ||||
| 		ctx.HTML(200, "user/signup", ctx.Data) | ||||
| 		ctx.HTML(200, "user/signup") | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
|  | @ -126,7 +132,7 @@ func SignUp(ctx *middleware.Context, form auth.RegisterForm) { | |||
| 	} | ||||
| 
 | ||||
| 	if ctx.HasError() { | ||||
| 		ctx.HTML(200, "user/signup", ctx.Data) | ||||
| 		ctx.HTML(200, "user/signup") | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
|  | @ -139,11 +145,13 @@ func SignUp(ctx *middleware.Context, form auth.RegisterForm) { | |||
| 
 | ||||
| 	var err error | ||||
| 	if u, err = models.RegisterUser(u); err != nil { | ||||
| 		switch err.Error() { | ||||
| 		case models.ErrUserAlreadyExist.Error(): | ||||
| 		switch err { | ||||
| 		case models.ErrUserAlreadyExist: | ||||
| 			ctx.RenderWithErr("Username has been already taken", "user/signup", &form) | ||||
| 		case models.ErrEmailAlreadyUsed.Error(): | ||||
| 		case models.ErrEmailAlreadyUsed: | ||||
| 			ctx.RenderWithErr("E-mail address has been already used", "user/signup", &form) | ||||
| 		case models.ErrUserNameIllegal: | ||||
| 			ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), "user/signup", &form) | ||||
| 		default: | ||||
| 			ctx.Handle(200, "user.SignUp", err) | ||||
| 		} | ||||
|  | @ -153,12 +161,16 @@ func SignUp(ctx *middleware.Context, form auth.RegisterForm) { | |||
| 	log.Trace("%s User created: %s", ctx.Req.RequestURI, strings.ToLower(form.UserName)) | ||||
| 
 | ||||
| 	// Send confirmation e-mail.
 | ||||
| 	if base.Service.RegisterEmailConfirm { | ||||
| 	if base.Service.RegisterEmailConfirm && u.Id > 1 { | ||||
| 		mailer.SendRegisterMail(ctx.Render, u) | ||||
| 		ctx.Data["IsSendRegisterMail"] = true | ||||
| 		ctx.Data["Email"] = u.Email | ||||
| 		ctx.Data["Hours"] = base.Service.ActiveCodeLives / 60 | ||||
| 		ctx.Render.HTML(200, "user/active", ctx.Data) | ||||
| 		ctx.HTML(200, "user/active") | ||||
| 
 | ||||
| 		if err = ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil { | ||||
| 			log.Error("Set cache(MailResendLimit) fail: %v", err) | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 	ctx.Redirect("/user/login") | ||||
|  | @ -170,7 +182,7 @@ func Delete(ctx *middleware.Context) { | |||
| 	ctx.Data["IsUserPageSettingDelete"] = true | ||||
| 
 | ||||
| 	if ctx.Req.Method == "GET" { | ||||
| 		ctx.HTML(200, "user/delete", ctx.Data) | ||||
| 		ctx.HTML(200, "user/delete") | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
|  | @ -195,7 +207,7 @@ func Delete(ctx *middleware.Context) { | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	ctx.HTML(200, "user/delete", ctx.Data) | ||||
| 	ctx.HTML(200, "user/delete") | ||||
| } | ||||
| 
 | ||||
| const ( | ||||
|  | @ -218,15 +230,15 @@ func Feeds(ctx *middleware.Context, form auth.FeedsForm) { | |||
| } | ||||
| 
 | ||||
| func Issues(ctx *middleware.Context) { | ||||
| 	ctx.HTML(200, "user/issues", ctx.Data) | ||||
| 	ctx.HTML(200, "user/issues") | ||||
| } | ||||
| 
 | ||||
| func Pulls(ctx *middleware.Context) { | ||||
| 	ctx.HTML(200, "user/pulls", ctx.Data) | ||||
| 	ctx.HTML(200, "user/pulls") | ||||
| } | ||||
| 
 | ||||
| func Stars(ctx *middleware.Context) { | ||||
| 	ctx.HTML(200, "user/stars", ctx.Data) | ||||
| 	ctx.HTML(200, "user/stars") | ||||
| } | ||||
| 
 | ||||
| func Activate(ctx *middleware.Context) { | ||||
|  | @ -239,12 +251,16 @@ func Activate(ctx *middleware.Context) { | |||
| 		} | ||||
| 		// Resend confirmation e-mail.
 | ||||
| 		if base.Service.RegisterEmailConfirm { | ||||
| 			ctx.Data["Hours"] = base.Service.ActiveCodeLives / 60 | ||||
| 			mailer.SendActiveMail(ctx.Render, ctx.User) | ||||
| 			if ctx.Cache.IsExist("MailResendLimit_" + ctx.User.LowerName) { | ||||
| 				ctx.Data["ResendLimited"] = true | ||||
| 			} else { | ||||
| 				ctx.Data["Hours"] = base.Service.ActiveCodeLives / 60 | ||||
| 				mailer.SendActiveMail(ctx.Render, ctx.User) | ||||
| 			} | ||||
| 		} else { | ||||
| 			ctx.Data["ServiceNotEnabled"] = true | ||||
| 		} | ||||
| 		ctx.Render.HTML(200, "user/active", ctx.Data) | ||||
| 		ctx.HTML(200, "user/active") | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
|  | @ -263,5 +279,5 @@ func Activate(ctx *middleware.Context) { | |||
| 	} | ||||
| 
 | ||||
| 	ctx.Data["IsActivateFailed"] = true | ||||
| 	ctx.Render.HTML(200, "user/active", ctx.Data) | ||||
| 	ctx.HTML(200, "user/active") | ||||
| } | ||||
|  |  | |||
							
								
								
									
										8
									
								
								serve.go
								
								
								
								
							
							
						
						
									
										8
									
								
								serve.go
								
								
								
								
							|  | @ -12,7 +12,9 @@ import ( | |||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/codegangsta/cli" | ||||
| 
 | ||||
| 	"github.com/gogits/gogs/models" | ||||
| 	"github.com/gogits/gogs/modules/base" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
|  | @ -43,6 +45,10 @@ func In(b string, sl map[string]int) bool { | |||
| } | ||||
| 
 | ||||
| func runServ(*cli.Context) { | ||||
| 	base.NewConfigContext() | ||||
| 	models.LoadModelsConfig() | ||||
| 	models.NewEngine() | ||||
| 
 | ||||
| 	keys := strings.Split(os.Args[2], "-") | ||||
| 	if len(keys) != 2 { | ||||
| 		fmt.Println("auth file format error") | ||||
|  | @ -144,7 +150,7 @@ func runServ(*cli.Context) { | |||
| 	} | ||||
| 
 | ||||
| 	gitcmd := exec.Command(verb, rRepo) | ||||
| 	gitcmd.Dir = models.RepoRootPath | ||||
| 	gitcmd.Dir = base.RepoRootPath | ||||
| 	gitcmd.Stdout = os.Stdout | ||||
| 	gitcmd.Stdin = os.Stdin | ||||
| 	gitcmd.Stderr = os.Stderr | ||||
|  |  | |||
|  | @ -0,0 +1,93 @@ | |||
| {{template "base/head" .}} | ||||
| {{template "base/navbar" .}} | ||||
| <div id="gogs-body" class="container" data-page="admin"> | ||||
|     {{template "admin/nav" .}} | ||||
|     <div id="gogs-admin-container" class="col-md-9"> | ||||
|         <div class="panel panel-default"> | ||||
|             <div class="panel-heading"> | ||||
|                 Server Configuration | ||||
|             </div> | ||||
| 
 | ||||
|             <div class="panel-body"> | ||||
|                 <div><b>Application Name:</b> {{AppName}}</div> | ||||
|                 <div><b>Application Version:</b> {{AppVer}}</div> | ||||
|                 <div><b>Application URL:</b> {{.AppUrl}}</div> | ||||
|                 <div><b>Domain:</b> {{.Domain}}</div> | ||||
|                 <hr/> | ||||
|                 <div><b>Run User:</b> {{.RunUser}}</div> | ||||
|                 <div><b>Run Mode:</b> {{.RunMode}}</div> | ||||
|                 <hr/> | ||||
|                 <div><b>Repository Root Path:</b> {{.RepoRootPath}}</div> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="panel panel-default"> | ||||
|             <div class="panel-heading"> | ||||
|                 Database Configuration | ||||
|             </div> | ||||
| 
 | ||||
|             <div class="panel-body"> | ||||
|                 <div><b>Type:</b> {{.DbCfg.Type}}</div> | ||||
|                 <div><b>Host:</b> {{.DbCfg.Host}}</div> | ||||
|                 <div><b>Name:</b> {{.DbCfg.Name}}</div> | ||||
|                 <div><b>User:</b> {{.DbCfg.User}}</div> | ||||
|                 <div><b>SslMode:</b> {{.DbCfg.SslMode}} (for "postgres" only)</div> | ||||
|                 <div><b>Path:</b> {{.DbCfg.Path}} (for "sqlite3" only)</div> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="panel panel-default"> | ||||
|             <div class="panel-heading"> | ||||
|                 Service Configuration | ||||
|             </div> | ||||
| 
 | ||||
|             <div class="panel-body"> | ||||
|                 <div><b>Register Email Confirmation:</b> <i class="fa fa{{if .Service.RegisterEmailConfirm}}-check{{end}}-square-o"></i></div> | ||||
|                 <div><b>Disenable Registeration:</b> <i class="fa fa{{if .Service.DisenableRegisteration}}-check{{end}}-square-o"></i></div> | ||||
|                 <div><b>Require Sign In View:</b> <i class="fa fa{{if .Service.RequireSignInView}}-check{{end}}-square-o"></i></div> | ||||
|                 <hr/> | ||||
|                 <div><b>Active Code Lives:</b> {{.Service.ActiveCodeLives}} minutes</div> | ||||
|                 <div><b>Reset Password Code Lives:</b> {{.Service.ResetPwdCodeLives}} minutes</div> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="panel panel-default"> | ||||
|             <div class="panel-heading"> | ||||
|                 Mailer Configuration | ||||
|             </div> | ||||
| 
 | ||||
|             <div class="panel-body"> | ||||
|                 <div><b>Enabled:</b> <i class="fa fa{{if .MailerEnabled}}-check{{end}}-square-o"></i></div> | ||||
|                 <div><b>Name:</b> {{.Mailer.Name}}</div> | ||||
|                 <div><b>Host:</b> {{.Mailer.Host}}</div> | ||||
|                 <div><b>User:</b> {{.Mailer.User}}</div> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="panel panel-default"> | ||||
|             <div class="panel-heading"> | ||||
|                 Cache Configuration | ||||
|             </div> | ||||
| 
 | ||||
|             <div class="panel-body"> | ||||
|                 <div><b>Cache Adapter:</b> {{.CacheAdapter}}</div> | ||||
|                 <div><b>Cache Config:</b></div> | ||||
|                 <div style="padding-top: 5px;"><pre>{{.CacheConfig}}</pre></div> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="panel panel-default"> | ||||
|             <div class="panel-heading"> | ||||
|                 Log Configuration | ||||
|             </div> | ||||
| 
 | ||||
|             <div class="panel-body"> | ||||
|                 <div><b>Log Mode:</b> {{.LogMode}}</div> | ||||
|                 <div><b>Log Config:</b></div> | ||||
|                 <div style="padding-top: 5px;"><pre>{{.LogConfig}}</pre></div> | ||||
|                  | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
| {{template "base/footer" .}} | ||||
|  | @ -0,0 +1,26 @@ | |||
| {{template "base/head" .}} | ||||
| {{template "base/navbar" .}} | ||||
| <div id="gogs-body" class="container" data-page="admin"> | ||||
|     {{template "admin/nav" .}} | ||||
|     <div id="gogs-admin-container" class="col-md-9"> | ||||
|         <div class="panel panel-default"> | ||||
|             <div class="panel-heading"> | ||||
|                 Statistic | ||||
|             </div> | ||||
| 
 | ||||
|             <div class="panel-body"> | ||||
|                 Gogs database has <b>{{.Stats.Counter.User}}</b> users, <b>{{.Stats.Counter.PublicKey}}</b> SSH keys, <b>{{.Stats.Counter.Repo}}</b> repositories, <b>{{.Stats.Counter.Watch}}</b> watches, <b>{{.Stats.Counter.Action}}</b> actions, and <b>{{.Stats.Counter.Access}}</b> accesses. | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="panel panel-default"> | ||||
|             <div class="panel-heading"> | ||||
|                 System Status | ||||
|             </div> | ||||
| 
 | ||||
|             <div class="panel-body"> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
| {{template "base/footer" .}} | ||||
|  | @ -0,0 +1,8 @@ | |||
| <div id="gogs-user-setting-nav" class="col-md-3 gogs-admin-nav"> | ||||
|     <ul class="list-group" data-init="tabs"> | ||||
|         <li class="list-group-item{{if .PageIsDashboard}} active{{end}}"><a href="/admin"><i class="fa fa-tachometer fa-lg"></i> Dashboard</a></li> | ||||
|         <li class="list-group-item{{if .PageIsUsers}} active{{end}}"><a href="/admin/users"><i class="fa fa-users fa-lg"></i> Users</a></li> | ||||
|         <li class="list-group-item{{if .PageIsRepos}} active{{end}}"><a href="/admin/repos"><i class="fa fa-book fa-lg"></i> Repositories</a></li> | ||||
|         <li class="list-group-item{{if .PageIsConfig}} active{{end}}"><a href="/admin/config"><i class="fa fa-cogs fa-lg"></i> Configuration</a></li> | ||||
|     </ul> | ||||
| </div> | ||||
|  | @ -0,0 +1,42 @@ | |||
| {{template "base/head" .}} | ||||
| {{template "base/navbar" .}} | ||||
| <div id="gogs-body" class="container" data-page="admin"> | ||||
|     {{template "admin/nav" .}} | ||||
|     <div id="gogs-admin-container" class="col-md-9"> | ||||
|         <div class="panel panel-default"> | ||||
|             <div class="panel-heading"> | ||||
|                 Repository Management | ||||
|             </div> | ||||
| 
 | ||||
|             <div class="panel-body"> | ||||
|                 <table class="table table-striped"> | ||||
|                     <thead> | ||||
|                         <tr> | ||||
|                             <th>Id</th> | ||||
|                             <th>Owner</th> | ||||
|                             <th>Name</th> | ||||
|                             <th>Private</th> | ||||
|                             <th>Watches</th> | ||||
|                             <th>Forks</th> | ||||
|                             <th>Created</th> | ||||
|                         </tr> | ||||
|                     </thead> | ||||
|                     <tbody> | ||||
|                         {{range .Repos}} | ||||
|                         <tr> | ||||
|                             <td>{{.Id}}</td> | ||||
|                             <th>{{.UserName}}</th> | ||||
|                             <td><a href="/{{.UserName}}/{{.Name}}">{{.Name}}</a></td> | ||||
|                             <td><i class="fa fa{{if .Private}}-check{{end}}-square-o"></i></td> | ||||
|                             <td>{{.NumWatches}}</td> | ||||
|                             <td>{{.NumForks}}</td> | ||||
|                             <td>{{DateFormat .Created "M d, Y"}}</td> | ||||
|                         </tr> | ||||
|                         {{end}} | ||||
|                     </tbody> | ||||
|                 </table> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
| {{template "base/footer" .}} | ||||
|  | @ -0,0 +1,45 @@ | |||
| {{template "base/head" .}} | ||||
| {{template "base/navbar" .}} | ||||
| <div id="gogs-body" class="container" data-page="admin"> | ||||
|     {{template "admin/nav" .}} | ||||
|     <div id="gogs-admin-container" class="col-md-9"> | ||||
|         <div class="panel panel-default"> | ||||
|             <div class="panel-heading"> | ||||
|                 User Management | ||||
|             </div> | ||||
| 
 | ||||
|             <div class="panel-body"> | ||||
|                 <a href="/admin/users/new" class="btn btn-primary">New Account</a> | ||||
|                 <table class="table table-striped"> | ||||
|                     <thead> | ||||
|                         <tr> | ||||
|                             <th>Id</th> | ||||
|                             <th>Name</th> | ||||
|                             <th>E-mail</th> | ||||
|                             <th>Actived</th> | ||||
|                             <th>Admin</th> | ||||
|                             <th>Repos</th> | ||||
|                             <th>Join</th> | ||||
|                             <th>Edit</th> | ||||
|                         </tr> | ||||
|                     </thead> | ||||
|                     <tbody> | ||||
|                         {{range .Users}} | ||||
|                         <tr> | ||||
|                             <td>{{.Id}}</td> | ||||
|                             <td><a href="/user/{{.Name}}">{{.Name}}</a></td> | ||||
|                             <td>{{.Email}}</td> | ||||
|                             <td><i class="fa fa{{if .IsActive}}-check{{end}}-square-o"></i></td> | ||||
|                             <td><i class="fa fa{{if .IsAdmin}}-check{{end}}-square-o"></i></td> | ||||
|                             <td>{{.NumRepos}}</td> | ||||
|                             <td>{{DateFormat .Created "M d, Y"}}</td> | ||||
|                             <td><a href="/admin/users/{{.Id}}"><i class="fa fa-pencil-square-o"></i></a></td> | ||||
|                         </tr> | ||||
|                         {{end}} | ||||
|                     </tbody> | ||||
|                 </table> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
| {{template "base/footer" .}} | ||||
|  | @ -0,0 +1,83 @@ | |||
| {{template "base/head" .}} | ||||
| {{template "base/navbar" .}} | ||||
| <div id="gogs-body" class="container" data-page="admin"> | ||||
|     {{template "admin/nav" .}} | ||||
|     <div id="gogs-admin-container" class="col-md-9"> | ||||
|         <div class="panel panel-default"> | ||||
|             <div class="panel-heading"> | ||||
|                 Edit Account | ||||
|             </div> | ||||
| 
 | ||||
|             <div class="panel-body"> | ||||
|             	<br/> | ||||
| 				<form action="/admin/users/{{.User.Id}}" method="post" class="form-horizontal"> | ||||
| 				    {{if .IsSuccess}}<p class="alert alert-success">Account profile has been successfully updated.</p>{{else if .HasError}}<p class="alert alert-danger form-error">{{.ErrorMsg}}</p>{{end}} | ||||
|                 	<input type="hidden" value="{{.User.Id}}" name="userId"/> | ||||
| 					<div class="form-group"> | ||||
| 						<label class="col-md-3 control-label">Username: </label> | ||||
| 						<label class="control-label">{{.User.Name}}</label> | ||||
| 					</div> | ||||
| 
 | ||||
| 					<div class="form-group {{if .Err_Email}}has-error has-feedback{{end}}"> | ||||
| 						<label class="col-md-3 control-label">Email<strong class="text-danger">*</strong></label> | ||||
| 						<div class="col-md-7"> | ||||
| 							<input name="email" class="form-control" placeholder="Type account's e-mail address" value="{{.User.Email}}" required="required"> | ||||
| 						</div> | ||||
| 					</div> | ||||
| 
 | ||||
| 	                <div class="form-group"> | ||||
| 	                    <label class="col-md-3 control-label">Website</label> | ||||
| 	                    <div class="col-md-7"> | ||||
| 	                        <input name="website" class="form-control" placeholder="Type account's website URL" value="{{.User.Website}}"> | ||||
| 	                    </div> | ||||
| 	                </div> | ||||
| 
 | ||||
| 	                <div class="form-group"> | ||||
| 	                    <label class="col-md-3 control-label">Location</label> | ||||
| 	                    <div class="col-md-7"> | ||||
| 	                        <input name="location" class="form-control" placeholder="Type account's current location" value="{{.User.Location}}"> | ||||
| 	                    </div> | ||||
| 	                </div> | ||||
| 
 | ||||
| 	                <div class="form-group {{if .Err_Avatar}}has-error has-feedback{{end}}"> | ||||
| 	                    <label class="col-md-3 control-label">Gravatar Email<strong class="text-danger">*</strong></label> | ||||
| 	                    <div class="col-md-7"> | ||||
| 	                        <input name="avatar" class="form-control" placeholder="Type account's Gravatar e-mail address" required="required" value="{{.User.AvatarEmail}}"> | ||||
| 	                    </div> | ||||
| 	                </div> | ||||
| 
 | ||||
| 	                <div class="form-group"> | ||||
| 			            <div class="col-md-7 col-md-offset-3"> | ||||
| 			                <div class="checkbox"> | ||||
| 			                    <label> | ||||
| 			                        <input type="checkbox" name="active" {{if .User.IsActive}}checked{{end}}> | ||||
| 			                        <strong>This account has activated</strong> | ||||
| 			                    </label> | ||||
| 			                </div> | ||||
| 			            </div> | ||||
| 	                </div> | ||||
| 
 | ||||
| 	                <div class="form-group"> | ||||
| 			            <div class="col-md-7 col-md-offset-3"> | ||||
| 			                <div class="checkbox"> | ||||
| 			                    <label> | ||||
| 			                        <input type="checkbox" name="admin" {{if .User.IsAdmin}}checked{{end}}> | ||||
| 			                        <strong>This account has administor permisson</strong> | ||||
| 			                    </label> | ||||
| 			                </div> | ||||
| 			            </div> | ||||
| 	                </div> | ||||
| 					<hr/> | ||||
| 					<div class="form-group"> | ||||
| 					    <div class="col-md-offset-3 col-md-6"> | ||||
| 					    	<button type="submit" class="btn btn-lg btn-primary btn-block">Update account profile</button> | ||||
| 					    	<!-- <a type="button" href="/admin/users/{{.User.Id}}/delete" class="btn btn-lg btn-danger btn-block">Delete this account</a> --> | ||||
| 					    </div> | ||||
| 					</div> | ||||
| 				</form> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
| 	</div> | ||||
| </div> | ||||
| {{template "base/footer" .}} | ||||
|  | @ -0,0 +1,54 @@ | |||
| {{template "base/head" .}} | ||||
| {{template "base/navbar" .}} | ||||
| <div id="gogs-body" class="container" data-page="admin"> | ||||
|     {{template "admin/nav" .}} | ||||
|     <div id="gogs-admin-container" class="col-md-9"> | ||||
|         <div class="panel panel-default"> | ||||
|             <div class="panel-heading"> | ||||
|                 New Account | ||||
|             </div> | ||||
| 
 | ||||
|             <div class="panel-body"> | ||||
|             	<br/> | ||||
| 				<form action="/admin/users/new" method="post" class="form-horizontal"> | ||||
| 				    <div class="alert alert-danger form-error{{if .HasError}}{{else}} hidden{{end}}">{{.ErrorMsg}}</div> | ||||
| 					<div class="form-group {{if .Err_UserName}}has-error has-feedback{{end}}"> | ||||
| 						<label class="col-md-3 control-label">Username: </label> | ||||
| 						<div class="col-md-7"> | ||||
| 							<input name="username" class="form-control" placeholder="Type account's username" value="{{.username}}" required="required"> | ||||
| 						</div> | ||||
| 					</div> | ||||
| 
 | ||||
| 					<div class="form-group {{if .Err_Email}}has-error has-feedback{{end}}"> | ||||
| 						<label class="col-md-3 control-label">Email: </label> | ||||
| 						<div class="col-md-7"> | ||||
| 							<input name="email" class="form-control" placeholder="Type account's e-mail address" value="{{.email}}" required="required" title="Email is not valid"> | ||||
| 						</div> | ||||
| 					</div> | ||||
| 
 | ||||
| 					<div class="form-group {{if .Err_Password}}has-error has-feedback{{end}}"> | ||||
| 						<label class="col-md-3 control-label">Password: </label> | ||||
| 						<div class="col-md-7"> | ||||
| 							<input name="passwd" type="password" class="form-control" placeholder="Type account's password" required="required" title="Password must contain at least 6 characters"> | ||||
| 						</div> | ||||
| 					</div> | ||||
| 
 | ||||
| 					<div class="form-group {{if .Err_RetypePasswd}}has-error has-feedback{{end}}"> | ||||
| 						<label class="col-md-3 control-label">Re-type: </label> | ||||
| 						<div class="col-md-7"> | ||||
| 							<input name="retypepasswd" type="password" class="form-control" placeholder="Re-type account's password" required="required" title="Re-type Password must be same to Password"> | ||||
| 						</div> | ||||
| 					</div> | ||||
| 					<hr/> | ||||
| 					<div class="form-group"> | ||||
| 					    <div class="col-md-offset-3 col-md-7"> | ||||
| 					    	<button type="submit" class="btn btn-lg btn-primary">Create new account</button> | ||||
| 					    </div> | ||||
| 					</div> | ||||
| 				</form> | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
| 	</div> | ||||
| </div> | ||||
| {{template "base/footer" .}} | ||||
|  | @ -2,12 +2,19 @@ | |||
| </div> | ||||
| <footer id="footer"> | ||||
|     <div class="container footer-wrap"> | ||||
|         <p>© 2014 Gogs · ver {{AppVer}} · | ||||
|             All: {{LoadTimes .PageStartTime}} · | ||||
|             Tmpl: {{call .TmplLoadTimes}} · | ||||
|             <i class="fa fa-github"></i><a target="_blank" href="https://github.com/gogits/gogs">GitHub</a> · | ||||
|         </p> | ||||
|         <p class="desc"></p> | ||||
|     	<div class="row"> | ||||
| 	    	<div class="col-md-6"> | ||||
| 		        <p>© 2014 GoGits · Version: {{AppVer}} · | ||||
| 		            Page: <b>{{LoadTimes .PageStartTime}}</b> · | ||||
| 		            Template: <b>{{call .TmplLoadTimes}}</b> | ||||
| 		        </p> | ||||
| 	        </div> | ||||
| 
 | ||||
| 	    	<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> | ||||
| 	        </div> | ||||
| 	        <p class="desc"></p> | ||||
|     	</div> | ||||
|     </div> | ||||
| </footer> | ||||
| </body> | ||||
|  |  | |||
|  | @ -10,7 +10,9 @@ | |||
|             </a> | ||||
|             <a class="navbar-right gogs-nav-item{{if .PageIsNewRepo}} active{{end}}" href="/repo/create" data-toggle="tooltip" data-placement="bottom" title="New Repository"><i class="fa fa-plus fa-lg"></i></a> | ||||
|             <a class="navbar-right gogs-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> | ||||
|             {{else}}<a id="gogs-nav-signin" class="gogs-nav-item navbar-right navbar-btn btn btn-danger" href="/user/login/">Sign in</a>{{end}} | ||||
|             {{if .IsAdmin}}<a class="navbar-right gogs-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}} | ||||
|             {{else}}<a id="gogs-nav-signin" class="gogs-nav-item navbar-right navbar-btn btn btn-danger" href="/user/login/">Sign In</a> | ||||
|             <a id="gogs-nav-signup" class="gogs-nav-item navbar-right navbar-btn btn btn-info" href="/user/sign_up/">Sign Up</a>{{end}} | ||||
|         </nav> | ||||
|     </div> | ||||
| </div> | ||||
|  |  | |||
|  | @ -5,40 +5,62 @@ | |||
|                 <h3 class="name"><i class="fa fa-book fa-lg"></i><a href="{{.Owner.HomeLink}}">{{.Owner.Name}}</a> / {{.Repository.Name}}</h3> | ||||
|                 <p class="desc">{{.Repository.Description}}{{if .Repository.Website}}<a href="{{.Repository.Website}}">{{.Repository.Website}}</a>{{end}}</p> | ||||
|             </div> | ||||
|             {{if not .IsBareRepo}} | ||||
|             <div class="col-md-6 actions text-right"> | ||||
|                 <div class="btn-group" id="gogs-repo-clone"> | ||||
|             <div class="col-md-6 actions text-right clone-group-btn"> | ||||
|                 {{if not .IsBareRepo}} | ||||
|                 <!--<div class="btn-group" id="gogs-repo-clone"> | ||||
|                     <button type="button" class="btn btn-default"><i class="fa fa-download fa-lg fa-m"></i></button> | ||||
|                     <button type="button" class="btn btn-default dropdown-toggle" data-container="body" data-toggle="popover" data-placement="bottom" data-content="<label>SSH:</label><div class='input-group'><input type='text' class='form-control' value='{{.CloneLink.SSH}}'></div>" data-html="1"> | ||||
|                         <span class="caret"></span> | ||||
|                     </button> | ||||
|                 </div> | ||||
|                 <div class="btn-group" id="gogs-repo-watching"> | ||||
|                     <button type="button" class="btn btn-default"><i class="fa fa-eye fa-lg fa-m"></i></button> | ||||
|                 </div>--> | ||||
|                 <div class="btn-group" id="gogs-repo-clone"> | ||||
|                     <button type="button" class="btn btn-default"><i class="fa fa-download fa-lg fa-m"></i></button> | ||||
|                     <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"> | ||||
|                         <span class="caret"></span> | ||||
|                         <span class="sr-only">Toggle Dropdown</span> | ||||
|                     </button> | ||||
|                     <div class="dropdown-menu" role="menu"> | ||||
|                         <div class="dropdown-item text-left" data-val="not-watching"> | ||||
|                             <h4 role="presentation" class="dropdown-header">Not Watching</h4> | ||||
|                     <div class="dropdown-menu clone-group-btn dropdown-menu-right"> | ||||
|                         <div class="input-group"> | ||||
|                             <span class="input-group-btn"> | ||||
|                                 <button class="btn btn-default" data-link="{{.CloneLink.SSH}}" type="button">SSH</button> | ||||
|                                 <button class="btn btn-default" data-link="{{.CloneLink.HTTPS}}" type="button">HTTPS</button> | ||||
|                             </span> | ||||
|                             <input type="text" class="form-control clone-group-url" value="" readonly/> | ||||
|                             <span class="input-group-btn"> | ||||
|                                 <button class="btn btn-default" type="button"><i class="fa fa-copy" data-toggle="tooltip" title="copy to clipboard" data-placement="top"></i></button> | ||||
|                             </span> | ||||
|                         </div> | ||||
|                         <p class="help-block text-center">Need help cloning? Visit <a href="#">Help</a>!</p> | ||||
|                     </div> | ||||
|                 </div> | ||||
|                 <div class="btn-group {{if .IsRepositoryWatching}}watching{{else}}no-watching{{end}}" id="gogs-repo-watching" data-watch="/{{.SignedUser.Name}}/{{.Repository.Name}}/action/watch" data-unwatch="/{{.SignedUser.Name}}/{{.Repository.Name}}/action/unwatch"> | ||||
|                     {{if .IsRepositoryWatching}} | ||||
|                     <button type="button" class="btn btn-default"><i class="fa fa-eye fa-lg fa-m"></i></button> | ||||
|                     {{else}} | ||||
|                     <button type="button" class="btn btn-default"><i class="fa fa-eye-slash fa-lg fa-m"></i></button> | ||||
|                     {{end}} | ||||
|                     <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"> | ||||
|                         <span class="caret"></span> | ||||
|                     </button> | ||||
|                     <div class="dropdown-menu"> | ||||
|                         <div class="dropdown-item text-left to-unwatch"> | ||||
|                             <h4 role="presentation" class="dropdown-header {{if not .IsRepositoryWatching}}text-primary{{end}}">Not Watching</h4> | ||||
|                             <p class="description">You only receive notifications for conversations in which you participate or are @mentioned.</p> | ||||
|                             <p class="divider"></p> | ||||
|                         </div> | ||||
|                         <div class="dropdown-item text-left" data-val="watching"> | ||||
|                             <h4 role="presentation" class="dropdown-header">Watching</h4> | ||||
|                         <div class="dropdown-item text-left to-watch"> | ||||
|                             <h4 role="presentation" class="dropdown-header {{if .IsRepositoryWatching}}text-primary{{end}}">Watching</h4> | ||||
|                             <p class="description">You receive notifications for all conversations in this repository.</p> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|                 <div class="btn-group"> | ||||
|                     <button type="button" class="btn btn-default"><i class="fa fa-star"></i>Star  {{.Repository.NumStars}}</button> | ||||
|                     <button type="button" class="btn btn-default" data-toggle="tooltip" data-placement="top" title="Star"><i class="fa fa-star"></i> {{.Repository.NumStars}}</button> | ||||
|                 </div> | ||||
|                 {{end}} | ||||
|                 <div class="btn-group"> | ||||
|                     <button type="button" class="btn btn-default"><i class="fa fa-code-fork"></i>Fork  {{.Repository.NumForks}}</button> | ||||
|                     <a type="button" {{if not .IsRepositoryOwner}}href="/{{.Username}}/{{.Reponame}}/fork"{{end}} class="btn btn-default" data-toggle="tooltip" data-placement="top" title="Fork"><i class="fa fa-code-fork fa-lg"></i> {{.Repository.NumForks}}</a> | ||||
|                 </div> | ||||
|             </div> | ||||
|             {{end}} | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
|  | @ -10,20 +10,24 @@ | |||
|             <li class="list-group-item"><a href="#">Notifications</a></li>--> | ||||
|         </ul> | ||||
|     </div> | ||||
| 
 | ||||
|     <div id="gogs-repo-setting-container" class="col-md-9"> | ||||
|         {{if .ErrorMsg}}<p class="alert alert-danger">{{.ErrorMsg}}</p>{{end}} | ||||
|         <div class="panel panel-default"> | ||||
|             <div class="panel-heading"> | ||||
|                 Repository Options | ||||
|             </div> | ||||
| 
 | ||||
|             <div class="panel-body"> | ||||
|                  | ||||
|             </div> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="panel panel-warning"> | ||||
|             <div class="panel-heading"> | ||||
|                 Danger Zone | ||||
|             </div> | ||||
|              | ||||
|             <div class="panel-body"> | ||||
|                 <button type="button" class="btn btn-default pull-right" href="#delete-repository-modal" data-toggle="modal"> | ||||
|                     Delete this repository | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ | |||
| <div id="gogs-body" class="container"> | ||||
|     <div id="gogs-source"> | ||||
|         {{if .IsBareRepo}} | ||||
|         Need to fill in some guide. | ||||
|         {{template "repo/single_bare" .}} | ||||
|         {{else}} | ||||
|         <div class="source-toolbar"> | ||||
|             {{ $n := len .Treenames}} | ||||
|  | @ -15,7 +15,7 @@ | |||
|                     <b class="caret"></b></a> | ||||
|                 <ul class="dropdown-menu"> | ||||
|                     {{range .Branches}} | ||||
|                     <li><a {{if eq . $.Branchname}}class="current" {{end}}href="{{$.BranchLink}}">{{.}}</a></li> | ||||
|                     <li><a {{if eq . $.Branchname}}class="current" {{end}}href="/{{$.Username}}/{{$.Reponame}}/src/{{.}}">{{.}}</a></li> | ||||
|                     {{end}} | ||||
|                 </ul> | ||||
|             </div> | ||||
|  |  | |||
|  | @ -0,0 +1,31 @@ | |||
| <div class="panel panel-default guide-box clone-group-btn"> | ||||
|     <div class="panel-heading guide-head"> | ||||
|         <h4>Quick Guide</h4> | ||||
|     </div> | ||||
|     <div class="panel-body guide-content text-center"> | ||||
|         <h3>Clone this repository</h3> | ||||
|         <div class="input-group col-md-8 col-md-offset-2 guide-buttons"> | ||||
|             <span class="input-group-btn"> | ||||
|                 <button class="btn btn-default" data-link="{{.CloneLink.SSH}}" type="button">SSH</button> | ||||
|                 <button class="btn btn-default" data-link="{{.CloneLink.HTTPS}}" type="button">HTTPS</button> | ||||
|             </span> | ||||
|             <input type="text" class="form-control clone-group-url" id="guide-clone-url" value="" readonly/> | ||||
|             <span class="input-group-btn"> | ||||
|                 <button class="btn btn-default" type="button"><i class="fa fa-copy" data-toggle="tooltip" title="copy to clipboard" data-placement="top"></i></button> | ||||
|             </span> | ||||
|         </div> | ||||
|         <p>We recommend every repository include a <strong>README</strong>, <strong>LICENSE</strong>, and <strong>.gitignore</strong>.</p> | ||||
|         <hr/> | ||||
|         <h3>Create a new repository on the command line</h3> | ||||
|             <pre class="text-left"><code>touch README.md | ||||
| git init | ||||
| git add README.md | ||||
| git commit -m "first commit" | ||||
| git remote add origin <span class="clone-url"></span> | ||||
| git push -u origin master</code></pre> | ||||
|         <hr/> | ||||
|         <h3>Push an existing repository from the command line</h3> | ||||
|         <pre class="text-left"><code>git remote add origin <span class="clone-url"></span> | ||||
| git push -u origin master</code></pre> | ||||
|     </div> | ||||
| </div> | ||||
|  | @ -1,6 +1,10 @@ | |||
| <div class="panel panel-default file-content"> | ||||
|     <div class="panel-heading file-head"> | ||||
|         <i class="icon fa fa-book"></i> {{.FileName}} | ||||
|         {{if .ReadmeExist}} | ||||
|             <i class="icon fa fa-book"></i> | ||||
|         {{else}} | ||||
|             <i class="icon fa fa-file-text-o"></i> | ||||
|         {{end}}{{.FileName}} | ||||
|     </div> | ||||
|     {{if .FileIsLarge}} | ||||
|         <div class="panel-footer"> | ||||
|  | @ -12,8 +16,15 @@ | |||
|                 {{.FileContent|str2html}} | ||||
|             </div> | ||||
|         {{else}} | ||||
|             <div class="panel-body file-body markdown"> | ||||
|                 <pre><code>{{.FileContent}}</code></pre> | ||||
|             <div class="panel-body file-body file-code"> | ||||
|                 <table> | ||||
|                     <tbody> | ||||
|                         <tr> | ||||
|                             <td class="lines-num"></td> | ||||
|                             <td class="lines-code markdown"><pre class="linenums lang-{{.FileExt}}"><code>{{.FileContent}}</code></pre></td> | ||||
|                         </tr> | ||||
|                     </tbody> | ||||
|                 </table> | ||||
|             </div> | ||||
|         {{end}} | ||||
|     {{end}} | ||||
|  |  | |||
|  | @ -15,9 +15,8 @@ | |||
|                             <li><a href="/{{.RepositoryLink}}/release">Release</a></li> | ||||
|                             <li><a href="//{{.RepositoryLink}}/wiki">Wiki</a></li> | ||||
|                         </ul> | ||||
|                     </li> | ||||
|                     </li>{{end}} | ||||
|                 </ul> | ||||
|                 {{end}} | ||||
|                 <ul class="nav navbar-nav navbar-right"> | ||||
|                     {{if not .IsBareRepo}} | ||||
|                     <li class="dropdown"> | ||||
|  |  | |||
|  | @ -6,6 +6,8 @@ | |||
|         {{if .IsActivatePage}} | ||||
|             {{if .ServiceNotEnabled}} | ||||
|             <p>Sorry, Register Mail Confirmation has been disabled.</p> | ||||
|             {{else if .ResendLimited}} | ||||
|             <p>Sorry, you are sending activation e-mail too frequently, please wait 3 minutes.</p> | ||||
|             {{else}} | ||||
|             <p>New confirmation e-mail has been sent to <b>{{.SignedUser.Email}}</b>, please check your inbox within {{.Hours}} hours to complete your registeration.</p> | ||||
|             <hr/> | ||||
|  |  | |||
|  | @ -33,8 +33,9 @@ | |||
|             </div> | ||||
|             <div class="panel-body"> | ||||
|                 <ul class="list-group">{{range .MyRepos}} | ||||
|                     <li class="list-group-item"><i class="fa fa-book"></i><a href="/{{$.SignedUserName}}/{{.Name}}">{{.Name}}</a> | ||||
|                     <li class="list-group-item"><a href="/{{$.SignedUserName}}/{{.Name}}"> | ||||
|                         <span class="stars pull-right"><i class="fa fa-star"></i>{{.NumStars}}</span> | ||||
|                         <i class="fa fa-book"></i>{{.Name}}</a> | ||||
|                     </li>{{end}} | ||||
|                 </ul> | ||||
|             </div> | ||||
|  |  | |||
|  | @ -5,8 +5,8 @@ | |||
|     <div id="gogs-user-setting-container" class="col-md-9"> | ||||
|         <div id="gogs-setting-pwd"> | ||||
|             <h4>Account Profile</h4> | ||||
|             <form class="form-horizontal" id="gogs-password-form" method="post" action="/user/setting">{{if .IsSuccess}} | ||||
|                 <p class="alert alert-success">Your profile has been successfully updated.</p>{{else if .HasError}}<p class="alert alert-danger form-error">{{.ErrorMsg}}</p>{{end}} | ||||
|             <form class="form-horizontal" id="gogs-password-form" method="post" action="/user/setting"> | ||||
|                 {{if .IsSuccess}}<p class="alert alert-success">Your profile has been successfully updated.</p>{{else if .HasError}}<p class="alert alert-danger form-error">{{.ErrorMsg}}</p>{{end}} | ||||
|                 <p>Your Email will be public and used for Account related notifications and any web based operations made via the web.</p> | ||||
|                 <div class="form-group"> | ||||
|                     <label class="col-md-2 control-label">Email</label> | ||||
|  | @ -29,7 +29,7 @@ | |||
|                     </div> | ||||
|                 </div> | ||||
| 
 | ||||
|                 <div class="form-group"> | ||||
|                 <div class="form-group {{if .Err_Avatar}}has-error has-feedback{{end}}"> | ||||
|                     <label class="col-md-2 control-label">Gravatar Email<strong class="text-danger">*</strong></label> | ||||
|                     <div class="col-md-8"> | ||||
|                         <input type="text" name="avatar" class="form-control" placeholder="Type your Gravatar e-mail address" required="required" value="{{.Owner.AvatarEmail}}"> | ||||
|  |  | |||
|  | @ -32,7 +32,7 @@ | |||
|         </div> | ||||
| 
 | ||||
|         <div class="form-group text-center" id="gogs-social-login"> | ||||
|             <a class="btn btn-default btn-lg">Social Login</a> | ||||
|             <a class="btn btn-danger btn-lg">Register new account</a> | ||||
|         </div> | ||||
|     </form> | ||||
| </div> | ||||
|  |  | |||
|  | @ -2,6 +2,9 @@ | |||
| {{template "base/navbar" .}} | ||||
| <div class="container" id="gogs-body" data-page="user-signup"> | ||||
| 	<form action="/user/sign_up" method="post" class="form-horizontal gogs-card" id="gogs-login-card"> | ||||
| 		{{if .DisenableRegisteration}} | ||||
| 		Sorry, registeration has been disenabled, you can only get account from administrator. | ||||
| 		{{else}} | ||||
|         <h3>Sign Up</h3> | ||||
| 	    <div class="alert alert-danger form-error{{if .HasError}}{{else}} hidden{{end}}">{{.ErrorMsg}}</div> | ||||
| 		<div class="form-group {{if .Err_UserName}}has-error has-feedback{{end}}"> | ||||
|  | @ -43,6 +46,7 @@ | |||
|                 <a href="/user/login">Already have an account? Sign in now!</a> | ||||
|             </div> | ||||
| 	    </div> | ||||
| 	    {{end}} | ||||
| 	</form> | ||||
| </div> | ||||
| {{template "base/footer" .}} | ||||
							
								
								
									
										25
									
								
								web.go
								
								
								
								
							
							
						
						
									
										25
									
								
								web.go
								
								
								
								
							|  | @ -16,11 +16,14 @@ import ( | |||
| 
 | ||||
| 	"github.com/gogits/binding" | ||||
| 
 | ||||
| 	"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/mailer" | ||||
| 	"github.com/gogits/gogs/modules/middleware" | ||||
| 	"github.com/gogits/gogs/routers" | ||||
| 	"github.com/gogits/gogs/routers/admin" | ||||
| 	"github.com/gogits/gogs/routers/dev" | ||||
| 	"github.com/gogits/gogs/routers/repo" | ||||
| 	"github.com/gogits/gogs/routers/user" | ||||
|  | @ -35,6 +38,16 @@ gogs web`, | |||
| 	Flags:  []cli.Flag{}, | ||||
| } | ||||
| 
 | ||||
| // globalInit is for global configuration reload-able.
 | ||||
| func globalInit() { | ||||
| 	base.NewConfigContext() | ||||
| 	mailer.NewMailerContext() | ||||
| 	models.LoadModelsConfig() | ||||
| 	models.LoadRepoConfig() | ||||
| 	models.NewRepoContext() | ||||
| 	models.NewEngine() | ||||
| } | ||||
| 
 | ||||
| // Check run mode(Default of martini is Dev).
 | ||||
| func checkRunMode() { | ||||
| 	switch base.Cfg.MustValue("", "RUN_MODE") { | ||||
|  | @ -58,6 +71,7 @@ func newMartini() *martini.ClassicMartini { | |||
| } | ||||
| 
 | ||||
| func runWeb(*cli.Context) { | ||||
| 	globalInit() | ||||
| 	base.NewServices() | ||||
| 	checkRunMode() | ||||
| 	log.Info("%s %s", base.AppName, base.AppVer) | ||||
|  | @ -73,7 +87,8 @@ func runWeb(*cli.Context) { | |||
| 
 | ||||
| 	m.Use(middleware.InitContext()) | ||||
| 
 | ||||
| 	reqSignIn, ignSignIn := middleware.SignInRequire(true), middleware.SignInRequire(false) | ||||
| 	reqSignIn := middleware.SignInRequire(true) | ||||
| 	ignSignIn := middleware.SignInRequire(base.Service.RequireSignInView) | ||||
| 	reqSignOut := middleware.SignOutRequire() | ||||
| 	// Routers.
 | ||||
| 	m.Get("/", ignSignIn, routers.Home) | ||||
|  | @ -99,6 +114,14 @@ func runWeb(*cli.Context) { | |||
| 
 | ||||
| 	m.Get("/help", routers.Help) | ||||
| 
 | ||||
| 	adminReq := middleware.AdminRequire() | ||||
| 	m.Get("/admin", reqSignIn, adminReq, admin.Dashboard) | ||||
| 	m.Get("/admin/users", reqSignIn, adminReq, admin.Users) | ||||
| 	m.Any("/admin/users/new", reqSignIn, adminReq, binding.BindIgnErr(auth.RegisterForm{}), admin.NewUser) | ||||
| 	m.Any("/admin/users/:userid", reqSignIn, adminReq, binding.BindIgnErr(auth.AdminEditUserForm{}), admin.EditUser) | ||||
| 	m.Get("/admin/repos", reqSignIn, adminReq, admin.Repositories) | ||||
| 	m.Get("/admin/config", reqSignIn, adminReq, admin.Config) | ||||
| 
 | ||||
| 	m.Post("/:username/:reponame/settings", reqSignIn, middleware.RepoAssignment(true), repo.SettingPost) | ||||
| 	m.Get("/:username/:reponame/settings", reqSignIn, middleware.RepoAssignment(true), repo.Setting) | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue