| @@ -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.4 Alpha | |||
| ##### Current version: 0.1.5 Alpha | |||
| ## Purpose | |||
| @@ -61,8 +61,14 @@ USER = | |||
| PASSWD = | |||
| [cache] | |||
| ; Either "memory", "redis", or "memcache", default is "memory" | |||
| ADAPTER = memory | |||
| CONFIG = | |||
| ; 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" | |||
| @@ -20,7 +20,7 @@ import ( | |||
| // Test that go1.2 tag above is included in builds. main.go refers to this definition. | |||
| const go12tag = true | |||
| const APP_VER = "0.1.4.0321" | |||
| const APP_VER = "0.1.5.0321" | |||
| func init() { | |||
| base.AppVer = APP_VER | |||
| @@ -35,7 +35,6 @@ func LoadModelsConfig() { | |||
| } | |||
| func setEngine() { | |||
| var err error | |||
| switch DbCfg.Type { | |||
| case "mysql": | |||
| @@ -133,6 +133,30 @@ func newLogService() { | |||
| log.Info("Log Mode: %s(%s)", strings.Title(mode), 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() { | |||
| // Check mailer setting. | |||
| if Cfg.MustBool("mailer", "ENABLED") { | |||
| @@ -188,16 +212,6 @@ func NewConfigContext() { | |||
| SecretKey = Cfg.MustValue("security", "SECRET_KEY") | |||
| RunUser = Cfg.MustValue("", "RUN_USER") | |||
| CacheAdapter = Cfg.MustValue("cache", "ADAPTER") | |||
| CacheConfig = Cfg.MustValue("cache", "CONFIG") | |||
| 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) | |||
| } | |||
| // Determine and create root git reposiroty path. | |||
| RepoRootPath = Cfg.MustValue("repository", "ROOT") | |||
| if err = os.MkdirAll(RepoRootPath, os.ModePerm); err != nil { | |||
| @@ -209,6 +223,7 @@ func NewConfigContext() { | |||
| func NewServices() { | |||
| newService() | |||
| newLogService() | |||
| newCacheService() | |||
| newMailService() | |||
| newRegisterMailService() | |||
| } | |||
| @@ -575,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; | |||
| @@ -63,6 +63,12 @@ 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 () { | |||
| @@ -136,6 +142,7 @@ function initCore() { | |||
| Gogits.initPopovers(); | |||
| Gogits.initTabs(); | |||
| Gogits.initModals(); | |||
| Gogits.initDropDown(); | |||
| Gogits.renderMarkdown(); | |||
| } | |||
| @@ -181,18 +188,18 @@ function initUserSetting() { | |||
| } | |||
| function initRepository() { | |||
| // guide box script | |||
| // clone group button script | |||
| (function () { | |||
| var $guide = $('.guide-box'); | |||
| if ($guide.length) { | |||
| var $url = $('#guide-clone-url'); | |||
| $guide.find('button[data-link]').on("click",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')) { | |||
| $guide.find('.btn-primary').removeClass('btn-primary').addClass("btn-default"); | |||
| $clone.find('.btn-primary').removeClass('btn-primary').addClass("btn-default"); | |||
| $(this).addClass('btn-primary').removeClass('btn-default'); | |||
| $url.val($this.data("link")); | |||
| $guide.find('span.clone-url').text($this.data('link')); | |||
| $clone.find('span.clone-url').text($this.data('link')); | |||
| } | |||
| }).eq(0).trigger("click"); | |||
| // todo copy to clipboard | |||
| @@ -67,5 +67,8 @@ func Config(ctx *middleware.Context) { | |||
| ctx.Data["Mailer"] = base.MailService | |||
| } | |||
| ctx.Data["CacheAdapter"] = base.CacheAdapter | |||
| ctx.Data["CacheConfig"] = base.CacheConfig | |||
| ctx.HTML(200, "admin/config") | |||
| } | |||
| @@ -167,6 +167,10 @@ func SignUp(ctx *middleware.Context, form auth.RegisterForm) { | |||
| ctx.Data["Email"] = u.Email | |||
| ctx.Data["Hours"] = base.Service.ActiveCodeLives / 60 | |||
| 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") | |||
| @@ -247,8 +251,12 @@ 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 | |||
| } | |||
| @@ -63,6 +63,17 @@ | |||
| <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> <code>{{.CacheConfig}}</code></div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| {{template "base/footer" .}} | |||
| @@ -5,13 +5,32 @@ | |||
| <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> | |||
| <div class="col-md-6 actions text-right"> | |||
| <div class="col-md-6 actions text-right clone-group-btn"> | |||
| {{if not .IsBareRepo}} | |||
| <div class="btn-group" id="gogs-repo-clone"> | |||
| <!--<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-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> | |||
| </button> | |||
| <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}} | |||
| @@ -21,9 +40,8 @@ | |||
| {{end}} | |||
| <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-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> | |||
| @@ -36,11 +54,11 @@ | |||
| </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"> | |||
| <a type="button" {{if not .IsRepositoryOwner}}href="/{{.Username}}/{{.Reponame}}/fork"{{end}} class="btn btn-default"><i class="fa fa-code-fork"></i>Fork {{.Repository.NumForks}}</a> | |||
| <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> | |||
| </div> | |||
| @@ -1,4 +1,4 @@ | |||
| <div class="panel panel-default guide-box"> | |||
| <div class="panel panel-default guide-box clone-group-btn"> | |||
| <div class="panel-heading guide-head"> | |||
| <h4>Quick Guide</h4> | |||
| </div> | |||
| @@ -9,7 +9,7 @@ | |||
| <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" id="guide-clone-url" value="" readonly/> | |||
| <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> | |||
| @@ -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/> | |||