From a3e1383cac3dfa2a71b04b47a295e9836fcb0d50 Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 10 Jun 2014 19:11:53 -0400 Subject: Add gogs fix location command --- cmd/serve.go | 1 - 1 file changed, 1 deletion(-) (limited to 'cmd/serve.go') diff --git a/cmd/serve.go b/cmd/serve.go index 302f8568..3a17bf9f 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -36,7 +36,6 @@ func newLogger(logPath string) { } qlog.SetOutput(f) - //qlog.SetOutputLevel(qlog.Ldebug) qlog.Info("Start logging serv...") } -- cgit v1.2.3 From f147ad619a68440ef6c30d797a8217e687e8d51d Mon Sep 17 00:00:00 2001 From: Unknown Date: Thu, 19 Jun 2014 01:08:03 -0400 Subject: Basic process manager --- cmd/serve.go | 6 +- gogs.go | 2 +- models/fix.go | 6 - models/git_diff.go | 13 +- models/publickey.go | 3 +- models/repo.go | 268 +++++++++++++++++++---------------- modules/process/manager.go | 89 ++++++++++++ routers/admin/admin.go | 5 +- templates/VERSION | 2 +- templates/admin/monitor/process.tmpl | 38 +++++ 10 files changed, 289 insertions(+), 143 deletions(-) delete mode 100644 models/fix.go create mode 100644 modules/process/manager.go create mode 100644 templates/admin/monitor/process.tmpl (limited to 'cmd/serve.go') diff --git a/cmd/serve.go b/cmd/serve.go index 3a17bf9f..a21500c7 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -32,7 +32,7 @@ func newLogger(logPath string) { f, err := os.OpenFile(logPath, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.ModePerm) if err != nil { - qlog.Fatal(err) + qlog.Fatal("Fail to open log file(%s): %v", logPath, err) } qlog.SetOutput(f) @@ -185,8 +185,8 @@ func runServ(k *cli.Context) { gitcmd.Stdout = os.Stdout gitcmd.Stdin = os.Stdin gitcmd.Stderr = os.Stderr - - if err = gitcmd.Run(); err != nil { + err = gitcmd.Run() + if err != nil { println("Gogs: internal error:", err) qlog.Fatalf("Fail to execute git command: %v", err) } diff --git a/gogs.go b/gogs.go index b4129e90..7e1459e5 100644 --- a/gogs.go +++ b/gogs.go @@ -17,7 +17,7 @@ import ( "github.com/gogits/gogs/modules/setting" ) -const APP_VER = "0.4.4.0613 Alpha" +const APP_VER = "0.4.4.0619 Alpha" func init() { runtime.GOMAXPROCS(runtime.NumCPU()) diff --git a/models/fix.go b/models/fix.go deleted file mode 100644 index 9fc141bd..00000000 --- a/models/fix.go +++ /dev/null @@ -1,6 +0,0 @@ -package models - -func Fix() error { - _, err := orm.Exec("alter table repository drop column num_releases") - return err -} diff --git a/models/git_diff.go b/models/git_diff.go index 5b5a46a1..ed114b75 100644 --- a/models/git_diff.go +++ b/models/git_diff.go @@ -6,6 +6,7 @@ package models import ( "bufio" + "fmt" "io" "os" "os/exec" @@ -15,6 +16,7 @@ import ( "github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/log" + "github.com/gogits/gogs/modules/process" ) // Diff line types. @@ -67,7 +69,7 @@ func (diff *Diff) NumFiles() int { const DIFF_HEAD = "diff --git " -func ParsePatch(cmd *exec.Cmd, reader io.Reader) (*Diff, error) { +func ParsePatch(pid int64, cmd *exec.Cmd, reader io.Reader) (*Diff, error) { scanner := bufio.NewScanner(reader) var ( curFile *DiffFile @@ -169,11 +171,8 @@ func ParsePatch(cmd *exec.Cmd, reader io.Reader) (*Diff, error) { } // In case process became zombie. - if !cmd.ProcessState.Exited() { - log.Debug("git_diff.ParsePatch: process doesn't exit and now will be killed") - if err := cmd.Process.Kill(); err != nil { - log.Error("git_diff.ParsePatch: fail to kill zombie process: %v", err) - } + if err := process.Kill(pid); err != nil { + log.Error("git_diff.ParsePatch(Kill): %v", err) } return diff, nil } @@ -207,5 +206,5 @@ func GetDiff(repoPath, commitid string) (*Diff, error) { wr.Close() }() defer rd.Close() - return ParsePatch(cmd, rd) + return ParsePatch(process.Add(fmt.Sprintf("GetDiff(%s)", repoPath), cmd), cmd, rd) } diff --git a/models/publickey.go b/models/publickey.go index 76dc0cc7..72b45c5b 100644 --- a/models/publickey.go +++ b/models/publickey.go @@ -22,6 +22,7 @@ import ( qlog "github.com/qiniu/log" "github.com/gogits/gogs/modules/log" + "github.com/gogits/gogs/modules/process" ) const ( @@ -121,7 +122,7 @@ func AddPublicKey(key *PublicKey) (err error) { if err = ioutil.WriteFile(tmpPath, []byte(key.Content), os.ModePerm); err != nil { return err } - stdout, stderr, err := com.ExecCmd("ssh-keygen", "-l", "-f", tmpPath) + stdout, stderr, err := process.Exec("AddPublicKey", "ssh-keygen", "-l", "-f", tmpPath) if err != nil { return errors.New("ssh-keygen -l -f: " + stderr) } else if len(stdout) < 2 { diff --git a/models/repo.go b/models/repo.go index 0f018135..6b98d0e4 100644 --- a/models/repo.go +++ b/models/repo.go @@ -9,7 +9,6 @@ import ( "fmt" "io/ioutil" "os" - "os/exec" "path" "path/filepath" "sort" @@ -25,6 +24,7 @@ import ( "github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/bin" "github.com/gogits/gogs/modules/log" + "github.com/gogits/gogs/modules/process" "github.com/gogits/gogs/modules/setting" ) @@ -88,13 +88,13 @@ func NewRepoContext() { zip.Verbose = false // Check if server has basic git setting. - stdout, stderr, err := com.ExecCmd("git", "config", "--get", "user.name") + stdout, stderr, err := process.Exec("NewRepoContext(get setting)", "git", "config", "--get", "user.name") if strings.Contains(stderr, "fatal:") { log.Fatal("repo.NewRepoContext(fail to get git user.name): %s", stderr) } else if err != nil || len(strings.TrimSpace(stdout)) == 0 { - if _, stderr, err = com.ExecCmd("git", "config", "--global", "user.email", "gogitservice@gmail.com"); err != nil { + if _, stderr, err = process.Exec("NewRepoContext(set email)", "git", "config", "--global", "user.email", "gogitservice@gmail.com"); err != nil { log.Fatal("repo.NewRepoContext(fail to set git user.email): %s", stderr) - } else if _, stderr, err = com.ExecCmd("git", "config", "--global", "user.name", "Gogs"); err != nil { + } else if _, stderr, err = process.Exec("NewRepoContext(set name)", "git", "config", "--global", "user.name", "Gogs"); err != nil { log.Fatal("repo.NewRepoContext(fail to set git user.name): %s", stderr) } } @@ -190,7 +190,9 @@ type Mirror struct { // MirrorRepository creates a mirror repository from source. func MirrorRepository(repoId int64, userName, repoName, repoPath, url string) error { - _, stderr, err := com.ExecCmd("git", "clone", "--mirror", url, repoPath) + // TODO: need timeout. + _, stderr, err := process.Exec(fmt.Sprintf("MirrorRepository: %s/%s", userName, repoName), + "git", "clone", "--mirror", url, repoPath) if err != nil { return errors.New("git clone --mirror: " + stderr) } @@ -231,9 +233,11 @@ func MirrorUpdate() { return nil } + // TODO: need timeout. repoPath := filepath.Join(setting.RepoRootPath, m.RepoName+".git") - _, stderr, err := com.ExecCmdDir(repoPath, "git", "remote", "update") - if err != nil { + if _, stderr, err := process.ExecDir( + repoPath, fmt.Sprintf("MirrorUpdate: %s", repoPath), + "git", "remote", "update"); err != nil { return errors.New("git remote update: " + stderr) } else if err = git.UnpackRefs(repoPath); err != nil { return err @@ -268,133 +272,34 @@ func MigrateRepository(user *User, name, desc string, private, mirror bool, url return repo, UpdateRepository(repo) } + // TODO: need timeout. // Clone from local repository. - _, stderr, err := com.ExecCmd("git", "clone", repoPath, tmpDir) + _, stderr, err := process.Exec( + fmt.Sprintf("MigrateRepository(git clone): %s", repoPath), + "git", "clone", repoPath, tmpDir) if err != nil { return repo, errors.New("git clone: " + stderr) } + // TODO: need timeout. // Pull data from source. - _, stderr, err = com.ExecCmdDir(tmpDir, "git", "pull", url) - if err != nil { + if _, stderr, err = process.ExecDir( + tmpDir, fmt.Sprintf("MigrateRepository(git pull): %s", repoPath), + "git", "pull", url); err != nil { return repo, errors.New("git pull: " + stderr) } + // TODO: need timeout. // Push data to local repository. - if _, stderr, err = com.ExecCmdDir(tmpDir, "git", "push", "origin", "master"); err != nil { + if _, stderr, err = process.ExecDir( + tmpDir, fmt.Sprintf("MigrateRepository(git push): %s", repoPath), + "git", "push", "origin", "master"); err != nil { return repo, errors.New("git push: " + stderr) } return repo, UpdateRepository(repo) } -// CreateRepository creates a repository for given user or orgnaziation. -func CreateRepository(user *User, name, desc, lang, license string, private, mirror, initReadme bool) (*Repository, error) { - if !IsLegalName(name) { - return nil, ErrRepoNameIllegal - } - - isExist, err := IsRepositoryExist(user, name) - if err != nil { - return nil, err - } else if isExist { - return nil, ErrRepoAlreadyExist - } - - repo := &Repository{ - OwnerId: user.Id, - Name: name, - LowerName: strings.ToLower(name), - Description: desc, - IsPrivate: private, - IsBare: lang == "" && license == "" && !initReadme, - } - if !repo.IsBare { - repo.DefaultBranch = "master" - } - - repoPath := RepoPath(user.Name, repo.Name) - - sess := orm.NewSession() - defer sess.Close() - sess.Begin() - - if _, err = sess.Insert(repo); err != nil { - if err2 := os.RemoveAll(repoPath); err2 != nil { - log.Error("repo.CreateRepository(repo): %v", err) - return nil, errors.New(fmt.Sprintf( - "delete repo directory %s/%s failed(1): %v", user.Name, repo.Name, err2)) - } - sess.Rollback() - return nil, err - } - - mode := AU_WRITABLE - if mirror { - mode = AU_READABLE - } - access := Access{ - UserName: user.LowerName, - RepoName: strings.ToLower(path.Join(user.Name, repo.Name)), - Mode: mode, - } - if _, err = sess.Insert(&access); err != nil { - sess.Rollback() - if err2 := os.RemoveAll(repoPath); err2 != nil { - log.Error("repo.CreateRepository(access): %v", err) - return nil, errors.New(fmt.Sprintf( - "delete repo directory %s/%s failed(2): %v", user.Name, repo.Name, err2)) - } - return nil, err - } - - rawSql := "UPDATE `user` SET num_repos = num_repos + 1 WHERE id = ?" - if _, err = sess.Exec(rawSql, user.Id); err != nil { - sess.Rollback() - if err2 := os.RemoveAll(repoPath); err2 != nil { - log.Error("repo.CreateRepository(repo count): %v", err) - return nil, errors.New(fmt.Sprintf( - "delete repo directory %s/%s failed(3): %v", user.Name, repo.Name, err2)) - } - return nil, err - } - - if err = sess.Commit(); err != nil { - sess.Rollback() - if err2 := os.RemoveAll(repoPath); err2 != nil { - log.Error("repo.CreateRepository(commit): %v", err) - return nil, errors.New(fmt.Sprintf( - "delete repo directory %s/%s failed(3): %v", user.Name, repo.Name, err2)) - } - return nil, err - } - - if err = WatchRepo(user.Id, repo.Id, true); err != nil { - log.Error("repo.CreateRepository(WatchRepo): %v", err) - } - - if err = NewRepoAction(user, repo); err != nil { - log.Error("repo.CreateRepository(NewRepoAction): %v", err) - } - - // No need for init for mirror. - if mirror { - return repo, nil - } - - if err = initRepository(repoPath, user, repo, initReadme, lang, license); err != nil { - return nil, err - } - - c := exec.Command("git", "update-server-info") - c.Dir = repoPath - if err = c.Run(); err != nil { - log.Error("repo.CreateRepository(exec update-server-info): %v", err) - } - - return repo, nil -} - // extractGitBareZip extracts git-bare.zip to repository path. func extractGitBareZip(repoPath string) error { z, err := zip.Open(path.Join(setting.RepoRootPath, "git-bare.zip")) @@ -409,15 +314,22 @@ func extractGitBareZip(repoPath string) error { // initRepoCommit temporarily changes with work directory. func initRepoCommit(tmpPath string, sig *git.Signature) (err error) { var stderr string - if _, stderr, err = com.ExecCmdDir(tmpPath, "git", "add", "--all"); err != nil { + if _, stderr, err = process.ExecDir( + tmpPath, fmt.Sprintf("initRepoCommit(git add): %s", tmpPath), + "git", "add", "--all"); err != nil { return errors.New("git add: " + stderr) } - if _, stderr, err = com.ExecCmdDir(tmpPath, "git", "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), + + if _, stderr, err = process.ExecDir( + tmpPath, fmt.Sprintf("initRepoCommit(git commit): %s", tmpPath), + "git", "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email), "-m", "Init commit"); err != nil { return errors.New("git commit: " + stderr) } - if _, stderr, err = com.ExecCmdDir(tmpPath, "git", "push", "origin", "master"); err != nil { + if _, stderr, err = process.ExecDir( + tmpPath, fmt.Sprintf("initRepoCommit(git push): %s", tmpPath), + "git", "push", "origin", "master"); err != nil { return errors.New("git push: " + stderr) } return nil @@ -475,9 +387,11 @@ func initRepository(f string, user *User, repo *Repository, initReadme bool, rep tmpDir := filepath.Join(os.TempDir(), base.ToStr(time.Now().Nanosecond())) os.MkdirAll(tmpDir, os.ModePerm) - _, stderr, err := com.ExecCmd("git", "clone", repoPath, tmpDir) + _, stderr, err := process.Exec( + fmt.Sprintf("initRepository(git clone): %s", repoPath), + "git", "clone", repoPath, tmpDir) if err != nil { - return errors.New("git clone: " + stderr) + return errors.New("initRepository(git clone): " + stderr) } // README @@ -540,6 +454,114 @@ func initRepository(f string, user *User, repo *Repository, initReadme bool, rep return initRepoCommit(tmpDir, user.NewGitSig()) } +// CreateRepository creates a repository for given user or orgnaziation. +func CreateRepository(user *User, name, desc, lang, license string, private, mirror, initReadme bool) (*Repository, error) { + if !IsLegalName(name) { + return nil, ErrRepoNameIllegal + } + + isExist, err := IsRepositoryExist(user, name) + if err != nil { + return nil, err + } else if isExist { + return nil, ErrRepoAlreadyExist + } + + repo := &Repository{ + OwnerId: user.Id, + Name: name, + LowerName: strings.ToLower(name), + Description: desc, + IsPrivate: private, + IsBare: lang == "" && license == "" && !initReadme, + } + if !repo.IsBare { + repo.DefaultBranch = "master" + } + + repoPath := RepoPath(user.Name, repo.Name) + + sess := orm.NewSession() + defer sess.Close() + sess.Begin() + + if _, err = sess.Insert(repo); err != nil { + if err2 := os.RemoveAll(repoPath); err2 != nil { + log.Error("repo.CreateRepository(repo): %v", err) + return nil, errors.New(fmt.Sprintf( + "delete repo directory %s/%s failed(1): %v", user.Name, repo.Name, err2)) + } + sess.Rollback() + return nil, err + } + + mode := AU_WRITABLE + if mirror { + mode = AU_READABLE + } + access := Access{ + UserName: user.LowerName, + RepoName: strings.ToLower(path.Join(user.Name, repo.Name)), + Mode: mode, + } + if _, err = sess.Insert(&access); err != nil { + sess.Rollback() + if err2 := os.RemoveAll(repoPath); err2 != nil { + log.Error("repo.CreateRepository(access): %v", err) + return nil, errors.New(fmt.Sprintf( + "delete repo directory %s/%s failed(2): %v", user.Name, repo.Name, err2)) + } + return nil, err + } + + rawSql := "UPDATE `user` SET num_repos = num_repos + 1 WHERE id = ?" + if _, err = sess.Exec(rawSql, user.Id); err != nil { + sess.Rollback() + if err2 := os.RemoveAll(repoPath); err2 != nil { + log.Error("repo.CreateRepository(repo count): %v", err) + return nil, errors.New(fmt.Sprintf( + "delete repo directory %s/%s failed(3): %v", user.Name, repo.Name, err2)) + } + return nil, err + } + + if err = sess.Commit(); err != nil { + sess.Rollback() + if err2 := os.RemoveAll(repoPath); err2 != nil { + log.Error("repo.CreateRepository(commit): %v", err) + return nil, errors.New(fmt.Sprintf( + "delete repo directory %s/%s failed(3): %v", user.Name, repo.Name, err2)) + } + return nil, err + } + + if err = WatchRepo(user.Id, repo.Id, true); err != nil { + log.Error("repo.CreateRepository(WatchRepo): %v", err) + } + + if err = NewRepoAction(user, repo); err != nil { + log.Error("repo.CreateRepository(NewRepoAction): %v", err) + } + + // No need for init for mirror. + if mirror { + return repo, nil + } + + if err = initRepository(repoPath, user, repo, initReadme, lang, license); err != nil { + return nil, err + } + + _, stderr, err := process.ExecDir( + repoPath, fmt.Sprintf("CreateRepository(git update-server-info): %s", repoPath), + "git", "update-server-info") + if err != nil { + return nil, errors.New("CreateRepository(git update-server-info): " + stderr) + } + + return repo, nil +} + // GetRepositoriesWithUsers returns given number of repository objects with offset. // It also auto-gets corresponding users. func GetRepositoriesWithUsers(num, offset int) ([]*Repository, error) { diff --git a/modules/process/manager.go b/modules/process/manager.go new file mode 100644 index 00000000..173b2aa4 --- /dev/null +++ b/modules/process/manager.go @@ -0,0 +1,89 @@ +// 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 process + +import ( + "bytes" + "fmt" + "os/exec" + "time" + + "github.com/gogits/gogs/modules/log" +) + +// Process represents a working process inherit from Gogs. +type Process struct { + Pid int64 // Process ID, not system one. + Description string + Start time.Time + Cmd *exec.Cmd +} + +// List of existing processes. +var ( + curPid int64 = 1 + Processes []*Process +) + +// Add adds a existing process and returns its PID. +func Add(desc string, cmd *exec.Cmd) int64 { + pid := curPid + Processes = append(Processes, &Process{ + Pid: pid, + Description: desc, + Start: time.Now(), + Cmd: cmd, + }) + curPid++ + return pid +} + +func ExecDir(dir, desc, cmdName string, args ...string) (string, string, error) { + bufOut := new(bytes.Buffer) + bufErr := new(bytes.Buffer) + + cmd := exec.Command(cmdName, args...) + cmd.Dir = dir + cmd.Stdout = bufOut + cmd.Stderr = bufErr + + pid := Add(desc, cmd) + err := cmd.Run() + if errKill := Kill(pid); errKill != nil { + log.Error("Exec: %v", pid, desc, errKill) + } + return bufOut.String(), bufErr.String(), err +} + +// Exec starts executing a command and record its process. +func Exec(desc, cmdName string, args ...string) (string, string, error) { + return ExecDir("", desc, cmdName, args...) +} + +// Remove removes a process from list. +func Remove(pid int64) { + for i, proc := range Processes { + if proc.Pid == pid { + Processes = append(Processes[:i], Processes[i+1:]...) + return + } + } +} + +// Kill kills and removes a process from list. +func Kill(pid int64) error { + for i, proc := range Processes { + if proc.Pid == pid { + if proc.Cmd.Process != nil && proc.Cmd.ProcessState != nil && !proc.Cmd.ProcessState.Exited() { + if err := proc.Cmd.Process.Kill(); err != nil { + return fmt.Errorf("fail to kill process(%d/%s): %v", proc.Pid, proc.Description, err) + } + } + Processes = append(Processes[:i], Processes[i+1:]...) + return nil + } + } + return nil +} diff --git a/routers/admin/admin.go b/routers/admin/admin.go index d4b49a9e..a14ffae0 100644 --- a/routers/admin/admin.go +++ b/routers/admin/admin.go @@ -16,6 +16,7 @@ import ( "github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/cron" "github.com/gogits/gogs/modules/middleware" + "github.com/gogits/gogs/modules/process" "github.com/gogits/gogs/modules/setting" ) @@ -238,10 +239,12 @@ func Monitor(ctx *middleware.Context) { switch tab { case "process": ctx.Data["PageIsMonitorProcess"] = true + ctx.Data["Processes"] = process.Processes + ctx.HTML(200, "admin/monitor/process") default: ctx.Data["PageIsMonitorCron"] = true ctx.Data["Entries"] = cron.ListEntries() + ctx.HTML(200, "admin/monitor/cron") } - ctx.HTML(200, "admin/monitor/cron") } diff --git a/templates/VERSION b/templates/VERSION index c2606e90..d86ece15 100644 --- a/templates/VERSION +++ b/templates/VERSION @@ -1 +1 @@ -0.4.4.0613 Alpha \ No newline at end of file +0.4.4.0619 Alpha \ No newline at end of file diff --git a/templates/admin/monitor/process.tmpl b/templates/admin/monitor/process.tmpl new file mode 100644 index 00000000..2d60ff68 --- /dev/null +++ b/templates/admin/monitor/process.tmpl @@ -0,0 +1,38 @@ +{{template "base/head" .}} +{{template "base/navbar" .}} +
+ {{template "admin/nav" .}} +
+ +
+
+ {{if .PageIsMonitorProcess}} + + + + + + + + + + + {{range .Processes}} + + + + + + + {{end}} + +
PidDescriptionStart TimeExecution Time
{{.Pid}}{{.Description}}{{.Start}}{{TimeSince .Start}}
+ {{end}} +
+
+
+
+{{template "base/footer" .}} \ No newline at end of file -- cgit v1.2.3 From 8bfa7ae7453e56191aa6f7de8067d5b6bb5a4a8b Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 20 Jun 2014 01:14:54 -0400 Subject: Remove qiniu/log --- cmd/serve.go | 58 ++++++++++++++++------------------------------------ cmd/update.go | 20 ++++-------------- models/action.go | 3 +-- models/publickey.go | 7 +++---- models/update.go | 23 ++++++++++----------- modules/log/log.go | 11 +++++++++- routers/install.go | 1 + routers/repo/http.go | 16 +++++++-------- 8 files changed, 56 insertions(+), 83 deletions(-) (limited to 'cmd/serve.go') diff --git a/cmd/serve.go b/cmd/serve.go index a21500c7..62e290d8 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -13,9 +13,9 @@ import ( "strings" "github.com/codegangsta/cli" - qlog "github.com/qiniu/log" "github.com/gogits/gogs/models" + "github.com/gogits/gogs/modules/log" "github.com/gogits/gogs/modules/setting" ) @@ -27,26 +27,13 @@ var CmdServ = cli.Command{ Flags: []cli.Flag{}, } -func newLogger(logPath string) { - os.MkdirAll(path.Dir(logPath), os.ModePerm) - - f, err := os.OpenFile(logPath, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.ModePerm) - if err != nil { - qlog.Fatal("Fail to open log file(%s): %v", logPath, err) - } - - qlog.SetOutput(f) - qlog.Info("Start logging serv...") -} - func setup(logPath string) { - workDir, _ := setting.WorkDir() - newLogger(path.Join(workDir, logPath)) - setting.NewConfigContext() + log.NewGitLogger(path.Join(setting.LogRootPath, logPath)) models.LoadModelsConfig() if models.UseSQLite3 { + workDir, _ := setting.WorkDir() os.Chdir(workDir) } @@ -87,27 +74,27 @@ func In(b string, sl map[string]int) bool { } func runServ(k *cli.Context) { - setup(path.Join(setting.LogRootPath, "serv.log")) + setup("serv.log") keys := strings.Split(os.Args[2], "-") if len(keys) != 2 { println("Gogs: auth file format error") - qlog.Fatal("Invalid auth file format: %s", os.Args[2]) + log.GitLogger.Fatal("Invalid auth file format: %s", os.Args[2]) } keyId, err := strconv.ParseInt(keys[1], 10, 64) if err != nil { println("Gogs: auth file format error") - qlog.Fatalf("Invalid auth file format: %v", err) + log.GitLogger.Fatal("Invalid auth file format: %v", err) } user, err := models.GetUserByKeyId(keyId) if err != nil { if err == models.ErrUserNotKeyOwner { println("Gogs: you are not the owner of SSH key") - qlog.Fatalf("Invalid owner of SSH key: %d", keyId) + log.GitLogger.Fatal("Invalid owner of SSH key: %d", keyId) } println("Gogs: internal error:", err) - qlog.Fatalf("Fail to get user by key ID(%d): %v", keyId, err) + log.GitLogger.Fatal("Fail to get user by key ID(%d): %v", keyId, err) } cmd := os.Getenv("SSH_ORIGINAL_COMMAND") @@ -121,7 +108,7 @@ func runServ(k *cli.Context) { rr := strings.SplitN(repoPath, "/", 2) if len(rr) != 2 { println("Gogs: unavailable repository", args) - qlog.Fatalf("Unavailable repository: %v", args) + log.GitLogger.Fatal("Unavailable repository: %v", args) } repoUserName := rr[0] repoName := strings.TrimSuffix(rr[1], ".git") @@ -133,10 +120,10 @@ func runServ(k *cli.Context) { if err != nil { if err == models.ErrUserNotExist { println("Gogs: given repository owner are not registered") - qlog.Fatalf("Unregistered owner: %s", repoUserName) + log.GitLogger.Fatal("Unregistered owner: %s", repoUserName) } println("Gogs: internal error:", err) - qlog.Fatalf("Fail to get repository owner(%s): %v", repoUserName, err) + log.GitLogger.Fatal("Fail to get repository owner(%s): %v", repoUserName, err) } // Access check. @@ -145,20 +132,20 @@ func runServ(k *cli.Context) { has, err := models.HasAccess(user.Name, path.Join(repoUserName, repoName), models.AU_WRITABLE) if err != nil { println("Gogs: internal error:", err) - qlog.Fatal("Fail to check write access:", err) + log.GitLogger.Fatal("Fail to check write access:", err) } else if !has { println("You have no right to write this repository") - qlog.Fatalf("User %s has no right to write repository %s", user.Name, repoPath) + log.GitLogger.Fatal("User %s has no right to write repository %s", user.Name, repoPath) } case isRead: repo, err := models.GetRepositoryByName(repoUser.Id, repoName) if err != nil { if err == models.ErrRepoNotExist { println("Gogs: given repository does not exist") - qlog.Fatalf("Repository does not exist: %s/%s", repoUser.Name, repoName) + log.GitLogger.Fatal("Repository does not exist: %s/%s", repoUser.Name, repoName) } println("Gogs: internal error:", err) - qlog.Fatalf("Fail to get repository: %v", err) + log.GitLogger.Fatal("Fail to get repository: %v", err) } if !repo.IsPrivate { @@ -168,10 +155,10 @@ func runServ(k *cli.Context) { has, err := models.HasAccess(user.Name, path.Join(repoUserName, repoName), models.AU_READABLE) if err != nil { println("Gogs: internal error:", err) - qlog.Fatal("Fail to check read access:", err) + log.GitLogger.Fatal("Fail to check read access:", err) } else if !has { println("You have no right to access this repository") - qlog.Fatalf("User %s has no right to read repository %s", user.Name, repoPath) + log.GitLogger.Fatal("User %s has no right to read repository %s", user.Name, repoPath) } default: println("Unknown command") @@ -188,15 +175,6 @@ func runServ(k *cli.Context) { err = gitcmd.Run() if err != nil { println("Gogs: internal error:", err) - qlog.Fatalf("Fail to execute git command: %v", err) + log.GitLogger.Fatal("Fail to execute git command: %v", err) } - - //refName := os.Getenv("refName") - //oldCommitId := os.Getenv("oldCommitId") - //newCommitId := os.Getenv("newCommitId") - - //qlog.Error("get envs:", refName, oldCommitId, newCommitId) - - // update - //models.Update(refName, oldCommitId, newCommitId, repoUserName, repoName, user.Id) } diff --git a/cmd/update.go b/cmd/update.go index b8686a3e..d0e0acde 100644 --- a/cmd/update.go +++ b/cmd/update.go @@ -6,14 +6,12 @@ package cmd import ( "os" - "path" "strconv" "github.com/codegangsta/cli" - qlog "github.com/qiniu/log" "github.com/gogits/gogs/models" - "github.com/gogits/gogs/modules/setting" + "github.com/gogits/gogs/modules/log" ) var CmdUpdate = cli.Command{ @@ -24,33 +22,23 @@ var CmdUpdate = cli.Command{ Flags: []cli.Flag{}, } -func updateEnv(refName, oldCommitId, newCommitId string) { - os.Setenv("refName", refName) - os.Setenv("oldCommitId", oldCommitId) - os.Setenv("newCommitId", newCommitId) - qlog.Info("set envs:", refName, oldCommitId, newCommitId) -} - func runUpdate(c *cli.Context) { cmd := os.Getenv("SSH_ORIGINAL_COMMAND") if cmd == "" { return } - setup(path.Join(setting.LogRootPath, "update.log")) + setup("update.log") args := c.Args() if len(args) != 3 { - qlog.Fatal("received less 3 parameters") + log.GitLogger.Fatal("received less 3 parameters") } else if args[0] == "" { - qlog.Fatal("refName is empty, shouldn't use") + log.GitLogger.Fatal("refName is empty, shouldn't use") } - //updateEnv(args[0], args[1], args[2]) - userName := os.Getenv("userName") userId, _ := strconv.ParseInt(os.Getenv("userId"), 10, 64) - //repoId := os.Getenv("repoId") repoUserName := os.Getenv("repoUserName") repoName := os.Getenv("repoName") diff --git a/models/action.go b/models/action.go index e39b04a1..28468233 100644 --- a/models/action.go +++ b/models/action.go @@ -12,7 +12,6 @@ import ( "time" "github.com/gogits/git" - qlog "github.com/qiniu/log" "github.com/gogits/gogs/modules/base" "github.com/gogits/gogs/modules/log" @@ -115,7 +114,7 @@ func CommitRepoAction(userId, repoUserId int64, userName, actEmail string, return errors.New("action.CommitRepoAction(NotifyWatchers): " + err.Error()) } - qlog.Info("action.CommitRepoAction(end): %d/%s", repoUserId, repoName) + //qlog.Info("action.CommitRepoAction(end): %d/%s", repoUserId, repoName) // New push event hook. if err := repo.GetOwner(); err != nil { diff --git a/models/publickey.go b/models/publickey.go index 72b45c5b..b0021a68 100644 --- a/models/publickey.go +++ b/models/publickey.go @@ -19,7 +19,6 @@ import ( "time" "github.com/Unknwon/com" - qlog "github.com/qiniu/log" "github.com/gogits/gogs/modules/log" "github.com/gogits/gogs/modules/process" @@ -55,7 +54,7 @@ func exePath() (string, error) { func homeDir() string { home, err := com.HomeDir() if err != nil { - qlog.Fatalln(err) + log.Fatal("Fail to get home directory: %v", err) } return home } @@ -64,13 +63,13 @@ func init() { var err error if appPath, err = exePath(); err != nil { - qlog.Fatalf("publickey.init(fail to get app path): %v\n", err) + log.Fatal("publickey.init(fail to get app path): %v\n", err) } // Determine and create .ssh path. SshPath = filepath.Join(homeDir(), ".ssh") if err = os.MkdirAll(SshPath, os.ModePerm); err != nil { - qlog.Fatalf("publickey.init(fail to create SshPath(%s)): %v\n", SshPath, err) + log.Fatal("publickey.init(fail to create SshPath(%s)): %v\n", SshPath, err) } } diff --git a/models/update.go b/models/update.go index b7242cde..5675a94c 100644 --- a/models/update.go +++ b/models/update.go @@ -9,18 +9,17 @@ import ( "os/exec" "strings" - qlog "github.com/qiniu/log" - "github.com/gogits/git" "github.com/gogits/gogs/modules/base" + "github.com/gogits/gogs/modules/log" ) func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName string, userId int64) { isNew := strings.HasPrefix(oldCommitId, "0000000") if isNew && strings.HasPrefix(newCommitId, "0000000") { - qlog.Fatal("old rev and new rev both 000000") + log.GitLogger.Fatal("old rev and new rev both 000000") } f := RepoPath(repoUserName, repoName) @@ -31,18 +30,18 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName isDel := strings.HasPrefix(newCommitId, "0000000") if isDel { - qlog.Info("del rev", refName, "from", userName+"/"+repoName+".git", "by", userId) + log.GitLogger.Info("del rev", refName, "from", userName+"/"+repoName+".git", "by", userId) return } repo, err := git.OpenRepository(f) if err != nil { - qlog.Fatalf("runUpdate.Open repoId: %v", err) + log.GitLogger.Fatal("runUpdate.Open repoId: %v", err) } newCommit, err := repo.GetCommit(newCommitId) if err != nil { - qlog.Fatalf("runUpdate GetCommit of newCommitId: %v", err) + log.GitLogger.Fatal("runUpdate GetCommit of newCommitId: %v", err) return } @@ -51,28 +50,28 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName if isNew { l, err = newCommit.CommitsBefore() if err != nil { - qlog.Fatalf("Find CommitsBefore erro: %v", err) + log.GitLogger.Fatal("Find CommitsBefore erro: %v", err) } } else { l, err = newCommit.CommitsBeforeUntil(oldCommitId) if err != nil { - qlog.Fatalf("Find CommitsBeforeUntil erro: %v", err) + log.GitLogger.Fatal("Find CommitsBeforeUntil erro: %v", err) return } } if err != nil { - qlog.Fatalf("runUpdate.Commit repoId: %v", err) + log.GitLogger.Fatal("runUpdate.Commit repoId: %v", err) } ru, err := GetUserByName(repoUserName) if err != nil { - qlog.Fatalf("runUpdate.GetUserByName: %v", err) + log.GitLogger.Fatal("runUpdate.GetUserByName: %v", err) } repos, err := GetRepositoryByName(ru.Id, repoName) if err != nil { - qlog.Fatalf("runUpdate.GetRepositoryByName userId: %v", err) + log.GitLogger.Fatal("runUpdate.GetRepositoryByName userId: %v", err) } commits := make([]*base.PushCommit, 0) @@ -96,6 +95,6 @@ func Update(refName, oldCommitId, newCommitId, userName, repoUserName, repoName //commits = append(commits, []string{lastCommit.Id().String(), lastCommit.Message()}) if err = CommitRepoAction(userId, ru.Id, userName, actEmail, repos.Id, repoUserName, repoName, refName, &base.PushCommits{l.Len(), commits}); err != nil { - qlog.Fatalf("runUpdate.models.CommitRepoAction: %s/%s:%v", repoUserName, repoName, err) + log.GitLogger.Fatal("runUpdate.models.CommitRepoAction: %s/%s:%v", repoUserName, repoName, err) } } diff --git a/modules/log/log.go b/modules/log/log.go index a62baad1..24f0442d 100644 --- a/modules/log/log.go +++ b/modules/log/log.go @@ -6,13 +6,16 @@ package log import ( + "fmt" "os" + "path" "github.com/gogits/logs" ) var ( - loggers []*logs.BeeLogger + loggers []*logs.BeeLogger + GitLogger *logs.BeeLogger ) func init() { @@ -38,6 +41,12 @@ func NewLogger(bufLen int64, mode, config string) { } } +func NewGitLogger(logPath string) { + os.MkdirAll(path.Dir(logPath), os.ModePerm) + GitLogger = logs.NewLogger(0) + GitLogger.SetLogger("file", fmt.Sprintf(`{"level":0,"filename":"%s","rotate":false}`, logPath)) +} + func Trace(format string, v ...interface{}) { for _, logger := range loggers { logger.Trace(format, v...) diff --git a/routers/install.go b/routers/install.go index eb0fc199..c2eee88a 100644 --- a/routers/install.go +++ b/routers/install.go @@ -60,6 +60,7 @@ func GlobalInit() { models.HasEngine = true cron.NewCronContext() + log.NewGitLogger(path.Join(setting.LogRootPath, "http.log")) } if models.EnableSQLite3 { log.Info("SQLite3 Enabled") diff --git a/routers/repo/http.go b/routers/repo/http.go index c5856d60..5915e876 100644 --- a/routers/repo/http.go +++ b/routers/repo/http.go @@ -9,7 +9,6 @@ import ( "fmt" "io" "io/ioutil" - "log" "net/http" "os" "os/exec" @@ -22,6 +21,7 @@ import ( "github.com/go-martini/martini" "github.com/gogits/gogs/models" + "github.com/gogits/gogs/modules/log" "github.com/gogits/gogs/modules/middleware" "github.com/gogits/gogs/modules/setting" ) @@ -190,7 +190,7 @@ var routes = []route{ // Request handling function func HttpBackend(config *Config) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - //log.Printf("%s %s %s %s", r.RemoteAddr, r.Method, r.URL.Path, r.Proto) + //log.GitLogger.Printf("%s %s %s %s", r.RemoteAddr, r.Method, r.URL.Path, r.Proto) for _, route := range routes { if m := route.cr.FindStringSubmatch(r.URL.Path); m != nil { if route.method != r.Method { @@ -202,7 +202,7 @@ func HttpBackend(config *Config) http.HandlerFunc { dir, err := getGitDir(config, m[1]) if err != nil { - log.Print(err) + log.GitLogger.Error(err.Error()) renderNotFound(w) return } @@ -246,19 +246,19 @@ func serviceRpc(rpc string, hr handler) { cmd.Dir = dir in, err := cmd.StdinPipe() if err != nil { - log.Print(err) + log.GitLogger.Error(err.Error()) return } stdout, err := cmd.StdoutPipe() if err != nil { - log.Print(err) + log.GitLogger.Error(err.Error()) return } err = cmd.Start() if err != nil { - log.Print(err) + log.GitLogger.Error(err.Error()) return } @@ -345,7 +345,7 @@ func getGitDir(config *Config, fPath string) (string, error) { cwd, err := os.Getwd() if err != nil { - log.Print(err) + log.GitLogger.Error(err.Error()) return "", err } @@ -422,7 +422,7 @@ func gitCommand(gitBinPath, dir string, args ...string) []byte { out, err := command.Output() if err != nil { - log.Print(err) + log.GitLogger.Error(err.Error()) } return out -- cgit v1.2.3 From e0f9c628c5ff7399167944b3d0730698487af498 Mon Sep 17 00:00:00 2001 From: Unknown Date: Wed, 25 Jun 2014 00:44:48 -0400 Subject: Add create organization --- cmd/serve.go | 20 ++--- cmd/web.go | 5 +- gogs.go | 2 +- models/access.go | 17 ++-- models/issue.go | 4 +- models/login.go | 4 +- models/models.go | 2 +- models/org.go | 69 ++++++++++++++++ models/repo.go | 10 ++- models/user.go | 186 +++++++++++++++++++++++++++++++++--------- modules/auth/org.go | 33 ++++++++ modules/middleware/repo.go | 4 +- routers/admin/user.go | 4 +- routers/install.go | 2 +- routers/org/org.go | 96 ++++++++++++++++++++-- routers/repo/http.go | 8 +- routers/repo/setting.go | 4 +- routers/user/home.go | 13 ++- routers/user/user.go | 7 +- templates/VERSION | 2 +- templates/org/dashboard.tmpl | 73 ----------------- templates/org/new.tmpl | 24 +----- templates/user/dashboard.tmpl | 39 ++++++--- templates/user/issues.tmpl | 3 +- 24 files changed, 436 insertions(+), 195 deletions(-) create mode 100644 models/org.go create mode 100644 modules/auth/org.go delete mode 100644 templates/org/dashboard.tmpl (limited to 'cmd/serve.go') diff --git a/cmd/serve.go b/cmd/serve.go index 62e290d8..2a76da79 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -56,19 +56,19 @@ func parseCmd(cmd string) (string, string) { } var ( - COMMANDS_READONLY = map[string]int{ - "git-upload-pack": models.AU_WRITABLE, - "git upload-pack": models.AU_WRITABLE, - "git-upload-archive": models.AU_WRITABLE, + COMMANDS_READONLY = map[string]models.AccessType{ + "git-upload-pack": models.WRITABLE, + "git upload-pack": models.WRITABLE, + "git-upload-archive": models.WRITABLE, } - COMMANDS_WRITE = map[string]int{ - "git-receive-pack": models.AU_READABLE, - "git receive-pack": models.AU_READABLE, + COMMANDS_WRITE = map[string]models.AccessType{ + "git-receive-pack": models.READABLE, + "git receive-pack": models.READABLE, } ) -func In(b string, sl map[string]int) bool { +func In(b string, sl map[string]models.AccessType) bool { _, e := sl[b] return e } @@ -129,7 +129,7 @@ func runServ(k *cli.Context) { // Access check. switch { case isWrite: - has, err := models.HasAccess(user.Name, path.Join(repoUserName, repoName), models.AU_WRITABLE) + has, err := models.HasAccess(user.Name, path.Join(repoUserName, repoName), models.WRITABLE) if err != nil { println("Gogs: internal error:", err) log.GitLogger.Fatal("Fail to check write access:", err) @@ -152,7 +152,7 @@ func runServ(k *cli.Context) { break } - has, err := models.HasAccess(user.Name, path.Join(repoUserName, repoName), models.AU_READABLE) + has, err := models.HasAccess(user.Name, path.Join(repoUserName, repoName), models.READABLE) if err != nil { println("Gogs: internal error:", err) log.GitLogger.Fatal("Fail to check read access:", err) diff --git a/cmd/web.go b/cmd/web.go index d29183a9..878fdeac 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -188,14 +188,15 @@ func runWeb(*cli.Context) { reqOwner := middleware.RequireOwner() - m.Group("/o", func(r martini.Router) { + m.Group("/org", func(r martini.Router) { r.Get("/create", org.New) + r.Post("/create", bindIgnErr(auth.CreateOrganizationForm{}), org.NewPost) r.Get("/:org", org.Organization) r.Get("/:org/dashboard", org.Dashboard) r.Get("/:org/members", org.Members) r.Get("/:org/teams", org.Teams) r.Get("/:org/setting", org.Setting) - }) + }, reqSignIn) m.Group("/:username/:reponame", func(r martini.Router) { r.Get("/settings", repo.Setting) diff --git a/gogs.go b/gogs.go index 75d3eb4b..5c2c6ed9 100644 --- a/gogs.go +++ b/gogs.go @@ -17,7 +17,7 @@ import ( "github.com/gogits/gogs/modules/setting" ) -const APP_VER = "0.4.5.0624 Alpha" +const APP_VER = "0.4.5.0625 Alpha" func init() { runtime.GOMAXPROCS(runtime.NumCPU()) diff --git a/models/access.go b/models/access.go index cf31fc13..5238daba 100644 --- a/models/access.go +++ b/models/access.go @@ -11,19 +11,20 @@ import ( "github.com/go-xorm/xorm" ) -// Access types. +type AccessType int + const ( - AU_READABLE = iota + 1 - AU_WRITABLE + READABLE AccessType = iota + 1 + WRITABLE ) // Access represents the accessibility of user to repository. type Access struct { Id int64 - UserName string `xorm:"unique(s)"` - RepoName string `xorm:"unique(s)"` // / - Mode int `xorm:"unique(s)"` - Created time.Time `xorm:"created"` + UserName string `xorm:"unique(s)"` + RepoName string `xorm:"unique(s)"` // / + Mode AccessType `xorm:"unique(s)"` + Created time.Time `xorm:"created"` } // AddAccess adds new access record. @@ -59,7 +60,7 @@ func UpdateAccessWithSession(sess *xorm.Session, access *Access) error { // HasAccess returns true if someone can read or write to given repository. // The repoName should be in format /. -func HasAccess(uname, repoName string, mode int) (bool, error) { +func HasAccess(uname, repoName string, mode AccessType) (bool, error) { if len(repoName) == 0 { return false, nil } diff --git a/models/issue.go b/models/issue.go index 11f6dd4e..6d67a72b 100644 --- a/models/issue.go +++ b/models/issue.go @@ -213,9 +213,9 @@ func GetIssueCountByPoster(uid, rid int64, isClosed bool) int64 { // IssueUser represents an issue-user relation. type IssueUser struct { Id int64 - Uid int64 // User ID. + Uid int64 `xorm:"INDEX"` // User ID. IssueId int64 - RepoId int64 + RepoId int64 `xorm:"INDEX"` MilestoneId int64 IsRead bool IsAssigned bool diff --git a/models/login.go b/models/login.go index 98c5c64e..e99b61e7 100644 --- a/models/login.go +++ b/models/login.go @@ -255,7 +255,7 @@ func LoginUserLdapSource(user *User, name, passwd string, sourceId int64, cfg *L Email: mail, } - return RegisterUser(user) + return CreateUser(user) } type loginAuth struct { @@ -359,5 +359,5 @@ func LoginUserSMTPSource(user *User, name, passwd string, sourceId int64, cfg *S Passwd: passwd, Email: name, } - return RegisterUser(user) + return CreateUser(user) } diff --git a/models/models.go b/models/models.go index d6273d7f..4e65c00b 100644 --- a/models/models.go +++ b/models/models.go @@ -35,7 +35,7 @@ func init() { tables = append(tables, new(User), new(PublicKey), new(Repository), new(Watch), new(Action), new(Access), new(Issue), new(Comment), new(Oauth2), new(Follow), new(Mirror), new(Release), new(LoginSource), new(Webhook), new(IssueUser), - new(Milestone), new(Label), new(HookTask)) + new(Milestone), new(Label), new(HookTask), new(Team), new(OrgUser), new(TeamUser)) } func LoadModelsConfig() { diff --git a/models/org.go b/models/org.go new file mode 100644 index 00000000..1cfe1798 --- /dev/null +++ b/models/org.go @@ -0,0 +1,69 @@ +// 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 AuthorizeType int + +const ( + ORG_READABLE AuthorizeType = iota + 1 + ORG_WRITABLE + ORG_ADMIN +) + +// Team represents a organization team. +type Team struct { + Id int64 + OrgId int64 `xorm:"INDEX"` + Name string + Description string + Authorize AuthorizeType + NumMembers int + NumRepos int +} + +// NewTeam creates a record of new team. +func NewTeam(t *Team) error { + _, err := x.Insert(t) + return err +} + +// ________ ____ ___ +// \_____ \_______ ____ | | \______ ___________ +// / | \_ __ \/ ___\| | / ___// __ \_ __ \ +// / | \ | \/ /_/ > | /\___ \\ ___/| | \/ +// \_______ /__| \___ /|______//____ >\___ >__| +// \/ /_____/ \/ \/ + +// OrgUser represents an organization-user relation. +type OrgUser struct { + Id int64 + Uid int64 `xorm:"INDEX"` + OrgId int64 `xorm:"INDEX"` + IsPublic bool + IsOwner bool + NumTeam int +} + +// GetOrgUsersByUserId returns all organization-user relations by user ID. +func GetOrgUsersByUserId(uid int64) ([]*OrgUser, error) { + ous := make([]*OrgUser, 0, 10) + err := x.Where("uid=?", uid).Find(&ous) + return ous, err +} + +// ___________ ____ ___ +// \__ ___/___ _____ _____ | | \______ ___________ +// | |_/ __ \\__ \ / \| | / ___// __ \_ __ \ +// | |\ ___/ / __ \| Y Y \ | /\___ \\ ___/| | \/ +// |____| \___ >____ /__|_| /______//____ >\___ >__| +// \/ \/ \/ \/ \/ + +// TeamUser represents an team-user relation. +type TeamUser struct { + Id int64 + Uid int64 + OrgId int64 `xorm:"INDEX"` + TeamId int64 +} diff --git a/models/repo.go b/models/repo.go index 4ccaccbf..f0e46c71 100644 --- a/models/repo.go +++ b/models/repo.go @@ -158,7 +158,7 @@ func IsRepositoryExist(u *User, repoName string) (bool, error) { } var ( - illegalEquals = []string{"raw", "install", "api", "avatar", "user", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin"} + illegalEquals = []string{"raw", "install", "api", "avatar", "user", "org", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin"} illegalSuffixs = []string{".git"} ) @@ -483,7 +483,9 @@ func CreateRepository(user *User, name, desc, lang, license string, private, mir sess := x.NewSession() defer sess.Close() - sess.Begin() + if err = sess.Begin(); err != nil { + return nil, err + } if _, err = sess.Insert(repo); err != nil { if err2 := os.RemoveAll(repoPath); err2 != nil { @@ -495,9 +497,9 @@ func CreateRepository(user *User, name, desc, lang, license string, private, mir return nil, err } - mode := AU_WRITABLE + mode := WRITABLE if mirror { - mode = AU_READABLE + mode = READABLE } access := Access{ UserName: user.LowerName, diff --git a/models/user.go b/models/user.go index 50d81c94..2388be9a 100644 --- a/models/user.go +++ b/models/user.go @@ -21,10 +21,11 @@ import ( "github.com/gogits/gogs/modules/setting" ) -// User types. +type UserType int + const ( - UT_INDIVIDUAL = iota + 1 - UT_ORGANIZATION + INDIVIDUAL UserType = iota // Historic reason to make it starts at 0. + ORGANIZATION ) var ( @@ -50,7 +51,8 @@ type User struct { LoginType LoginType LoginSource int64 `xorm:"not null default 0"` LoginName string - Type int + Type UserType + Orgs []*User `xorm:"-"` NumFollowers int NumFollowings int NumStars int @@ -65,36 +67,60 @@ type User struct { Salt string `xorm:"VARCHAR(10)"` Created time.Time `xorm:"created"` Updated time.Time `xorm:"updated"` + + // For organization. + NumTeams int + NumMembers int } // HomeLink returns the user home page link. -func (user *User) HomeLink() string { - return "/user/" + user.Name +func (u *User) HomeLink() string { + return "/user/" + u.Name } // AvatarLink returns user gravatar link. -func (user *User) AvatarLink() string { +func (u *User) AvatarLink() string { if setting.DisableGravatar { return "/img/avatar_default.jpg" } else if setting.Service.EnableCacheAvatar { - return "/avatar/" + user.Avatar + return "/avatar/" + u.Avatar } - return "//1.gravatar.com/avatar/" + user.Avatar + return "//1.gravatar.com/avatar/" + u.Avatar } // NewGitSig generates and returns the signature of given user. -func (user *User) NewGitSig() *git.Signature { +func (u *User) NewGitSig() *git.Signature { return &git.Signature{ - Name: user.Name, - Email: user.Email, + Name: u.Name, + Email: u.Email, When: time.Now(), } } // EncodePasswd encodes password to safe format. -func (user *User) EncodePasswd() { - newPasswd := base.PBKDF2([]byte(user.Passwd), []byte(user.Salt), 10000, 50, sha256.New) - user.Passwd = fmt.Sprintf("%x", newPasswd) +func (u *User) EncodePasswd() { + newPasswd := base.PBKDF2([]byte(u.Passwd), []byte(u.Salt), 10000, 50, sha256.New) + u.Passwd = fmt.Sprintf("%x", newPasswd) +} + +func (u *User) IsOrganization() bool { + return u.Type == ORGANIZATION +} + +func (u *User) GetOrganizations() error { + ous, err := GetOrgUsersByUserId(u.Id) + if err != nil { + return err + } + + u.Orgs = make([]*User, len(ous)) + for i, ou := range ous { + u.Orgs[i], err = GetUserById(ou.OrgId) + if err != nil { + return err + } + } + return nil } // Member represents user is member of organization. @@ -126,49 +152,135 @@ func GetUserSalt() string { return base.GetRandomString(10) } -// RegisterUser creates record of a new user. -func RegisterUser(user *User) (*User, error) { +// CreateUser creates record of a new user. +func CreateUser(u *User) (*User, error) { + if !IsLegalName(u.Name) { + return nil, ErrUserNameIllegal + } + + isExist, err := IsUserExist(u.Name) + if err != nil { + return nil, err + } else if isExist { + return nil, ErrUserAlreadyExist + } + + isExist, err = IsEmailUsed(u.Email) + if err != nil { + return nil, err + } else if isExist { + return nil, ErrEmailAlreadyUsed + } + + u.LowerName = strings.ToLower(u.Name) + u.Avatar = base.EncodeMd5(u.Email) + u.AvatarEmail = u.Email + u.Rands = GetUserSalt() + u.Salt = GetUserSalt() + u.EncodePasswd() + + sess := x.NewSession() + defer sess.Close() + if err = sess.Begin(); err != nil { + return nil, err + } - if !IsLegalName(user.Name) { + if _, err = sess.Insert(u); err != nil { + sess.Rollback() + return nil, err + } + + if err = os.MkdirAll(UserPath(u.Name), os.ModePerm); err != nil { + sess.Rollback() + return nil, err + } + + if err = sess.Commit(); err != nil { + return nil, err + } + + // Auto-set admin for user whose ID is 1. + if u.Id == 1 { + u.IsAdmin = true + u.IsActive = true + _, err = x.Id(u.Id).UseBool().Update(u) + } + return u, err +} + +// CreateOrganization creates record of a new organization. +func CreateOrganization(org, owner *User) (*User, error) { + if !IsLegalName(org.Name) { return nil, ErrUserNameIllegal } - isExist, err := IsUserExist(user.Name) + isExist, err := IsUserExist(org.Name) if err != nil { return nil, err } else if isExist { return nil, ErrUserAlreadyExist } - isExist, err = IsEmailUsed(user.Email) + isExist, err = IsEmailUsed(org.Email) if err != nil { return nil, err } else if isExist { return nil, ErrEmailAlreadyUsed } - user.LowerName = strings.ToLower(user.Name) - user.Avatar = base.EncodeMd5(user.Email) - user.AvatarEmail = user.Email - user.Rands = GetUserSalt() - user.Salt = GetUserSalt() - user.EncodePasswd() - if _, err = x.Insert(user); err != nil { + org.LowerName = strings.ToLower(org.Name) + org.Avatar = base.EncodeMd5(org.Email) + org.AvatarEmail = org.Email + // No password for organization. + org.NumTeams = 1 + org.NumMembers = 1 + + sess := x.NewSession() + defer sess.Close() + if err = sess.Begin(); err != nil { + return nil, err + } + + if _, err = sess.Insert(org); err != nil { + sess.Rollback() return nil, err - } else if err = os.MkdirAll(UserPath(user.Name), os.ModePerm); err != nil { - if _, err := x.Id(user.Id).Delete(&User{}); err != nil { - return nil, errors.New(fmt.Sprintf( - "both create userpath %s and delete table record faild: %v", user.Name, err)) - } + } + + // Create default owner team. + t := &Team{ + OrgId: org.Id, + Name: "Owner", + Authorize: ORG_ADMIN, + NumMembers: 1, + } + if _, err = sess.Insert(t); err != nil { + sess.Rollback() return nil, err } - if user.Id == 1 { - user.IsAdmin = true - user.IsActive = true - _, err = x.Id(user.Id).UseBool().Update(user) + // Add initial creator to organization and owner team. + ou := &OrgUser{ + Uid: owner.Id, + OrgId: org.Id, + IsOwner: true, + NumTeam: 1, } - return user, err + if _, err = sess.Insert(ou); err != nil { + sess.Rollback() + return nil, err + } + + tu := &TeamUser{ + Uid: owner.Id, + OrgId: org.Id, + TeamId: t.Id, + } + if _, err = sess.Insert(tu); err != nil { + sess.Rollback() + return nil, err + } + + return org, sess.Commit() } // GetUsers returns given number of user objects with offset. diff --git a/modules/auth/org.go b/modules/auth/org.go new file mode 100644 index 00000000..a60fbb85 --- /dev/null +++ b/modules/auth/org.go @@ -0,0 +1,33 @@ +// 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/go-martini/martini" + + "github.com/gogits/gogs/modules/base" + "github.com/gogits/gogs/modules/middleware/binding" +) + +type CreateOrganizationForm struct { + OrgName string `form:"orgname" binding:"Required;AlphaDashDot;MaxSize(30)"` + Email string `form:"email" binding:"Required;Email;MaxSize(50)"` +} + +func (f *CreateOrganizationForm) Name(field string) string { + names := map[string]string{ + "OrgName": "Organization name", + "Email": "E-mail address", + } + return names[field] +} + +func (f *CreateOrganizationForm) Validate(errs *binding.Errors, req *http.Request, ctx martini.Context) { + data := ctx.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) + validate(errs, data, f) +} diff --git a/modules/middleware/repo.go b/modules/middleware/repo.go index 6c77ed2a..43ba1e8c 100644 --- a/modules/middleware/repo.go +++ b/modules/middleware/repo.go @@ -46,7 +46,7 @@ func RepoAssignment(redirect bool, args ...bool) martini.Handler { // Collaborators who have write access can be seen as owners. if ctx.IsSigned { - ctx.Repo.IsOwner, err = models.HasAccess(ctx.User.Name, userName+"/"+repoName, models.AU_WRITABLE) + ctx.Repo.IsOwner, err = models.HasAccess(ctx.User.Name, userName+"/"+repoName, models.WRITABLE) if err != nil { ctx.Handle(500, "RepoAssignment(HasAccess)", err) return @@ -107,7 +107,7 @@ func RepoAssignment(redirect bool, args ...bool) martini.Handler { return } - hasAccess, err := models.HasAccess(ctx.User.Name, ctx.Repo.Owner.Name+"/"+repo.Name, models.AU_READABLE) + hasAccess, err := models.HasAccess(ctx.User.Name, ctx.Repo.Owner.Name+"/"+repo.Name, models.READABLE) if err != nil { ctx.Handle(500, "RepoAssignment(HasAccess)", err) return diff --git a/routers/admin/user.go b/routers/admin/user.go index d1bbb480..cf99db2b 100644 --- a/routers/admin/user.go +++ b/routers/admin/user.go @@ -67,7 +67,7 @@ func NewUserPost(ctx *middleware.Context, form auth.RegisterForm) { } var err error - if u, err = models.RegisterUser(u); err != nil { + if u, err = models.CreateUser(u); err != nil { switch err { case models.ErrUserAlreadyExist: ctx.RenderWithErr("Username has been already taken", USER_NEW, &form) @@ -76,7 +76,7 @@ func NewUserPost(ctx *middleware.Context, form auth.RegisterForm) { case models.ErrUserNameIllegal: ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), USER_NEW, &form) default: - ctx.Handle(500, "admin.user.NewUser(RegisterUser)", err) + ctx.Handle(500, "admin.user.NewUser(CreateUser)", err) } return } diff --git a/routers/install.go b/routers/install.go index 6ce7c980..bb3c16ea 100644 --- a/routers/install.go +++ b/routers/install.go @@ -227,7 +227,7 @@ func InstallPost(ctx *middleware.Context, form auth.InstallForm) { GlobalInit() // Create admin account. - if _, err := models.RegisterUser(&models.User{Name: form.AdminName, Email: form.AdminEmail, Passwd: form.AdminPasswd, + if _, err := models.CreateUser(&models.User{Name: form.AdminName, Email: form.AdminEmail, Passwd: form.AdminPasswd, IsAdmin: true, IsActive: true}); err != nil { if err != models.ErrUserAlreadyExist { setting.InstallLock = false diff --git a/routers/org/org.go b/routers/org/org.go index ff97402e..0595a81b 100644 --- a/routers/org/org.go +++ b/routers/org/org.go @@ -1,33 +1,117 @@ +// 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 org import ( "github.com/go-martini/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" + "github.com/gogits/gogs/routers/user" +) + +const ( + NEW base.TplName = "org/new" ) func Organization(ctx *middleware.Context, params martini.Params) { - ctx.Data["Title"] = "Organization "+params["org"] + ctx.Data["Title"] = "Organization " + params["org"] ctx.HTML(200, "org/org") } func Members(ctx *middleware.Context, params martini.Params) { - ctx.Data["Title"] = "Organization "+params["org"]+" Members" + ctx.Data["Title"] = "Organization " + params["org"] + " Members" ctx.HTML(200, "org/members") } func Teams(ctx *middleware.Context, params martini.Params) { - ctx.Data["Title"] = "Organization "+params["org"]+" Teams" + ctx.Data["Title"] = "Organization " + params["org"] + " Teams" ctx.HTML(200, "org/teams") } func New(ctx *middleware.Context) { - ctx.Data["Title"] = "Create an Organization" - ctx.HTML(200, "org/new") + ctx.Data["Title"] = "Create An Organization" + ctx.HTML(200, NEW) +} + +func NewPost(ctx *middleware.Context, form auth.CreateOrganizationForm) { + ctx.Data["Title"] = "Create An Organization" + + if ctx.HasError() { + ctx.HTML(200, NEW) + return + } + + org := &models.User{ + Name: form.OrgName, + Email: form.Email, + IsActive: true, // NOTE: may need to set false when require e-mail confirmation. + Type: models.ORGANIZATION, + } + + var err error + if org, err = models.CreateOrganization(org, ctx.User); err != nil { + switch err { + case models.ErrUserAlreadyExist: + ctx.Data["Err_OrgName"] = true + ctx.RenderWithErr("Organization name has been already taken", NEW, &form) + case models.ErrEmailAlreadyUsed: + ctx.Data["Err_Email"] = true + ctx.RenderWithErr("E-mail address has been already used", NEW, &form) + case models.ErrUserNameIllegal: + ctx.Data["Err_OrgName"] = true + ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), NEW, &form) + default: + ctx.Handle(500, "user.NewPost(CreateUser)", err) + } + return + } + log.Trace("%s Organization created: %s", ctx.Req.RequestURI, org.Name) + + ctx.Redirect("/org/" + form.OrgName + "/dashboard") } func Dashboard(ctx *middleware.Context, params martini.Params) { ctx.Data["Title"] = "Dashboard" - ctx.HTML(200, "org/dashboard") + ctx.Data["PageIsUserDashboard"] = true + ctx.Data["PageIsOrgDashboard"] = true + + org, err := models.GetUserByName(params["org"]) + if err != nil { + if err == models.ErrUserNotExist { + ctx.Handle(404, "org.Dashboard(GetUserByName)", err) + } else { + ctx.Handle(500, "org.Dashboard(GetUserByName)", err) + } + return + } + + if err := ctx.User.GetOrganizations(); err != nil { + ctx.Handle(500, "home.Dashboard(GetOrganizations)", err) + return + } + ctx.Data["Orgs"] = ctx.User.Orgs + ctx.Data["ContextUser"] = org + + ctx.Data["MyRepos"], err = models.GetRepositories(org.Id, true) + if err != nil { + ctx.Handle(500, "org.Dashboard(GetRepositories)", err) + return + } + + actions, err := models.GetFeeds(org.Id, 0, false) + if err != nil { + ctx.Handle(500, "org.Dashboard(GetFeeds)", err) + return + } + ctx.Data["Feeds"] = actions + + ctx.HTML(200, user.DASHBOARD) } func Setting(ctx *middleware.Context, param martini.Params) { diff --git a/routers/repo/http.go b/routers/repo/http.go index d2bff299..981266d5 100644 --- a/routers/repo/http.go +++ b/routers/repo/http.go @@ -107,9 +107,9 @@ func Http(ctx *middleware.Context, params martini.Params) { } if !isPublicPull { - var tp = models.AU_WRITABLE + var tp = models.WRITABLE if isPull { - tp = models.AU_READABLE + tp = models.READABLE } has, err := models.HasAccess(authUsername, username+"/"+reponame, tp) @@ -117,8 +117,8 @@ func Http(ctx *middleware.Context, params martini.Params) { ctx.Handle(401, "no basic auth and digit auth", nil) return } else if !has { - if tp == models.AU_READABLE { - has, err = models.HasAccess(authUsername, username+"/"+reponame, models.AU_WRITABLE) + if tp == models.READABLE { + has, err = models.HasAccess(authUsername, username+"/"+reponame, models.WRITABLE) if err != nil || !has { ctx.Handle(401, "no basic auth and digit auth", nil) return diff --git a/routers/repo/setting.go b/routers/repo/setting.go index 6479cb30..3d48e79c 100644 --- a/routers/repo/setting.go +++ b/routers/repo/setting.go @@ -175,7 +175,7 @@ func CollaborationPost(ctx *middleware.Context) { ctx.Redirect(ctx.Req.RequestURI) return } - has, err := models.HasAccess(name, repoLink, models.AU_WRITABLE) + has, err := models.HasAccess(name, repoLink, models.WRITABLE) if err != nil { ctx.Handle(500, "setting.CollaborationPost(HasAccess)", err) return @@ -196,7 +196,7 @@ func CollaborationPost(ctx *middleware.Context) { } if err = models.AddAccess(&models.Access{UserName: name, RepoName: repoLink, - Mode: models.AU_WRITABLE}); err != nil { + Mode: models.WRITABLE}); err != nil { ctx.Handle(500, "setting.CollaborationPost(AddAccess)", err) return } diff --git a/routers/user/home.go b/routers/user/home.go index 0f2cee25..86907b5a 100644 --- a/routers/user/home.go +++ b/routers/user/home.go @@ -20,7 +20,7 @@ import ( const ( DASHBOARD base.TplName = "user/dashboard" PROFILE base.TplName = "user/profile" - ISSUES base.TplName = "user/issue" + ISSUES base.TplName = "user/issues" PULLS base.TplName = "user/pulls" STARS base.TplName = "user/stars" ) @@ -29,6 +29,13 @@ func Dashboard(ctx *middleware.Context) { ctx.Data["Title"] = "Dashboard" ctx.Data["PageIsUserDashboard"] = true + if err := ctx.User.GetOrganizations(); err != nil { + ctx.Handle(500, "home.Dashboard(GetOrganizations)", err) + return + } + ctx.Data["Orgs"] = ctx.User.Orgs + ctx.Data["ContextUser"] = ctx.User + var err error ctx.Data["MyRepos"], err = models.GetRepositories(ctx.User.Id, true) if err != nil { @@ -53,7 +60,7 @@ func Dashboard(ctx *middleware.Context) { for _, act := range actions { if act.IsPrivate { if has, _ := models.HasAccess(ctx.User.Name, act.RepoUserName+"/"+act.RepoName, - models.AU_READABLE); !has { + models.READABLE); !has { continue } } @@ -131,7 +138,7 @@ func Feeds(ctx *middleware.Context, form auth.FeedsForm) { for _, act := range actions { if act.IsPrivate { if has, _ := models.HasAccess(ctx.User.Name, act.RepoUserName+"/"+act.RepoName, - models.AU_READABLE); !has { + models.READABLE); !has { continue } } diff --git a/routers/user/user.go b/routers/user/user.go index 8144730e..a50f126c 100644 --- a/routers/user/user.go +++ b/routers/user/user.go @@ -226,7 +226,7 @@ func SignUpPost(ctx *middleware.Context, form auth.RegisterForm) { } var err error - if u, err = models.RegisterUser(u); err != nil { + if u, err = models.CreateUser(u); err != nil { switch err { case models.ErrUserAlreadyExist: ctx.Data["Err_UserName"] = true @@ -235,13 +235,14 @@ func SignUpPost(ctx *middleware.Context, form auth.RegisterForm) { ctx.Data["Err_Email"] = true ctx.RenderWithErr("E-mail address has been already used", SIGNUP, &form) case models.ErrUserNameIllegal: + ctx.Data["Err_UserName"] = true ctx.RenderWithErr(models.ErrRepoNameIllegal.Error(), SIGNUP, &form) default: - ctx.Handle(500, "user.SignUpPost(RegisterUser)", err) + ctx.Handle(500, "user.SignUpPost(CreateUser)", err) } return } - log.Trace("%s User created: %s", ctx.Req.RequestURI, form.UserName) + log.Trace("%s User created: %s", ctx.Req.RequestURI, u.Name) // Bind social account. if isOauth { diff --git a/templates/VERSION b/templates/VERSION index 8c2be60b..b5cda695 100644 --- a/templates/VERSION +++ b/templates/VERSION @@ -1 +1 @@ -0.4.5.0624 Alpha \ No newline at end of file +0.4.5.0625 Alpha \ No newline at end of file diff --git a/templates/org/dashboard.tmpl b/templates/org/dashboard.tmpl deleted file mode 100644 index f86de1f4..00000000 --- a/templates/org/dashboard.tmpl +++ /dev/null @@ -1,73 +0,0 @@ -{{template "base/head" .}} -{{template "base/navbar" .}} -
-
-
- - - -
- -

News Feed

-
-
-
- {{if .HasInfo}}
{{.InfoMsg}}
{{end}} -
-
    - {{range .Feeds}} -
  • - -
    {{TimeSince .Created}}
    {{ActionDesc . | str2html}}
    - -
  • - {{else}} -
  • Oh. Looks like there isn't any activity here yet. Get Busy!
  • - {{end}} -
-
-
-
-
Repositories -
- - -
-
- -
- -
-
-
-
-{{template "base/footer" .}} diff --git a/templates/org/new.tmpl b/templates/org/new.tmpl index baa9c9df..bb46db4a 100644 --- a/templates/org/new.tmpl +++ b/templates/org/new.tmpl @@ -1,22 +1,14 @@ {{template "base/head" .}} {{template "base/navbar" .}}
-
+ {{.CsrfTokenHtml}}

Create New Organization

{{template "base/alert" .}} -
- -
-

{{.SignedUserName}}

- -
-
- -
+
- + Great organization names are short and memorable.
@@ -24,18 +16,10 @@
- + Organization's Email receives all notifications and confirmations.
- -
diff --git a/templates/user/dashboard.tmpl b/templates/user/dashboard.tmpl index 12018ad8..e1b43e15 100644 --- a/templates/user/dashboard.tmpl +++ b/templates/user/dashboard.tmpl @@ -4,29 +4,46 @@
-

News Feed

+
{{if .HasInfo}}
{{.InfoMsg}}
{{end}}
@@ -44,7 +61,7 @@
-
Your Repositories +
{{if not .PageIsOrgDashboard}}Your {{end}}Repositories
- + + {{if not .PageIsOrgDashboard}}
Collaborative Repositories
@@ -78,6 +96,7 @@
+ {{end}}
{{template "base/footer" .}} diff --git a/templates/user/issues.tmpl b/templates/user/issues.tmpl index d1c2bd99..c4ad64a4 100644 --- a/templates/user/issues.tmpl +++ b/templates/user/issues.tmpl @@ -3,7 +3,7 @@
+
{{if .HasInfo}}
{{.InfoMsg}}
{{end}}
-- cgit v1.2.3