diff options
Diffstat (limited to 'models')
-rw-r--r-- | models/cron/cron.go | 59 | ||||
-rw-r--r-- | models/login.go | 8 | ||||
-rw-r--r-- | models/publickey.go | 6 | ||||
-rw-r--r-- | models/repo.go | 132 | ||||
-rw-r--r-- | models/token.go | 18 | ||||
-rw-r--r-- | models/user.go | 128 |
6 files changed, 240 insertions, 111 deletions
diff --git a/models/cron/cron.go b/models/cron/cron.go new file mode 100644 index 00000000..cbf980c0 --- /dev/null +++ b/models/cron/cron.go @@ -0,0 +1,59 @@ +// 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 cron + +import ( + "time" + + "github.com/gogits/gogs/models" + "github.com/gogits/gogs/modules/cron" + "github.com/gogits/gogs/modules/log" + "github.com/gogits/gogs/modules/setting" +) + +var c = cron.New() + +func NewCronContext() { + var ( + entry *cron.Entry + err error + ) + if setting.Cron.UpdateMirror.Enabled { + entry, err = c.AddFunc("Update mirrors", setting.Cron.UpdateMirror.Schedule, models.MirrorUpdate) + if err != nil { + log.Fatal(4, "Cron[Update mirrors]: %v", err) + } + if setting.Cron.UpdateMirror.RunAtStart { + entry.Prev = time.Now() + go models.MirrorUpdate() + } + } + if setting.Cron.RepoHealthCheck.Enabled { + entry, err = c.AddFunc("Repository health check", setting.Cron.RepoHealthCheck.Schedule, models.GitFsck) + if err != nil { + log.Fatal(4, "Cron[Repository health check]: %v", err) + } + if setting.Cron.RepoHealthCheck.RunAtStart { + entry.Prev = time.Now() + go models.GitFsck() + } + } + if setting.Cron.CheckRepoStats.Enabled { + entry, err = c.AddFunc("Check repository statistics", setting.Cron.CheckRepoStats.Schedule, models.CheckRepoStats) + if err != nil { + log.Fatal(4, "Cron[Check repository statistics]: %v", err) + } + if setting.Cron.CheckRepoStats.RunAtStart { + entry.Prev = time.Now() + go models.CheckRepoStats() + } + } + c.Start() +} + +// ListTasks returns all running cron tasks. +func ListTasks() []*cron.Entry { + return c.Entries() +} diff --git a/models/login.go b/models/login.go index 82cea35f..8ac4b827 100644 --- a/models/login.go +++ b/models/login.go @@ -19,7 +19,6 @@ import ( "github.com/gogits/gogs/modules/auth/ldap" "github.com/gogits/gogs/modules/auth/pam" "github.com/gogits/gogs/modules/log" - "github.com/gogits/gogs/modules/uuid" ) type LoginType int @@ -258,18 +257,19 @@ func UserSignIn(uname, passwd string) (*User, error) { // Return the same LoginUserPlain semantic // FIXME: https://github.com/gogits/gogs/issues/672 func LoginUserLdapSource(u *User, name, passwd string, sourceId int64, cfg *LDAPConfig, autoRegister bool) (*User, error) { - name, fn, sn, mail, logged := cfg.Ldapsource.SearchEntry(name, passwd) + fn, sn, mail, logged := cfg.Ldapsource.SearchEntry(name, passwd) if !logged { // User not in LDAP, do nothing - return nil, ErrUserNotExist{u.Id, u.Name} + return nil, ErrUserNotExist{0, name} } + if !autoRegister { return u, nil } // Fallback. if len(mail) == 0 { - mail = uuid.NewV4().String() + "@localhost" + mail = fmt.Sprintf("%s@localhost", name) } u = &User{ diff --git a/models/publickey.go b/models/publickey.go index 70da8057..400486eb 100644 --- a/models/publickey.go +++ b/models/publickey.go @@ -386,9 +386,6 @@ func ListPublicKeys(uid int64) ([]*PublicKey, error) { // rewriteAuthorizedKeys finds and deletes corresponding line in authorized_keys file. func rewriteAuthorizedKeys(key *PublicKey, p, tmpP string) error { - sshOpLocker.Lock() - defer sshOpLocker.Unlock() - fr, err := os.Open(p) if err != nil { return err @@ -444,6 +441,9 @@ func UpdatePublicKey(key *PublicKey) error { } func deletePublicKey(e *xorm.Session, key *PublicKey) error { + sshOpLocker.Lock() + defer sshOpLocker.Unlock() + has, err := e.Get(key) if err != nil { return err diff --git a/models/repo.go b/models/repo.go index 9aed7d7d..e4122966 100644 --- a/models/repo.go +++ b/models/repo.go @@ -173,7 +173,7 @@ func (repo *Repository) getOwner(e Engine) (err error) { return err } -func (repo *Repository) GetOwner() (err error) { +func (repo *Repository) GetOwner() error { return repo.getOwner(x) } @@ -326,12 +326,23 @@ func IsUsableName(name string) error { type Mirror struct { ID int64 `xorm:"pk autoincr"` RepoID int64 - RepoName string // <user name>/<repo name> - Interval int // Hour. - Updated time.Time `xorm:"UPDATED"` + Repo *Repository `xorm:"-"` + Interval int // Hour. + Updated time.Time `xorm:"UPDATED"` NextUpdate time.Time } +func (m *Mirror) AfterSet(colName string, _ xorm.Cell) { + var err error + switch colName { + case "repo_id": + m.Repo, err = GetRepositoryByID(m.RepoID) + if err != nil { + log.Error(3, "GetRepositoryByID[%d]: %v", m.ID, err) + } + } +} + func getMirror(e Engine, repoId int64) (*Mirror, error) { m := &Mirror{RepoID: repoId} has, err := e.Get(m) @@ -368,7 +379,6 @@ func MirrorRepository(repoId int64, userName, repoName, repoPath, url string) er if _, err = x.InsertOne(&Mirror{ RepoID: repoId, - RepoName: strings.ToLower(userName + "/" + repoName), Interval: 24, NextUpdate: time.Now().Add(24 * time.Hour), }); err != nil { @@ -784,18 +794,6 @@ func TransferOwnership(u *User, newOwnerName string, repo *Repository) error { return fmt.Errorf("transferRepoAction: %v", err) } - // Update mirror information. - if repo.IsMirror { - mirror, err := getMirror(sess, repo.ID) - if err != nil { - return fmt.Errorf("getMirror: %v", err) - } - mirror.RepoName = newOwner.LowerName + "/" + repo.LowerName - if err = updateMirror(sess, mirror); err != nil { - return fmt.Errorf("updateMirror: %v", err) - } - } - // Change repository directory name. if err = os.Rename(RepoPath(owner.Name, repo.Name), RepoPath(newOwner.Name, repo.Name)); err != nil { return fmt.Errorf("rename directory: %v", err) @@ -1108,7 +1106,7 @@ func RewriteRepositoryUpdateHook() error { } var ( - // Prevent duplicate tasks. + // Prevent duplicate running tasks. isMirrorUpdating = false isGitFscking = false isCheckingRepos = false @@ -1122,22 +1120,32 @@ func MirrorUpdate() { isMirrorUpdating = true defer func() { isMirrorUpdating = false }() - mirrors := make([]*Mirror, 0, 10) + log.Trace("Doing: MirrorUpdate") + mirrors := make([]*Mirror, 0, 10) if err := x.Iterate(new(Mirror), func(idx int, bean interface{}) error { m := bean.(*Mirror) if m.NextUpdate.After(time.Now()) { return nil } - repoPath := filepath.Join(setting.RepoRootPath, m.RepoName+".git") + if m.Repo == nil { + log.Error(4, "Disconnected mirror repository found: %d", m.ID) + return nil + } + + repoPath, err := m.Repo.RepoPath() + if err != nil { + return fmt.Errorf("Repo.RepoPath: %v", err) + } + if _, stderr, err := process.ExecDir(10*time.Minute, repoPath, fmt.Sprintf("MirrorUpdate: %s", repoPath), "git", "remote", "update", "--prune"); err != nil { desc := fmt.Sprintf("Fail to update mirror repository(%s): %s", repoPath, stderr) log.Error(4, desc) if err = CreateRepositoryNotice(desc); err != nil { - log.Error(4, "Fail to add notice: %v", err) + log.Error(4, "CreateRepositoryNotice: %v", err) } return nil } @@ -1151,7 +1159,7 @@ func MirrorUpdate() { for i := range mirrors { if err := UpdateMirror(mirrors[i]); err != nil { - log.Error(4, "UpdateMirror", fmt.Sprintf("%s: %v", mirrors[i].RepoName, err)) + log.Error(4, "UpdateMirror[%d]: %v", mirrors[i].ID, err) } } } @@ -1164,26 +1172,28 @@ func GitFsck() { isGitFscking = true defer func() { isGitFscking = false }() - args := append([]string{"fsck"}, setting.Git.Fsck.Args...) - if err := x.Where("id > 0").Iterate(new(Repository), + log.Trace("Doing: GitFsck") + + args := append([]string{"fsck"}, setting.Cron.RepoHealthCheck.Args...) + if err := x.Where("id>0").Iterate(new(Repository), func(idx int, bean interface{}) error { repo := bean.(*Repository) - if err := repo.GetOwner(); err != nil { - return err + repoPath, err := repo.RepoPath() + if err != nil { + return fmt.Errorf("RepoPath: %v", err) } - repoPath := RepoPath(repo.Owner.Name, repo.Name) - _, _, err := process.ExecDir(-1, repoPath, "Repository health check", "git", args...) + _, _, err = process.ExecDir(-1, repoPath, "Repository health check", "git", args...) if err != nil { desc := fmt.Sprintf("Fail to health check repository(%s)", repoPath) log.Warn(desc) if err = CreateRepositoryNotice(desc); err != nil { - log.Error(4, "Fail to add notice: %v", err) + log.Error(4, "CreateRepositoryNotice: %v", err) } } return nil }); err != nil { - log.Error(4, "repo.Fsck: %v", err) + log.Error(4, "GitFsck: %v", err) } } @@ -1210,33 +1220,55 @@ func CheckRepoStats() { isCheckingRepos = true defer func() { isCheckingRepos = false }() - // Check count watchers - results_watch, err := x.Query("SELECT r.id FROM `repository` r WHERE r.num_watches!=(SELECT count(*) FROM `watch` WHERE repo_id=r.id)") + log.Trace("Doing: CheckRepoStats") + + // ***** START: Watch ***** + results, err := x.Query("SELECT repo.id FROM `repository` repo WHERE repo.num_watches!=(SELECT COUNT(*) FROM `watch` WHERE repo_id=repo.id)") + if err != nil { + log.Error(4, "Select repository check 'watch': %v", err) + return + } + for _, watch := range results { + repoID := com.StrTo(watch["id"]).MustInt64() + log.Trace("Updating repository count 'watch': %d", repoID) + _, err = x.Exec("UPDATE `repository` SET num_watches=(SELECT COUNT(*) FROM `watch` WHERE repo_id=?) WHERE id=?", repoID, repoID) + if err != nil { + log.Error(4, "Update repository check 'watch'[%d]: %v", repoID, err) + } + } + // ***** END: Watch ***** + + // ***** START: Star ***** + results, err = x.Query("SELECT repo.id FROM `repository` repo WHERE repo.num_stars!=(SELECT COUNT(*) FROM `star` WHERE repo_id=repo.id)") if err != nil { - log.Error(4, "select repository check 'watch': %v", err) + log.Error(4, "Select repository check 'star': %v", err) + return } - for _, repo_id := range results_watch { - log.Info("updating repository count 'watch'") - repoID := com.StrTo(repo_id["id"]).MustInt64() - _, err := x.Exec("UPDATE `repository` SET num_watches=(SELECT count(*) FROM `watch` WHERE repo_id=?) WHERE id=?", repoID, repoID) + for _, star := range results { + repoID := com.StrTo(star["id"]).MustInt64() + log.Trace("Updating repository count 'star': %d", repoID) + _, err = x.Exec("UPDATE `repository` SET num_stars=(SELECT COUNT(*) FROM `star` WHERE repo_id=?) WHERE id=?", repoID, repoID) if err != nil { - log.Error(4, "update repository check 'watch', repo %v: %v", repo_id, err) + log.Error(4, "Update repository check 'star'[%d]: %v", repoID, err) } } + // ***** END: Star ***** - // Check count stars - results_star, err := x.Query("SELECT s.id FROM `repository` s WHERE s.num_stars!=(SELECT count(*) FROM `star` WHERE repo_id=s.id)") + // ***** START: Label ***** + results, err = x.Query("SELECT label.id FROM `label` WHERE label.num_issues!=(SELECT COUNT(*) FROM `issue_label` WHERE label_id=label.id)") if err != nil { - log.Error(4, "select repository check 'star': %v", err) + log.Error(4, "Select label check 'num_issues': %v", err) + return } - for _, repo_id := range results_star { - log.Info("updating repository count 'star'") - repoID := com.StrTo(repo_id["id"]).MustInt64() - _, err := x.Exec("UPDATE `repository` SET .num_stars=(SELECT count(*) FROM `star` WHERE repo_id=?) WHERE id=?", repoID, repoID) + for _, label := range results { + labelID := com.StrTo(label["id"]).MustInt64() + log.Trace("Updating label count 'num_issues': %d", labelID) + _, err = x.Exec("UPDATE `label` SET num_issues=(SELECT COUNT(*) FROM `issue_label` WHERE label_id=?) WHERE id=?", labelID, labelID) if err != nil { - log.Error(4, "update repository check 'star', repo %v: %v", repo_id, err) + log.Error(4, "Update label check 'num_issues'[%d]: %v", labelID, err) } } + // ***** END: Label ***** } // _________ .__ .__ ___. __ .__ @@ -1435,9 +1467,9 @@ func NotifyWatchers(act *Action) error { // \/ \/ type Star struct { - Id int64 - Uid int64 `xorm:"UNIQUE(s)"` - RepoId int64 `xorm:"UNIQUE(s)"` + ID int64 `xorm:"pk autoincr"` + UID int64 `xorm:"uid UNIQUE(s)"` + RepoID int64 `xorm:"UNIQUE(s)"` } // Star or unstar repository. @@ -1446,7 +1478,7 @@ func StarRepo(uid, repoId int64, star bool) (err error) { if IsStaring(uid, repoId) { return nil } - if _, err = x.Insert(&Star{Uid: uid, RepoId: repoId}); err != nil { + if _, err = x.Insert(&Star{UID: uid, RepoID: repoId}); err != nil { return err } else if _, err = x.Exec("UPDATE `repository` SET num_stars = num_stars + 1 WHERE id = ?", repoId); err != nil { return err diff --git a/models/token.go b/models/token.go index 909d05e0..6c4328e5 100644 --- a/models/token.go +++ b/models/token.go @@ -18,8 +18,8 @@ var ( // AccessToken represents a personal access token. type AccessToken struct { - Id int64 - Uid int64 + ID int64 `xorm:"pk autoincr"` + UID int64 `xorm:"uid INDEX"` Name string Sha1 string `xorm:"UNIQUE VARCHAR(40)"` Created time.Time `xorm:"CREATED"` @@ -35,8 +35,8 @@ func NewAccessToken(t *AccessToken) error { return err } -// GetAccessTokenBySha returns access token by given sha1. -func GetAccessTokenBySha(sha string) (*AccessToken, error) { +// GetAccessTokenBySHA returns access token by given sha1. +func GetAccessTokenBySHA(sha string) (*AccessToken, error) { t := &AccessToken{Sha1: sha} has, err := x.Get(t) if err != nil { @@ -62,8 +62,14 @@ func ListAccessTokens(uid int64) ([]*AccessToken, error) { return tokens, nil } -// DeleteAccessTokenById deletes access token by given ID. -func DeleteAccessTokenById(id int64) error { +// UpdateAccessToekn updates information of access token. +func UpdateAccessToekn(t *AccessToken) error { + _, err := x.Id(t.ID).AllCols().Update(t) + return err +} + +// DeleteAccessTokenByID deletes access token by given ID. +func DeleteAccessTokenByID(id int64) error { _, err := x.Id(id).Delete(new(AccessToken)) return err } diff --git a/models/user.go b/models/user.go index ca49a5b8..bc0a0461 100644 --- a/models/user.go +++ b/models/user.go @@ -373,17 +373,9 @@ func CreateUser(u *User) (err error) { } else if err = os.MkdirAll(UserPath(u.Name), os.ModePerm); err != nil { sess.Rollback() return err - } else if err = sess.Commit(); err != nil { - return err } - // Auto-set admin for the first user. - if CountUsers() == 1 { - u.IsAdmin = true - u.IsActive = true - _, err = x.Id(u.Id).AllCols().Update(u) - } - return err + return sess.Commit() } func countUsers(e Engine) int64 { @@ -515,8 +507,12 @@ func DeleteBeans(e Engine, beans ...interface{}) (err error) { } // FIXME: need some kind of mechanism to record failure. HINT: system notice -// DeleteUser completely and permanently deletes everything of user. +// DeleteUser completely and permanently deletes everything of a user, +// but issues/comments/pulls will be kept and shown as someone has been deleted. func DeleteUser(u *User) error { + // Note: A user owns any repository or belongs to any organization + // cannot perform delete operation. + // Check ownership of repository. count, err := GetRepositoryCount(u) if err != nil { @@ -533,80 +529,116 @@ func DeleteUser(u *User) error { return ErrUserHasOrgs{UID: u.Id} } - // Get watches before session. + sess := x.NewSession() + defer sessionRelease(sess) + if err = sess.Begin(); err != nil { + return err + } + + // ***** START: Watch ***** watches := make([]*Watch, 0, 10) - if err = x.Where("user_id=?", u.Id).Find(&watches); err != nil { + if err = x.Find(&watches, &Watch{UserID: u.Id}); err != nil { return fmt.Errorf("get all watches: %v", err) } - repoIDs := make([]int64, 0, len(watches)) for i := range watches { - repoIDs = append(repoIDs, watches[i].RepoID) + if _, err = sess.Exec("UPDATE `repository` SET num_watches=num_watches-1 WHERE id=?", watches[i].RepoID); err != nil { + return fmt.Errorf("decrease repository watch number[%d]: %v", watches[i].RepoID, err) + } } + // ***** END: Watch ***** - // FIXME: check issues, other repos' commits + // ***** START: Star ***** + stars := make([]*Star, 0, 10) + if err = x.Find(&stars, &Star{UID: u.Id}); err != nil { + return fmt.Errorf("get all stars: %v", err) + } + for i := range stars { + if _, err = sess.Exec("UPDATE `repository` SET num_stars=num_stars-1 WHERE id=?", stars[i].RepoID); err != nil { + return fmt.Errorf("decrease repository star number[%d]: %v", stars[i].RepoID, err) + } + } + // ***** END: Star ***** - sess := x.NewSession() - defer sessionRelease(sess) - if err = sess.Begin(); err != nil { - return err + // ***** START: Follow ***** + followers := make([]*Follow, 0, 10) + if err = x.Find(&followers, &Follow{UserID: u.Id}); err != nil { + return fmt.Errorf("get all followers: %v", err) + } + for i := range followers { + if _, err = sess.Exec("UPDATE `user` SET num_followers=num_followers-1 WHERE id=?", followers[i].UserID); err != nil { + return fmt.Errorf("decrease user follower number[%d]: %v", followers[i].UserID, err) + } } + // ***** END: Follow ***** if err = DeleteBeans(sess, - &Follow{FollowID: u.Id}, &Oauth2{Uid: u.Id}, - &Action{UserID: u.Id}, - &Access{UserID: u.Id}, + &AccessToken{UID: u.Id}, &Collaboration{UserID: u.Id}, - &EmailAddress{Uid: u.Id}, + &Access{UserID: u.Id}, &Watch{UserID: u.Id}, + &Star{UID: u.Id}, + &Follow{FollowID: u.Id}, + &Action{UserID: u.Id}, &IssueUser{UID: u.Id}, + &EmailAddress{Uid: u.Id}, ); err != nil { - return err + return fmt.Errorf("DeleteBeans: %v", err) } - // Decrease all watch numbers. - for i := range repoIDs { - if _, err = sess.Exec("UPDATE `repository` SET num_watches=num_watches-1 WHERE id=?", repoIDs[i]); err != nil { - return err - } - } - - // Delete all SSH keys. + // ***** START: PublicKey ***** keys := make([]*PublicKey, 0, 10) if err = sess.Find(&keys, &PublicKey{OwnerID: u.Id}); err != nil { - return err + return fmt.Errorf("get all public keys: %v", err) } for _, key := range keys { if err = deletePublicKey(sess, key); err != nil { - return err + return fmt.Errorf("deletePublicKey: %v", err) } } + // ***** END: PublicKey ***** // Clear assignee. if _, err = sess.Exec("UPDATE `issue` SET assignee_id=0 WHERE assignee_id=?", u.Id); err != nil { - return err + return fmt.Errorf("clear assignee: %v", err) } if _, err = sess.Delete(u); err != nil { - return err + return fmt.Errorf("Delete: %v", err) } - // Delete user data. - if err = os.RemoveAll(UserPath(u.Name)); err != nil { - return err + if err = sess.Commit(); err != nil { + return fmt.Errorf("Commit: %v", err) } - // Delete avatar. + + // FIXME: system notice + // Note: There are something just cannot be roll back, + // so just keep error logs of those operations. + + RewriteAllPublicKeys() + os.RemoveAll(UserPath(u.Name)) os.Remove(u.CustomAvatarPath()) - return sess.Commit() + return nil } // DeleteInactivateUsers deletes all inactivate users and email addresses. -func DeleteInactivateUsers() error { - _, err := x.Where("is_active=?", false).Delete(new(User)) - if err == nil { - _, err = x.Where("is_activated=?", false).Delete(new(EmailAddress)) +func DeleteInactivateUsers() (err error) { + users := make([]*User, 0, 10) + if err = x.Where("is_active=?", false).Find(&users); err != nil { + return fmt.Errorf("get all inactive users: %v", err) + } + for _, u := range users { + if err = DeleteUser(u); err != nil { + // Ignore users that were set inactive by admin. + if IsErrUserOwnRepos(err) || IsErrUserHasOrgs(err) { + continue + } + return err + } } + + _, err = x.Where("is_activated=?", false).Delete(new(EmailAddress)) return err } @@ -895,9 +927,9 @@ func SearchUserByName(opt SearchOption) (us []*User, err error) { // Follow is connection request for receiving user notification. type Follow struct { - Id int64 - UserID int64 `xorm:"unique(follow)"` - FollowID int64 `xorm:"unique(follow)"` + ID int64 `xorm:"pk autoincr"` + UserID int64 `xorm:"UNIQUE(follow)"` + FollowID int64 `xorm:"UNIQUE(follow)"` } // FollowUser marks someone be another's follower. |