aboutsummaryrefslogtreecommitdiff
path: root/models
diff options
context:
space:
mode:
Diffstat (limited to 'models')
-rw-r--r--models/cron/cron.go59
-rw-r--r--models/login.go8
-rw-r--r--models/publickey.go6
-rw-r--r--models/repo.go132
-rw-r--r--models/token.go18
-rw-r--r--models/user.go128
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.