]> source.dussan.org Git - gitea.git/commitdiff
Finish close and reopen issue, install page, ready going to test stage of v0.2.0
authorUnknown <joe2010xtmf@163.com>
Sat, 29 Mar 2014 21:50:51 +0000 (17:50 -0400)
committerUnknown <joe2010xtmf@163.com>
Sat, 29 Mar 2014 21:50:51 +0000 (17:50 -0400)
15 files changed:
README.md
README_ZH.md
gogs.go
models/issue.go
models/models.go
models/repo.go
modules/auth/auth.go
modules/base/conf.go
public/css/gogs.css
routers/install.go
routers/repo/issue.go
routers/user/user.go
templates/install.tmpl
templates/issue/view.tmpl
web.go

index e88a247705a03e25c2a340d1eb3e1f3e70cf57f7..1d3aaf3e8a94e4a9272cd7f43aec02d251846d51 100644 (file)
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@ Gogs(Go Git Service) is a Self Hosted Git Service in the Go Programming Language
 
 ![Demo](http://gowalker.org/public/gogs_demo.gif)
 
-##### Current version: 0.1.9 Alpha
+##### Current version: 0.2.0 Alpha
 
 #### Due to testing purpose, data of [try.gogits.org](http://try.gogits.org) has been reset in March 29, 2014 and will reset multiple times after. Please do NOT put your important data on the site.
 
index 8e187c73648b28f22012955dfa6cf429c5881845..4590e36b1d39ed6ff191c2e421490030a1151189 100644 (file)
@@ -5,7 +5,7 @@ Gogs(Go Git Service) 是一个由 Go 语言编写的自助 Git 托管服务。
 
 ![Demo](http://gowalker.org/public/gogs_demo.gif)
 
-##### 当前版本:0.1.9 Alpha
+##### 当前版本:0.2.0 Alpha
 
 ## 开发目的
 
diff --git a/gogs.go b/gogs.go
index f1372f0cfc95e83e44fd588a44efb2e68a0dc18e..2ef35ca4da8a26a9500c99fdac27ea40209b8f11 100644 (file)
--- a/gogs.go
+++ b/gogs.go
@@ -19,7 +19,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.9.0329 Alpha"
+const APP_VER = "0.2.0.0329 Alpha"
 
 func init() {
        base.AppVer = APP_VER
index 9fd1b905a5852000fb8e78174563bac9419368c7..f14030df5e53c76ab24b609620bf65dcc7e89f1d 100644 (file)
@@ -170,9 +170,17 @@ type Milestone struct {
        Created   time.Time `xorm:"created"`
 }
 
+// Issue types.
+const (
+       IT_PLAIN  = iota // Pure comment.
+       IT_REOPEN        // Issue reopen status change prompt.
+       IT_CLOSE         // Issue close status change prompt.
+)
+
 // Comment represents a comment in commit and issue page.
 type Comment struct {
        Id       int64
+       Type     int
        PosterId int64
        Poster   *User `xorm:"-"`
        IssueId  int64
@@ -183,21 +191,37 @@ type Comment struct {
 }
 
 // CreateComment creates comment of issue or commit.
-func CreateComment(userId, issueId, commitId, line int64, content string) error {
+func CreateComment(userId, repoId, issueId, commitId, line int64, cmtType int, content string) error {
        sess := orm.NewSession()
        defer sess.Close()
        sess.Begin()
 
-       if _, err := orm.Insert(&Comment{PosterId: userId, IssueId: issueId,
+       if _, err := orm.Insert(&Comment{PosterId: userId, Type: cmtType, IssueId: issueId,
                CommitId: commitId, Line: line, Content: content}); err != nil {
                sess.Rollback()
                return err
        }
 
-       rawSql := "UPDATE `issue` SET num_comments = num_comments + 1 WHERE id = ?"
-       if _, err := sess.Exec(rawSql, issueId); err != nil {
-               sess.Rollback()
-               return err
+       // Check comment type.
+       switch cmtType {
+       case IT_PLAIN:
+               rawSql := "UPDATE `issue` SET num_comments = num_comments + 1 WHERE id = ?"
+               if _, err := sess.Exec(rawSql, issueId); err != nil {
+                       sess.Rollback()
+                       return err
+               }
+       case IT_REOPEN:
+               rawSql := "UPDATE `repository` SET num_closed_issues = num_closed_issues - 1 WHERE id = ?"
+               if _, err := sess.Exec(rawSql, repoId); err != nil {
+                       sess.Rollback()
+                       return err
+               }
+       case IT_CLOSE:
+               rawSql := "UPDATE `repository` SET num_closed_issues = num_closed_issues + 1 WHERE id = ?"
+               if _, err := sess.Exec(rawSql, repoId); err != nil {
+                       sess.Rollback()
+                       return err
+               }
        }
        return sess.Commit()
 }
index bafa1747e86bc99604ae29a15e7525930e14ceb3..825730c5a8f7d3e1c7e3cd2c21af812bf5a59ec1 100644 (file)
@@ -34,8 +34,7 @@ func LoadModelsConfig() {
        DbCfg.Path = base.Cfg.MustValue("database", "PATH", "data/gogs.db")
 }
 
-func SetEngine() {
-       var err error
+func SetEngine() (err error) {
        switch DbCfg.Type {
        case "mysql":
                orm, err = xorm.NewEngine("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8",
@@ -47,12 +46,10 @@ func SetEngine() {
                os.MkdirAll(path.Dir(DbCfg.Path), os.ModePerm)
                orm, err = xorm.NewEngine("sqlite3", DbCfg.Path)
        default:
-               fmt.Printf("Unknown database type: %s\n", DbCfg.Type)
-               os.Exit(2)
+               return fmt.Errorf("Unknown database type: %s\n", DbCfg.Type)
        }
        if err != nil {
-               fmt.Printf("models.init(fail to conntect database): %v\n", err)
-               os.Exit(2)
+               return fmt.Errorf("models.init(fail to conntect database): %v\n", err)
        }
 
        // WARNNING: for serv command, MUST remove the output to os.stdout,
@@ -62,20 +59,21 @@ func SetEngine() {
        //orm.ShowErr = true
        f, err := os.Create("xorm.log")
        if err != nil {
-               fmt.Printf("models.init(fail to create xorm.log): %v\n", err)
-               os.Exit(2)
+               return fmt.Errorf("models.init(fail to create xorm.log): %v\n", err)
        }
        orm.Logger = f
        orm.ShowSQL = true
+       return nil
 }
 
-func NewEngine() {
-       SetEngine()
-       if err := orm.Sync(new(User), new(PublicKey), new(Repository), new(Watch),
+func NewEngine() (err error) {
+       if err = SetEngine(); err != nil {
+               return err
+       } else if err = orm.Sync(new(User), new(PublicKey), new(Repository), new(Watch),
                new(Action), new(Access), new(Issue), new(Comment)); err != nil {
-               fmt.Printf("sync database struct error: %v\n", err)
-               os.Exit(2)
+               return fmt.Errorf("sync database struct error: %v\n", err)
        }
+       return nil
 }
 
 type Statistic struct {
index a848694da6fb1d991f57604b61466b0a3785ea76..0b2bbe486227320721af4398545fd8594813b46e 100644 (file)
@@ -11,7 +11,6 @@ import (
        "os"
        "os/exec"
        "path/filepath"
-       "regexp"
        "strings"
        "time"
        "unicode/utf8"
@@ -59,15 +58,6 @@ func NewRepoContext() {
                        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.
@@ -105,15 +95,20 @@ func IsRepositoryExist(user *User, repoName string) (bool, error) {
 }
 
 var (
-       // Define as all lower case!!
-       illegalPatterns = []string{"[.][Gg][Ii][Tt]", "raw", "user", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin"}
+       illegalEquals  = []string{"raw", "install", "api", "avatar", "user", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin"}
+       illegalSuffixs = []string{".git"}
 )
 
 // IsLegalName returns false if name contains illegal characters.
 func IsLegalName(repoName string) bool {
-       for _, pattern := range illegalPatterns {
-               has, _ := regexp.MatchString(pattern, repoName)
-               if has {
+       repoName = strings.ToLower(repoName)
+       for _, char := range illegalEquals {
+               if repoName == char {
+                       return false
+               }
+       }
+       for _, char := range illegalSuffixs {
+               if strings.HasSuffix(repoName, char) {
                        return false
                }
        }
index ac03a8f1263cc5eb3305a9c9df5ee58f1ce8f27c..361f55b2d32cb3f310ba6530f572875a4aa8c4b9 100644 (file)
@@ -172,6 +172,7 @@ type InstallForm struct {
        DatabasePath    string `form:"database_path"`
        RepoRootPath    string `form:"repo_path"`
        RunUser         string `form:"run_user"`
+       Domain          string `form:"domain"`
        AppUrl          string `form:"app_url"`
        AdminName       string `form:"admin_name" binding:"Required"`
        AdminPasswd     string `form:"admin_pwd" binding:"Required;MinSize(6);MaxSize(30)"`
index fd77cfd3ceac20b3cddeb9cc43b69d07090d1f5f..f696d083f7b1e83ac92e0dc6ab0031215522195a 100644 (file)
@@ -272,18 +272,19 @@ func NewConfigContext() {
        Domain = Cfg.MustValue("server", "DOMAIN")
        SecretKey = Cfg.MustValue("security", "SECRET_KEY")
 
+       InstallLock = Cfg.MustBool("security", "INSTALL_LOCK", false)
+
        RunUser = Cfg.MustValue("", "RUN_USER")
        curUser := os.Getenv("USERNAME")
        if len(curUser) == 0 {
                curUser = os.Getenv("USER")
        }
-       if RunUser != curUser {
+       // Does not check run user when the install lock is off.
+       if InstallLock && RunUser != curUser {
                fmt.Printf("Expect user(%s) but current user is: %s\n", RunUser, curUser)
                os.Exit(2)
        }
 
-       InstallLock = Cfg.MustBool("security", "INSTALL_LOCK", false)
-
        LogInRememberDays = Cfg.MustInt("security", "LOGIN_REMEMBER_DAYS")
        CookieUserName = Cfg.MustValue("security", "COOKIE_USERNAME")
        CookieRememberName = Cfg.MustValue("security", "COOKIE_REMEMBER_NAME")
index d6c117c846c23ec1a8f4eac9b0df8e77e42bacd7..965c90962c8a657f4e4bd95d91ace926007c2846 100755 (executable)
@@ -1197,13 +1197,13 @@ html, body {
     line-height: 42px;
 }
 
-#issue .issue-closed{
-    border-bottom: 3px solid #CCC;
+#issue .issue-closed, #issue .issue-opened {
+    border-bottom: 2px solid #CCC;
     margin-bottom: 24px;
     padding-bottom: 24px;
 }
 
-#issue .issue-closed .btn-danger,#issue .issue-opened .btn-success{
+#issue .issue-closed .label-danger,#issue .issue-opened .label-success{
     margin: 0 .8em;
 }
 
index b5c3a9364b72623f40c7fa9f10874a5858f7b391..407705b73a552c91db219daed99ba898263081f4 100644 (file)
@@ -6,13 +6,46 @@ package routers
 
 import (
        "errors"
+       "os"
+       "strings"
+
+       "github.com/Unknwon/goconfig"
+       "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/mailer"
        "github.com/gogits/gogs/modules/middleware"
 )
 
+// Check run mode(Default of martini is Dev).
+func checkRunMode() {
+       switch base.Cfg.MustValue("", "RUN_MODE") {
+       case "prod":
+               martini.Env = martini.Prod
+       case "test":
+               martini.Env = martini.Test
+       }
+       log.Info("Run Mode: %s", strings.Title(martini.Env))
+}
+
+// GlobalInit is for global configuration reload-able.
+func GlobalInit() {
+       base.NewConfigContext()
+       mailer.NewMailerContext()
+       models.LoadModelsConfig()
+       models.LoadRepoConfig()
+       models.NewRepoContext()
+       if err := models.NewEngine(); err != nil && base.InstallLock {
+               log.Error("%v", err)
+               os.Exit(2)
+       }
+       base.NewServices()
+       checkRunMode()
+}
+
 func Install(ctx *middleware.Context, form auth.InstallForm) {
        if base.InstallLock {
                ctx.Handle(404, "install.Install", errors.New("Installation is prohibited"))
@@ -20,14 +53,114 @@ func Install(ctx *middleware.Context, form auth.InstallForm) {
        }
 
        ctx.Data["Title"] = "Install"
-       ctx.Data["DbCfg"] = models.DbCfg
-       ctx.Data["RepoRootPath"] = base.RepoRootPath
-       ctx.Data["RunUser"] = base.RunUser
-       ctx.Data["AppUrl"] = base.AppUrl
        ctx.Data["PageIsInstall"] = true
 
+       // Get and assign value to install form.
+       if len(form.Host) == 0 {
+               form.Host = models.DbCfg.Host
+       }
+       if len(form.User) == 0 {
+               form.User = models.DbCfg.User
+       }
+       if len(form.Passwd) == 0 {
+               form.Passwd = models.DbCfg.Pwd
+       }
+       if len(form.DatabaseName) == 0 {
+               form.DatabaseName = models.DbCfg.Name
+       }
+       if len(form.DatabasePath) == 0 {
+               form.DatabasePath = models.DbCfg.Path
+       }
+
+       if len(form.RepoRootPath) == 0 {
+               form.RepoRootPath = base.RepoRootPath
+       }
+       if len(form.RunUser) == 0 {
+               form.RunUser = base.RunUser
+       }
+       if len(form.Domain) == 0 {
+               form.Domain = base.Domain
+       }
+       if len(form.AppUrl) == 0 {
+               form.AppUrl = base.AppUrl
+       }
+
+       auth.AssignForm(form, ctx.Data)
+
        if ctx.Req.Method == "GET" {
                ctx.HTML(200, "install")
                return
        }
+
+       if ctx.HasError() {
+               ctx.HTML(200, "install")
+               return
+       }
+
+       // Pass basic check, now test configuration.
+       // Test database setting.
+       dbTypes := map[string]string{"mysql": "mysql", "pgsql": "postgres", "sqlite": "sqlite3"}
+       models.DbCfg.Type = dbTypes[form.Database]
+       models.DbCfg.Host = form.Host
+       models.DbCfg.User = form.User
+       models.DbCfg.Pwd = form.Passwd
+       models.DbCfg.Name = form.DatabaseName
+       models.DbCfg.SslMode = form.SslMode
+       models.DbCfg.Path = form.DatabasePath
+
+       if err := models.NewEngine(); err != nil {
+               ctx.RenderWithErr("Database setting is not correct: "+err.Error(), "install", &form)
+               return
+       }
+
+       // Test repository root path.
+       if err := os.MkdirAll(form.RepoRootPath, os.ModePerm); err != nil {
+               ctx.RenderWithErr("Repository root path is invalid: "+err.Error(), "install", &form)
+               return
+       }
+
+       // Create admin account.
+       if _, err := models.RegisterUser(&models.User{Name: form.AdminName, Email: form.AdminEmail, Passwd: form.AdminPasswd,
+               IsAdmin: true, IsActive: true}); err != nil {
+               if err != models.ErrUserAlreadyExist {
+                       ctx.RenderWithErr("Admin account setting is invalid: "+err.Error(), "install", &form)
+                       return
+               }
+       }
+
+       // Save settings.
+       base.Cfg.SetValue("database", "DB_TYPE", models.DbCfg.Type)
+       base.Cfg.SetValue("database", "HOST", models.DbCfg.Host)
+       base.Cfg.SetValue("database", "NAME", models.DbCfg.Name)
+       base.Cfg.SetValue("database", "USER", models.DbCfg.User)
+       base.Cfg.SetValue("database", "PASSWD", models.DbCfg.Pwd)
+       base.Cfg.SetValue("database", "SSL_MODE", models.DbCfg.SslMode)
+       base.Cfg.SetValue("database", "PATH", models.DbCfg.Path)
+
+       base.Cfg.SetValue("repository", "ROOT", form.RepoRootPath)
+       base.Cfg.SetValue("", "RUN_USER", form.RunUser)
+       base.Cfg.SetValue("server", "DOMAIN", form.Domain)
+       base.Cfg.SetValue("server", "ROOT_URL", form.AppUrl)
+
+       if len(form.Host) > 0 {
+               base.Cfg.SetValue("mailer", "ENABLED", "true")
+               base.Cfg.SetValue("mailer", "HOST", form.SmtpHost)
+               base.Cfg.SetValue("mailer", "USER", form.SmtpEmail)
+               base.Cfg.SetValue("mailer", "PASSWD", form.SmtpPasswd)
+
+               base.Cfg.SetValue("service", "REGISTER_EMAIL_CONFIRM", base.ToStr(form.RegisterConfirm == "on"))
+               base.Cfg.SetValue("service", "ENABLE_NOTIFY_MAIL", base.ToStr(form.MailNotify == "on"))
+       }
+
+       base.Cfg.SetValue("security", "INSTALL_LOCK", "true")
+
+       if err := goconfig.SaveConfigFile(base.Cfg, "custom/conf/app.ini"); err != nil {
+               ctx.RenderWithErr("Fail to save configuration: "+err.Error(), "install", &form)
+               return
+       }
+
+       GlobalInit()
+
+       log.Info("First-time run install finished!")
+       ctx.Redirect("/user/login")
 }
index 337bd4bf1ce282bc3a1887e1014e46b653aacae3..3506e901631ceff727c19cf05e04bf64ec97e9ca 100644 (file)
@@ -7,6 +7,7 @@ package repo
 import (
        "fmt"
        "net/url"
+       "strings"
 
        "github.com/codegangsta/martini"
 
@@ -175,7 +176,7 @@ func ViewIssue(ctx *middleware.Context, params martini.Params) {
        ctx.Data["Title"] = issue.Name
        ctx.Data["Issue"] = issue
        ctx.Data["Comments"] = comments
-       ctx.Data["IsIssueOwner"] = issue.PosterId == ctx.User.Id
+       ctx.Data["IsIssueOwner"] = ctx.Repo.IsOwner || issue.PosterId == ctx.User.Id
        ctx.Data["IsRepoToolbarIssues"] = true
        ctx.Data["IsRepoToolbarIssuesList"] = false
        ctx.HTML(200, "issue/view")
@@ -225,24 +226,17 @@ func UpdateIssue(ctx *middleware.Context, params martini.Params, form auth.Creat
 }
 
 func Comment(ctx *middleware.Context, params martini.Params) {
-       fmt.Println(ctx.Query("change_status"))
        if !ctx.Repo.IsValid {
                ctx.Handle(404, "issue.Comment(invalid repo):", nil)
        }
 
-       index, err := base.StrTo(ctx.Query("issueIndex")).Int()
+       index, err := base.StrTo(ctx.Query("issueIndex")).Int64()
        if err != nil {
-               ctx.Handle(404, "issue.Comment", err)
+               ctx.Handle(404, "issue.Comment(get index)", err)
                return
        }
 
-       content := ctx.Query("content")
-       if len(content) == 0 {
-               ctx.Redirect(fmt.Sprintf("/%s/%s/issues/%d", ctx.User.Name, ctx.Repo.Repository.Name, index))
-               return
-       }
-
-       issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, int64(index))
+       issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, index)
        if err != nil {
                if err == models.ErrIssueNotExist {
                        ctx.Handle(404, "issue.Comment", err)
@@ -252,16 +246,46 @@ func Comment(ctx *middleware.Context, params martini.Params) {
                return
        }
 
-       switch params["action"] {
-       case "new":
-               if err = models.CreateComment(ctx.User.Id, issue.Id, 0, 0, content); err != nil {
-                       ctx.Handle(500, "issue.Comment(create comment)", err)
+       // Check if issue owner changes the status of issue.
+       var newStatus string
+       if ctx.Repo.IsOwner || issue.PosterId == ctx.User.Id {
+               newStatus = ctx.Query("change_status")
+       }
+       if len(newStatus) > 0 {
+               if (strings.Contains(newStatus, "Reopen") && issue.IsClosed) ||
+                       (strings.Contains(newStatus, "Close") && !issue.IsClosed) {
+                       issue.IsClosed = !issue.IsClosed
+                       if err = models.UpdateIssue(issue); err != nil {
+                               ctx.Handle(200, "issue.Comment(update issue status)", err)
+                               return
+                       }
+
+                       cmtType := models.IT_CLOSE
+                       if !issue.IsClosed {
+                               cmtType = models.IT_REOPEN
+                       }
+
+                       if err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, cmtType, ""); err != nil {
+                               ctx.Handle(200, "issue.Comment(create status change comment)", err)
+                               return
+                       }
+                       log.Trace("%s Issue(%d) status changed: %v", ctx.Req.RequestURI, issue.Id, !issue.IsClosed)
+               }
+       }
+
+       content := ctx.Query("content")
+       if len(content) > 0 {
+               switch params["action"] {
+               case "new":
+                       if err = models.CreateComment(ctx.User.Id, ctx.Repo.Repository.Id, issue.Id, 0, 0, models.IT_PLAIN, content); err != nil {
+                               ctx.Handle(500, "issue.Comment(create comment)", err)
+                               return
+                       }
+                       log.Trace("%s Comment created: %d", ctx.Req.RequestURI, issue.Id)
+               default:
+                       ctx.Handle(404, "issue.Comment", err)
                        return
                }
-               log.Trace("%s Comment created: %d", ctx.Req.RequestURI, issue.Id)
-       default:
-               ctx.Handle(404, "issue.Comment", err)
-               return
        }
 
        ctx.Redirect(fmt.Sprintf("/%s/%s/issues/%d", ctx.User.Name, ctx.Repo.Repository.Name, index))
index 114169e606b14950d2bb57842a3a3c00e9001839..aeaf91c97dda90e34117159dbbb101b5b740164e 100644 (file)
@@ -120,7 +120,7 @@ func SignIn(ctx *middleware.Context, form auth.LogInForm) {
                return
        }
 
-       if hasErr, ok := ctx.Data["HasError"]; ok && hasErr.(bool) {
+       if ctx.HasError() {
                ctx.HTML(200, "user/signin")
                return
        }
@@ -308,17 +308,19 @@ func Issues(ctx *middleware.Context) {
 
        showRepos := make([]models.Repository, 0, len(repos))
 
-       var closedIssueCount, createdByCount int
+       isShowClosed := ctx.Query("state") == "closed"
+       var closedIssueCount, createdByCount, allIssueCount int
 
        // Get all issues.
        allIssues := make([]models.Issue, 0, 5*len(repos))
        for i, repo := range repos {
-               issues, err := models.GetIssues(0, repo.Id, posterId, 0, page, false, false, "", "")
+               issues, err := models.GetIssues(0, repo.Id, posterId, 0, page, isShowClosed, false, "", "")
                if err != nil {
                        ctx.Handle(200, "user.Issues(get issues)", err)
                        return
                }
 
+               allIssueCount += repo.NumIssues
                closedIssueCount += repo.NumClosedIssues
 
                // Set repository information to issues.
@@ -330,12 +332,10 @@ func Issues(ctx *middleware.Context) {
                repos[i].NumOpenIssues = repo.NumIssues - repo.NumClosedIssues
                if repos[i].NumOpenIssues > 0 {
                        showRepos = append(showRepos, repos[i])
-
                }
        }
 
        showIssues := make([]models.Issue, 0, len(allIssues))
-       isShowClosed := ctx.Query("state") == "closed"
        ctx.Data["IsShowClosed"] = isShowClosed
 
        // Get posters and filter issues.
@@ -361,9 +361,9 @@ func Issues(ctx *middleware.Context) {
 
        ctx.Data["Repos"] = showRepos
        ctx.Data["Issues"] = showIssues
-       ctx.Data["AllIssueCount"] = len(allIssues)
+       ctx.Data["AllIssueCount"] = allIssueCount
        ctx.Data["ClosedIssueCount"] = closedIssueCount
-       ctx.Data["OpenIssueCount"] = len(allIssues) - closedIssueCount
+       ctx.Data["OpenIssueCount"] = allIssueCount - closedIssueCount
        ctx.Data["CreatedByCount"] = createdByCount
        ctx.HTML(200, "issue/user")
 }
index a456ac5f2cfec255c2937ef0af54422db002ba54..20bd502da2c05e619e912386d086896d74d17c11 100644 (file)
@@ -3,9 +3,8 @@
     <form action="/install" method="post" class="form-horizontal card" id="install-card">
         {{.CsrfTokenHtml}}
         <h3>Install Steps For First-time Run</h3>
-
         <div class="alert alert-danger form-error{{if .HasError}}{{else}} hidden{{end}}">{{.ErrorMsg}}</div>
-        <p class="help-block text-center">Gogs requires MySQL or PostgreSQL based on your choice</p>
+        <p class="help-block text-center">Gogs requires MySQL or PostgreSQL, SQLite3 only available for official binary version</p>
         <div class="form-group">
             <label class="col-md-3 control-label">Database Type: </label>
             <div class="col-md-8">
                 </select>
             </div>
         </div>
+
         <div class="server-sql">
             <div class="form-group">
                 <label class="col-md-3 control-label">Host: </label>
-
                 <div class="col-md-8">
-                    <input name="host" class="form-control" placeholder="Type database server host, leave blank to keep default" value="{{.DbCfg.Host}}" required="required">
+                    <input name="host" class="form-control" placeholder="Type database server host" value="{{.host}}" required="required">
                 </div>
             </div>
+
             <div class="form-group">
                 <label class="col-md-3 control-label">User: </label>
 
                 <div class="col-md-8">
-                    <input name="user" class="form-control" placeholder="Type database username" required="required" value="{{.DbCfg.User}}">
+                    <input name="user" class="form-control" placeholder="Type database username" required="required" value="{{.user}}">
                 </div>
             </div>
+
             <div class="form-group">
                 <label class="col-md-3 control-label">Password: </label>
 
                 <div class="col-md-8">
-                    <input name="passwd" type="password" class="form-control" placeholder="Type database password" required="required" value="{{.DbCfg.Pwd}}">
+                    <input name="passwd" type="password" class="form-control" placeholder="Type database password" required="required" value="{{.passwd}}">
                 </div>
             </div>
 
@@ -43,7 +44,7 @@
                 <label class="col-md-3 control-label">Database Name: </label>
 
                 <div class="col-md-8">
-                    <input name="database_name" type="text" class="form-control" placeholder="Type mysql database name" value="{{.DbCfg.Name}}" required="required">
+                    <input name="database_name" type="text" class="form-control" placeholder="Type mysql database name" value="{{.database_name}}" required="required">
                     <p class="help-block">Recommend use INNODB engine with utf8_general_ci charset.</p>
                 </div>
             </div>
                 </div>
             </div>
         </div>
+
         <div class="sqlite-setting hide">
             <div class="form-group">
                 <label class="col-md-3 control-label">Path: </label>
 
                 <div class="col-md-8">
-                    <input name="database_path" class="form-control" placeholder="Type sqlite3 file path" value="{{.DbCfg.Path}}">
+                    <input name="database_path" class="form-control" placeholder="Type sqlite3 file path" value="{{.database_path}}">
                     <p class="help-block">The file path of SQLite3 database.</p>
                 </div>
             </div>
         <hr/>
 
         <p class="help-block text-center">General Settings of Gogs</p>
-
         <div class="form-group">
             <label class="col-md-3 control-label">Repository Path: </label>
 
             <div class="col-md-8">
-                <input name="repo_path" type="text" class="form-control" placeholder="Type your repository directory" value="{{.RepoRootPath}}" required="required">
+                <input name="repo_path" type="text" class="form-control" placeholder="Type your repository directory" value="{{.repo_path}}" required="required">
 
                 <p class="help-block">The git copy of each repository is saved in this directory.</p>
             </div>
             <label class="col-md-3 control-label">Run User: </label>
 
             <div class="col-md-8">
-                <input name="run_user" type="text" class="form-control" placeholder="Type system user name" value="{{.RunUser}}" required="required">
+                <input name="run_user" type="text" class="form-control" placeholder="Type system user name" value="{{.run_user}}" required="required">
                 <p class="help-block">The user has access to visit and run Gogs.</p>
             </div>
         </div>
         
+        <div class="form-group">
+            <label class="col-md-3 control-label">Domain: </label>
+
+            <div class="col-md-8">
+                <input name="domain" type="text" class="form-control" placeholder="Type your domain name" value="{{.domain}}" required="required">
+                <p class="help-block">This affects SSH clone URL.</p>
+            </div>
+        </div>
+        
         <div class="form-group">
             <label class="col-md-3 control-label">App URL: </label>
 
             <div class="col-md-8">
-                <input name="app_url" type="text" class="form-control" placeholder="Type app root URL " value="{{.AppUrl}}" required="required">
+                <input name="app_url" type="text" class="form-control" placeholder="Type app root URL" value="{{.app_url}}" required="required">
                 <p class="help-block">This affects HTTP/HTTPS clone URL and somewhere in e-mail.</p>
             </div>
         </div>
         <hr/>
 
         <p class="help-block text-center">Admin Account Settings</p>
-
         <div class="form-group">
             <label class="col-md-3 control-label">Username: </label>
-
             <div class="col-md-8">
-                <input name="admin_name" type="text" class="form-control" placeholder="Type admin user name" value="admin" required="required">
+                <input name="admin_name" type="text" class="form-control" placeholder="Type admin user name" value="{{.admin_name}}" required="required">
             </div>
         </div>
 
-        <div class="form-group">
+        <div class="form-group {{if .Err_AdminPasswd}}has-error has-feedback{{end}}">
             <label class="col-md-3 control-label">Password: </label>
-
             <div class="col-md-8">
-                <input name="admin_pwd" type="password" class="form-control" placeholder="Type admin user password" required="required">
+                <input name="admin_pwd" type="password" class="form-control" placeholder="Type admin user password" value="{{.admin_pwd}}" required="required">
             </div>
         </div>
 
-        <div class="form-group">
+        <div class="form-group {{if .Err_AdminEmail}}has-error has-feedback{{end}}">
             <label class="col-md-3 control-label">E-mail: </label>
-
             <div class="col-md-8">
-                <input name="admin_email" type="text" class="form-control" placeholder="Type admin user e-mail" required="required">
+                <input name="admin_email" type="text" class="form-control" placeholder="Type admin user e-mail" value="{{.admin_email}}" required="required">
             </div>
         </div>
 
         <hr/>
 
         <div class="form-group text-center">
-            <!-- <button class="btn btn-primary btn-lg">Test Configuration</button> -->
             <button class="btn btn-danger btn-lg">Install Gogs</button>
             <button class="btn btn-default btn-sm" type="button" data-toggle="modal" data-target="#advance-options-modal">
                 Advanced Options
                             <label class="col-md-3 control-label">SMTP Host: </label>
 
                             <div class="col-md-8">
-                                <input name="smtp_host" type="text" class="form-control" placeholder="Type SMTP host address">
+                                <input name="smtp_host" type="text" class="form-control" placeholder="Type SMTP host address" value="{{.smtp_host}}">
                             </div>
                         </div>
                         <div class="form-group">
                             <label class="col-md-3 control-label">Email: </label>
 
                             <div class="col-md-8">
-                                <input name="mailer_user" type="text" class="form-control" placeholder="Type SMTP user e-mail address">
+                                <input name="mailer_user" type="text" class="form-control" placeholder="Type SMTP user e-mail address" value="{{.mailer_user}}">
                             </div>
                         </div>
                         <div class="form-group">
                             <label class="col-md-3 control-label">Password: </label>
 
                             <div class="col-md-8">
-                                <input name="mailer_pwd" type="password" class="form-control" placeholder="Type SMTP user password">
+                                <input name="mailer_pwd" type="password" class="form-control" placeholder="Type SMTP user password" value="{{.mailer_pwd}}">
                             </div>
                         </div>
                         <hr/>
                             <div class="col-md-offset-3 col-md-7">
                                 <div class="checkbox">
                                     <label>
-                                        <input name="register_confirm" type="checkbox">
+                                        <input name="register_confirm" type="checkbox" {{if .register_confirm}}checked{{end}}>
                                         <strong>Enable Register Confirmation</strong>
                                     </label>
                                 </div>
                             <div class="col-md-offset-3 col-md-7">
                                 <div class="checkbox">
                                     <label>
-                                        <input name="mail_notify" type="checkbox">
+                                        <input name="mail_notify" type="checkbox" {{if .mail_notify}}checked{{end}}>
                                         <strong>Enable Mail Notification</strong>
                                     </label>
                                 </div>
index 0481a33b40aeb92ea29ca4caaeab0b8834b66c22..91e5250ca3ee5121bff486cee5cb6e792b6bcc6f 100644 (file)
                    </div>
                </div>
                {{range .Comments}}
-               <div class="issue-child" id="issue-comment-{{.Id}}">
-                   <a class="user pull-left" href="/user/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a>
-                   <div class="issue-content panel panel-default">
-                       <div class="panel-heading">
-                           <a href="/user/{{.Poster.Name}}" class="user">{{.Poster.Name}}</a> commented <span class="time">{{TimeSince .Created}}</span>
-                           <!-- <a class="issue-comment-del pull-right issue-action" href="#" title="Edit Comment"><i class="fa fa-times-circle"></i></a>
-                           <a class="issue-comment-edit pull-right issue-action" href="#" title="Remove Comment" data-url="{remove-link}"><i class="fa fa-edit"></i></a> -->
-                           <span class="role label label-default pull-right">Owner</span>
-                       </div>
-                       <div class="panel-body markdown">
-                          {{str2html .Content}}
-                       </div>
-                   </div>
-                </div>
-                {{end}}
-                <!-- <div class="issue-child issue-closed">
-                    <a class="user pull-left" href="{user.link}"><img class="avatar" src="{user.avatar}" alt=""/></a>
+                {{if eq .Type 0}}
+                 <div class="issue-child" id="issue-comment-{{.Id}}">
+                     <a class="user pull-left" href="/user/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a>
+                     <div class="issue-content panel panel-default">
+                         <div class="panel-heading">
+                             <a href="/user/{{.Poster.Name}}" class="user">{{.Poster.Name}}</a> commented <span class="time">{{TimeSince .Created}}</span>
+                             <!-- <a class="issue-comment-del pull-right issue-action" href="#" title="Edit Comment"><i class="fa fa-times-circle"></i></a>
+                             <a class="issue-comment-edit pull-right issue-action" href="#" title="Remove Comment" data-url="{remove-link}"><i class="fa fa-edit"></i></a> -->
+                             <span class="role label label-default pull-right">Owner</span>
+                         </div>
+                         <div class="panel-body markdown">
+                            {{str2html .Content}}
+                         </div>
+                     </div>
+                  </div>
+                  {{else if eq .Type 1}}
+                  <div class="issue-child issue-opened">
+                      <a class="user pull-left" href="/user/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt="" /></a>
+                      <div class="issue-content">
+                          <a class="user pull-left" href="/user/{{.Poster.Name}}">{{.Poster.Name}}</a> <span class="label label-success">Reopened</span> this issue <span class="time">{{TimeSince .Created}}</span>
+                      </div>
+                  </div>
+                  {{else if eq .Type 2}}
+                  <div class="issue-child issue-closed">
+                    <a class="user pull-left" href="/user/{{.Poster.Name}}"><img class="avatar" src="{{.Poster.AvatarLink}}" alt=""/></a>
                     <div class="issue-content">
-                        <a class="user pull-left" href="{user.link}">{user.name}</a>
-                        <span class="btn btn-danger">Closed</span> this
-                        <span class="time">{close.time}</span>
+                        <a class="user pull-left" href="/user/{{.Poster.Name}}">{{.Poster.Name}}</a> <span class="label label-danger">Closed</span> this issue <span class="time">{{TimeSince .Created}}</span>
                     </div>
-                </div>
-                <div class="issue-child issue-opened">
-                    <a class="user pull-left" href="{user.link}"><img class="avatar" src="{user.avatar}" alt=""/></a>
-                    <div class="issue-content">
-                        <a class="user pull-left" href="{user.link}">{user.name}</a>
-                        <span class="btn btn-success">Reopened</span> this
-                        <span class="time">{close.time}</span>
-                    </div>
-                </div> -->
+                  </div>
+                  {{end}}
+                {{end}}
                 <hr class="issue-line"/>
                 {{if .SignedUser}}<div class="issue-child issue-reply">
                     <a class="user pull-left" href="/user/{{.SignedUser.Name}}"><img class="avatar" src="{{.SignedUser.AvatarLink}}" alt=""/></a>
@@ -68,8 +68,7 @@
                         {{.CsrfTokenHtml}}
                         <div class="panel-body">
                             <div class="form-group">
-                                <div class="md-help pull-right"><!-- todo help link -->
-                                    Content with <a href="https://help.github.com/articles/markdown-basics">Markdown</a>
+                                <div class="md-help pull-right">Content with <a href="https://help.github.com/articles/markdown-basics">Markdown</a>
                                 </div>
                                 <ul class="nav nav-tabs" data-init="tabs">
                                     <li class="active issue-write"><a href="#issue-textarea" data-toggle="tab">Write</a></li>
                                             <textarea class="form-control" name="content" id="issue-reply-content" rows="10" placeholder="Write some content" data-ajax-rel="issue-preview" data-ajax-val="val" data-ajax-field="content">{{.content}}</textarea>
                                         </div>
                                     </div>
-                                    <div class="tab-pane issue-preview-content" id="issue-preview">loading...</div>
+                                    <div class="tab-pane issue-preview-content" id="issue-preview">Loading...</div>
                                 </div>
                             </div>
                             <div class="text-right">
                                 <div class="form-group">
                                     {{if .Issue.IsClosed}}
-                                    <input type="submit" class="btn-default btn issue-open" id="issue-open-btn" data-origin="Re-Open" data-text="Re-Open & Comment" name="change_status" value="Reopen"/>{{else}}
+                                    <input type="submit" class="btn-default btn issue-open" id="issue-open-btn" data-origin="Reopen" data-text="Reopen & Comment" name="change_status" value="Reopen"/>{{else}}
                                     <input type="submit" class="btn-default btn issue-close" id="issue-close-btn" data-origin="Close" data-text="Close & Comment" name="change_status" value="Close"/>{{end}}&nbsp;&nbsp;
                                     <button class="btn-success btn" id="issue-reply-btn">Comment</button>
                                 </div>
diff --git a/web.go b/web.go
index 7098717a050abcba63064c6c77570131f40dc8fe..6aabc0e909daa34668c59fb85e5320c13f66d4e4 100644 (file)
--- a/web.go
+++ b/web.go
@@ -8,19 +8,16 @@ import (
        "fmt"
        "html/template"
        "net/http"
-       "strings"
 
        "github.com/codegangsta/cli"
        "github.com/codegangsta/martini"
 
        "github.com/gogits/binding"
 
-       "github.com/gogits/gogs/models"
        "github.com/gogits/gogs/modules/auth"
        "github.com/gogits/gogs/modules/avatar"
        "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"
@@ -40,27 +37,6 @@ and it takes care of all the other things for you`,
        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") {
-       case "prod":
-               martini.Env = martini.Prod
-       case "test":
-               martini.Env = martini.Test
-       }
-       log.Info("Run Mode: %s", strings.Title(martini.Env))
-}
-
 func newMartini() *martini.ClassicMartini {
        r := martini.NewRouter()
        m := martini.New()
@@ -74,9 +50,7 @@ func newMartini() *martini.ClassicMartini {
 
 func runWeb(*cli.Context) {
        fmt.Println("Server is running...")
-       globalInit()
-       base.NewServices()
-       checkRunMode()
+       routers.GlobalInit()
        log.Info("%s %s", base.AppName, base.AppVer)
 
        m := newMartini()