mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-11-28 11:22:50 +01:00
Some repository refactors (#17950)
* some repository refactors * remove unnecessary code * Fix test * Remove unnecessary banner
This commit is contained in:
parent
0a7e8327a0
commit
5723240490
88 changed files with 1363 additions and 1388 deletions
|
@ -102,7 +102,7 @@ func migrateAvatars(dstStorage storage.ObjectStorage) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func migrateRepoAvatars(dstStorage storage.ObjectStorage) error {
|
func migrateRepoAvatars(dstStorage storage.ObjectStorage) error {
|
||||||
return models.IterateRepository(func(repo *repo_model.Repository) error {
|
return repo_model.IterateRepository(func(repo *repo_model.Repository) error {
|
||||||
_, err := storage.Copy(dstStorage, repo.CustomAvatarRelativePath(), storage.RepoAvatars, repo.CustomAvatarRelativePath())
|
_, err := storage.Copy(dstStorage, repo.CustomAvatarRelativePath(), storage.RepoAvatars, repo.CustomAvatarRelativePath())
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
|
|
|
@ -24,7 +24,7 @@ func assertUserDeleted(t *testing.T, userID int64) {
|
||||||
unittest.AssertNotExistsBean(t, &models.OrgUser{UID: userID})
|
unittest.AssertNotExistsBean(t, &models.OrgUser{UID: userID})
|
||||||
unittest.AssertNotExistsBean(t, &models.IssueUser{UID: userID})
|
unittest.AssertNotExistsBean(t, &models.IssueUser{UID: userID})
|
||||||
unittest.AssertNotExistsBean(t, &models.TeamUser{UID: userID})
|
unittest.AssertNotExistsBean(t, &models.TeamUser{UID: userID})
|
||||||
unittest.AssertNotExistsBean(t, &models.Star{UID: userID})
|
unittest.AssertNotExistsBean(t, &repo_model.Star{UID: userID})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUserDeleteAccount(t *testing.T) {
|
func TestUserDeleteAccount(t *testing.T) {
|
||||||
|
|
|
@ -89,7 +89,7 @@ func createOutdatedPR(t *testing.T, actor, forkOrg *user_model.User) *models.Pul
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotEmpty(t, baseRepo)
|
assert.NotEmpty(t, baseRepo)
|
||||||
|
|
||||||
headRepo, err := repo_service.ForkRepository(actor, forkOrg, models.ForkRepoOptions{
|
headRepo, err := repo_service.ForkRepository(actor, forkOrg, repo_service.ForkRepoOptions{
|
||||||
BaseRepo: baseRepo,
|
BaseRepo: baseRepo,
|
||||||
Name: "repo-pr-update",
|
Name: "repo-pr-update",
|
||||||
Description: "desc",
|
Description: "desc",
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
)
|
)
|
||||||
|
@ -18,8 +18,8 @@ func TestRepoWatch(t *testing.T) {
|
||||||
// Test round-trip auto-watch
|
// Test round-trip auto-watch
|
||||||
setting.Service.AutoWatchOnChanges = true
|
setting.Service.AutoWatchOnChanges = true
|
||||||
session := loginUser(t, "user2")
|
session := loginUser(t, "user2")
|
||||||
unittest.AssertNotExistsBean(t, &models.Watch{UserID: 2, RepoID: 3})
|
unittest.AssertNotExistsBean(t, &repo_model.Watch{UserID: 2, RepoID: 3})
|
||||||
testEditFile(t, session, "user3", "repo3", "master", "README.md", "Hello, World (Edited for watch)\n")
|
testEditFile(t, session, "user3", "repo3", "master", "README.md", "Hello, World (Edited for watch)\n")
|
||||||
unittest.AssertExistsAndLoadBean(t, &models.Watch{UserID: 2, RepoID: 3, Mode: models.RepoWatchModeAuto})
|
unittest.AssertExistsAndLoadBean(t, &repo_model.Watch{UserID: 2, RepoID: 3, Mode: repo_model.WatchModeAuto})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
125
models/action.go
125
models/action.go
|
@ -16,6 +16,7 @@ import (
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
"code.gitea.io/gitea/models/unit"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
@ -414,3 +415,127 @@ func DeleteOldActions(olderThan time.Duration) (err error) {
|
||||||
_, err = db.GetEngine(db.DefaultContext).Where("created_unix < ?", time.Now().Add(-olderThan).Unix()).Delete(&Action{})
|
_, err = db.GetEngine(db.DefaultContext).Where("created_unix < ?", time.Now().Add(-olderThan).Unix()).Delete(&Action{})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func notifyWatchers(ctx context.Context, actions ...*Action) error {
|
||||||
|
var watchers []*repo_model.Watch
|
||||||
|
var repo *repo_model.Repository
|
||||||
|
var err error
|
||||||
|
var permCode []bool
|
||||||
|
var permIssue []bool
|
||||||
|
var permPR []bool
|
||||||
|
|
||||||
|
e := db.GetEngine(ctx)
|
||||||
|
|
||||||
|
for _, act := range actions {
|
||||||
|
repoChanged := repo == nil || repo.ID != act.RepoID
|
||||||
|
|
||||||
|
if repoChanged {
|
||||||
|
// Add feeds for user self and all watchers.
|
||||||
|
watchers, err = repo_model.GetWatchers(ctx, act.RepoID)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("get watchers: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add feed for actioner.
|
||||||
|
act.UserID = act.ActUserID
|
||||||
|
if _, err = e.Insert(act); err != nil {
|
||||||
|
return fmt.Errorf("insert new actioner: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if repoChanged {
|
||||||
|
act.loadRepo()
|
||||||
|
repo = act.Repo
|
||||||
|
|
||||||
|
// check repo owner exist.
|
||||||
|
if err := act.Repo.GetOwner(ctx); err != nil {
|
||||||
|
return fmt.Errorf("can't get repo owner: %v", err)
|
||||||
|
}
|
||||||
|
} else if act.Repo == nil {
|
||||||
|
act.Repo = repo
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add feed for organization
|
||||||
|
if act.Repo.Owner.IsOrganization() && act.ActUserID != act.Repo.Owner.ID {
|
||||||
|
act.ID = 0
|
||||||
|
act.UserID = act.Repo.Owner.ID
|
||||||
|
if _, err = e.InsertOne(act); err != nil {
|
||||||
|
return fmt.Errorf("insert new actioner: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if repoChanged {
|
||||||
|
permCode = make([]bool, len(watchers))
|
||||||
|
permIssue = make([]bool, len(watchers))
|
||||||
|
permPR = make([]bool, len(watchers))
|
||||||
|
for i, watcher := range watchers {
|
||||||
|
user, err := user_model.GetUserByIDEngine(e, watcher.UserID)
|
||||||
|
if err != nil {
|
||||||
|
permCode[i] = false
|
||||||
|
permIssue[i] = false
|
||||||
|
permPR[i] = false
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
perm, err := getUserRepoPermission(ctx, repo, user)
|
||||||
|
if err != nil {
|
||||||
|
permCode[i] = false
|
||||||
|
permIssue[i] = false
|
||||||
|
permPR[i] = false
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
permCode[i] = perm.CanRead(unit.TypeCode)
|
||||||
|
permIssue[i] = perm.CanRead(unit.TypeIssues)
|
||||||
|
permPR[i] = perm.CanRead(unit.TypePullRequests)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, watcher := range watchers {
|
||||||
|
if act.ActUserID == watcher.UserID {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
act.ID = 0
|
||||||
|
act.UserID = watcher.UserID
|
||||||
|
act.Repo.Units = nil
|
||||||
|
|
||||||
|
switch act.OpType {
|
||||||
|
case ActionCommitRepo, ActionPushTag, ActionDeleteTag, ActionPublishRelease, ActionDeleteBranch:
|
||||||
|
if !permCode[i] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
case ActionCreateIssue, ActionCommentIssue, ActionCloseIssue, ActionReopenIssue:
|
||||||
|
if !permIssue[i] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
case ActionCreatePullRequest, ActionCommentPull, ActionMergePullRequest, ActionClosePullRequest, ActionReopenPullRequest:
|
||||||
|
if !permPR[i] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = e.InsertOne(act); err != nil {
|
||||||
|
return fmt.Errorf("insert new action: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotifyWatchers creates batch of actions for every watcher.
|
||||||
|
func NotifyWatchers(actions ...*Action) error {
|
||||||
|
return notifyWatchers(db.DefaultContext, actions...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotifyWatchersActions creates batch of actions for every watcher.
|
||||||
|
func NotifyWatchersActions(acts []*Action) error {
|
||||||
|
ctx, committer, err := db.TxContext()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer committer.Close()
|
||||||
|
for _, act := range acts {
|
||||||
|
if err := notifyWatchers(ctx, act); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return committer.Commit()
|
||||||
|
}
|
||||||
|
|
|
@ -92,3 +92,40 @@ func TestGetFeeds2(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, actions, 0)
|
assert.Len(t, actions, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNotifyWatchers(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
action := &Action{
|
||||||
|
ActUserID: 8,
|
||||||
|
RepoID: 1,
|
||||||
|
OpType: ActionStarRepo,
|
||||||
|
}
|
||||||
|
assert.NoError(t, NotifyWatchers(action))
|
||||||
|
|
||||||
|
// One watchers are inactive, thus action is only created for user 8, 1, 4, 11
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &Action{
|
||||||
|
ActUserID: action.ActUserID,
|
||||||
|
UserID: 8,
|
||||||
|
RepoID: action.RepoID,
|
||||||
|
OpType: action.OpType,
|
||||||
|
})
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &Action{
|
||||||
|
ActUserID: action.ActUserID,
|
||||||
|
UserID: 1,
|
||||||
|
RepoID: action.RepoID,
|
||||||
|
OpType: action.OpType,
|
||||||
|
})
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &Action{
|
||||||
|
ActUserID: action.ActUserID,
|
||||||
|
UserID: 4,
|
||||||
|
RepoID: action.RepoID,
|
||||||
|
OpType: action.OpType,
|
||||||
|
})
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &Action{
|
||||||
|
ActUserID: action.ActUserID,
|
||||||
|
UserID: 11,
|
||||||
|
RepoID: action.RepoID,
|
||||||
|
OpType: action.OpType,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -71,21 +71,6 @@ func (err ErrUserNotAllowedCreateOrg) Error() string {
|
||||||
return "user is not allowed to create organizations"
|
return "user is not allowed to create organizations"
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrReachLimitOfRepo represents a "ReachLimitOfRepo" kind of error.
|
|
||||||
type ErrReachLimitOfRepo struct {
|
|
||||||
Limit int
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrReachLimitOfRepo checks if an error is a ErrReachLimitOfRepo.
|
|
||||||
func IsErrReachLimitOfRepo(err error) bool {
|
|
||||||
_, ok := err.(ErrReachLimitOfRepo)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrReachLimitOfRepo) Error() string {
|
|
||||||
return fmt.Sprintf("user has reached maximum limit of repositories [limit: %d]", err.Limit)
|
|
||||||
}
|
|
||||||
|
|
||||||
// __ __.__ __ .__
|
// __ __.__ __ .__
|
||||||
// / \ / \__| | _|__|
|
// / \ / \__| | _|__|
|
||||||
// \ \/\/ / | |/ / |
|
// \ \/\/ / | |/ / |
|
||||||
|
@ -322,38 +307,6 @@ func (err ErrRepoTransferInProgress) Error() string {
|
||||||
return fmt.Sprintf("repository is already being transferred [uname: %s, name: %s]", err.Uname, err.Name)
|
return fmt.Sprintf("repository is already being transferred [uname: %s, name: %s]", err.Uname, err.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrRepoAlreadyExist represents a "RepoAlreadyExist" kind of error.
|
|
||||||
type ErrRepoAlreadyExist struct {
|
|
||||||
Uname string
|
|
||||||
Name string
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrRepoAlreadyExist checks if an error is a ErrRepoAlreadyExist.
|
|
||||||
func IsErrRepoAlreadyExist(err error) bool {
|
|
||||||
_, ok := err.(ErrRepoAlreadyExist)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrRepoAlreadyExist) Error() string {
|
|
||||||
return fmt.Sprintf("repository already exists [uname: %s, name: %s]", err.Uname, err.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrRepoFilesAlreadyExist represents a "RepoFilesAlreadyExist" kind of error.
|
|
||||||
type ErrRepoFilesAlreadyExist struct {
|
|
||||||
Uname string
|
|
||||||
Name string
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrRepoFilesAlreadyExist checks if an error is a ErrRepoAlreadyExist.
|
|
||||||
func IsErrRepoFilesAlreadyExist(err error) bool {
|
|
||||||
_, ok := err.(ErrRepoFilesAlreadyExist)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrRepoFilesAlreadyExist) Error() string {
|
|
||||||
return fmt.Sprintf("repository files already exist [uname: %s, name: %s]", err.Uname, err.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrForkAlreadyExist represents a "ForkAlreadyExist" kind of error.
|
// ErrForkAlreadyExist represents a "ForkAlreadyExist" kind of error.
|
||||||
type ErrForkAlreadyExist struct {
|
type ErrForkAlreadyExist struct {
|
||||||
Uname string
|
Uname string
|
||||||
|
@ -371,22 +324,6 @@ func (err ErrForkAlreadyExist) Error() string {
|
||||||
return fmt.Sprintf("repository is already forked by user [uname: %s, repo path: %s, fork path: %s]", err.Uname, err.RepoName, err.ForkName)
|
return fmt.Sprintf("repository is already forked by user [uname: %s, repo path: %s, fork path: %s]", err.Uname, err.RepoName, err.ForkName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrRepoRedirectNotExist represents a "RepoRedirectNotExist" kind of error.
|
|
||||||
type ErrRepoRedirectNotExist struct {
|
|
||||||
OwnerID int64
|
|
||||||
RepoName string
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrRepoRedirectNotExist check if an error is an ErrRepoRedirectNotExist.
|
|
||||||
func IsErrRepoRedirectNotExist(err error) bool {
|
|
||||||
_, ok := err.(ErrRepoRedirectNotExist)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrRepoRedirectNotExist) Error() string {
|
|
||||||
return fmt.Sprintf("repository redirect does not exist [uid: %d, name: %s]", err.OwnerID, err.RepoName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrInvalidCloneAddr represents a "InvalidCloneAddr" kind of error.
|
// ErrInvalidCloneAddr represents a "InvalidCloneAddr" kind of error.
|
||||||
type ErrInvalidCloneAddr struct {
|
type ErrInvalidCloneAddr struct {
|
||||||
Host string
|
Host string
|
||||||
|
|
|
@ -6,6 +6,7 @@ package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
)
|
)
|
||||||
|
@ -80,11 +81,11 @@ func CheckIssueWatch(user *user_model.User, issue *Issue) (bool, error) {
|
||||||
if exist {
|
if exist {
|
||||||
return iw.IsWatching, nil
|
return iw.IsWatching, nil
|
||||||
}
|
}
|
||||||
w, err := getWatch(db.GetEngine(db.DefaultContext), user.ID, issue.RepoID)
|
w, err := repo_model.GetWatch(db.DefaultContext, user.ID, issue.RepoID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
return isWatchMode(w.Mode) || IsUserParticipantsOfIssue(user, issue), nil
|
return repo_model.IsWatchMode(w.Mode) || IsUserParticipantsOfIssue(user, issue), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetIssueWatchersIDs returns IDs of subscribers or explicit unsubscribers to a given issue id
|
// GetIssueWatchersIDs returns IDs of subscribers or explicit unsubscribers to a given issue id
|
||||||
|
|
|
@ -225,7 +225,7 @@ func createOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, n
|
||||||
toNotify[id] = struct{}{}
|
toNotify[id] = struct{}{}
|
||||||
}
|
}
|
||||||
if !(issue.IsPull && HasWorkInProgressPrefix(issue.Title)) {
|
if !(issue.IsPull && HasWorkInProgressPrefix(issue.Title)) {
|
||||||
repoWatches, err := getRepoWatchersIDs(e, issue.RepoID)
|
repoWatches, err := repo_model.GetRepoWatchersIDs(ctx, issue.RepoID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -794,7 +794,7 @@ func removeOrgUser(ctx context.Context, orgID, userID int64) error {
|
||||||
return fmt.Errorf("GetUserRepositories [%d]: %v", userID, err)
|
return fmt.Errorf("GetUserRepositories [%d]: %v", userID, err)
|
||||||
}
|
}
|
||||||
for _, repoID := range repoIDs {
|
for _, repoID := range repoIDs {
|
||||||
if err = watchRepo(sess, userID, repoID, false); err != nil {
|
if err = repo_model.WatchRepoCtx(ctx, userID, repoID, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -238,7 +238,7 @@ func (t *Team) addRepository(ctx context.Context, repo *repo_model.Repository) (
|
||||||
return fmt.Errorf("getMembers: %v", err)
|
return fmt.Errorf("getMembers: %v", err)
|
||||||
}
|
}
|
||||||
for _, u := range t.Members {
|
for _, u := range t.Members {
|
||||||
if err = watchRepo(e, u.ID, repo.ID, true); err != nil {
|
if err = repo_model.WatchRepoCtx(ctx, u.ID, repo.ID, true); err != nil {
|
||||||
return fmt.Errorf("watchRepo: %v", err)
|
return fmt.Errorf("watchRepo: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -341,7 +341,7 @@ func (t *Team) removeAllRepositories(ctx context.Context) (err error) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = watchRepo(e, user.ID, repo.ID, false); err != nil {
|
if err = repo_model.WatchRepoCtx(ctx, user.ID, repo.ID, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -399,7 +399,7 @@ func (t *Team) removeRepository(ctx context.Context, repo *repo_model.Repository
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = watchRepo(e, teamUser.UID, repo.ID, false); err != nil {
|
if err = repo_model.WatchRepoCtx(ctx, teamUser.UID, repo.ID, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -857,7 +857,7 @@ func AddTeamMember(team *Team, userID int64) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if setting.Service.AutoWatchNewRepos {
|
if setting.Service.AutoWatchNewRepos {
|
||||||
if err = watchRepo(sess, userID, repo.ID, true); err != nil {
|
if err = repo_model.WatchRepoCtx(ctx, userID, repo.ID, true); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -370,3 +370,89 @@ func UpdateReleasesMigrationsByType(gitServiceType structs.GitServiceType, origi
|
||||||
})
|
})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PushUpdateDeleteTagsContext updates a number of delete tags with context
|
||||||
|
func PushUpdateDeleteTagsContext(ctx context.Context, repo *repo_model.Repository, tags []string) error {
|
||||||
|
return pushUpdateDeleteTags(db.GetEngine(ctx), repo, tags)
|
||||||
|
}
|
||||||
|
|
||||||
|
func pushUpdateDeleteTags(e db.Engine, repo *repo_model.Repository, tags []string) error {
|
||||||
|
if len(tags) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
lowerTags := make([]string, 0, len(tags))
|
||||||
|
for _, tag := range tags {
|
||||||
|
lowerTags = append(lowerTags, strings.ToLower(tag))
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := e.
|
||||||
|
Where("repo_id = ? AND is_tag = ?", repo.ID, true).
|
||||||
|
In("lower_tag_name", lowerTags).
|
||||||
|
Delete(new(Release)); err != nil {
|
||||||
|
return fmt.Errorf("Delete: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := e.
|
||||||
|
Where("repo_id = ? AND is_tag = ?", repo.ID, false).
|
||||||
|
In("lower_tag_name", lowerTags).
|
||||||
|
Cols("is_draft", "num_commits", "sha1").
|
||||||
|
Update(&Release{
|
||||||
|
IsDraft: true,
|
||||||
|
}); err != nil {
|
||||||
|
return fmt.Errorf("Update: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushUpdateDeleteTag must be called for any push actions to delete tag
|
||||||
|
func PushUpdateDeleteTag(repo *repo_model.Repository, tagName string) error {
|
||||||
|
rel, err := GetRelease(repo.ID, tagName)
|
||||||
|
if err != nil {
|
||||||
|
if IsErrReleaseNotExist(err) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fmt.Errorf("GetRelease: %v", err)
|
||||||
|
}
|
||||||
|
if rel.IsTag {
|
||||||
|
if _, err = db.GetEngine(db.DefaultContext).ID(rel.ID).Delete(new(Release)); err != nil {
|
||||||
|
return fmt.Errorf("Delete: %v", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rel.IsDraft = true
|
||||||
|
rel.NumCommits = 0
|
||||||
|
rel.Sha1 = ""
|
||||||
|
if _, err = db.GetEngine(db.DefaultContext).ID(rel.ID).AllCols().Update(rel); err != nil {
|
||||||
|
return fmt.Errorf("Update: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveOrUpdateTag must be called for any push actions to add tag
|
||||||
|
func SaveOrUpdateTag(repo *repo_model.Repository, newRel *Release) error {
|
||||||
|
rel, err := GetRelease(repo.ID, newRel.TagName)
|
||||||
|
if err != nil && !IsErrReleaseNotExist(err) {
|
||||||
|
return fmt.Errorf("GetRelease: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rel == nil {
|
||||||
|
rel = newRel
|
||||||
|
if _, err = db.GetEngine(db.DefaultContext).Insert(rel); err != nil {
|
||||||
|
return fmt.Errorf("InsertOne: %v", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rel.Sha1 = newRel.Sha1
|
||||||
|
rel.CreatedUnix = newRel.CreatedUnix
|
||||||
|
rel.NumCommits = newRel.NumCommits
|
||||||
|
rel.IsDraft = false
|
||||||
|
if rel.IsTag && newRel.PublisherID > 0 {
|
||||||
|
rel.PublisherID = newRel.PublisherID
|
||||||
|
}
|
||||||
|
if _, err = db.GetEngine(db.DefaultContext).ID(rel.ID).AllCols().Update(rel); err != nil {
|
||||||
|
return fmt.Errorf("Update: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
303
models/repo.go
303
models/repo.go
|
@ -14,7 +14,6 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
_ "image/jpeg" // Needed for jpeg support
|
_ "image/jpeg" // Needed for jpeg support
|
||||||
|
@ -218,7 +217,7 @@ func getReviewers(ctx context.Context, repo *repo_model.Repository, doerID, post
|
||||||
"SELECT uid AS user_id FROM `org_user` WHERE org_id = ? "+
|
"SELECT uid AS user_id FROM `org_user` WHERE org_id = ? "+
|
||||||
") AND id NOT IN (?, ?) ORDER BY name",
|
") AND id NOT IN (?, ?) ORDER BY name",
|
||||||
repo.ID, perm.AccessModeRead,
|
repo.ID, perm.AccessModeRead,
|
||||||
repo.ID, RepoWatchModeNormal, RepoWatchModeAuto,
|
repo.ID, repo_model.WatchModeNormal, repo_model.WatchModeAuto,
|
||||||
repo.OwnerID,
|
repo.OwnerID,
|
||||||
doerID, posterID).
|
doerID, posterID).
|
||||||
Find(&users); err != nil {
|
Find(&users); err != nil {
|
||||||
|
@ -280,7 +279,7 @@ func CanUserForkRepo(user *user_model.User, repo *repo_model.Repository) (bool,
|
||||||
if user == nil {
|
if user == nil {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
if repo.OwnerID != user.ID && !HasForkedRepo(user.ID, repo.ID) {
|
if repo.OwnerID != user.ID && !repo_model.HasForkedRepo(user.ID, repo.ID) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
ownedOrgs, err := GetOrgsCanCreateRepoByUserID(user.ID)
|
ownedOrgs, err := GetOrgsCanCreateRepoByUserID(user.ID)
|
||||||
|
@ -288,7 +287,7 @@ func CanUserForkRepo(user *user_model.User, repo *repo_model.Repository) (bool,
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
for _, org := range ownedOrgs {
|
for _, org := range ownedOrgs {
|
||||||
if repo.OwnerID != org.ID && !HasForkedRepo(org.ID, repo.ID) {
|
if repo.OwnerID != org.ID && !repo_model.HasForkedRepo(org.ID, repo.ID) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -317,24 +316,6 @@ func CanUserDelete(repo *repo_model.Repository, user *user_model.User) (bool, er
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRepoReaders returns all users that have explicit read access or higher to the repository.
|
|
||||||
func GetRepoReaders(repo *repo_model.Repository) (_ []*user_model.User, err error) {
|
|
||||||
return getUsersWithAccessMode(db.DefaultContext, repo, perm.AccessModeRead)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetRepoWriters returns all users that have write access to the repository.
|
|
||||||
func GetRepoWriters(repo *repo_model.Repository) (_ []*user_model.User, err error) {
|
|
||||||
return getUsersWithAccessMode(db.DefaultContext, repo, perm.AccessModeWrite)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsRepoReader returns true if user has explicit read access or higher to the repository.
|
|
||||||
func IsRepoReader(repo *repo_model.Repository, userID int64) (bool, error) {
|
|
||||||
if repo.OwnerID == userID {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
return db.GetEngine(db.DefaultContext).Where("repo_id = ? AND user_id = ? AND mode >= ?", repo.ID, userID, perm.AccessModeRead).Get(&Access{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// getUsersWithAccessMode returns users that have at least given access mode to the repository.
|
// getUsersWithAccessMode returns users that have at least given access mode to the repository.
|
||||||
func getUsersWithAccessMode(ctx context.Context, repo *repo_model.Repository, mode perm.AccessMode) (_ []*user_model.User, err error) {
|
func getUsersWithAccessMode(ctx context.Context, repo *repo_model.Repository, mode perm.AccessMode) (_ []*user_model.User, err error) {
|
||||||
if err = repo.GetOwner(ctx); err != nil {
|
if err = repo.GetOwner(ctx); err != nil {
|
||||||
|
@ -372,35 +353,6 @@ func SetRepoReadBy(repoID, userID int64) error {
|
||||||
return setRepoNotificationStatusReadIfUnread(db.GetEngine(db.DefaultContext), userID, repoID)
|
return setRepoNotificationStatusReadIfUnread(db.GetEngine(db.DefaultContext), userID, repoID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckCreateRepository check if could created a repository
|
|
||||||
func CheckCreateRepository(doer, u *user_model.User, name string, overwriteOrAdopt bool) error {
|
|
||||||
if !doer.CanCreateRepo() {
|
|
||||||
return ErrReachLimitOfRepo{u.MaxRepoCreation}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := IsUsableRepoName(name); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
has, err := repo_model.IsRepositoryExist(u, name)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("IsRepositoryExist: %v", err)
|
|
||||||
} else if has {
|
|
||||||
return ErrRepoAlreadyExist{u.Name, name}
|
|
||||||
}
|
|
||||||
|
|
||||||
repoPath := repo_model.RepoPath(u.Name, name)
|
|
||||||
isExist, err := util.IsExist(repoPath)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Unable to check if %s exists. Error: %v", repoPath, err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !overwriteOrAdopt && isExist {
|
|
||||||
return ErrRepoFilesAlreadyExist{u.Name, name}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateRepoOptions contains the create repository options
|
// CreateRepoOptions contains the create repository options
|
||||||
type CreateRepoOptions struct {
|
type CreateRepoOptions struct {
|
||||||
Name string
|
Name string
|
||||||
|
@ -421,13 +373,6 @@ type CreateRepoOptions struct {
|
||||||
MirrorInterval string
|
MirrorInterval string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ForkRepoOptions contains the fork repository options
|
|
||||||
type ForkRepoOptions struct {
|
|
||||||
BaseRepo *repo_model.Repository
|
|
||||||
Name string
|
|
||||||
Description string
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetRepoInitFile returns repository init files
|
// GetRepoInitFile returns repository init files
|
||||||
func GetRepoInitFile(tp, name string) ([]byte, error) {
|
func GetRepoInitFile(tp, name string) ([]byte, error) {
|
||||||
cleanedName := strings.TrimLeft(path.Clean("/"+name), "/")
|
cleanedName := strings.TrimLeft(path.Clean("/"+name), "/")
|
||||||
|
@ -457,23 +402,9 @@ func GetRepoInitFile(tp, name string) ([]byte, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
reservedRepoNames = []string{".", ".."}
|
|
||||||
reservedRepoPatterns = []string{"*.git", "*.wiki", "*.rss", "*.atom"}
|
|
||||||
)
|
|
||||||
|
|
||||||
// IsUsableRepoName returns true when repository is usable
|
|
||||||
func IsUsableRepoName(name string) error {
|
|
||||||
if db.AlphaDashDotPattern.MatchString(name) {
|
|
||||||
// Note: usually this error is normally caught up earlier in the UI
|
|
||||||
return db.ErrNameCharsNotAllowed{Name: name}
|
|
||||||
}
|
|
||||||
return db.IsUsableName(reservedRepoNames, reservedRepoPatterns, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateRepository creates a repository for the user/organization.
|
// CreateRepository creates a repository for the user/organization.
|
||||||
func CreateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository, overwriteOrAdopt bool) (err error) {
|
func CreateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository, overwriteOrAdopt bool) (err error) {
|
||||||
if err = IsUsableRepoName(repo.Name); err != nil {
|
if err = repo_model.IsUsableRepoName(repo.Name); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -481,7 +412,10 @@ func CreateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("IsRepositoryExist: %v", err)
|
return fmt.Errorf("IsRepositoryExist: %v", err)
|
||||||
} else if has {
|
} else if has {
|
||||||
return ErrRepoAlreadyExist{u.Name, repo.Name}
|
return repo_model.ErrRepoAlreadyExist{
|
||||||
|
Uname: u.Name,
|
||||||
|
Name: repo.Name,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repoPath := repo_model.RepoPath(u.Name, repo.Name)
|
repoPath := repo_model.RepoPath(u.Name, repo.Name)
|
||||||
|
@ -492,7 +426,7 @@ func CreateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_
|
||||||
}
|
}
|
||||||
if !overwriteOrAdopt && isExist {
|
if !overwriteOrAdopt && isExist {
|
||||||
log.Error("Files already exist in %s and we are not going to adopt or delete.", repoPath)
|
log.Error("Files already exist in %s and we are not going to adopt or delete.", repoPath)
|
||||||
return ErrRepoFilesAlreadyExist{
|
return repo_model.ErrRepoFilesAlreadyExist{
|
||||||
Uname: u.Name,
|
Uname: u.Name,
|
||||||
Name: repo.Name,
|
Name: repo.Name,
|
||||||
}
|
}
|
||||||
|
@ -501,7 +435,7 @@ func CreateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_
|
||||||
if err = db.Insert(ctx, repo); err != nil {
|
if err = db.Insert(ctx, repo); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err = deleteRepoRedirect(db.GetEngine(ctx), u.ID, repo.Name); err != nil {
|
if err = repo_model.DeleteRedirect(ctx, u.ID, repo.Name); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -578,7 +512,7 @@ func CreateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_
|
||||||
}
|
}
|
||||||
|
|
||||||
if setting.Service.AutoWatchNewRepos {
|
if setting.Service.AutoWatchNewRepos {
|
||||||
if err = watchRepo(db.GetEngine(ctx), doer.ID, repo.ID, true); err != nil {
|
if err = repo_model.WatchRepoCtx(ctx, doer.ID, repo.ID, true); err != nil {
|
||||||
return fmt.Errorf("watchRepo: %v", err)
|
return fmt.Errorf("watchRepo: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -633,67 +567,6 @@ func DecrementRepoForkNum(ctx context.Context, repoID int64) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChangeRepositoryName changes all corresponding setting from old repository name to new one.
|
|
||||||
func ChangeRepositoryName(doer *user_model.User, repo *repo_model.Repository, newRepoName string) (err error) {
|
|
||||||
oldRepoName := repo.Name
|
|
||||||
newRepoName = strings.ToLower(newRepoName)
|
|
||||||
if err = IsUsableRepoName(newRepoName); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := repo.GetOwner(db.DefaultContext); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
has, err := repo_model.IsRepositoryExist(repo.Owner, newRepoName)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("IsRepositoryExist: %v", err)
|
|
||||||
} else if has {
|
|
||||||
return ErrRepoAlreadyExist{repo.Owner.Name, newRepoName}
|
|
||||||
}
|
|
||||||
|
|
||||||
newRepoPath := repo_model.RepoPath(repo.Owner.Name, newRepoName)
|
|
||||||
if err = util.Rename(repo.RepoPath(), newRepoPath); err != nil {
|
|
||||||
return fmt.Errorf("rename repository directory: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
wikiPath := repo.WikiPath()
|
|
||||||
isExist, err := util.IsExist(wikiPath)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Unable to check if %s exists. Error: %v", wikiPath, err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if isExist {
|
|
||||||
if err = util.Rename(wikiPath, repo_model.WikiPath(repo.Owner.Name, newRepoName)); err != nil {
|
|
||||||
return fmt.Errorf("rename repository wiki: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, committer, err := db.TxContext()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer committer.Close()
|
|
||||||
|
|
||||||
if err := newRepoRedirect(db.GetEngine(ctx), repo.Owner.ID, repo.ID, oldRepoName, newRepoName); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return committer.Commit()
|
|
||||||
}
|
|
||||||
|
|
||||||
func getRepositoriesByForkID(e db.Engine, forkID int64) ([]*repo_model.Repository, error) {
|
|
||||||
repos := make([]*repo_model.Repository, 0, 10)
|
|
||||||
return repos, e.
|
|
||||||
Where("fork_id=?", forkID).
|
|
||||||
Find(&repos)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetRepositoriesByForkID returns all repositories with given fork ID.
|
|
||||||
func GetRepositoriesByForkID(forkID int64) ([]*repo_model.Repository, error) {
|
|
||||||
return getRepositoriesByForkID(db.GetEngine(db.DefaultContext), forkID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateRepository(ctx context.Context, repo *repo_model.Repository, visibilityChanged bool) (err error) {
|
func updateRepository(ctx context.Context, repo *repo_model.Repository, visibilityChanged bool) (err error) {
|
||||||
repo.LowerName = strings.ToLower(repo.Name)
|
repo.LowerName = strings.ToLower(repo.Name)
|
||||||
|
|
||||||
|
@ -740,7 +613,7 @@ func updateRepository(ctx context.Context, repo *repo_model.Repository, visibili
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
forkRepos, err := getRepositoriesByForkID(e, repo.ID)
|
forkRepos, err := repo_model.GetRepositoriesByForkID(ctx, repo.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("getRepositoriesByForkID: %v", err)
|
return fmt.Errorf("getRepositoriesByForkID: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -775,58 +648,6 @@ func UpdateRepository(repo *repo_model.Repository, visibilityChanged bool) (err
|
||||||
return committer.Commit()
|
return committer.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateRepositoryOwnerNames updates repository owner_names (this should only be used when the ownerName has changed case)
|
|
||||||
func UpdateRepositoryOwnerNames(ownerID int64, ownerName string) error {
|
|
||||||
if ownerID == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
ctx, committer, err := db.TxContext()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer committer.Close()
|
|
||||||
|
|
||||||
if _, err := db.GetEngine(ctx).Where("owner_id = ?", ownerID).Cols("owner_name").Update(&repo_model.Repository{
|
|
||||||
OwnerName: ownerName,
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return committer.Commit()
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateRepositoryUpdatedTime updates a repository's updated time
|
|
||||||
func UpdateRepositoryUpdatedTime(repoID int64, updateTime time.Time) error {
|
|
||||||
_, err := db.GetEngine(db.DefaultContext).Exec("UPDATE repository SET updated_unix = ? WHERE id = ?", updateTime.Unix(), repoID)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateRepositoryUnits updates a repository's units
|
|
||||||
func UpdateRepositoryUnits(repo *repo_model.Repository, units []repo_model.RepoUnit, deleteUnitTypes []unit.Type) (err error) {
|
|
||||||
ctx, committer, err := db.TxContext()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer committer.Close()
|
|
||||||
|
|
||||||
// Delete existing settings of units before adding again
|
|
||||||
for _, u := range units {
|
|
||||||
deleteUnitTypes = append(deleteUnitTypes, u.Type)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = db.GetEngine(ctx).Where("repo_id = ?", repo.ID).In("type", deleteUnitTypes).Delete(new(repo_model.RepoUnit)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(units) > 0 {
|
|
||||||
if err = db.Insert(ctx, units); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return committer.Commit()
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteRepository deletes a repository for a user or organization.
|
// DeleteRepository deletes a repository for a user or organization.
|
||||||
// make sure if you call this func to close open sessions (sqlite will otherwise get a deadlock)
|
// make sure if you call this func to close open sessions (sqlite will otherwise get a deadlock)
|
||||||
func DeleteRepository(doer *user_model.User, uid, repoID int64) error {
|
func DeleteRepository(doer *user_model.User, uid, repoID int64) error {
|
||||||
|
@ -927,11 +748,11 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error {
|
||||||
&repo_model.PushMirror{RepoID: repoID},
|
&repo_model.PushMirror{RepoID: repoID},
|
||||||
&Release{RepoID: repoID},
|
&Release{RepoID: repoID},
|
||||||
&repo_model.RepoIndexerStatus{RepoID: repoID},
|
&repo_model.RepoIndexerStatus{RepoID: repoID},
|
||||||
&RepoRedirect{RedirectRepoID: repoID},
|
&repo_model.Redirect{RedirectRepoID: repoID},
|
||||||
&repo_model.RepoUnit{RepoID: repoID},
|
&repo_model.RepoUnit{RepoID: repoID},
|
||||||
&Star{RepoID: repoID},
|
&repo_model.Star{RepoID: repoID},
|
||||||
&Task{RepoID: repoID},
|
&Task{RepoID: repoID},
|
||||||
&Watch{RepoID: repoID},
|
&repo_model.Watch{RepoID: repoID},
|
||||||
&webhook.Webhook{RepoID: repoID},
|
&webhook.Webhook{RepoID: repoID},
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return fmt.Errorf("deleteBeans: %v", err)
|
return fmt.Errorf("deleteBeans: %v", err)
|
||||||
|
@ -964,7 +785,7 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(repo.Topics) > 0 {
|
if len(repo.Topics) > 0 {
|
||||||
if err := removeTopicsFromRepo(sess, repo.ID); err != nil {
|
if err := repo_model.RemoveTopicsFromRepo(ctx, repo.ID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1261,76 +1082,6 @@ func CheckRepoStats(ctx context.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetArchiveRepoState sets if a repo is archived
|
|
||||||
func SetArchiveRepoState(repo *repo_model.Repository, isArchived bool) (err error) {
|
|
||||||
repo.IsArchived = isArchived
|
|
||||||
_, err = db.GetEngine(db.DefaultContext).Where("id = ?", repo.ID).Cols("is_archived").NoAutoTime().Update(repo)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// ___________ __
|
|
||||||
// \_ _____/__________| | __
|
|
||||||
// | __)/ _ \_ __ \ |/ /
|
|
||||||
// | \( <_> ) | \/ <
|
|
||||||
// \___ / \____/|__| |__|_ \
|
|
||||||
// \/ \/
|
|
||||||
|
|
||||||
// GetForkedRepo checks if given user has already forked a repository with given ID.
|
|
||||||
func GetForkedRepo(ownerID, repoID int64) *repo_model.Repository {
|
|
||||||
repo := new(repo_model.Repository)
|
|
||||||
has, _ := db.GetEngine(db.DefaultContext).
|
|
||||||
Where("owner_id=? AND fork_id=?", ownerID, repoID).
|
|
||||||
Get(repo)
|
|
||||||
if has {
|
|
||||||
return repo
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasForkedRepo checks if given user has already forked a repository with given ID.
|
|
||||||
func HasForkedRepo(ownerID, repoID int64) bool {
|
|
||||||
has, _ := db.GetEngine(db.DefaultContext).
|
|
||||||
Table("repository").
|
|
||||||
Where("owner_id=? AND fork_id=?", ownerID, repoID).
|
|
||||||
Exist()
|
|
||||||
return has
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetForks returns all the forks of the repository
|
|
||||||
func GetForks(repo *repo_model.Repository, listOptions db.ListOptions) ([]*repo_model.Repository, error) {
|
|
||||||
if listOptions.Page == 0 {
|
|
||||||
forks := make([]*repo_model.Repository, 0, repo.NumForks)
|
|
||||||
return forks, db.GetEngine(db.DefaultContext).Find(&forks, &repo_model.Repository{ForkID: repo.ID})
|
|
||||||
}
|
|
||||||
|
|
||||||
sess := db.GetPaginatedSession(&listOptions)
|
|
||||||
forks := make([]*repo_model.Repository, 0, listOptions.PageSize)
|
|
||||||
return forks, sess.Find(&forks, &repo_model.Repository{ForkID: repo.ID})
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetUserFork return user forked repository from this repository, if not forked return nil
|
|
||||||
func GetUserFork(repoID, userID int64) (*repo_model.Repository, error) {
|
|
||||||
var forkedRepo repo_model.Repository
|
|
||||||
has, err := db.GetEngine(db.DefaultContext).Where("fork_id = ?", repoID).And("owner_id = ?", userID).Get(&forkedRepo)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if !has {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return &forkedRepo, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateRepositoryCols(e db.Engine, repo *repo_model.Repository, cols ...string) error {
|
|
||||||
_, err := e.ID(repo.ID).Cols(cols...).Update(repo)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateRepositoryCols updates repository's columns
|
|
||||||
func UpdateRepositoryCols(repo *repo_model.Repository, cols ...string) error {
|
|
||||||
return updateRepositoryCols(db.GetEngine(db.DefaultContext), repo, cols...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateUserStarNumbers(users []user_model.User) error {
|
func updateUserStarNumbers(users []user_model.User) error {
|
||||||
ctx, committer, err := db.TxContext()
|
ctx, committer, err := db.TxContext()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1370,28 +1121,6 @@ func DoctorUserStarNum() (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// IterateRepository iterate repositories
|
|
||||||
func IterateRepository(f func(repo *repo_model.Repository) error) error {
|
|
||||||
var start int
|
|
||||||
batchSize := setting.Database.IterateBufferSize
|
|
||||||
for {
|
|
||||||
repos := make([]*repo_model.Repository, 0, batchSize)
|
|
||||||
if err := db.GetEngine(db.DefaultContext).Limit(batchSize, start).Find(&repos); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if len(repos) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
start += len(repos)
|
|
||||||
|
|
||||||
for _, repo := range repos {
|
|
||||||
if err := f(repo); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// LinkedRepository returns the linked repo if any
|
// LinkedRepository returns the linked repo if any
|
||||||
func LinkedRepository(a *repo_model.Attachment) (*repo_model.Repository, unit.Type, error) {
|
func LinkedRepository(a *repo_model.Attachment) (*repo_model.Repository, unit.Type, error) {
|
||||||
if a.IssueID != 0 {
|
if a.IssueID != 0 {
|
||||||
|
|
|
@ -107,3 +107,10 @@ func FindRepoArchives(opts FindRepoArchiversOption) ([]*RepoArchiver, error) {
|
||||||
Find(&archivers)
|
Find(&archivers)
|
||||||
return archivers, err
|
return archivers, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetArchiveRepoState sets if a repo is archived
|
||||||
|
func SetArchiveRepoState(repo *Repository, isArchived bool) (err error) {
|
||||||
|
repo.IsArchived = isArchived
|
||||||
|
_, err = db.GetEngine(db.DefaultContext).Where("id = ?", repo.ID).Cols("is_archived").NoAutoTime().Update(repo)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
69
models/repo/fork.go
Normal file
69
models/repo/fork.go
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
// Copyright 2021 The Gitea 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 repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getRepositoriesByForkID(e db.Engine, forkID int64) ([]*Repository, error) {
|
||||||
|
repos := make([]*Repository, 0, 10)
|
||||||
|
return repos, e.
|
||||||
|
Where("fork_id=?", forkID).
|
||||||
|
Find(&repos)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRepositoriesByForkID returns all repositories with given fork ID.
|
||||||
|
func GetRepositoriesByForkID(ctx context.Context, forkID int64) ([]*Repository, error) {
|
||||||
|
return getRepositoriesByForkID(db.GetEngine(ctx), forkID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetForkedRepo checks if given user has already forked a repository with given ID.
|
||||||
|
func GetForkedRepo(ownerID, repoID int64) *Repository {
|
||||||
|
repo := new(Repository)
|
||||||
|
has, _ := db.GetEngine(db.DefaultContext).
|
||||||
|
Where("owner_id=? AND fork_id=?", ownerID, repoID).
|
||||||
|
Get(repo)
|
||||||
|
if has {
|
||||||
|
return repo
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasForkedRepo checks if given user has already forked a repository with given ID.
|
||||||
|
func HasForkedRepo(ownerID, repoID int64) bool {
|
||||||
|
has, _ := db.GetEngine(db.DefaultContext).
|
||||||
|
Table("repository").
|
||||||
|
Where("owner_id=? AND fork_id=?", ownerID, repoID).
|
||||||
|
Exist()
|
||||||
|
return has
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserFork return user forked repository from this repository, if not forked return nil
|
||||||
|
func GetUserFork(repoID, userID int64) (*Repository, error) {
|
||||||
|
var forkedRepo Repository
|
||||||
|
has, err := db.GetEngine(db.DefaultContext).Where("fork_id = ?", repoID).And("owner_id = ?", userID).Get(&forkedRepo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !has {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return &forkedRepo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetForks returns all the forks of the repository
|
||||||
|
func GetForks(repo *Repository, listOptions db.ListOptions) ([]*Repository, error) {
|
||||||
|
if listOptions.Page == 0 {
|
||||||
|
forks := make([]*Repository, 0, repo.NumForks)
|
||||||
|
return forks, db.GetEngine(db.DefaultContext).Find(&forks, &Repository{ForkID: repo.ID})
|
||||||
|
}
|
||||||
|
|
||||||
|
sess := db.GetPaginatedSession(&listOptions)
|
||||||
|
forks := make([]*Repository, 0, listOptions.PageSize)
|
||||||
|
return forks, sess.Find(&forks, &Repository{ForkID: repo.ID})
|
||||||
|
}
|
32
models/repo/fork_test.go
Normal file
32
models/repo/fork_test.go
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
// Copyright 2021 The Gitea 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 repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetUserFork(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
// User13 has repo 11 forked from repo10
|
||||||
|
repo, err := GetRepositoryByID(10)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, repo)
|
||||||
|
repo, err = GetUserFork(repo.ID, 13)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, repo)
|
||||||
|
|
||||||
|
repo, err = GetRepositoryByID(9)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, repo)
|
||||||
|
repo, err = GetUserFork(repo.ID, 13)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Nil(t, repo)
|
||||||
|
}
|
|
@ -18,5 +18,11 @@ func TestMain(m *testing.M) {
|
||||||
"repository.yml",
|
"repository.yml",
|
||||||
"repo_unit.yml",
|
"repo_unit.yml",
|
||||||
"repo_indexer_status.yml",
|
"repo_indexer_status.yml",
|
||||||
|
"repo_redirect.yml",
|
||||||
|
"watch.yml",
|
||||||
|
"star.yml",
|
||||||
|
"topic.yml",
|
||||||
|
"repo_topic.yml",
|
||||||
|
"user.yml",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
82
models/repo/redirect.go
Normal file
82
models/repo/redirect.go
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
// Copyright 2017 The Gitea 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 repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrRedirectNotExist represents a "RedirectNotExist" kind of error.
|
||||||
|
type ErrRedirectNotExist struct {
|
||||||
|
OwnerID int64
|
||||||
|
RepoName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrRedirectNotExist check if an error is an ErrRepoRedirectNotExist.
|
||||||
|
func IsErrRedirectNotExist(err error) bool {
|
||||||
|
_, ok := err.(ErrRedirectNotExist)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrRedirectNotExist) Error() string {
|
||||||
|
return fmt.Sprintf("repository redirect does not exist [uid: %d, name: %s]", err.OwnerID, err.RepoName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Redirect represents that a repo name should be redirected to another
|
||||||
|
type Redirect struct {
|
||||||
|
ID int64 `xorm:"pk autoincr"`
|
||||||
|
OwnerID int64 `xorm:"UNIQUE(s)"`
|
||||||
|
LowerName string `xorm:"UNIQUE(s) INDEX NOT NULL"`
|
||||||
|
RedirectRepoID int64 // repoID to redirect to
|
||||||
|
}
|
||||||
|
|
||||||
|
// TableName represents real table name in database
|
||||||
|
func (Redirect) TableName() string {
|
||||||
|
return "repo_redirect"
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
db.RegisterModel(new(Redirect))
|
||||||
|
}
|
||||||
|
|
||||||
|
// LookupRedirect look up if a repository has a redirect name
|
||||||
|
func LookupRedirect(ownerID int64, repoName string) (int64, error) {
|
||||||
|
repoName = strings.ToLower(repoName)
|
||||||
|
redirect := &Redirect{OwnerID: ownerID, LowerName: repoName}
|
||||||
|
if has, err := db.GetEngine(db.DefaultContext).Get(redirect); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if !has {
|
||||||
|
return 0, ErrRedirectNotExist{OwnerID: ownerID, RepoName: repoName}
|
||||||
|
}
|
||||||
|
return redirect.RedirectRepoID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRedirect create a new repo redirect
|
||||||
|
func NewRedirect(ctx context.Context, ownerID, repoID int64, oldRepoName, newRepoName string) error {
|
||||||
|
oldRepoName = strings.ToLower(oldRepoName)
|
||||||
|
newRepoName = strings.ToLower(newRepoName)
|
||||||
|
|
||||||
|
if err := DeleteRedirect(ctx, ownerID, newRepoName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return db.Insert(ctx, &Redirect{
|
||||||
|
OwnerID: ownerID,
|
||||||
|
LowerName: oldRepoName,
|
||||||
|
RedirectRepoID: repoID,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteRedirect delete any redirect from the specified repo name to
|
||||||
|
// anything else
|
||||||
|
func DeleteRedirect(ctx context.Context, ownerID int64, repoName string) error {
|
||||||
|
repoName = strings.ToLower(repoName)
|
||||||
|
_, err := db.GetEngine(ctx).Delete(&Redirect{OwnerID: ownerID, LowerName: repoName})
|
||||||
|
return err
|
||||||
|
}
|
77
models/repo/redirect_test.go
Normal file
77
models/repo/redirect_test.go
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
// Copyright 2017 The Gitea 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 repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLookupRedirect(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
repoID, err := LookupRedirect(2, "oldrepo1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 1, repoID)
|
||||||
|
|
||||||
|
_, err = LookupRedirect(unittest.NonexistentID, "doesnotexist")
|
||||||
|
assert.True(t, IsErrRedirectNotExist(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewRedirect(t *testing.T) {
|
||||||
|
// redirect to a completely new name
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
|
||||||
|
assert.NoError(t, NewRedirect(db.DefaultContext, repo.OwnerID, repo.ID, repo.Name, "newreponame"))
|
||||||
|
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &Redirect{
|
||||||
|
OwnerID: repo.OwnerID,
|
||||||
|
LowerName: repo.LowerName,
|
||||||
|
RedirectRepoID: repo.ID,
|
||||||
|
})
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &Redirect{
|
||||||
|
OwnerID: repo.OwnerID,
|
||||||
|
LowerName: "oldrepo1",
|
||||||
|
RedirectRepoID: repo.ID,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewRedirect2(t *testing.T) {
|
||||||
|
// redirect to previously used name
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
|
||||||
|
assert.NoError(t, NewRedirect(db.DefaultContext, repo.OwnerID, repo.ID, repo.Name, "oldrepo1"))
|
||||||
|
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &Redirect{
|
||||||
|
OwnerID: repo.OwnerID,
|
||||||
|
LowerName: repo.LowerName,
|
||||||
|
RedirectRepoID: repo.ID,
|
||||||
|
})
|
||||||
|
unittest.AssertNotExistsBean(t, &Redirect{
|
||||||
|
OwnerID: repo.OwnerID,
|
||||||
|
LowerName: "oldrepo1",
|
||||||
|
RedirectRepoID: repo.ID,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewRedirect3(t *testing.T) {
|
||||||
|
// redirect for a previously-unredirected repo
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 2}).(*Repository)
|
||||||
|
assert.NoError(t, NewRedirect(db.DefaultContext, repo.OwnerID, repo.ID, repo.Name, "newreponame"))
|
||||||
|
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &Redirect{
|
||||||
|
OwnerID: repo.OwnerID,
|
||||||
|
LowerName: repo.LowerName,
|
||||||
|
RedirectRepoID: repo.ID,
|
||||||
|
})
|
||||||
|
}
|
|
@ -25,6 +25,20 @@ import (
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
reservedRepoNames = []string{".", ".."}
|
||||||
|
reservedRepoPatterns = []string{"*.git", "*.wiki", "*.rss", "*.atom"}
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsUsableRepoName returns true when repository is usable
|
||||||
|
func IsUsableRepoName(name string) error {
|
||||||
|
if db.AlphaDashDotPattern.MatchString(name) {
|
||||||
|
// Note: usually this error is normally caught up earlier in the UI
|
||||||
|
return db.ErrNameCharsNotAllowed{Name: name}
|
||||||
|
}
|
||||||
|
return db.IsUsableName(reservedRepoNames, reservedRepoPatterns, name)
|
||||||
|
}
|
||||||
|
|
||||||
// TrustModelType defines the types of trust model for this repository
|
// TrustModelType defines the types of trust model for this repository
|
||||||
type TrustModelType int
|
type TrustModelType int
|
||||||
|
|
||||||
|
@ -734,3 +748,25 @@ func GetPublicRepositoryCount(u *user_model.User) (int64, error) {
|
||||||
func GetPrivateRepositoryCount(u *user_model.User) (int64, error) {
|
func GetPrivateRepositoryCount(u *user_model.User) (int64, error) {
|
||||||
return getPrivateRepositoryCount(db.GetEngine(db.DefaultContext), u)
|
return getPrivateRepositoryCount(db.GetEngine(db.DefaultContext), u)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IterateRepository iterate repositories
|
||||||
|
func IterateRepository(f func(repo *Repository) error) error {
|
||||||
|
var start int
|
||||||
|
batchSize := setting.Database.IterateBufferSize
|
||||||
|
for {
|
||||||
|
repos := make([]*Repository, 0, batchSize)
|
||||||
|
if err := db.GetEngine(db.DefaultContext).Limit(batchSize, start).Find(&repos); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(repos) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
start += len(repos)
|
||||||
|
|
||||||
|
for _, repo := range repos {
|
||||||
|
if err := f(repo); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -42,3 +42,10 @@ func TestGetPrivateRepositoryCount(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, int64(2), count)
|
assert.Equal(t, int64(2), count)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRepoAPIURL(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 10}).(*Repository)
|
||||||
|
|
||||||
|
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user12/repo10", repo.APIURL())
|
||||||
|
}
|
||||||
|
|
|
@ -242,3 +242,29 @@ func UpdateRepoUnit(unit *RepoUnit) error {
|
||||||
_, err := db.GetEngine(db.DefaultContext).ID(unit.ID).Update(unit)
|
_, err := db.GetEngine(db.DefaultContext).ID(unit.ID).Update(unit)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateRepositoryUnits updates a repository's units
|
||||||
|
func UpdateRepositoryUnits(repo *Repository, units []RepoUnit, deleteUnitTypes []unit.Type) (err error) {
|
||||||
|
ctx, committer, err := db.TxContext()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer committer.Close()
|
||||||
|
|
||||||
|
// Delete existing settings of units before adding again
|
||||||
|
for _, u := range units {
|
||||||
|
deleteUnitTypes = append(deleteUnitTypes, u.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = db.GetEngine(ctx).Where("repo_id = ?", repo.ID).In("type", deleteUnitTypes).Delete(new(RepoUnit)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(units) > 0 {
|
||||||
|
if err = db.Insert(ctx, units); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return committer.Commit()
|
||||||
|
}
|
||||||
|
|
|
@ -2,11 +2,10 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package repo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
)
|
)
|
||||||
|
@ -76,7 +75,7 @@ func isStaring(e db.Engine, userID, repoID int64) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetStargazers returns the users that starred the repo.
|
// GetStargazers returns the users that starred the repo.
|
||||||
func GetStargazers(repo *repo_model.Repository, opts db.ListOptions) ([]*user_model.User, error) {
|
func GetStargazers(repo *Repository, opts db.ListOptions) ([]*user_model.User, error) {
|
||||||
sess := db.GetEngine(db.DefaultContext).Where("star.repo_id = ?", repo.ID).
|
sess := db.GetEngine(db.DefaultContext).Where("star.repo_id = ?", repo.ID).
|
||||||
Join("LEFT", "star", "`user`.id = star.uid")
|
Join("LEFT", "star", "`user`.id = star.uid")
|
||||||
if opts.Page > 0 {
|
if opts.Page > 0 {
|
|
@ -2,13 +2,12 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package repo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -36,7 +35,7 @@ func TestIsStaring(t *testing.T) {
|
||||||
func TestRepository_GetStargazers(t *testing.T) {
|
func TestRepository_GetStargazers(t *testing.T) {
|
||||||
// repo with stargazers
|
// repo with stargazers
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 4}).(*Repository)
|
||||||
gazers, err := GetStargazers(repo, db.ListOptions{Page: 0})
|
gazers, err := GetStargazers(repo, db.ListOptions{Page: 0})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
if assert.Len(t, gazers, 1) {
|
if assert.Len(t, gazers, 1) {
|
||||||
|
@ -47,7 +46,7 @@ func TestRepository_GetStargazers(t *testing.T) {
|
||||||
func TestRepository_GetStargazers2(t *testing.T) {
|
func TestRepository_GetStargazers2(t *testing.T) {
|
||||||
// repo with stargazers
|
// repo with stargazers
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 3}).(*Repository)
|
||||||
gazers, err := GetStargazers(repo, db.ListOptions{Page: 0})
|
gazers, err := GetStargazers(repo, db.ListOptions{Page: 0})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, gazers, 0)
|
assert.Len(t, gazers, 0)
|
|
@ -2,15 +2,15 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package repo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
|
|
||||||
"xorm.io/builder"
|
"xorm.io/builder"
|
||||||
|
@ -33,7 +33,7 @@ type Topic struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RepoTopic represents associated repositories and topics
|
// RepoTopic represents associated repositories and topics
|
||||||
type RepoTopic struct {
|
type RepoTopic struct { //revive:disable-line:exported
|
||||||
RepoID int64 `xorm:"pk"`
|
RepoID int64 `xorm:"pk"`
|
||||||
TopicID int64 `xorm:"pk"`
|
TopicID int64 `xorm:"pk"`
|
||||||
}
|
}
|
||||||
|
@ -145,8 +145,9 @@ func removeTopicFromRepo(e db.Engine, repoID int64, topic *Topic) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// removeTopicsFromRepo remove all topics from the repo and decrements respective topics repo count
|
// RemoveTopicsFromRepo remove all topics from the repo and decrements respective topics repo count
|
||||||
func removeTopicsFromRepo(e db.Engine, repoID int64) error {
|
func RemoveTopicsFromRepo(ctx context.Context, repoID int64) error {
|
||||||
|
e := db.GetEngine(ctx)
|
||||||
_, err := e.Where(
|
_, err := e.Where(
|
||||||
builder.In("id",
|
builder.In("id",
|
||||||
builder.Select("topic_id").From("repo_topic").Where(builder.Eq{"repo_id": repoID}),
|
builder.Select("topic_id").From("repo_topic").Where(builder.Eq{"repo_id": repoID}),
|
||||||
|
@ -254,7 +255,7 @@ func AddTopic(repoID int64, topicName string) (*Topic, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := sess.ID(repoID).Cols("topics").Update(&repo_model.Repository{
|
if _, err := sess.ID(repoID).Cols("topics").Update(&Repository{
|
||||||
Topics: topicNames,
|
Topics: topicNames,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -348,7 +349,7 @@ func SaveTopics(repoID int64, topicNames ...string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := sess.ID(repoID).Cols("topics").Update(&repo_model.Repository{
|
if _, err := sess.ID(repoID).Cols("topics").Update(&Repository{
|
||||||
Topics: topicNames,
|
Topics: topicNames,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -356,3 +357,13 @@ func SaveTopics(repoID int64, topicNames ...string) error {
|
||||||
|
|
||||||
return committer.Commit()
|
return committer.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GenerateTopics generates topics from a template repository
|
||||||
|
func GenerateTopics(ctx context.Context, templateRepo, generateRepo *Repository) error {
|
||||||
|
for _, topic := range templateRepo.Topics {
|
||||||
|
if _, err := addTopicByNameToRepo(db.GetEngine(ctx), generateRepo.ID, topic); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package repo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
179
models/repo/update.go
Normal file
179
models/repo/update.go
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
// Copyright 2021 The Gitea 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 repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UpdateRepositoryOwnerNames updates repository owner_names (this should only be used when the ownerName has changed case)
|
||||||
|
func UpdateRepositoryOwnerNames(ownerID int64, ownerName string) error {
|
||||||
|
if ownerID == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ctx, committer, err := db.TxContext()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer committer.Close()
|
||||||
|
|
||||||
|
if _, err := db.GetEngine(ctx).Where("owner_id = ?", ownerID).Cols("owner_name").Update(&Repository{
|
||||||
|
OwnerName: ownerName,
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return committer.Commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateRepositoryUpdatedTime updates a repository's updated time
|
||||||
|
func UpdateRepositoryUpdatedTime(repoID int64, updateTime time.Time) error {
|
||||||
|
_, err := db.GetEngine(db.DefaultContext).Exec("UPDATE repository SET updated_unix = ? WHERE id = ?", updateTime.Unix(), repoID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateRepositoryColsCtx updates repository's columns
|
||||||
|
func UpdateRepositoryColsCtx(ctx context.Context, repo *Repository, cols ...string) error {
|
||||||
|
_, err := db.GetEngine(ctx).ID(repo.ID).Cols(cols...).Update(repo)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateRepositoryCols updates repository's columns
|
||||||
|
func UpdateRepositoryCols(repo *Repository, cols ...string) error {
|
||||||
|
return UpdateRepositoryColsCtx(db.DefaultContext, repo, cols...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrReachLimitOfRepo represents a "ReachLimitOfRepo" kind of error.
|
||||||
|
type ErrReachLimitOfRepo struct {
|
||||||
|
Limit int
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrReachLimitOfRepo checks if an error is a ErrReachLimitOfRepo.
|
||||||
|
func IsErrReachLimitOfRepo(err error) bool {
|
||||||
|
_, ok := err.(ErrReachLimitOfRepo)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrReachLimitOfRepo) Error() string {
|
||||||
|
return fmt.Sprintf("user has reached maximum limit of repositories [limit: %d]", err.Limit)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrRepoAlreadyExist represents a "RepoAlreadyExist" kind of error.
|
||||||
|
type ErrRepoAlreadyExist struct {
|
||||||
|
Uname string
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrRepoAlreadyExist checks if an error is a ErrRepoAlreadyExist.
|
||||||
|
func IsErrRepoAlreadyExist(err error) bool {
|
||||||
|
_, ok := err.(ErrRepoAlreadyExist)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrRepoAlreadyExist) Error() string {
|
||||||
|
return fmt.Sprintf("repository already exists [uname: %s, name: %s]", err.Uname, err.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrRepoFilesAlreadyExist represents a "RepoFilesAlreadyExist" kind of error.
|
||||||
|
type ErrRepoFilesAlreadyExist struct {
|
||||||
|
Uname string
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrRepoFilesAlreadyExist checks if an error is a ErrRepoAlreadyExist.
|
||||||
|
func IsErrRepoFilesAlreadyExist(err error) bool {
|
||||||
|
_, ok := err.(ErrRepoFilesAlreadyExist)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrRepoFilesAlreadyExist) Error() string {
|
||||||
|
return fmt.Sprintf("repository files already exist [uname: %s, name: %s]", err.Uname, err.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckCreateRepository check if could created a repository
|
||||||
|
func CheckCreateRepository(doer, u *user_model.User, name string, overwriteOrAdopt bool) error {
|
||||||
|
if !doer.CanCreateRepo() {
|
||||||
|
return ErrReachLimitOfRepo{u.MaxRepoCreation}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := IsUsableRepoName(name); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
has, err := IsRepositoryExist(u, name)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("IsRepositoryExist: %v", err)
|
||||||
|
} else if has {
|
||||||
|
return ErrRepoAlreadyExist{u.Name, name}
|
||||||
|
}
|
||||||
|
|
||||||
|
repoPath := RepoPath(u.Name, name)
|
||||||
|
isExist, err := util.IsExist(repoPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Unable to check if %s exists. Error: %v", repoPath, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !overwriteOrAdopt && isExist {
|
||||||
|
return ErrRepoFilesAlreadyExist{u.Name, name}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChangeRepositoryName changes all corresponding setting from old repository name to new one.
|
||||||
|
func ChangeRepositoryName(doer *user_model.User, repo *Repository, newRepoName string) (err error) {
|
||||||
|
oldRepoName := repo.Name
|
||||||
|
newRepoName = strings.ToLower(newRepoName)
|
||||||
|
if err = IsUsableRepoName(newRepoName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := repo.GetOwner(db.DefaultContext); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
has, err := IsRepositoryExist(repo.Owner, newRepoName)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("IsRepositoryExist: %v", err)
|
||||||
|
} else if has {
|
||||||
|
return ErrRepoAlreadyExist{repo.Owner.Name, newRepoName}
|
||||||
|
}
|
||||||
|
|
||||||
|
newRepoPath := RepoPath(repo.Owner.Name, newRepoName)
|
||||||
|
if err = util.Rename(repo.RepoPath(), newRepoPath); err != nil {
|
||||||
|
return fmt.Errorf("rename repository directory: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
wikiPath := repo.WikiPath()
|
||||||
|
isExist, err := util.IsExist(wikiPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Unable to check if %s exists. Error: %v", wikiPath, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if isExist {
|
||||||
|
if err = util.Rename(wikiPath, WikiPath(repo.Owner.Name, newRepoName)); err != nil {
|
||||||
|
return fmt.Errorf("rename repository wiki: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, committer, err := db.TxContext()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer committer.Close()
|
||||||
|
|
||||||
|
if err := NewRedirect(ctx, repo.Owner.ID, repo.ID, oldRepoName, newRepoName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return committer.Commit()
|
||||||
|
}
|
196
models/repo/watch.go
Normal file
196
models/repo/watch.go
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
// Copyright 2017 The Gitea 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 repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WatchMode specifies what kind of watch the user has on a repository
|
||||||
|
type WatchMode int8
|
||||||
|
|
||||||
|
const (
|
||||||
|
// WatchModeNone don't watch
|
||||||
|
WatchModeNone WatchMode = iota // 0
|
||||||
|
// WatchModeNormal watch repository (from other sources)
|
||||||
|
WatchModeNormal // 1
|
||||||
|
// WatchModeDont explicit don't auto-watch
|
||||||
|
WatchModeDont // 2
|
||||||
|
// WatchModeAuto watch repository (from AutoWatchOnChanges)
|
||||||
|
WatchModeAuto // 3
|
||||||
|
)
|
||||||
|
|
||||||
|
// Watch is connection request for receiving repository notification.
|
||||||
|
type Watch struct {
|
||||||
|
ID int64 `xorm:"pk autoincr"`
|
||||||
|
UserID int64 `xorm:"UNIQUE(watch)"`
|
||||||
|
RepoID int64 `xorm:"UNIQUE(watch)"`
|
||||||
|
Mode WatchMode `xorm:"SMALLINT NOT NULL DEFAULT 1"`
|
||||||
|
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
|
||||||
|
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
db.RegisterModel(new(Watch))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWatch gets what kind of subscription a user has on a given repository; returns dummy record if none found
|
||||||
|
func GetWatch(ctx context.Context, userID, repoID int64) (Watch, error) {
|
||||||
|
watch := Watch{UserID: userID, RepoID: repoID}
|
||||||
|
has, err := db.GetEngine(ctx).Get(&watch)
|
||||||
|
if err != nil {
|
||||||
|
return watch, err
|
||||||
|
}
|
||||||
|
if !has {
|
||||||
|
watch.Mode = WatchModeNone
|
||||||
|
}
|
||||||
|
return watch, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsWatchMode Decodes watchability of WatchMode
|
||||||
|
func IsWatchMode(mode WatchMode) bool {
|
||||||
|
return mode != WatchModeNone && mode != WatchModeDont
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsWatching checks if user has watched given repository.
|
||||||
|
func IsWatching(userID, repoID int64) bool {
|
||||||
|
watch, err := GetWatch(db.DefaultContext, userID, repoID)
|
||||||
|
return err == nil && IsWatchMode(watch.Mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func watchRepoMode(ctx context.Context, watch Watch, mode WatchMode) (err error) {
|
||||||
|
if watch.Mode == mode {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if mode == WatchModeAuto && (watch.Mode == WatchModeDont || IsWatchMode(watch.Mode)) {
|
||||||
|
// Don't auto watch if already watching or deliberately not watching
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
hadrec := watch.Mode != WatchModeNone
|
||||||
|
needsrec := mode != WatchModeNone
|
||||||
|
repodiff := 0
|
||||||
|
|
||||||
|
if IsWatchMode(mode) && !IsWatchMode(watch.Mode) {
|
||||||
|
repodiff = 1
|
||||||
|
} else if !IsWatchMode(mode) && IsWatchMode(watch.Mode) {
|
||||||
|
repodiff = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
watch.Mode = mode
|
||||||
|
|
||||||
|
e := db.GetEngine(ctx)
|
||||||
|
|
||||||
|
if !hadrec && needsrec {
|
||||||
|
watch.Mode = mode
|
||||||
|
if _, err = e.Insert(watch); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if needsrec {
|
||||||
|
watch.Mode = mode
|
||||||
|
if _, err := e.ID(watch.ID).AllCols().Update(watch); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if _, err = e.Delete(Watch{ID: watch.ID}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if repodiff != 0 {
|
||||||
|
_, err = e.Exec("UPDATE `repository` SET num_watches = num_watches + ? WHERE id = ?", repodiff, watch.RepoID)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// WatchRepoMode watch repository in specific mode.
|
||||||
|
func WatchRepoMode(userID, repoID int64, mode WatchMode) (err error) {
|
||||||
|
var watch Watch
|
||||||
|
if watch, err = GetWatch(db.DefaultContext, userID, repoID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return watchRepoMode(db.DefaultContext, watch, mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WatchRepoCtx watch or unwatch repository.
|
||||||
|
func WatchRepoCtx(ctx context.Context, userID, repoID int64, doWatch bool) (err error) {
|
||||||
|
var watch Watch
|
||||||
|
if watch, err = GetWatch(ctx, userID, repoID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !doWatch && watch.Mode == WatchModeAuto {
|
||||||
|
err = watchRepoMode(ctx, watch, WatchModeDont)
|
||||||
|
} else if !doWatch {
|
||||||
|
err = watchRepoMode(ctx, watch, WatchModeNone)
|
||||||
|
} else {
|
||||||
|
err = watchRepoMode(ctx, watch, WatchModeNormal)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// WatchRepo watch or unwatch repository.
|
||||||
|
func WatchRepo(userID, repoID int64, watch bool) (err error) {
|
||||||
|
return WatchRepoCtx(db.DefaultContext, userID, repoID, watch)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWatchers returns all watchers of given repository.
|
||||||
|
func GetWatchers(ctx context.Context, repoID int64) ([]*Watch, error) {
|
||||||
|
watches := make([]*Watch, 0, 10)
|
||||||
|
return watches, db.GetEngine(ctx).Where("`watch`.repo_id=?", repoID).
|
||||||
|
And("`watch`.mode<>?", WatchModeDont).
|
||||||
|
And("`user`.is_active=?", true).
|
||||||
|
And("`user`.prohibit_login=?", false).
|
||||||
|
Join("INNER", "`user`", "`user`.id = `watch`.user_id").
|
||||||
|
Find(&watches)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRepoWatchersIDs returns IDs of watchers for a given repo ID
|
||||||
|
// but avoids joining with `user` for performance reasons
|
||||||
|
// User permissions must be verified elsewhere if required
|
||||||
|
func GetRepoWatchersIDs(ctx context.Context, repoID int64) ([]int64, error) {
|
||||||
|
ids := make([]int64, 0, 64)
|
||||||
|
return ids, db.GetEngine(ctx).Table("watch").
|
||||||
|
Where("watch.repo_id=?", repoID).
|
||||||
|
And("watch.mode<>?", WatchModeDont).
|
||||||
|
Select("user_id").
|
||||||
|
Find(&ids)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRepoWatchers returns range of users watching given repository.
|
||||||
|
func GetRepoWatchers(repoID int64, opts db.ListOptions) ([]*user_model.User, error) {
|
||||||
|
sess := db.GetEngine(db.DefaultContext).Where("watch.repo_id=?", repoID).
|
||||||
|
Join("LEFT", "watch", "`user`.id=`watch`.user_id").
|
||||||
|
And("`watch`.mode<>?", WatchModeDont)
|
||||||
|
if opts.Page > 0 {
|
||||||
|
sess = db.SetSessionPagination(sess, &opts)
|
||||||
|
users := make([]*user_model.User, 0, opts.PageSize)
|
||||||
|
|
||||||
|
return users, sess.Find(&users)
|
||||||
|
}
|
||||||
|
|
||||||
|
users := make([]*user_model.User, 0, 8)
|
||||||
|
return users, sess.Find(&users)
|
||||||
|
}
|
||||||
|
|
||||||
|
func watchIfAuto(ctx context.Context, userID, repoID int64, isWrite bool) error {
|
||||||
|
if !isWrite || !setting.Service.AutoWatchOnChanges {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
watch, err := GetWatch(ctx, userID, repoID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if watch.Mode != WatchModeNone {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return watchRepoMode(ctx, watch, WatchModeAuto)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WatchIfAuto subscribes to repo if AutoWatchOnChanges is set
|
||||||
|
func WatchIfAuto(userID, repoID int64, isWrite bool) error {
|
||||||
|
return watchIfAuto(db.DefaultContext, userID, repoID, isWrite)
|
||||||
|
}
|
|
@ -2,13 +2,12 @@
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package repo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
|
@ -27,25 +26,11 @@ func TestIsWatching(t *testing.T) {
|
||||||
assert.False(t, IsWatching(unittest.NonexistentID, unittest.NonexistentID))
|
assert.False(t, IsWatching(unittest.NonexistentID, unittest.NonexistentID))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWatchRepo(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
const repoID = 3
|
|
||||||
const userID = 2
|
|
||||||
|
|
||||||
assert.NoError(t, WatchRepo(userID, repoID, true))
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &Watch{RepoID: repoID, UserID: userID})
|
|
||||||
unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repoID})
|
|
||||||
|
|
||||||
assert.NoError(t, WatchRepo(userID, repoID, false))
|
|
||||||
unittest.AssertNotExistsBean(t, &Watch{RepoID: repoID, UserID: userID})
|
|
||||||
unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repoID})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetWatchers(t *testing.T) {
|
func TestGetWatchers(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
|
||||||
watches, err := GetWatchers(repo.ID)
|
watches, err := GetWatchers(db.DefaultContext, repo.ID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
// One watchers are inactive, thus minus 1
|
// One watchers are inactive, thus minus 1
|
||||||
assert.Len(t, watches, repo.NumWatches-1)
|
assert.Len(t, watches, repo.NumWatches-1)
|
||||||
|
@ -53,7 +38,7 @@ func TestGetWatchers(t *testing.T) {
|
||||||
assert.EqualValues(t, repo.ID, watch.RepoID)
|
assert.EqualValues(t, repo.ID, watch.RepoID)
|
||||||
}
|
}
|
||||||
|
|
||||||
watches, err = GetWatchers(unittest.NonexistentID)
|
watches, err = GetWatchers(db.DefaultContext, unittest.NonexistentID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, watches, 0)
|
assert.Len(t, watches, 0)
|
||||||
}
|
}
|
||||||
|
@ -61,7 +46,7 @@ func TestGetWatchers(t *testing.T) {
|
||||||
func TestRepository_GetWatchers(t *testing.T) {
|
func TestRepository_GetWatchers(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
|
||||||
watchers, err := GetRepoWatchers(repo.ID, db.ListOptions{Page: 1})
|
watchers, err := GetRepoWatchers(repo.ID, db.ListOptions{Page: 1})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, watchers, repo.NumWatches)
|
assert.Len(t, watchers, repo.NumWatches)
|
||||||
|
@ -69,53 +54,16 @@ func TestRepository_GetWatchers(t *testing.T) {
|
||||||
unittest.AssertExistsAndLoadBean(t, &Watch{UserID: watcher.ID, RepoID: repo.ID})
|
unittest.AssertExistsAndLoadBean(t, &Watch{UserID: watcher.ID, RepoID: repo.ID})
|
||||||
}
|
}
|
||||||
|
|
||||||
repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 9}).(*repo_model.Repository)
|
repo = unittest.AssertExistsAndLoadBean(t, &Repository{ID: 9}).(*Repository)
|
||||||
watchers, err = GetRepoWatchers(repo.ID, db.ListOptions{Page: 1})
|
watchers, err = GetRepoWatchers(repo.ID, db.ListOptions{Page: 1})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, watchers, 0)
|
assert.Len(t, watchers, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNotifyWatchers(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
|
|
||||||
action := &Action{
|
|
||||||
ActUserID: 8,
|
|
||||||
RepoID: 1,
|
|
||||||
OpType: ActionStarRepo,
|
|
||||||
}
|
|
||||||
assert.NoError(t, NotifyWatchers(action))
|
|
||||||
|
|
||||||
// One watchers are inactive, thus action is only created for user 8, 1, 4, 11
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &Action{
|
|
||||||
ActUserID: action.ActUserID,
|
|
||||||
UserID: 8,
|
|
||||||
RepoID: action.RepoID,
|
|
||||||
OpType: action.OpType,
|
|
||||||
})
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &Action{
|
|
||||||
ActUserID: action.ActUserID,
|
|
||||||
UserID: 1,
|
|
||||||
RepoID: action.RepoID,
|
|
||||||
OpType: action.OpType,
|
|
||||||
})
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &Action{
|
|
||||||
ActUserID: action.ActUserID,
|
|
||||||
UserID: 4,
|
|
||||||
RepoID: action.RepoID,
|
|
||||||
OpType: action.OpType,
|
|
||||||
})
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &Action{
|
|
||||||
ActUserID: action.ActUserID,
|
|
||||||
UserID: 11,
|
|
||||||
RepoID: action.RepoID,
|
|
||||||
OpType: action.OpType,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWatchIfAuto(t *testing.T) {
|
func TestWatchIfAuto(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
|
||||||
watchers, err := GetRepoWatchers(repo.ID, db.ListOptions{Page: 1})
|
watchers, err := GetRepoWatchers(repo.ID, db.ListOptions{Page: 1})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, watchers, repo.NumWatches)
|
assert.Len(t, watchers, repo.NumWatches)
|
||||||
|
@ -174,18 +122,18 @@ func TestWatchRepoMode(t *testing.T) {
|
||||||
|
|
||||||
unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1}, 0)
|
unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1}, 0)
|
||||||
|
|
||||||
assert.NoError(t, WatchRepoMode(12, 1, RepoWatchModeAuto))
|
assert.NoError(t, WatchRepoMode(12, 1, WatchModeAuto))
|
||||||
unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1}, 1)
|
unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1}, 1)
|
||||||
unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1, Mode: RepoWatchModeAuto}, 1)
|
unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1, Mode: WatchModeAuto}, 1)
|
||||||
|
|
||||||
assert.NoError(t, WatchRepoMode(12, 1, RepoWatchModeNormal))
|
assert.NoError(t, WatchRepoMode(12, 1, WatchModeNormal))
|
||||||
unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1}, 1)
|
unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1}, 1)
|
||||||
unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1, Mode: RepoWatchModeNormal}, 1)
|
unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1, Mode: WatchModeNormal}, 1)
|
||||||
|
|
||||||
assert.NoError(t, WatchRepoMode(12, 1, RepoWatchModeDont))
|
assert.NoError(t, WatchRepoMode(12, 1, WatchModeDont))
|
||||||
unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1}, 1)
|
unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1}, 1)
|
||||||
unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1, Mode: RepoWatchModeDont}, 1)
|
unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1, Mode: WatchModeDont}, 1)
|
||||||
|
|
||||||
assert.NoError(t, WatchRepoMode(12, 1, RepoWatchModeNone))
|
assert.NoError(t, WatchRepoMode(12, 1, WatchModeNone))
|
||||||
unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1}, 0)
|
unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1}, 0)
|
||||||
}
|
}
|
|
@ -1,25 +0,0 @@
|
||||||
// Copyright 2021 The Gitea 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
|
|
||||||
|
|
||||||
import (
|
|
||||||
"code.gitea.io/gitea/models/db"
|
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
|
||||||
)
|
|
||||||
|
|
||||||
// LoadArchiverRepo loads repository
|
|
||||||
func LoadArchiverRepo(archiver *repo_model.RepoArchiver) (*repo_model.Repository, error) {
|
|
||||||
var repo repo_model.Repository
|
|
||||||
has, err := db.GetEngine(db.DefaultContext).ID(archiver.RepoID).Get(&repo)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if !has {
|
|
||||||
return nil, repo_model.ErrRepoNotExist{
|
|
||||||
ID: archiver.RepoID,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &repo, nil
|
|
||||||
}
|
|
|
@ -207,15 +207,13 @@ func DeleteCollaboration(repo *repo_model.Repository, uid int64) (err error) {
|
||||||
}
|
}
|
||||||
defer committer.Close()
|
defer committer.Close()
|
||||||
|
|
||||||
sess := db.GetEngine(ctx)
|
if has, err := db.GetEngine(ctx).Delete(collaboration); err != nil || has == 0 {
|
||||||
|
|
||||||
if has, err := sess.Delete(collaboration); err != nil || has == 0 {
|
|
||||||
return err
|
return err
|
||||||
} else if err = recalculateAccesses(ctx, repo); err != nil {
|
} else if err = recalculateAccesses(ctx, repo); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = watchRepo(sess, uid, repo.ID, false); err != nil {
|
if err = repo_model.WatchRepoCtx(ctx, uid, repo.ID, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,13 +251,12 @@ func reconsiderWatches(ctx context.Context, repo *repo_model.Repository, uid int
|
||||||
if has, err := hasAccess(ctx, uid, repo); err != nil || has {
|
if has, err := hasAccess(ctx, uid, repo); err != nil || has {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
e := db.GetEngine(ctx)
|
if err := repo_model.WatchRepoCtx(ctx, uid, repo.ID, false); err != nil {
|
||||||
if err := watchRepo(e, uid, repo.ID, false); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all IssueWatches a user has subscribed to in the repository
|
// Remove all IssueWatches a user has subscribed to in the repository
|
||||||
return removeIssueWatchersByRepoID(e, uid, repo.ID)
|
return removeIssueWatchersByRepoID(db.GetEngine(ctx), uid, repo.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRepoTeams(e db.Engine, repo *repo_model.Repository) (teams []*Team, err error) {
|
func getRepoTeams(e db.Engine, repo *repo_model.Repository) (teams []*Team, err error) {
|
||||||
|
|
|
@ -8,15 +8,12 @@ import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/webhook"
|
"code.gitea.io/gitea/models/webhook"
|
||||||
"code.gitea.io/gitea/modules/git"
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/storage"
|
|
||||||
|
|
||||||
"github.com/gobwas/glob"
|
"github.com/gobwas/glob"
|
||||||
)
|
)
|
||||||
|
@ -70,49 +67,6 @@ func (gt GiteaTemplate) Globs() []glob.Glob {
|
||||||
return gt.globs
|
return gt.globs
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateTopics generates topics from a template repository
|
|
||||||
func GenerateTopics(ctx context.Context, templateRepo, generateRepo *repo_model.Repository) error {
|
|
||||||
for _, topic := range templateRepo.Topics {
|
|
||||||
if _, err := addTopicByNameToRepo(db.GetEngine(ctx), generateRepo.ID, topic); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateGitHooks generates git hooks from a template repository
|
|
||||||
func GenerateGitHooks(ctx context.Context, templateRepo, generateRepo *repo_model.Repository) error {
|
|
||||||
generateGitRepo, err := git.OpenRepository(generateRepo.RepoPath())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer generateGitRepo.Close()
|
|
||||||
|
|
||||||
templateGitRepo, err := git.OpenRepository(templateRepo.RepoPath())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer templateGitRepo.Close()
|
|
||||||
|
|
||||||
templateHooks, err := templateGitRepo.Hooks()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, templateHook := range templateHooks {
|
|
||||||
generateHook, err := generateGitRepo.GetHook(templateHook.Name())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
generateHook.Content = templateHook.Content
|
|
||||||
if err := generateHook.Update(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateWebhooks generates webhooks from a template repository
|
// GenerateWebhooks generates webhooks from a template repository
|
||||||
func GenerateWebhooks(ctx context.Context, templateRepo, generateRepo *repo_model.Repository) error {
|
func GenerateWebhooks(ctx context.Context, templateRepo, generateRepo *repo_model.Repository) error {
|
||||||
templateWebhooks, err := webhook.ListWebhooksByOpts(&webhook.ListWebhookOptions{RepoID: templateRepo.ID})
|
templateWebhooks, err := webhook.ListWebhooksByOpts(&webhook.ListWebhookOptions{RepoID: templateRepo.ID})
|
||||||
|
@ -141,16 +95,6 @@ func GenerateWebhooks(ctx context.Context, templateRepo, generateRepo *repo_mode
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateAvatar generates the avatar from a template repository
|
|
||||||
func GenerateAvatar(ctx context.Context, templateRepo, generateRepo *repo_model.Repository) error {
|
|
||||||
generateRepo.Avatar = strings.Replace(templateRepo.Avatar, strconv.FormatInt(templateRepo.ID, 10), strconv.FormatInt(generateRepo.ID, 10), 1)
|
|
||||||
if _, err := storage.Copy(storage.RepoAvatars, generateRepo.CustomAvatarRelativePath(), storage.RepoAvatars, templateRepo.CustomAvatarRelativePath()); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return updateRepositoryCols(db.GetEngine(ctx), generateRepo, "avatar")
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateIssueLabels generates issue labels from a template repository
|
// GenerateIssueLabels generates issue labels from a template repository
|
||||||
func GenerateIssueLabels(ctx context.Context, templateRepo, generateRepo *repo_model.Repository) error {
|
func GenerateIssueLabels(ctx context.Context, templateRepo, generateRepo *repo_model.Repository) error {
|
||||||
templateLabels, err := getLabelsByRepoID(db.GetEngine(ctx), templateRepo.ID, "", db.ListOptions{})
|
templateLabels, err := getLabelsByRepoID(db.GetEngine(ctx), templateRepo.ID, "", db.ListOptions{})
|
||||||
|
|
|
@ -419,3 +419,21 @@ func FilterOutRepoIdsWithoutUnitAccess(u *user_model.User, repoIDs []int64, unit
|
||||||
}
|
}
|
||||||
return repoIDs[:i], nil
|
return repoIDs[:i], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRepoReaders returns all users that have explicit read access or higher to the repository.
|
||||||
|
func GetRepoReaders(repo *repo_model.Repository) (_ []*user_model.User, err error) {
|
||||||
|
return getUsersWithAccessMode(db.DefaultContext, repo, perm_model.AccessModeRead)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRepoWriters returns all users that have write access to the repository.
|
||||||
|
func GetRepoWriters(repo *repo_model.Repository) (_ []*user_model.User, err error) {
|
||||||
|
return getUsersWithAccessMode(db.DefaultContext, repo, perm_model.AccessModeWrite)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsRepoReader returns true if user has explicit read access or higher to the repository.
|
||||||
|
func IsRepoReader(repo *repo_model.Repository, userID int64) (bool, error) {
|
||||||
|
if repo.OwnerID == userID {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return db.GetEngine(db.DefaultContext).Where("repo_id = ? AND user_id = ? AND mode >= ?", repo.ID, userID, perm_model.AccessModeRead).Get(&Access{})
|
||||||
|
}
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
// Copyright 2017 The Gitea 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
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
|
||||||
)
|
|
||||||
|
|
||||||
// RepoRedirect represents that a repo name should be redirected to another
|
|
||||||
type RepoRedirect struct {
|
|
||||||
ID int64 `xorm:"pk autoincr"`
|
|
||||||
OwnerID int64 `xorm:"UNIQUE(s)"`
|
|
||||||
LowerName string `xorm:"UNIQUE(s) INDEX NOT NULL"`
|
|
||||||
RedirectRepoID int64 // repoID to redirect to
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
db.RegisterModel(new(RepoRedirect))
|
|
||||||
}
|
|
||||||
|
|
||||||
// LookupRepoRedirect look up if a repository has a redirect name
|
|
||||||
func LookupRepoRedirect(ownerID int64, repoName string) (int64, error) {
|
|
||||||
repoName = strings.ToLower(repoName)
|
|
||||||
redirect := &RepoRedirect{OwnerID: ownerID, LowerName: repoName}
|
|
||||||
if has, err := db.GetEngine(db.DefaultContext).Get(redirect); err != nil {
|
|
||||||
return 0, err
|
|
||||||
} else if !has {
|
|
||||||
return 0, ErrRepoRedirectNotExist{OwnerID: ownerID, RepoName: repoName}
|
|
||||||
}
|
|
||||||
return redirect.RedirectRepoID, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// newRepoRedirect create a new repo redirect
|
|
||||||
func newRepoRedirect(e db.Engine, ownerID, repoID int64, oldRepoName, newRepoName string) error {
|
|
||||||
oldRepoName = strings.ToLower(oldRepoName)
|
|
||||||
newRepoName = strings.ToLower(newRepoName)
|
|
||||||
|
|
||||||
if err := deleteRepoRedirect(e, ownerID, newRepoName); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := e.Insert(&RepoRedirect{
|
|
||||||
OwnerID: ownerID,
|
|
||||||
LowerName: oldRepoName,
|
|
||||||
RedirectRepoID: repoID,
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// deleteRepoRedirect delete any redirect from the specified repo name to
|
|
||||||
// anything else
|
|
||||||
func deleteRepoRedirect(e db.Engine, ownerID int64, repoName string) error {
|
|
||||||
repoName = strings.ToLower(repoName)
|
|
||||||
_, err := e.Delete(&RepoRedirect{OwnerID: ownerID, LowerName: repoName})
|
|
||||||
return err
|
|
||||||
}
|
|
|
@ -1,78 +0,0 @@
|
||||||
// Copyright 2017 The Gitea 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
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
|
||||||
"code.gitea.io/gitea/models/unittest"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestLookupRepoRedirect(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
|
|
||||||
repoID, err := LookupRepoRedirect(2, "oldrepo1")
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.EqualValues(t, 1, repoID)
|
|
||||||
|
|
||||||
_, err = LookupRepoRedirect(unittest.NonexistentID, "doesnotexist")
|
|
||||||
assert.True(t, IsErrRepoRedirectNotExist(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewRepoRedirect(t *testing.T) {
|
|
||||||
// redirect to a completely new name
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
|
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
|
||||||
assert.NoError(t, newRepoRedirect(db.GetEngine(db.DefaultContext), repo.OwnerID, repo.ID, repo.Name, "newreponame"))
|
|
||||||
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &RepoRedirect{
|
|
||||||
OwnerID: repo.OwnerID,
|
|
||||||
LowerName: repo.LowerName,
|
|
||||||
RedirectRepoID: repo.ID,
|
|
||||||
})
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &RepoRedirect{
|
|
||||||
OwnerID: repo.OwnerID,
|
|
||||||
LowerName: "oldrepo1",
|
|
||||||
RedirectRepoID: repo.ID,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewRepoRedirect2(t *testing.T) {
|
|
||||||
// redirect to previously used name
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
|
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
|
||||||
assert.NoError(t, newRepoRedirect(db.GetEngine(db.DefaultContext), repo.OwnerID, repo.ID, repo.Name, "oldrepo1"))
|
|
||||||
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &RepoRedirect{
|
|
||||||
OwnerID: repo.OwnerID,
|
|
||||||
LowerName: repo.LowerName,
|
|
||||||
RedirectRepoID: repo.ID,
|
|
||||||
})
|
|
||||||
unittest.AssertNotExistsBean(t, &RepoRedirect{
|
|
||||||
OwnerID: repo.OwnerID,
|
|
||||||
LowerName: "oldrepo1",
|
|
||||||
RedirectRepoID: repo.ID,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewRepoRedirect3(t *testing.T) {
|
|
||||||
// redirect for a previously-unredirected repo
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
|
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository)
|
|
||||||
assert.NoError(t, newRepoRedirect(db.GetEngine(db.DefaultContext), repo.OwnerID, repo.ID, repo.Name, "newreponame"))
|
|
||||||
|
|
||||||
unittest.AssertExistsAndLoadBean(t, &RepoRedirect{
|
|
||||||
OwnerID: repo.OwnerID,
|
|
||||||
LowerName: repo.LowerName,
|
|
||||||
RedirectRepoID: repo.ID,
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -5,11 +5,6 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"crypto/md5"
|
|
||||||
"fmt"
|
|
||||||
"image"
|
|
||||||
"image/png"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
@ -22,6 +17,20 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestWatchRepo(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
const repoID = 3
|
||||||
|
const userID = 2
|
||||||
|
|
||||||
|
assert.NoError(t, repo_model.WatchRepo(userID, repoID, true))
|
||||||
|
unittest.AssertExistsAndLoadBean(t, &repo_model.Watch{RepoID: repoID, UserID: userID})
|
||||||
|
unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repoID})
|
||||||
|
|
||||||
|
assert.NoError(t, repo_model.WatchRepo(userID, repoID, false))
|
||||||
|
unittest.AssertNotExistsBean(t, &repo_model.Watch{RepoID: repoID, UserID: userID})
|
||||||
|
unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repoID})
|
||||||
|
}
|
||||||
|
|
||||||
func TestMetas(t *testing.T) {
|
func TestMetas(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
@ -90,77 +99,6 @@ func TestUpdateRepositoryVisibilityChanged(t *testing.T) {
|
||||||
assert.True(t, act.IsPrivate)
|
assert.True(t, act.IsPrivate)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetUserFork(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
|
|
||||||
// User13 has repo 11 forked from repo10
|
|
||||||
repo, err := repo_model.GetRepositoryByID(10)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.NotNil(t, repo)
|
|
||||||
repo, err = GetUserFork(repo.ID, 13)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.NotNil(t, repo)
|
|
||||||
|
|
||||||
repo, err = repo_model.GetRepositoryByID(9)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.NotNil(t, repo)
|
|
||||||
repo, err = GetUserFork(repo.ID, 13)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Nil(t, repo)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRepoAPIURL(t *testing.T) {
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}).(*repo_model.Repository)
|
|
||||||
|
|
||||||
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user12/repo10", repo.APIURL())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUploadAvatar(t *testing.T) {
|
|
||||||
// Generate image
|
|
||||||
myImage := image.NewRGBA(image.Rect(0, 0, 1, 1))
|
|
||||||
var buff bytes.Buffer
|
|
||||||
png.Encode(&buff, myImage)
|
|
||||||
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}).(*repo_model.Repository)
|
|
||||||
|
|
||||||
err := UploadRepoAvatar(repo, buff.Bytes())
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, fmt.Sprintf("%d-%x", 10, md5.Sum(buff.Bytes())), repo.Avatar)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUploadBigAvatar(t *testing.T) {
|
|
||||||
// Generate BIG image
|
|
||||||
myImage := image.NewRGBA(image.Rect(0, 0, 5000, 1))
|
|
||||||
var buff bytes.Buffer
|
|
||||||
png.Encode(&buff, myImage)
|
|
||||||
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}).(*repo_model.Repository)
|
|
||||||
|
|
||||||
err := UploadRepoAvatar(repo, buff.Bytes())
|
|
||||||
assert.Error(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDeleteAvatar(t *testing.T) {
|
|
||||||
// Generate image
|
|
||||||
myImage := image.NewRGBA(image.Rect(0, 0, 1, 1))
|
|
||||||
var buff bytes.Buffer
|
|
||||||
png.Encode(&buff, myImage)
|
|
||||||
|
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}).(*repo_model.Repository)
|
|
||||||
|
|
||||||
err := UploadRepoAvatar(repo, buff.Bytes())
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
err = DeleteRepoAvatar(repo)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
assert.Equal(t, "", repo.Avatar)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDoctorUserStarNum(t *testing.T) {
|
func TestDoctorUserStarNum(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
@ -112,8 +113,8 @@ func GetPendingRepositoryTransfer(repo *repo_model.Repository) (*RepoTransfer, e
|
||||||
return transfer, nil
|
return transfer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteRepositoryTransfer(e db.Engine, repoID int64) error {
|
func deleteRepositoryTransfer(ctx context.Context, repoID int64) error {
|
||||||
_, err := e.Where("repo_id = ?", repoID).Delete(&RepoTransfer{})
|
_, err := db.GetEngine(ctx).Where("repo_id = ?", repoID).Delete(&RepoTransfer{})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,14 +126,13 @@ func CancelRepositoryTransfer(repo *repo_model.Repository) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer committer.Close()
|
defer committer.Close()
|
||||||
sess := db.GetEngine(ctx)
|
|
||||||
|
|
||||||
repo.Status = repo_model.RepositoryReady
|
repo.Status = repo_model.RepositoryReady
|
||||||
if err := updateRepositoryCols(sess, repo, "status"); err != nil {
|
if err := repo_model.UpdateRepositoryColsCtx(ctx, repo, "status"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := deleteRepositoryTransfer(sess, repo.ID); err != nil {
|
if err := deleteRepositoryTransfer(ctx, repo.ID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,7 +158,6 @@ func CreatePendingRepositoryTransfer(doer, newOwner *user_model.User, repoID int
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer committer.Close()
|
defer committer.Close()
|
||||||
sess := db.GetEngine(ctx)
|
|
||||||
|
|
||||||
repo, err := repo_model.GetRepositoryByIDCtx(ctx, repoID)
|
repo, err := repo_model.GetRepositoryByIDCtx(ctx, repoID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -171,7 +170,7 @@ func CreatePendingRepositoryTransfer(doer, newOwner *user_model.User, repoID int
|
||||||
}
|
}
|
||||||
|
|
||||||
repo.Status = repo_model.RepositoryPendingTransfer
|
repo.Status = repo_model.RepositoryPendingTransfer
|
||||||
if err := updateRepositoryCols(sess, repo, "status"); err != nil {
|
if err := repo_model.UpdateRepositoryColsCtx(ctx, repo, "status"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,7 +178,10 @@ func CreatePendingRepositoryTransfer(doer, newOwner *user_model.User, repoID int
|
||||||
if has, err := repo_model.IsRepositoryExistCtx(ctx, newOwner, repo.Name); err != nil {
|
if has, err := repo_model.IsRepositoryExistCtx(ctx, newOwner, repo.Name); err != nil {
|
||||||
return fmt.Errorf("IsRepositoryExist: %v", err)
|
return fmt.Errorf("IsRepositoryExist: %v", err)
|
||||||
} else if has {
|
} else if has {
|
||||||
return ErrRepoAlreadyExist{newOwner.LowerName, repo.Name}
|
return repo_model.ErrRepoAlreadyExist{
|
||||||
|
Uname: newOwner.LowerName,
|
||||||
|
Name: repo.Name,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
transfer := &RepoTransfer{
|
transfer := &RepoTransfer{
|
||||||
|
@ -256,7 +258,10 @@ func TransferOwnership(doer *user_model.User, newOwnerName string, repo *repo_mo
|
||||||
if has, err := repo_model.IsRepositoryExistCtx(ctx, newOwner, repo.Name); err != nil {
|
if has, err := repo_model.IsRepositoryExistCtx(ctx, newOwner, repo.Name); err != nil {
|
||||||
return fmt.Errorf("IsRepositoryExist: %v", err)
|
return fmt.Errorf("IsRepositoryExist: %v", err)
|
||||||
} else if has {
|
} else if has {
|
||||||
return ErrRepoAlreadyExist{newOwnerName, repo.Name}
|
return repo_model.ErrRepoAlreadyExist{
|
||||||
|
Uname: newOwnerName,
|
||||||
|
Name: repo.Name,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
oldOwner := repo.Owner
|
oldOwner := repo.Owner
|
||||||
|
@ -336,13 +341,13 @@ func TransferOwnership(doer *user_model.User, newOwnerName string, repo *repo_mo
|
||||||
return fmt.Errorf("decrease old owner repository count: %v", err)
|
return fmt.Errorf("decrease old owner repository count: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := watchRepo(sess, doer.ID, repo.ID, true); err != nil {
|
if err := repo_model.WatchRepoCtx(ctx, doer.ID, repo.ID, true); err != nil {
|
||||||
return fmt.Errorf("watchRepo: %v", err)
|
return fmt.Errorf("watchRepo: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove watch for organization.
|
// Remove watch for organization.
|
||||||
if oldOwner.IsOrganization() {
|
if oldOwner.IsOrganization() {
|
||||||
if err := watchRepo(sess, oldOwner.ID, repo.ID, false); err != nil {
|
if err := repo_model.WatchRepoCtx(ctx, oldOwner.ID, repo.ID, false); err != nil {
|
||||||
return fmt.Errorf("watchRepo [false]: %v", err)
|
return fmt.Errorf("watchRepo [false]: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -399,21 +404,21 @@ func TransferOwnership(doer *user_model.User, newOwnerName string, repo *repo_mo
|
||||||
wikiRenamed = true
|
wikiRenamed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := deleteRepositoryTransfer(sess, repo.ID); err != nil {
|
if err := deleteRepositoryTransfer(ctx, repo.ID); err != nil {
|
||||||
return fmt.Errorf("deleteRepositoryTransfer: %v", err)
|
return fmt.Errorf("deleteRepositoryTransfer: %v", err)
|
||||||
}
|
}
|
||||||
repo.Status = repo_model.RepositoryReady
|
repo.Status = repo_model.RepositoryReady
|
||||||
if err := updateRepositoryCols(sess, repo, "status"); err != nil {
|
if err := repo_model.UpdateRepositoryColsCtx(ctx, repo, "status"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there was previously a redirect at this location, remove it.
|
// If there was previously a redirect at this location, remove it.
|
||||||
if err := deleteRepoRedirect(sess, newOwner.ID, repo.Name); err != nil {
|
if err := repo_model.DeleteRedirect(ctx, newOwner.ID, repo.Name); err != nil {
|
||||||
return fmt.Errorf("delete repo redirect: %v", err)
|
return fmt.Errorf("delete repo redirect: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := newRepoRedirect(sess, oldOwner.ID, repo.ID, repo.Name, repo.Name); err != nil {
|
if err := repo_model.NewRedirect(ctx, oldOwner.ID, repo.ID, repo.Name, repo.Name); err != nil {
|
||||||
return fmt.Errorf("newRepoRedirect: %v", err)
|
return fmt.Errorf("repo_model.NewRedirect: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return committer.Commit()
|
return committer.Commit()
|
||||||
|
|
|
@ -1,328 +0,0 @@
|
||||||
// Copyright 2017 The Gitea 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
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
|
||||||
"code.gitea.io/gitea/models/unit"
|
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
|
||||||
"code.gitea.io/gitea/modules/setting"
|
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
// RepoWatchMode specifies what kind of watch the user has on a repository
|
|
||||||
type RepoWatchMode int8
|
|
||||||
|
|
||||||
const (
|
|
||||||
// RepoWatchModeNone don't watch
|
|
||||||
RepoWatchModeNone RepoWatchMode = iota // 0
|
|
||||||
// RepoWatchModeNormal watch repository (from other sources)
|
|
||||||
RepoWatchModeNormal // 1
|
|
||||||
// RepoWatchModeDont explicit don't auto-watch
|
|
||||||
RepoWatchModeDont // 2
|
|
||||||
// RepoWatchModeAuto watch repository (from AutoWatchOnChanges)
|
|
||||||
RepoWatchModeAuto // 3
|
|
||||||
)
|
|
||||||
|
|
||||||
// Watch is connection request for receiving repository notification.
|
|
||||||
type Watch struct {
|
|
||||||
ID int64 `xorm:"pk autoincr"`
|
|
||||||
UserID int64 `xorm:"UNIQUE(watch)"`
|
|
||||||
RepoID int64 `xorm:"UNIQUE(watch)"`
|
|
||||||
Mode RepoWatchMode `xorm:"SMALLINT NOT NULL DEFAULT 1"`
|
|
||||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
|
|
||||||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
db.RegisterModel(new(Watch))
|
|
||||||
}
|
|
||||||
|
|
||||||
// getWatch gets what kind of subscription a user has on a given repository; returns dummy record if none found
|
|
||||||
func getWatch(e db.Engine, userID, repoID int64) (Watch, error) {
|
|
||||||
watch := Watch{UserID: userID, RepoID: repoID}
|
|
||||||
has, err := e.Get(&watch)
|
|
||||||
if err != nil {
|
|
||||||
return watch, err
|
|
||||||
}
|
|
||||||
if !has {
|
|
||||||
watch.Mode = RepoWatchModeNone
|
|
||||||
}
|
|
||||||
return watch, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decodes watchability of RepoWatchMode
|
|
||||||
func isWatchMode(mode RepoWatchMode) bool {
|
|
||||||
return mode != RepoWatchModeNone && mode != RepoWatchModeDont
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsWatching checks if user has watched given repository.
|
|
||||||
func IsWatching(userID, repoID int64) bool {
|
|
||||||
watch, err := getWatch(db.GetEngine(db.DefaultContext), userID, repoID)
|
|
||||||
return err == nil && isWatchMode(watch.Mode)
|
|
||||||
}
|
|
||||||
|
|
||||||
func watchRepoMode(e db.Engine, watch Watch, mode RepoWatchMode) (err error) {
|
|
||||||
if watch.Mode == mode {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if mode == RepoWatchModeAuto && (watch.Mode == RepoWatchModeDont || isWatchMode(watch.Mode)) {
|
|
||||||
// Don't auto watch if already watching or deliberately not watching
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
hadrec := watch.Mode != RepoWatchModeNone
|
|
||||||
needsrec := mode != RepoWatchModeNone
|
|
||||||
repodiff := 0
|
|
||||||
|
|
||||||
if isWatchMode(mode) && !isWatchMode(watch.Mode) {
|
|
||||||
repodiff = 1
|
|
||||||
} else if !isWatchMode(mode) && isWatchMode(watch.Mode) {
|
|
||||||
repodiff = -1
|
|
||||||
}
|
|
||||||
|
|
||||||
watch.Mode = mode
|
|
||||||
|
|
||||||
if !hadrec && needsrec {
|
|
||||||
watch.Mode = mode
|
|
||||||
if _, err = e.Insert(watch); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else if needsrec {
|
|
||||||
watch.Mode = mode
|
|
||||||
if _, err := e.ID(watch.ID).AllCols().Update(watch); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else if _, err = e.Delete(Watch{ID: watch.ID}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if repodiff != 0 {
|
|
||||||
_, err = e.Exec("UPDATE `repository` SET num_watches = num_watches + ? WHERE id = ?", repodiff, watch.RepoID)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// WatchRepoMode watch repository in specific mode.
|
|
||||||
func WatchRepoMode(userID, repoID int64, mode RepoWatchMode) (err error) {
|
|
||||||
var watch Watch
|
|
||||||
if watch, err = getWatch(db.GetEngine(db.DefaultContext), userID, repoID); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return watchRepoMode(db.GetEngine(db.DefaultContext), watch, mode)
|
|
||||||
}
|
|
||||||
|
|
||||||
func watchRepo(e db.Engine, userID, repoID int64, doWatch bool) (err error) {
|
|
||||||
var watch Watch
|
|
||||||
if watch, err = getWatch(e, userID, repoID); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !doWatch && watch.Mode == RepoWatchModeAuto {
|
|
||||||
err = watchRepoMode(e, watch, RepoWatchModeDont)
|
|
||||||
} else if !doWatch {
|
|
||||||
err = watchRepoMode(e, watch, RepoWatchModeNone)
|
|
||||||
} else {
|
|
||||||
err = watchRepoMode(e, watch, RepoWatchModeNormal)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// WatchRepo watch or unwatch repository.
|
|
||||||
func WatchRepo(userID, repoID int64, watch bool) (err error) {
|
|
||||||
return watchRepo(db.GetEngine(db.DefaultContext), userID, repoID, watch)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getWatchers(e db.Engine, repoID int64) ([]*Watch, error) {
|
|
||||||
watches := make([]*Watch, 0, 10)
|
|
||||||
return watches, e.Where("`watch`.repo_id=?", repoID).
|
|
||||||
And("`watch`.mode<>?", RepoWatchModeDont).
|
|
||||||
And("`user`.is_active=?", true).
|
|
||||||
And("`user`.prohibit_login=?", false).
|
|
||||||
Join("INNER", "`user`", "`user`.id = `watch`.user_id").
|
|
||||||
Find(&watches)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetWatchers returns all watchers of given repository.
|
|
||||||
func GetWatchers(repoID int64) ([]*Watch, error) {
|
|
||||||
return getWatchers(db.GetEngine(db.DefaultContext), repoID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetRepoWatchersIDs returns IDs of watchers for a given repo ID
|
|
||||||
// but avoids joining with `user` for performance reasons
|
|
||||||
// User permissions must be verified elsewhere if required
|
|
||||||
func GetRepoWatchersIDs(repoID int64) ([]int64, error) {
|
|
||||||
return getRepoWatchersIDs(db.GetEngine(db.DefaultContext), repoID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getRepoWatchersIDs(e db.Engine, repoID int64) ([]int64, error) {
|
|
||||||
ids := make([]int64, 0, 64)
|
|
||||||
return ids, e.Table("watch").
|
|
||||||
Where("watch.repo_id=?", repoID).
|
|
||||||
And("watch.mode<>?", RepoWatchModeDont).
|
|
||||||
Select("user_id").
|
|
||||||
Find(&ids)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetRepoWatchers returns range of users watching given repository.
|
|
||||||
func GetRepoWatchers(repoID int64, opts db.ListOptions) ([]*user_model.User, error) {
|
|
||||||
sess := db.GetEngine(db.DefaultContext).Where("watch.repo_id=?", repoID).
|
|
||||||
Join("LEFT", "watch", "`user`.id=`watch`.user_id").
|
|
||||||
And("`watch`.mode<>?", RepoWatchModeDont)
|
|
||||||
if opts.Page > 0 {
|
|
||||||
sess = db.SetSessionPagination(sess, &opts)
|
|
||||||
users := make([]*user_model.User, 0, opts.PageSize)
|
|
||||||
|
|
||||||
return users, sess.Find(&users)
|
|
||||||
}
|
|
||||||
|
|
||||||
users := make([]*user_model.User, 0, 8)
|
|
||||||
return users, sess.Find(&users)
|
|
||||||
}
|
|
||||||
|
|
||||||
func notifyWatchers(ctx context.Context, actions ...*Action) error {
|
|
||||||
var watchers []*Watch
|
|
||||||
var repo *repo_model.Repository
|
|
||||||
var err error
|
|
||||||
var permCode []bool
|
|
||||||
var permIssue []bool
|
|
||||||
var permPR []bool
|
|
||||||
|
|
||||||
e := db.GetEngine(ctx)
|
|
||||||
|
|
||||||
for _, act := range actions {
|
|
||||||
repoChanged := repo == nil || repo.ID != act.RepoID
|
|
||||||
|
|
||||||
if repoChanged {
|
|
||||||
// Add feeds for user self and all watchers.
|
|
||||||
watchers, err = getWatchers(e, act.RepoID)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("get watchers: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add feed for actioner.
|
|
||||||
act.UserID = act.ActUserID
|
|
||||||
if _, err = e.InsertOne(act); err != nil {
|
|
||||||
return fmt.Errorf("insert new actioner: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if repoChanged {
|
|
||||||
act.loadRepo()
|
|
||||||
repo = act.Repo
|
|
||||||
|
|
||||||
// check repo owner exist.
|
|
||||||
if err := act.Repo.GetOwner(ctx); err != nil {
|
|
||||||
return fmt.Errorf("can't get repo owner: %v", err)
|
|
||||||
}
|
|
||||||
} else if act.Repo == nil {
|
|
||||||
act.Repo = repo
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add feed for organization
|
|
||||||
if act.Repo.Owner.IsOrganization() && act.ActUserID != act.Repo.Owner.ID {
|
|
||||||
act.ID = 0
|
|
||||||
act.UserID = act.Repo.Owner.ID
|
|
||||||
if _, err = e.InsertOne(act); err != nil {
|
|
||||||
return fmt.Errorf("insert new actioner: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if repoChanged {
|
|
||||||
permCode = make([]bool, len(watchers))
|
|
||||||
permIssue = make([]bool, len(watchers))
|
|
||||||
permPR = make([]bool, len(watchers))
|
|
||||||
for i, watcher := range watchers {
|
|
||||||
user, err := user_model.GetUserByIDEngine(e, watcher.UserID)
|
|
||||||
if err != nil {
|
|
||||||
permCode[i] = false
|
|
||||||
permIssue[i] = false
|
|
||||||
permPR[i] = false
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
perm, err := getUserRepoPermission(ctx, repo, user)
|
|
||||||
if err != nil {
|
|
||||||
permCode[i] = false
|
|
||||||
permIssue[i] = false
|
|
||||||
permPR[i] = false
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
permCode[i] = perm.CanRead(unit.TypeCode)
|
|
||||||
permIssue[i] = perm.CanRead(unit.TypeIssues)
|
|
||||||
permPR[i] = perm.CanRead(unit.TypePullRequests)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, watcher := range watchers {
|
|
||||||
if act.ActUserID == watcher.UserID {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
act.ID = 0
|
|
||||||
act.UserID = watcher.UserID
|
|
||||||
act.Repo.Units = nil
|
|
||||||
|
|
||||||
switch act.OpType {
|
|
||||||
case ActionCommitRepo, ActionPushTag, ActionDeleteTag, ActionPublishRelease, ActionDeleteBranch:
|
|
||||||
if !permCode[i] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
case ActionCreateIssue, ActionCommentIssue, ActionCloseIssue, ActionReopenIssue:
|
|
||||||
if !permIssue[i] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
case ActionCreatePullRequest, ActionCommentPull, ActionMergePullRequest, ActionClosePullRequest, ActionReopenPullRequest:
|
|
||||||
if !permPR[i] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = e.InsertOne(act); err != nil {
|
|
||||||
return fmt.Errorf("insert new action: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotifyWatchers creates batch of actions for every watcher.
|
|
||||||
func NotifyWatchers(actions ...*Action) error {
|
|
||||||
return notifyWatchers(db.DefaultContext, actions...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotifyWatchersActions creates batch of actions for every watcher.
|
|
||||||
func NotifyWatchersActions(acts []*Action) error {
|
|
||||||
ctx, committer, err := db.TxContext()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer committer.Close()
|
|
||||||
for _, act := range acts {
|
|
||||||
if err := notifyWatchers(ctx, act); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return committer.Commit()
|
|
||||||
}
|
|
||||||
|
|
||||||
func watchIfAuto(e db.Engine, userID, repoID int64, isWrite bool) error {
|
|
||||||
if !isWrite || !setting.Service.AutoWatchOnChanges {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
watch, err := getWatch(e, userID, repoID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if watch.Mode != RepoWatchModeNone {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return watchRepoMode(e, watch, RepoWatchModeAuto)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WatchIfAuto subscribes to repo if AutoWatchOnChanges is set
|
|
||||||
func WatchIfAuto(userID, repoID int64, isWrite bool) error {
|
|
||||||
return watchIfAuto(db.GetEngine(db.DefaultContext), userID, repoID, isWrite)
|
|
||||||
}
|
|
|
@ -50,8 +50,8 @@ func GetStatistic() (stats Statistic) {
|
||||||
stats.Counter.Org = CountOrganizations()
|
stats.Counter.Org = CountOrganizations()
|
||||||
stats.Counter.PublicKey, _ = e.Count(new(asymkey_model.PublicKey))
|
stats.Counter.PublicKey, _ = e.Count(new(asymkey_model.PublicKey))
|
||||||
stats.Counter.Repo = repo_model.CountRepositories(true)
|
stats.Counter.Repo = repo_model.CountRepositories(true)
|
||||||
stats.Counter.Watch, _ = e.Count(new(Watch))
|
stats.Counter.Watch, _ = e.Count(new(repo_model.Watch))
|
||||||
stats.Counter.Star, _ = e.Count(new(Star))
|
stats.Counter.Star, _ = e.Count(new(repo_model.Star))
|
||||||
stats.Counter.Action, _ = e.Count(new(Action))
|
stats.Counter.Action, _ = e.Count(new(Action))
|
||||||
stats.Counter.Access, _ = e.Count(new(Access))
|
stats.Counter.Access, _ = e.Count(new(Access))
|
||||||
|
|
||||||
|
|
100
models/update.go
100
models/update.go
|
@ -1,100 +0,0 @@
|
||||||
// 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
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
|
||||||
)
|
|
||||||
|
|
||||||
// PushUpdateDeleteTagsContext updates a number of delete tags with context
|
|
||||||
func PushUpdateDeleteTagsContext(ctx context.Context, repo *repo_model.Repository, tags []string) error {
|
|
||||||
return pushUpdateDeleteTags(db.GetEngine(ctx), repo, tags)
|
|
||||||
}
|
|
||||||
|
|
||||||
func pushUpdateDeleteTags(e db.Engine, repo *repo_model.Repository, tags []string) error {
|
|
||||||
if len(tags) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
lowerTags := make([]string, 0, len(tags))
|
|
||||||
for _, tag := range tags {
|
|
||||||
lowerTags = append(lowerTags, strings.ToLower(tag))
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := e.
|
|
||||||
Where("repo_id = ? AND is_tag = ?", repo.ID, true).
|
|
||||||
In("lower_tag_name", lowerTags).
|
|
||||||
Delete(new(Release)); err != nil {
|
|
||||||
return fmt.Errorf("Delete: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := e.
|
|
||||||
Where("repo_id = ? AND is_tag = ?", repo.ID, false).
|
|
||||||
In("lower_tag_name", lowerTags).
|
|
||||||
Cols("is_draft", "num_commits", "sha1").
|
|
||||||
Update(&Release{
|
|
||||||
IsDraft: true,
|
|
||||||
}); err != nil {
|
|
||||||
return fmt.Errorf("Update: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// PushUpdateDeleteTag must be called for any push actions to delete tag
|
|
||||||
func PushUpdateDeleteTag(repo *repo_model.Repository, tagName string) error {
|
|
||||||
rel, err := GetRelease(repo.ID, tagName)
|
|
||||||
if err != nil {
|
|
||||||
if IsErrReleaseNotExist(err) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return fmt.Errorf("GetRelease: %v", err)
|
|
||||||
}
|
|
||||||
if rel.IsTag {
|
|
||||||
if _, err = db.GetEngine(db.DefaultContext).ID(rel.ID).Delete(new(Release)); err != nil {
|
|
||||||
return fmt.Errorf("Delete: %v", err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rel.IsDraft = true
|
|
||||||
rel.NumCommits = 0
|
|
||||||
rel.Sha1 = ""
|
|
||||||
if _, err = db.GetEngine(db.DefaultContext).ID(rel.ID).AllCols().Update(rel); err != nil {
|
|
||||||
return fmt.Errorf("Update: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SaveOrUpdateTag must be called for any push actions to add tag
|
|
||||||
func SaveOrUpdateTag(repo *repo_model.Repository, newRel *Release) error {
|
|
||||||
rel, err := GetRelease(repo.ID, newRel.TagName)
|
|
||||||
if err != nil && !IsErrReleaseNotExist(err) {
|
|
||||||
return fmt.Errorf("GetRelease: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if rel == nil {
|
|
||||||
rel = newRel
|
|
||||||
if _, err = db.GetEngine(db.DefaultContext).Insert(rel); err != nil {
|
|
||||||
return fmt.Errorf("InsertOne: %v", err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rel.Sha1 = newRel.Sha1
|
|
||||||
rel.CreatedUnix = newRel.CreatedUnix
|
|
||||||
rel.NumCommits = newRel.NumCommits
|
|
||||||
rel.IsDraft = false
|
|
||||||
if rel.IsTag && newRel.PublisherID > 0 {
|
|
||||||
rel.PublisherID = newRel.PublisherID
|
|
||||||
}
|
|
||||||
if _, err = db.GetEngine(db.DefaultContext).ID(rel.ID).AllCols().Update(rel); err != nil {
|
|
||||||
return fmt.Errorf("Update: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -150,7 +150,7 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
|
||||||
// ***** START: Watch *****
|
// ***** START: Watch *****
|
||||||
watchedRepoIDs := make([]int64, 0, 10)
|
watchedRepoIDs := make([]int64, 0, 10)
|
||||||
if err = e.Table("watch").Cols("watch.repo_id").
|
if err = e.Table("watch").Cols("watch.repo_id").
|
||||||
Where("watch.user_id = ?", u.ID).And("watch.mode <>?", RepoWatchModeDont).Find(&watchedRepoIDs); err != nil {
|
Where("watch.user_id = ?", u.ID).And("watch.mode <>?", repo_model.WatchModeDont).Find(&watchedRepoIDs); err != nil {
|
||||||
return fmt.Errorf("get all watches: %v", err)
|
return fmt.Errorf("get all watches: %v", err)
|
||||||
}
|
}
|
||||||
if _, err = e.Decr("num_watches").In("id", watchedRepoIDs).NoAutoTime().Update(new(repo_model.Repository)); err != nil {
|
if _, err = e.Decr("num_watches").In("id", watchedRepoIDs).NoAutoTime().Update(new(repo_model.Repository)); err != nil {
|
||||||
|
@ -190,8 +190,8 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
|
||||||
&AccessToken{UID: u.ID},
|
&AccessToken{UID: u.ID},
|
||||||
&Collaboration{UserID: u.ID},
|
&Collaboration{UserID: u.ID},
|
||||||
&Access{UserID: u.ID},
|
&Access{UserID: u.ID},
|
||||||
&Watch{UserID: u.ID},
|
&repo_model.Watch{UserID: u.ID},
|
||||||
&Star{UID: u.ID},
|
&repo_model.Star{UID: u.ID},
|
||||||
&user_model.Follow{UserID: u.ID},
|
&user_model.Follow{UserID: u.ID},
|
||||||
&user_model.Follow{FollowID: u.ID},
|
&user_model.Follow{FollowID: u.ID},
|
||||||
&Action{UserID: u.ID},
|
&Action{UserID: u.ID},
|
||||||
|
@ -296,7 +296,7 @@ func GetStarredRepos(userID int64, private bool, listOptions db.ListOptions) ([]
|
||||||
// GetWatchedRepos returns the repos watched by a particular user
|
// GetWatchedRepos returns the repos watched by a particular user
|
||||||
func GetWatchedRepos(userID int64, private bool, listOptions db.ListOptions) ([]*repo_model.Repository, int64, error) {
|
func GetWatchedRepos(userID int64, private bool, listOptions db.ListOptions) ([]*repo_model.Repository, int64, error) {
|
||||||
sess := db.GetEngine(db.DefaultContext).Where("watch.user_id=?", userID).
|
sess := db.GetEngine(db.DefaultContext).Where("watch.user_id=?", userID).
|
||||||
And("`watch`.mode<>?", RepoWatchModeDont).
|
And("`watch`.mode<>?", repo_model.WatchModeDont).
|
||||||
Join("LEFT", "watch", "`repository`.id=`watch`.repo_id")
|
Join("LEFT", "watch", "`repository`.id=`watch`.repo_id")
|
||||||
if !private {
|
if !private {
|
||||||
sess = sess.And("is_private=?", false)
|
sess = sess.And("is_private=?", false)
|
||||||
|
|
|
@ -443,10 +443,10 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
|
||||||
repo, err := repo_model.GetRepositoryByName(owner.ID, repoName)
|
repo, err := repo_model.GetRepositoryByName(owner.ID, repoName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if repo_model.IsErrRepoNotExist(err) {
|
if repo_model.IsErrRepoNotExist(err) {
|
||||||
redirectRepoID, err := models.LookupRepoRedirect(owner.ID, repoName)
|
redirectRepoID, err := repo_model.LookupRedirect(owner.ID, repoName)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
RedirectToRepo(ctx, redirectRepoID)
|
RedirectToRepo(ctx, redirectRepoID)
|
||||||
} else if models.IsErrRepoRedirectNotExist(err) {
|
} else if repo_model.IsErrRedirectNotExist(err) {
|
||||||
if ctx.FormString("go-get") == "1" {
|
if ctx.FormString("go-get") == "1" {
|
||||||
EarlyResponseForGoGetMeta(ctx)
|
EarlyResponseForGoGetMeta(ctx)
|
||||||
return
|
return
|
||||||
|
@ -512,8 +512,8 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
|
||||||
ctx.Data["WikiCloneLink"] = repo.WikiCloneLink()
|
ctx.Data["WikiCloneLink"] = repo.WikiCloneLink()
|
||||||
|
|
||||||
if ctx.IsSigned {
|
if ctx.IsSigned {
|
||||||
ctx.Data["IsWatchingRepo"] = models.IsWatching(ctx.User.ID, repo.ID)
|
ctx.Data["IsWatchingRepo"] = repo_model.IsWatching(ctx.User.ID, repo.ID)
|
||||||
ctx.Data["IsStaringRepo"] = models.IsStaring(ctx.User.ID, repo.ID)
|
ctx.Data["IsStaringRepo"] = repo_model.IsStaring(ctx.User.ID, repo.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if repo.IsFork {
|
if repo.IsFork {
|
||||||
|
@ -613,7 +613,7 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
|
||||||
|
|
||||||
// People who have push access or have forked repository can propose a new pull request.
|
// People who have push access or have forked repository can propose a new pull request.
|
||||||
canPush := ctx.Repo.CanWrite(unit_model.TypeCode) ||
|
canPush := ctx.Repo.CanWrite(unit_model.TypeCode) ||
|
||||||
(ctx.IsSigned && models.HasForkedRepo(ctx.User.ID, ctx.Repo.Repository.ID))
|
(ctx.IsSigned && repo_model.HasForkedRepo(ctx.User.ID, ctx.Repo.Repository.ID))
|
||||||
canCompare := false
|
canCompare := false
|
||||||
|
|
||||||
// Pull request is allowed if this is a fork repository
|
// Pull request is allowed if this is a fork repository
|
||||||
|
|
|
@ -334,7 +334,7 @@ func ToAnnotatedTagObject(repo *repo_model.Repository, commit *git.Commit) *api.
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToTopicResponse convert from models.Topic to api.TopicResponse
|
// ToTopicResponse convert from models.Topic to api.TopicResponse
|
||||||
func ToTopicResponse(topic *models.Topic) *api.TopicResponse {
|
func ToTopicResponse(topic *repo_model.Topic) *api.TopicResponse {
|
||||||
return &api.TopicResponse{
|
return &api.TopicResponse{
|
||||||
ID: topic.ID,
|
ID: topic.ID,
|
||||||
Name: topic.Name,
|
Name: topic.Name,
|
||||||
|
|
|
@ -6,6 +6,7 @@ package ui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/graceful"
|
"code.gitea.io/gitea/modules/graceful"
|
||||||
|
@ -122,7 +123,7 @@ func (ns *notificationService) NotifyNewPullRequest(pr *models.PullRequest, ment
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
toNotify := make(map[int64]struct{}, 32)
|
toNotify := make(map[int64]struct{}, 32)
|
||||||
repoWatchers, err := models.GetRepoWatchersIDs(pr.Issue.RepoID)
|
repoWatchers, err := repo_model.GetRepoWatchersIDs(db.DefaultContext, pr.Issue.RepoID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetRepoWatchersIDs: %v", err)
|
log.Error("GetRepoWatchersIDs: %v", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
// Copyright 2019 The Gitea 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 repofiles
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
|
||||||
"code.gitea.io/gitea/modules/git"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CreateCommitStatus creates a new CommitStatus given a bunch of parameters
|
|
||||||
// NOTE: All text-values will be trimmed from whitespaces.
|
|
||||||
// Requires: Repo, Creator, SHA
|
|
||||||
func CreateCommitStatus(repo *repo_model.Repository, creator *user_model.User, sha string, status *models.CommitStatus) error {
|
|
||||||
repoPath := repo.RepoPath()
|
|
||||||
|
|
||||||
// confirm that commit is exist
|
|
||||||
gitRepo, err := git.OpenRepository(repoPath)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("OpenRepository[%s]: %v", repoPath, err)
|
|
||||||
}
|
|
||||||
if _, err := gitRepo.GetCommit(sha); err != nil {
|
|
||||||
gitRepo.Close()
|
|
||||||
return fmt.Errorf("GetCommit[%s]: %v", sha, err)
|
|
||||||
}
|
|
||||||
gitRepo.Close()
|
|
||||||
|
|
||||||
if err := models.NewCommitStatus(models.NewCommitStatusOptions{
|
|
||||||
Repo: repo,
|
|
||||||
Creator: creator,
|
|
||||||
SHA: sha,
|
|
||||||
CommitStatus: status,
|
|
||||||
}); err != nil {
|
|
||||||
return fmt.Errorf("NewCommitStatus[repo_id: %d, user_id: %d, sha: %s]: %v", repo.ID, creator.ID, sha, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -22,7 +22,7 @@ import (
|
||||||
// CreateRepository creates a repository for the user/organization.
|
// CreateRepository creates a repository for the user/organization.
|
||||||
func CreateRepository(doer, u *user_model.User, opts models.CreateRepoOptions) (*repo_model.Repository, error) {
|
func CreateRepository(doer, u *user_model.User, opts models.CreateRepoOptions) (*repo_model.Repository, error) {
|
||||||
if !doer.IsAdmin && !u.CanCreateRepo() {
|
if !doer.IsAdmin && !u.CanCreateRepo() {
|
||||||
return nil, models.ErrReachLimitOfRepo{
|
return nil, repo_model.ErrReachLimitOfRepo{
|
||||||
Limit: u.MaxRepoCreation,
|
Limit: u.MaxRepoCreation,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ func CreateRepository(doer, u *user_model.User, opts models.CreateRepoOptions) (
|
||||||
// Previously Gitea would just delete and start afresh - this was naughty.
|
// Previously Gitea would just delete and start afresh - this was naughty.
|
||||||
// So we will now fail and delegate to other functionality to adopt or delete
|
// So we will now fail and delegate to other functionality to adopt or delete
|
||||||
log.Error("Files already exist in %s and we are not going to adopt or delete.", repoPath)
|
log.Error("Files already exist in %s and we are not going to adopt or delete.", repoPath)
|
||||||
return models.ErrRepoFilesAlreadyExist{
|
return repo_model.ErrRepoFilesAlreadyExist{
|
||||||
Uname: u.Name,
|
Uname: u.Name,
|
||||||
Name: repo.Name,
|
Name: repo.Name,
|
||||||
}
|
}
|
||||||
|
|
|
@ -267,7 +267,7 @@ func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templ
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if isExist {
|
if isExist {
|
||||||
return nil, models.ErrRepoFilesAlreadyExist{
|
return nil, repo_model.ErrRepoFilesAlreadyExist{
|
||||||
Uname: generateRepo.OwnerName,
|
Uname: generateRepo.OwnerName,
|
||||||
Name: generateRepo.Name,
|
Name: generateRepo.Name,
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,7 +184,7 @@ func checkInitRepository(owner, name string) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if isExist {
|
if isExist {
|
||||||
return models.ErrRepoFilesAlreadyExist{
|
return repo_model.ErrRepoFilesAlreadyExist{
|
||||||
Uname: owner,
|
Uname: owner,
|
||||||
Name: name,
|
Name: name,
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,10 +161,10 @@ func repoAssignment() func(ctx *context.APIContext) {
|
||||||
repo, err := repo_model.GetRepositoryByName(owner.ID, repoName)
|
repo, err := repo_model.GetRepositoryByName(owner.ID, repoName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if repo_model.IsErrRepoNotExist(err) {
|
if repo_model.IsErrRepoNotExist(err) {
|
||||||
redirectRepoID, err := models.LookupRepoRedirect(owner.ID, repoName)
|
redirectRepoID, err := repo_model.LookupRedirect(owner.ID, repoName)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
context.RedirectToRepo(ctx.Context, redirectRepoID)
|
context.RedirectToRepo(ctx.Context, redirectRepoID)
|
||||||
} else if models.IsErrRepoRedirectNotExist(err) {
|
} else if repo_model.IsErrRedirectNotExist(err) {
|
||||||
ctx.NotFound()
|
ctx.NotFound()
|
||||||
} else {
|
} else {
|
||||||
ctx.Error(http.StatusInternalServerError, "LookupRepoRedirect", err)
|
ctx.Error(http.StatusInternalServerError, "LookupRepoRedirect", err)
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/models/perm"
|
"code.gitea.io/gitea/models/perm"
|
||||||
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
"code.gitea.io/gitea/modules/convert"
|
"code.gitea.io/gitea/modules/convert"
|
||||||
|
@ -50,7 +51,7 @@ func ListForks(ctx *context.APIContext) {
|
||||||
// "200":
|
// "200":
|
||||||
// "$ref": "#/responses/RepositoryList"
|
// "$ref": "#/responses/RepositoryList"
|
||||||
|
|
||||||
forks, err := models.GetForks(ctx.Repo.Repository, utils.GetListOptions(ctx))
|
forks, err := repo_model.GetForks(ctx.Repo.Repository, utils.GetListOptions(ctx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "GetForks", err)
|
ctx.Error(http.StatusInternalServerError, "GetForks", err)
|
||||||
return
|
return
|
||||||
|
@ -125,7 +126,7 @@ func CreateFork(ctx *context.APIContext) {
|
||||||
forker = org.AsUser()
|
forker = org.AsUser()
|
||||||
}
|
}
|
||||||
|
|
||||||
fork, err := repo_service.ForkRepository(ctx.User, forker, models.ForkRepoOptions{
|
fork, err := repo_service.ForkRepository(ctx.User, forker, repo_service.ForkRepoOptions{
|
||||||
BaseRepo: repo,
|
BaseRepo: repo,
|
||||||
Name: repo.Name,
|
Name: repo.Name,
|
||||||
Description: repo.Description,
|
Description: repo.Description,
|
||||||
|
|
|
@ -214,15 +214,15 @@ func Migrate(ctx *context.APIContext) {
|
||||||
|
|
||||||
func handleMigrateError(ctx *context.APIContext, repoOwner *user_model.User, remoteAddr string, err error) {
|
func handleMigrateError(ctx *context.APIContext, repoOwner *user_model.User, remoteAddr string, err error) {
|
||||||
switch {
|
switch {
|
||||||
case models.IsErrRepoAlreadyExist(err):
|
case repo_model.IsErrRepoAlreadyExist(err):
|
||||||
ctx.Error(http.StatusConflict, "", "The repository with the same name already exists.")
|
ctx.Error(http.StatusConflict, "", "The repository with the same name already exists.")
|
||||||
case models.IsErrRepoFilesAlreadyExist(err):
|
case repo_model.IsErrRepoFilesAlreadyExist(err):
|
||||||
ctx.Error(http.StatusConflict, "", "Files already exist for this repository. Adopt them or delete them.")
|
ctx.Error(http.StatusConflict, "", "Files already exist for this repository. Adopt them or delete them.")
|
||||||
case migrations.IsRateLimitError(err):
|
case migrations.IsRateLimitError(err):
|
||||||
ctx.Error(http.StatusUnprocessableEntity, "", "Remote visit addressed rate limitation.")
|
ctx.Error(http.StatusUnprocessableEntity, "", "Remote visit addressed rate limitation.")
|
||||||
case migrations.IsTwoFactorAuthError(err):
|
case migrations.IsTwoFactorAuthError(err):
|
||||||
ctx.Error(http.StatusUnprocessableEntity, "", "Remote visit required two factors authentication.")
|
ctx.Error(http.StatusUnprocessableEntity, "", "Remote visit required two factors authentication.")
|
||||||
case models.IsErrReachLimitOfRepo(err):
|
case repo_model.IsErrReachLimitOfRepo(err):
|
||||||
ctx.Error(http.StatusUnprocessableEntity, "", fmt.Sprintf("You have already reached your limit of %d repositories.", repoOwner.MaxCreationLimit()))
|
ctx.Error(http.StatusUnprocessableEntity, "", fmt.Sprintf("You have already reached your limit of %d repositories.", repoOwner.MaxCreationLimit()))
|
||||||
case db.IsErrNameReserved(err):
|
case db.IsErrNameReserved(err):
|
||||||
ctx.Error(http.StatusUnprocessableEntity, "", fmt.Sprintf("The username '%s' is reserved.", err.(db.ErrNameReserved).Name))
|
ctx.Error(http.StatusUnprocessableEntity, "", fmt.Sprintf("The username '%s' is reserved.", err.(db.ErrNameReserved).Name))
|
||||||
|
|
|
@ -956,7 +956,7 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if current user has fork of repository or in the same repository.
|
// Check if current user has fork of repository or in the same repository.
|
||||||
headRepo := models.GetForkedRepo(headUser.ID, baseRepo.ID)
|
headRepo := repo_model.GetForkedRepo(headUser.ID, baseRepo.ID)
|
||||||
if headRepo == nil && !isSameRepo {
|
if headRepo == nil && !isSameRepo {
|
||||||
log.Trace("parseCompareInfo[%d]: does not have fork or in same repository", baseRepo.ID)
|
log.Trace("parseCompareInfo[%d]: does not have fork or in same repository", baseRepo.ID)
|
||||||
ctx.NotFound("GetForkedRepo")
|
ctx.NotFound("GetForkedRepo")
|
||||||
|
|
|
@ -261,7 +261,7 @@ func CreateUserRepo(ctx *context.APIContext, owner *user_model.User, opt api.Cre
|
||||||
IsTemplate: opt.Template,
|
IsTemplate: opt.Template,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if models.IsErrRepoAlreadyExist(err) {
|
if repo_model.IsErrRepoAlreadyExist(err) {
|
||||||
ctx.Error(http.StatusConflict, "", "The repository with the same name already exists.")
|
ctx.Error(http.StatusConflict, "", "The repository with the same name already exists.")
|
||||||
} else if db.IsErrNameReserved(err) ||
|
} else if db.IsErrNameReserved(err) ||
|
||||||
db.IsErrNamePatternNotAllowed(err) {
|
db.IsErrNamePatternNotAllowed(err) {
|
||||||
|
@ -410,7 +410,7 @@ func Generate(ctx *context.APIContext) {
|
||||||
|
|
||||||
repo, err := repo_service.GenerateRepository(ctx.User, ctxUser, ctx.Repo.Repository, opts)
|
repo, err := repo_service.GenerateRepository(ctx.User, ctxUser, ctx.Repo.Repository, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if models.IsErrRepoAlreadyExist(err) {
|
if repo_model.IsErrRepoAlreadyExist(err) {
|
||||||
ctx.Error(http.StatusConflict, "", "The repository with the same name already exists.")
|
ctx.Error(http.StatusConflict, "", "The repository with the same name already exists.")
|
||||||
} else if db.IsErrNameReserved(err) ||
|
} else if db.IsErrNameReserved(err) ||
|
||||||
db.IsErrNamePatternNotAllowed(err) {
|
db.IsErrNamePatternNotAllowed(err) {
|
||||||
|
@ -650,7 +650,7 @@ func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) err
|
||||||
if repo.LowerName != strings.ToLower(newRepoName) {
|
if repo.LowerName != strings.ToLower(newRepoName) {
|
||||||
if err := repo_service.ChangeRepositoryName(ctx.User, repo, newRepoName); err != nil {
|
if err := repo_service.ChangeRepositoryName(ctx.User, repo, newRepoName); err != nil {
|
||||||
switch {
|
switch {
|
||||||
case models.IsErrRepoAlreadyExist(err):
|
case repo_model.IsErrRepoAlreadyExist(err):
|
||||||
ctx.Error(http.StatusUnprocessableEntity, fmt.Sprintf("repo name is already taken [name: %s]", newRepoName), err)
|
ctx.Error(http.StatusUnprocessableEntity, fmt.Sprintf("repo name is already taken [name: %s]", newRepoName), err)
|
||||||
case db.IsErrNameReserved(err):
|
case db.IsErrNameReserved(err):
|
||||||
ctx.Error(http.StatusUnprocessableEntity, fmt.Sprintf("repo name is reserved [name: %s]", newRepoName), err)
|
ctx.Error(http.StatusUnprocessableEntity, fmt.Sprintf("repo name is reserved [name: %s]", newRepoName), err)
|
||||||
|
@ -911,7 +911,7 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := models.UpdateRepositoryUnits(repo, units, deleteUnitTypes); err != nil {
|
if err := repo_model.UpdateRepositoryUnits(repo, units, deleteUnitTypes); err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "UpdateRepositoryUnits", err)
|
ctx.Error(http.StatusInternalServerError, "UpdateRepositoryUnits", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -931,14 +931,14 @@ func updateRepoArchivedState(ctx *context.APIContext, opts api.EditRepoOption) e
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if *opts.Archived {
|
if *opts.Archived {
|
||||||
if err := models.SetArchiveRepoState(repo, *opts.Archived); err != nil {
|
if err := repo_model.SetArchiveRepoState(repo, *opts.Archived); err != nil {
|
||||||
log.Error("Tried to archive a repo: %s", err)
|
log.Error("Tried to archive a repo: %s", err)
|
||||||
ctx.Error(http.StatusInternalServerError, "ArchiveRepoState", err)
|
ctx.Error(http.StatusInternalServerError, "ArchiveRepoState", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Trace("Repository was archived: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
log.Trace("Repository was archived: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
||||||
} else {
|
} else {
|
||||||
if err := models.SetArchiveRepoState(repo, *opts.Archived); err != nil {
|
if err := repo_model.SetArchiveRepoState(repo, *opts.Archived); err != nil {
|
||||||
log.Error("Tried to un-archive a repo: %s", err)
|
log.Error("Tried to un-archive a repo: %s", err)
|
||||||
ctx.Error(http.StatusInternalServerError, "ArchiveRepoState", err)
|
ctx.Error(http.StatusInternalServerError, "ArchiveRepoState", err)
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -7,7 +7,7 @@ package repo
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
"code.gitea.io/gitea/modules/convert"
|
"code.gitea.io/gitea/modules/convert"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
@ -44,7 +44,7 @@ func ListStargazers(ctx *context.APIContext) {
|
||||||
// "200":
|
// "200":
|
||||||
// "$ref": "#/responses/UserList"
|
// "$ref": "#/responses/UserList"
|
||||||
|
|
||||||
stargazers, err := models.GetStargazers(ctx.Repo.Repository, utils.GetListOptions(ctx))
|
stargazers, err := repo_model.GetStargazers(ctx.Repo.Repository, utils.GetListOptions(ctx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "GetStargazers", err)
|
ctx.Error(http.StatusInternalServerError, "GetStargazers", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -7,7 +7,7 @@ package repo
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
"code.gitea.io/gitea/modules/convert"
|
"code.gitea.io/gitea/modules/convert"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
@ -44,9 +44,9 @@ func ListSubscribers(ctx *context.APIContext) {
|
||||||
// "200":
|
// "200":
|
||||||
// "$ref": "#/responses/UserList"
|
// "$ref": "#/responses/UserList"
|
||||||
|
|
||||||
subscribers, err := models.GetRepoWatchers(ctx.Repo.Repository.ID, utils.GetListOptions(ctx))
|
subscribers, err := repo_model.GetRepoWatchers(ctx.Repo.Repository.ID, utils.GetListOptions(ctx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "GetWatchers", err)
|
ctx.Error(http.StatusInternalServerError, "GetRepoWatchers", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
users := make([]*api.User, len(subscribers))
|
users := make([]*api.User, len(subscribers))
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
"code.gitea.io/gitea/modules/convert"
|
"code.gitea.io/gitea/modules/convert"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
@ -47,12 +47,12 @@ func ListTopics(ctx *context.APIContext) {
|
||||||
// "200":
|
// "200":
|
||||||
// "$ref": "#/responses/TopicNames"
|
// "$ref": "#/responses/TopicNames"
|
||||||
|
|
||||||
opts := &models.FindTopicOptions{
|
opts := &repo_model.FindTopicOptions{
|
||||||
ListOptions: utils.GetListOptions(ctx),
|
ListOptions: utils.GetListOptions(ctx),
|
||||||
RepoID: ctx.Repo.Repository.ID,
|
RepoID: ctx.Repo.Repository.ID,
|
||||||
}
|
}
|
||||||
|
|
||||||
topics, total, err := models.FindTopics(opts)
|
topics, total, err := repo_model.FindTopics(opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.InternalServerError(err)
|
ctx.InternalServerError(err)
|
||||||
return
|
return
|
||||||
|
@ -99,7 +99,7 @@ func UpdateTopics(ctx *context.APIContext) {
|
||||||
|
|
||||||
form := web.GetForm(ctx).(*api.RepoTopicOptions)
|
form := web.GetForm(ctx).(*api.RepoTopicOptions)
|
||||||
topicNames := form.Topics
|
topicNames := form.Topics
|
||||||
validTopics, invalidTopics := models.SanitizeAndValidateTopics(topicNames)
|
validTopics, invalidTopics := repo_model.SanitizeAndValidateTopics(topicNames)
|
||||||
|
|
||||||
if len(validTopics) > 25 {
|
if len(validTopics) > 25 {
|
||||||
ctx.JSON(http.StatusUnprocessableEntity, map[string]interface{}{
|
ctx.JSON(http.StatusUnprocessableEntity, map[string]interface{}{
|
||||||
|
@ -117,7 +117,7 @@ func UpdateTopics(ctx *context.APIContext) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err := models.SaveTopics(ctx.Repo.Repository.ID, validTopics...)
|
err := repo_model.SaveTopics(ctx.Repo.Repository.ID, validTopics...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("SaveTopics failed: %v", err)
|
log.Error("SaveTopics failed: %v", err)
|
||||||
ctx.InternalServerError(err)
|
ctx.InternalServerError(err)
|
||||||
|
@ -158,7 +158,7 @@ func AddTopic(ctx *context.APIContext) {
|
||||||
|
|
||||||
topicName := strings.TrimSpace(strings.ToLower(ctx.Params(":topic")))
|
topicName := strings.TrimSpace(strings.ToLower(ctx.Params(":topic")))
|
||||||
|
|
||||||
if !models.ValidateTopic(topicName) {
|
if !repo_model.ValidateTopic(topicName) {
|
||||||
ctx.JSON(http.StatusUnprocessableEntity, map[string]interface{}{
|
ctx.JSON(http.StatusUnprocessableEntity, map[string]interface{}{
|
||||||
"invalidTopics": topicName,
|
"invalidTopics": topicName,
|
||||||
"message": "Topic name is invalid",
|
"message": "Topic name is invalid",
|
||||||
|
@ -167,7 +167,7 @@ func AddTopic(ctx *context.APIContext) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prevent adding more topics than allowed to repo
|
// Prevent adding more topics than allowed to repo
|
||||||
count, err := models.CountTopics(&models.FindTopicOptions{
|
count, err := repo_model.CountTopics(&repo_model.FindTopicOptions{
|
||||||
RepoID: ctx.Repo.Repository.ID,
|
RepoID: ctx.Repo.Repository.ID,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -182,7 +182,7 @@ func AddTopic(ctx *context.APIContext) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = models.AddTopic(ctx.Repo.Repository.ID, topicName)
|
_, err = repo_model.AddTopic(ctx.Repo.Repository.ID, topicName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("AddTopic failed: %v", err)
|
log.Error("AddTopic failed: %v", err)
|
||||||
ctx.InternalServerError(err)
|
ctx.InternalServerError(err)
|
||||||
|
@ -223,7 +223,7 @@ func DeleteTopic(ctx *context.APIContext) {
|
||||||
|
|
||||||
topicName := strings.TrimSpace(strings.ToLower(ctx.Params(":topic")))
|
topicName := strings.TrimSpace(strings.ToLower(ctx.Params(":topic")))
|
||||||
|
|
||||||
if !models.ValidateTopic(topicName) {
|
if !repo_model.ValidateTopic(topicName) {
|
||||||
ctx.JSON(http.StatusUnprocessableEntity, map[string]interface{}{
|
ctx.JSON(http.StatusUnprocessableEntity, map[string]interface{}{
|
||||||
"invalidTopics": topicName,
|
"invalidTopics": topicName,
|
||||||
"message": "Topic name is invalid",
|
"message": "Topic name is invalid",
|
||||||
|
@ -231,7 +231,7 @@ func DeleteTopic(ctx *context.APIContext) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
topic, err := models.DeleteTopic(ctx.Repo.Repository.ID, topicName)
|
topic, err := repo_model.DeleteTopic(ctx.Repo.Repository.ID, topicName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("DeleteTopic failed: %v", err)
|
log.Error("DeleteTopic failed: %v", err)
|
||||||
ctx.InternalServerError(err)
|
ctx.InternalServerError(err)
|
||||||
|
@ -272,12 +272,12 @@ func TopicSearch(ctx *context.APIContext) {
|
||||||
// "403":
|
// "403":
|
||||||
// "$ref": "#/responses/forbidden"
|
// "$ref": "#/responses/forbidden"
|
||||||
|
|
||||||
opts := &models.FindTopicOptions{
|
opts := &repo_model.FindTopicOptions{
|
||||||
Keyword: ctx.FormString("q"),
|
Keyword: ctx.FormString("q"),
|
||||||
ListOptions: utils.GetListOptions(ctx),
|
ListOptions: utils.GetListOptions(ctx),
|
||||||
}
|
}
|
||||||
|
|
||||||
topics, total, err := models.FindTopics(opts)
|
topics, total, err := repo_model.FindTopics(opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.InternalServerError(err)
|
ctx.InternalServerError(err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -104,7 +104,7 @@ func Transfer(ctx *context.APIContext) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if models.IsErrRepoAlreadyExist(err) {
|
if repo_model.IsErrRepoAlreadyExist(err) {
|
||||||
ctx.Error(http.StatusUnprocessableEntity, "CreatePendingRepositoryTransfer", err)
|
ctx.Error(http.StatusUnprocessableEntity, "CreatePendingRepositoryTransfer", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
"code.gitea.io/gitea/modules/convert"
|
"code.gitea.io/gitea/modules/convert"
|
||||||
|
@ -121,7 +122,7 @@ func IsStarring(ctx *context.APIContext) {
|
||||||
// "404":
|
// "404":
|
||||||
// "$ref": "#/responses/notFound"
|
// "$ref": "#/responses/notFound"
|
||||||
|
|
||||||
if models.IsStaring(ctx.User.ID, ctx.Repo.Repository.ID) {
|
if repo_model.IsStaring(ctx.User.ID, ctx.Repo.Repository.ID) {
|
||||||
ctx.Status(http.StatusNoContent)
|
ctx.Status(http.StatusNoContent)
|
||||||
} else {
|
} else {
|
||||||
ctx.NotFound()
|
ctx.NotFound()
|
||||||
|
@ -148,7 +149,7 @@ func Star(ctx *context.APIContext) {
|
||||||
// "204":
|
// "204":
|
||||||
// "$ref": "#/responses/empty"
|
// "$ref": "#/responses/empty"
|
||||||
|
|
||||||
err := models.StarRepo(ctx.User.ID, ctx.Repo.Repository.ID, true)
|
err := repo_model.StarRepo(ctx.User.ID, ctx.Repo.Repository.ID, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "StarRepo", err)
|
ctx.Error(http.StatusInternalServerError, "StarRepo", err)
|
||||||
return
|
return
|
||||||
|
@ -176,7 +177,7 @@ func Unstar(ctx *context.APIContext) {
|
||||||
// "204":
|
// "204":
|
||||||
// "$ref": "#/responses/empty"
|
// "$ref": "#/responses/empty"
|
||||||
|
|
||||||
err := models.StarRepo(ctx.User.ID, ctx.Repo.Repository.ID, false)
|
err := repo_model.StarRepo(ctx.User.ID, ctx.Repo.Repository.ID, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "StarRepo", err)
|
ctx.Error(http.StatusInternalServerError, "StarRepo", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -123,7 +123,7 @@ func IsWatching(ctx *context.APIContext) {
|
||||||
// "404":
|
// "404":
|
||||||
// description: User is not watching this repo or repo do not exist
|
// description: User is not watching this repo or repo do not exist
|
||||||
|
|
||||||
if models.IsWatching(ctx.User.ID, ctx.Repo.Repository.ID) {
|
if repo_model.IsWatching(ctx.User.ID, ctx.Repo.Repository.ID) {
|
||||||
ctx.JSON(http.StatusOK, api.WatchInfo{
|
ctx.JSON(http.StatusOK, api.WatchInfo{
|
||||||
Subscribed: true,
|
Subscribed: true,
|
||||||
Ignored: false,
|
Ignored: false,
|
||||||
|
@ -157,7 +157,7 @@ func Watch(ctx *context.APIContext) {
|
||||||
// "200":
|
// "200":
|
||||||
// "$ref": "#/responses/WatchInfo"
|
// "$ref": "#/responses/WatchInfo"
|
||||||
|
|
||||||
err := models.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, true)
|
err := repo_model.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "WatchRepo", err)
|
ctx.Error(http.StatusInternalServerError, "WatchRepo", err)
|
||||||
return
|
return
|
||||||
|
@ -193,7 +193,7 @@ func Unwatch(ctx *context.APIContext) {
|
||||||
// "204":
|
// "204":
|
||||||
// "$ref": "#/responses/empty"
|
// "$ref": "#/responses/empty"
|
||||||
|
|
||||||
err := models.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, false)
|
err := repo_model.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "UnwatchRepo", err)
|
ctx.Error(http.StatusInternalServerError, "UnwatchRepo", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -105,7 +105,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
|
||||||
|
|
||||||
repo.IsPrivate = opts.GitPushOptions.Bool(private.GitPushOptionRepoPrivate, repo.IsPrivate)
|
repo.IsPrivate = opts.GitPushOptions.Bool(private.GitPushOptionRepoPrivate, repo.IsPrivate)
|
||||||
repo.IsTemplate = opts.GitPushOptions.Bool(private.GitPushOptionRepoTemplate, repo.IsTemplate)
|
repo.IsTemplate = opts.GitPushOptions.Bool(private.GitPushOptionRepoTemplate, repo.IsTemplate)
|
||||||
if err := models.UpdateRepositoryCols(repo, "is_private", "is_template"); err != nil {
|
if err := repo_model.UpdateRepositoryCols(repo, "is_private", "is_template"); err != nil {
|
||||||
log.Error("Failed to Update: %s/%s Error: %v", ownerName, repoName, err)
|
log.Error("Failed to Update: %s/%s Error: %v", ownerName, repoName, err)
|
||||||
ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{
|
ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{
|
||||||
Err: fmt.Sprintf("Failed to Update: %s/%s Error: %v", ownerName, repoName, err),
|
Err: fmt.Sprintf("Failed to Update: %s/%s Error: %v", ownerName, repoName, err),
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/models/webhook"
|
"code.gitea.io/gitea/models/webhook"
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
|
@ -125,7 +126,7 @@ func SettingsPost(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if nameChanged {
|
} else if nameChanged {
|
||||||
if err := models.UpdateRepositoryOwnerNames(org.ID, org.Name); err != nil {
|
if err := repo_model.UpdateRepositoryOwnerNames(org.ID, org.Name); err != nil {
|
||||||
ctx.ServerError("UpdateRepository", err)
|
ctx.ServerError("UpdateRepository", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ func Branches(ctx *context.Context) {
|
||||||
ctx.Data["IsWriter"] = ctx.Repo.CanWrite(unit.TypeCode)
|
ctx.Data["IsWriter"] = ctx.Repo.CanWrite(unit.TypeCode)
|
||||||
ctx.Data["IsMirror"] = ctx.Repo.Repository.IsMirror
|
ctx.Data["IsMirror"] = ctx.Repo.Repository.IsMirror
|
||||||
ctx.Data["CanPull"] = ctx.Repo.CanWrite(unit.TypeCode) ||
|
ctx.Data["CanPull"] = ctx.Repo.CanWrite(unit.TypeCode) ||
|
||||||
(ctx.IsSigned && models.HasForkedRepo(ctx.User.ID, ctx.Repo.Repository.ID))
|
(ctx.IsSigned && repo_model.HasForkedRepo(ctx.User.ID, ctx.Repo.Repository.ID))
|
||||||
ctx.Data["PageIsViewCode"] = true
|
ctx.Data["PageIsViewCode"] = true
|
||||||
ctx.Data["PageIsBranches"] = true
|
ctx.Data["PageIsBranches"] = true
|
||||||
|
|
||||||
|
|
|
@ -340,7 +340,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
|
||||||
// "OwnForkRepo"
|
// "OwnForkRepo"
|
||||||
var ownForkRepo *repo_model.Repository
|
var ownForkRepo *repo_model.Repository
|
||||||
if ctx.User != nil && baseRepo.OwnerID != ctx.User.ID {
|
if ctx.User != nil && baseRepo.OwnerID != ctx.User.ID {
|
||||||
repo := models.GetForkedRepo(ctx.User.ID, baseRepo.ID)
|
repo := repo_model.GetForkedRepo(ctx.User.ID, baseRepo.ID)
|
||||||
if repo != nil {
|
if repo != nil {
|
||||||
ownForkRepo = repo
|
ownForkRepo = repo
|
||||||
ctx.Data["OwnForkRepo"] = ownForkRepo
|
ctx.Data["OwnForkRepo"] = ownForkRepo
|
||||||
|
@ -364,13 +364,13 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
|
||||||
|
|
||||||
// 5. If the headOwner has a fork of the baseRepo - use that
|
// 5. If the headOwner has a fork of the baseRepo - use that
|
||||||
if !has {
|
if !has {
|
||||||
ci.HeadRepo = models.GetForkedRepo(ci.HeadUser.ID, baseRepo.ID)
|
ci.HeadRepo = repo_model.GetForkedRepo(ci.HeadUser.ID, baseRepo.ID)
|
||||||
has = ci.HeadRepo != nil
|
has = ci.HeadRepo != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6. If the baseRepo is a fork and the headUser has a fork of that use that
|
// 6. If the baseRepo is a fork and the headUser has a fork of that use that
|
||||||
if !has && baseRepo.IsFork {
|
if !has && baseRepo.IsFork {
|
||||||
ci.HeadRepo = models.GetForkedRepo(ci.HeadUser.ID, baseRepo.ForkID)
|
ci.HeadRepo = repo_model.GetForkedRepo(ci.HeadUser.ID, baseRepo.ForkID)
|
||||||
has = ci.HeadRepo != nil
|
has = ci.HeadRepo != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -134,7 +134,7 @@ func httpBase(ctx *context.Context) (h *serviceHandler) {
|
||||||
repo, err := repo_model.GetRepositoryByName(owner.ID, reponame)
|
repo, err := repo_model.GetRepositoryByName(owner.ID, reponame)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if repo_model.IsErrRepoNotExist(err) {
|
if repo_model.IsErrRepoNotExist(err) {
|
||||||
if redirectRepoID, err := models.LookupRepoRedirect(owner.ID, reponame); err == nil {
|
if redirectRepoID, err := repo_model.LookupRedirect(owner.ID, reponame); err == nil {
|
||||||
context.RedirectToRepo(ctx, redirectRepoID)
|
context.RedirectToRepo(ctx, redirectRepoID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,7 +108,7 @@ func MustAllowPulls(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// User can send pull request if owns a forked repository.
|
// User can send pull request if owns a forked repository.
|
||||||
if ctx.IsSigned && models.HasForkedRepo(ctx.User.ID, ctx.Repo.Repository.ID) {
|
if ctx.IsSigned && repo_model.HasForkedRepo(ctx.User.ID, ctx.Repo.Repository.ID) {
|
||||||
ctx.Repo.PullRequest.Allowed = true
|
ctx.Repo.PullRequest.Allowed = true
|
||||||
ctx.Repo.PullRequest.HeadInfoSubURL = url.PathEscape(ctx.User.Name) + ":" + util.PathEscapeSegments(ctx.Repo.BranchName)
|
ctx.Repo.PullRequest.HeadInfoSubURL = url.PathEscape(ctx.User.Name) + ":" + util.PathEscapeSegments(ctx.Repo.BranchName)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
|
@ -79,12 +80,12 @@ func handleMigrateError(ctx *context.Context, owner *user_model.User, err error,
|
||||||
ctx.RenderWithErr(ctx.Tr("form.visit_rate_limit"), tpl, form)
|
ctx.RenderWithErr(ctx.Tr("form.visit_rate_limit"), tpl, form)
|
||||||
case migrations.IsTwoFactorAuthError(err):
|
case migrations.IsTwoFactorAuthError(err):
|
||||||
ctx.RenderWithErr(ctx.Tr("form.2fa_auth_required"), tpl, form)
|
ctx.RenderWithErr(ctx.Tr("form.2fa_auth_required"), tpl, form)
|
||||||
case models.IsErrReachLimitOfRepo(err):
|
case repo_model.IsErrReachLimitOfRepo(err):
|
||||||
ctx.RenderWithErr(ctx.Tr("repo.form.reach_limit_of_creation", owner.MaxCreationLimit()), tpl, form)
|
ctx.RenderWithErr(ctx.Tr("repo.form.reach_limit_of_creation", owner.MaxCreationLimit()), tpl, form)
|
||||||
case models.IsErrRepoAlreadyExist(err):
|
case repo_model.IsErrRepoAlreadyExist(err):
|
||||||
ctx.Data["Err_RepoName"] = true
|
ctx.Data["Err_RepoName"] = true
|
||||||
ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tpl, form)
|
ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tpl, form)
|
||||||
case models.IsErrRepoFilesAlreadyExist(err):
|
case repo_model.IsErrRepoFilesAlreadyExist(err):
|
||||||
ctx.Data["Err_RepoName"] = true
|
ctx.Data["Err_RepoName"] = true
|
||||||
switch {
|
switch {
|
||||||
case ctx.IsUserSiteAdmin() || (setting.Repository.AllowAdoptionOfUnadoptedRepositories && setting.Repository.AllowDeleteOfUnadoptedRepositories):
|
case ctx.IsUserSiteAdmin() || (setting.Repository.AllowAdoptionOfUnadoptedRepositories && setting.Repository.AllowDeleteOfUnadoptedRepositories):
|
||||||
|
@ -230,7 +231,7 @@ func MigratePost(ctx *context.Context) {
|
||||||
opts.Releases = false
|
opts.Releases = false
|
||||||
}
|
}
|
||||||
|
|
||||||
err = models.CheckCreateRepository(ctx.User, ctxUser, opts.RepoName, false)
|
err = repo_model.CheckCreateRepository(ctx.User, ctxUser, opts.RepoName, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handleMigrateError(ctx, ctxUser, err, "MigratePost", tpl, form)
|
handleMigrateError(ctx, ctxUser, err, "MigratePost", tpl, form)
|
||||||
return
|
return
|
||||||
|
|
|
@ -110,7 +110,7 @@ func getForkRepository(ctx *context.Context) *repo_model.Repository {
|
||||||
ctx.Data["repo_name"] = forkRepo.Name
|
ctx.Data["repo_name"] = forkRepo.Name
|
||||||
ctx.Data["description"] = forkRepo.Description
|
ctx.Data["description"] = forkRepo.Description
|
||||||
ctx.Data["IsPrivate"] = forkRepo.IsPrivate || forkRepo.Owner.Visibility == structs.VisibleTypePrivate
|
ctx.Data["IsPrivate"] = forkRepo.IsPrivate || forkRepo.Owner.Visibility == structs.VisibleTypePrivate
|
||||||
canForkToUser := forkRepo.OwnerID != ctx.User.ID && !models.HasForkedRepo(ctx.User.ID, forkRepo.ID)
|
canForkToUser := forkRepo.OwnerID != ctx.User.ID && !repo_model.HasForkedRepo(ctx.User.ID, forkRepo.ID)
|
||||||
|
|
||||||
ctx.Data["ForkRepo"] = forkRepo
|
ctx.Data["ForkRepo"] = forkRepo
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ func getForkRepository(ctx *context.Context) *repo_model.Repository {
|
||||||
}
|
}
|
||||||
var orgs []*models.Organization
|
var orgs []*models.Organization
|
||||||
for _, org := range ownedOrgs {
|
for _, org := range ownedOrgs {
|
||||||
if forkRepo.OwnerID != org.ID && !models.HasForkedRepo(org.ID, forkRepo.ID) {
|
if forkRepo.OwnerID != org.ID && !repo_model.HasForkedRepo(org.ID, forkRepo.ID) {
|
||||||
orgs = append(orgs, org)
|
orgs = append(orgs, org)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -202,7 +202,7 @@ func ForkPost(ctx *context.Context) {
|
||||||
ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplFork, &form)
|
ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplFork, &form)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
repo := models.GetForkedRepo(ctxUser.ID, traverseParentRepo.ID)
|
repo := repo_model.GetForkedRepo(ctxUser.ID, traverseParentRepo.ID)
|
||||||
if repo != nil {
|
if repo != nil {
|
||||||
ctx.Redirect(ctxUser.HomeLink() + "/" + url.PathEscape(repo.Name))
|
ctx.Redirect(ctxUser.HomeLink() + "/" + url.PathEscape(repo.Name))
|
||||||
return
|
return
|
||||||
|
@ -229,7 +229,7 @@ func ForkPost(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repo, err := repo_service.ForkRepository(ctx.User, ctxUser, models.ForkRepoOptions{
|
repo, err := repo_service.ForkRepository(ctx.User, ctxUser, repo_service.ForkRepoOptions{
|
||||||
BaseRepo: forkRepo,
|
BaseRepo: forkRepo,
|
||||||
Name: form.RepoName,
|
Name: form.RepoName,
|
||||||
Description: form.Description,
|
Description: form.Description,
|
||||||
|
@ -237,7 +237,7 @@ func ForkPost(ctx *context.Context) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Data["Err_RepoName"] = true
|
ctx.Data["Err_RepoName"] = true
|
||||||
switch {
|
switch {
|
||||||
case models.IsErrRepoAlreadyExist(err):
|
case repo_model.IsErrRepoAlreadyExist(err):
|
||||||
ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplFork, &form)
|
ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplFork, &form)
|
||||||
case db.IsErrNameReserved(err):
|
case db.IsErrNameReserved(err):
|
||||||
ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(db.ErrNameReserved).Name), tplFork, &form)
|
ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(db.ErrNameReserved).Name), tplFork, &form)
|
||||||
|
|
|
@ -161,12 +161,12 @@ func Create(ctx *context.Context) {
|
||||||
|
|
||||||
func handleCreateError(ctx *context.Context, owner *user_model.User, err error, name string, tpl base.TplName, form interface{}) {
|
func handleCreateError(ctx *context.Context, owner *user_model.User, err error, name string, tpl base.TplName, form interface{}) {
|
||||||
switch {
|
switch {
|
||||||
case models.IsErrReachLimitOfRepo(err):
|
case repo_model.IsErrReachLimitOfRepo(err):
|
||||||
ctx.RenderWithErr(ctx.Tr("repo.form.reach_limit_of_creation", owner.MaxCreationLimit()), tpl, form)
|
ctx.RenderWithErr(ctx.Tr("repo.form.reach_limit_of_creation", owner.MaxCreationLimit()), tpl, form)
|
||||||
case models.IsErrRepoAlreadyExist(err):
|
case repo_model.IsErrRepoAlreadyExist(err):
|
||||||
ctx.Data["Err_RepoName"] = true
|
ctx.Data["Err_RepoName"] = true
|
||||||
ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tpl, form)
|
ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tpl, form)
|
||||||
case models.IsErrRepoFilesAlreadyExist(err):
|
case repo_model.IsErrRepoFilesAlreadyExist(err):
|
||||||
ctx.Data["Err_RepoName"] = true
|
ctx.Data["Err_RepoName"] = true
|
||||||
switch {
|
switch {
|
||||||
case ctx.IsUserSiteAdmin() || (setting.Repository.AllowAdoptionOfUnadoptedRepositories && setting.Repository.AllowDeleteOfUnadoptedRepositories):
|
case ctx.IsUserSiteAdmin() || (setting.Repository.AllowAdoptionOfUnadoptedRepositories && setting.Repository.AllowDeleteOfUnadoptedRepositories):
|
||||||
|
@ -278,13 +278,13 @@ func Action(ctx *context.Context) {
|
||||||
var err error
|
var err error
|
||||||
switch ctx.Params(":action") {
|
switch ctx.Params(":action") {
|
||||||
case "watch":
|
case "watch":
|
||||||
err = models.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, true)
|
err = repo_model.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, true)
|
||||||
case "unwatch":
|
case "unwatch":
|
||||||
err = models.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, false)
|
err = repo_model.WatchRepo(ctx.User.ID, ctx.Repo.Repository.ID, false)
|
||||||
case "star":
|
case "star":
|
||||||
err = models.StarRepo(ctx.User.ID, ctx.Repo.Repository.ID, true)
|
err = repo_model.StarRepo(ctx.User.ID, ctx.Repo.Repository.ID, true)
|
||||||
case "unstar":
|
case "unstar":
|
||||||
err = models.StarRepo(ctx.User.ID, ctx.Repo.Repository.ID, false)
|
err = repo_model.StarRepo(ctx.User.ID, ctx.Repo.Repository.ID, false)
|
||||||
case "accept_transfer":
|
case "accept_transfer":
|
||||||
err = acceptOrRejectRepoTransfer(ctx, true)
|
err = acceptOrRejectRepoTransfer(ctx, true)
|
||||||
case "reject_transfer":
|
case "reject_transfer":
|
||||||
|
|
|
@ -103,11 +103,11 @@ func SettingsPost(ctx *context.Context) {
|
||||||
if err := repo_service.ChangeRepositoryName(ctx.User, repo, newRepoName); err != nil {
|
if err := repo_service.ChangeRepositoryName(ctx.User, repo, newRepoName); err != nil {
|
||||||
ctx.Data["Err_RepoName"] = true
|
ctx.Data["Err_RepoName"] = true
|
||||||
switch {
|
switch {
|
||||||
case models.IsErrRepoAlreadyExist(err):
|
case repo_model.IsErrRepoAlreadyExist(err):
|
||||||
ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tplSettingsOptions, &form)
|
ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tplSettingsOptions, &form)
|
||||||
case db.IsErrNameReserved(err):
|
case db.IsErrNameReserved(err):
|
||||||
ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(db.ErrNameReserved).Name), tplSettingsOptions, &form)
|
ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(db.ErrNameReserved).Name), tplSettingsOptions, &form)
|
||||||
case models.IsErrRepoFilesAlreadyExist(err):
|
case repo_model.IsErrRepoFilesAlreadyExist(err):
|
||||||
ctx.Data["Err_RepoName"] = true
|
ctx.Data["Err_RepoName"] = true
|
||||||
switch {
|
switch {
|
||||||
case ctx.IsUserSiteAdmin() || (setting.Repository.AllowAdoptionOfUnadoptedRepositories && setting.Repository.AllowDeleteOfUnadoptedRepositories):
|
case ctx.IsUserSiteAdmin() || (setting.Repository.AllowAdoptionOfUnadoptedRepositories && setting.Repository.AllowDeleteOfUnadoptedRepositories):
|
||||||
|
@ -461,7 +461,7 @@ func SettingsPost(ctx *context.Context) {
|
||||||
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypePullRequests)
|
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypePullRequests)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := models.UpdateRepositoryUnits(repo, units, deleteUnitTypes); err != nil {
|
if err := repo_model.UpdateRepositoryUnits(repo, units, deleteUnitTypes); err != nil {
|
||||||
ctx.ServerError("UpdateRepositoryUnits", err)
|
ctx.ServerError("UpdateRepositoryUnits", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -612,7 +612,7 @@ func SettingsPost(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := repo_service.StartRepositoryTransfer(ctx.User, newOwner, repo, nil); err != nil {
|
if err := repo_service.StartRepositoryTransfer(ctx.User, newOwner, repo, nil); err != nil {
|
||||||
if models.IsErrRepoAlreadyExist(err) {
|
if repo_model.IsErrRepoAlreadyExist(err) {
|
||||||
ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplSettingsOptions, nil)
|
ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplSettingsOptions, nil)
|
||||||
} else if models.IsErrRepoTransferInProgress(err) {
|
} else if models.IsErrRepoTransferInProgress(err) {
|
||||||
ctx.RenderWithErr(ctx.Tr("repo.settings.transfer_in_progress"), tplSettingsOptions, nil)
|
ctx.RenderWithErr(ctx.Tr("repo.settings.transfer_in_progress"), tplSettingsOptions, nil)
|
||||||
|
@ -714,7 +714,7 @@ func SettingsPost(ctx *context.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := models.SetArchiveRepoState(repo, true); err != nil {
|
if err := repo_model.SetArchiveRepoState(repo, true); err != nil {
|
||||||
log.Error("Tried to archive a repo: %s", err)
|
log.Error("Tried to archive a repo: %s", err)
|
||||||
ctx.Flash.Error(ctx.Tr("repo.settings.archive.error"))
|
ctx.Flash.Error(ctx.Tr("repo.settings.archive.error"))
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
|
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
|
||||||
|
@ -732,7 +732,7 @@ func SettingsPost(ctx *context.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := models.SetArchiveRepoState(repo, false); err != nil {
|
if err := repo_model.SetArchiveRepoState(repo, false); err != nil {
|
||||||
log.Error("Tried to unarchive a repo: %s", err)
|
log.Error("Tried to unarchive a repo: %s", err)
|
||||||
ctx.Flash.Error(ctx.Tr("repo.settings.unarchive.error"))
|
ctx.Flash.Error(ctx.Tr("repo.settings.unarchive.error"))
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
|
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
|
||||||
|
@ -1145,7 +1145,7 @@ func UpdateAvatarSetting(ctx *context.Context, form forms.AvatarForm) error {
|
||||||
if !(st.IsImage() && !st.IsSvgImage()) {
|
if !(st.IsImage() && !st.IsSvgImage()) {
|
||||||
return errors.New(ctx.Tr("settings.uploaded_avatar_not_a_image"))
|
return errors.New(ctx.Tr("settings.uploaded_avatar_not_a_image"))
|
||||||
}
|
}
|
||||||
if err = models.UploadRepoAvatar(ctxRepo, data); err != nil {
|
if err = repo_service.UploadAvatar(ctxRepo, data); err != nil {
|
||||||
return fmt.Errorf("UploadAvatar: %v", err)
|
return fmt.Errorf("UploadAvatar: %v", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -1165,7 +1165,7 @@ func SettingsAvatar(ctx *context.Context) {
|
||||||
|
|
||||||
// SettingsDeleteAvatar delete repository avatar
|
// SettingsDeleteAvatar delete repository avatar
|
||||||
func SettingsDeleteAvatar(ctx *context.Context) {
|
func SettingsDeleteAvatar(ctx *context.Context) {
|
||||||
if err := models.DeleteRepoAvatar(ctx.Repo.Repository); err != nil {
|
if err := repo_service.DeleteAvatar(ctx.Repo.Repository); err != nil {
|
||||||
ctx.Flash.Error(fmt.Sprintf("DeleteAvatar: %v", err))
|
ctx.Flash.Error(fmt.Sprintf("DeleteAvatar: %v", err))
|
||||||
}
|
}
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
|
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
)
|
)
|
||||||
|
@ -28,7 +28,7 @@ func TopicsPost(ctx *context.Context) {
|
||||||
topics = strings.Split(topicsStr, ",")
|
topics = strings.Split(topicsStr, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
validTopics, invalidTopics := models.SanitizeAndValidateTopics(topics)
|
validTopics, invalidTopics := repo_model.SanitizeAndValidateTopics(topics)
|
||||||
|
|
||||||
if len(validTopics) > 25 {
|
if len(validTopics) > 25 {
|
||||||
ctx.JSON(http.StatusUnprocessableEntity, map[string]interface{}{
|
ctx.JSON(http.StatusUnprocessableEntity, map[string]interface{}{
|
||||||
|
@ -46,7 +46,7 @@ func TopicsPost(ctx *context.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err := models.SaveTopics(ctx.Repo.Repository.ID, validTopics...)
|
err := repo_model.SaveTopics(ctx.Repo.Repository.ID, validTopics...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("SaveTopics failed: %v", err)
|
log.Error("SaveTopics failed: %v", err)
|
||||||
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
|
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
|
||||||
|
|
|
@ -822,7 +822,7 @@ func renderLanguageStats(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderRepoTopics(ctx *context.Context) {
|
func renderRepoTopics(ctx *context.Context) {
|
||||||
topics, _, err := models.FindTopics(&models.FindTopicOptions{
|
topics, _, err := repo_model.FindTopics(&repo_model.FindTopicOptions{
|
||||||
RepoID: ctx.Repo.Repository.ID,
|
RepoID: ctx.Repo.Repository.ID,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -931,7 +931,7 @@ func Watchers(ctx *context.Context) {
|
||||||
ctx.Data["PageIsWatchers"] = true
|
ctx.Data["PageIsWatchers"] = true
|
||||||
|
|
||||||
RenderUserCards(ctx, ctx.Repo.Repository.NumWatches, func(opts db.ListOptions) ([]*user_model.User, error) {
|
RenderUserCards(ctx, ctx.Repo.Repository.NumWatches, func(opts db.ListOptions) ([]*user_model.User, error) {
|
||||||
return models.GetRepoWatchers(ctx.Repo.Repository.ID, opts)
|
return repo_model.GetRepoWatchers(ctx.Repo.Repository.ID, opts)
|
||||||
}, tplWatchers)
|
}, tplWatchers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -941,7 +941,7 @@ func Stars(ctx *context.Context) {
|
||||||
ctx.Data["CardsTitle"] = ctx.Tr("repo.stargazers")
|
ctx.Data["CardsTitle"] = ctx.Tr("repo.stargazers")
|
||||||
ctx.Data["PageIsStargazers"] = true
|
ctx.Data["PageIsStargazers"] = true
|
||||||
RenderUserCards(ctx, ctx.Repo.Repository.NumStars, func(opts db.ListOptions) ([]*user_model.User, error) {
|
RenderUserCards(ctx, ctx.Repo.Repository.NumStars, func(opts db.ListOptions) ([]*user_model.User, error) {
|
||||||
return models.GetStargazers(ctx.Repo.Repository, opts)
|
return repo_model.GetStargazers(ctx.Repo.Repository, opts)
|
||||||
}, tplWatchers)
|
}, tplWatchers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -957,7 +957,7 @@ func Forks(ctx *context.Context) {
|
||||||
pager := context.NewPagination(ctx.Repo.Repository.NumForks, models.ItemsPerPage, page, 5)
|
pager := context.NewPagination(ctx.Repo.Repository.NumForks, models.ItemsPerPage, page, 5)
|
||||||
ctx.Data["Page"] = pager
|
ctx.Data["Page"] = pager
|
||||||
|
|
||||||
forks, err := models.GetForks(ctx.Repo.Repository, db.ListOptions{
|
forks, err := repo_model.GetForks(ctx.Repo.Repository, db.ListOptions{
|
||||||
Page: pager.Paginater.Current(),
|
Page: pager.Paginater.Current(),
|
||||||
PageSize: models.ItemsPerPage,
|
PageSize: models.ItemsPerPage,
|
||||||
})
|
})
|
||||||
|
|
|
@ -77,7 +77,7 @@ func HandleUsernameChange(ctx *context.Context, user *user_model.User, newName s
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err := models.UpdateRepositoryOwnerNames(user.ID, newName); err != nil {
|
if err := repo_model.UpdateRepositoryOwnerNames(user.ID, newName); err != nil {
|
||||||
ctx.ServerError("UpdateRepository", err)
|
ctx.ServerError("UpdateRepository", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -290,7 +290,7 @@ func Repos(ctx *context.Context) {
|
||||||
return filepath.SkipDir
|
return filepath.SkipDir
|
||||||
}
|
}
|
||||||
name = name[:len(name)-4]
|
name = name[:len(name)-4]
|
||||||
if models.IsUsableRepoName(name) != nil || strings.ToLower(name) != name {
|
if repo_model.IsUsableRepoName(name) != nil || strings.ToLower(name) != name {
|
||||||
return filepath.SkipDir
|
return filepath.SkipDir
|
||||||
}
|
}
|
||||||
if count >= start && count < end {
|
if count >= start && count < end {
|
||||||
|
|
|
@ -118,7 +118,7 @@ func registerRemoveRandomAvatars() {
|
||||||
RunAtStart: false,
|
RunAtStart: false,
|
||||||
Schedule: "@every 72h",
|
Schedule: "@every 72h",
|
||||||
}, func(ctx context.Context, _ *user_model.User, _ Config) error {
|
}, func(ctx context.Context, _ *user_model.User, _ Config) error {
|
||||||
return models.RemoveRandomAvatars(ctx)
|
return repo_service.RemoveRandomAvatars(ctx)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
@ -78,7 +80,7 @@ func mailIssueCommentToParticipants(ctx *mailCommentContext, mentions []*user_mo
|
||||||
// =========== Repo watchers ===========
|
// =========== Repo watchers ===========
|
||||||
// Make repo watchers last, since it's likely the list with the most users
|
// Make repo watchers last, since it's likely the list with the most users
|
||||||
if !(ctx.Issue.IsPull && ctx.Issue.PullRequest.IsWorkInProgress() && ctx.ActionType != models.ActionCreatePullRequest) {
|
if !(ctx.Issue.IsPull && ctx.Issue.PullRequest.IsWorkInProgress() && ctx.ActionType != models.ActionCreatePullRequest) {
|
||||||
ids, err = models.GetRepoWatchersIDs(ctx.Issue.RepoID)
|
ids, err = repo_model.GetRepoWatchersIDs(db.DefaultContext, ctx.Issue.RepoID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("GetRepoWatchersIDs(%d): %v", ctx.Issue.RepoID, err)
|
return fmt.Errorf("GetRepoWatchersIDs(%d): %v", ctx.Issue.RepoID, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
|
"code.gitea.io/gitea/models/db"
|
||||||
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
@ -29,7 +31,7 @@ func MailNewRelease(rel *models.Release) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
watcherIDList, err := models.GetRepoWatchersIDs(rel.RepoID)
|
watcherIDList, err := repo_model.GetRepoWatchersIDs(db.DefaultContext, rel.RepoID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetRepoWatchersIDs(%d): %v", rel.RepoID, err)
|
log.Error("GetRepoWatchersIDs(%d): %v", rel.RepoID, err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -154,7 +154,7 @@ func (g *GiteaLocalUploader) CreateTopics(topics ...string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
topics = topics[:c]
|
topics = topics[:c]
|
||||||
return models.SaveTopics(g.repo.ID, topics...)
|
return repo_model.SaveTopics(g.repo.ID, topics...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateMilestones creates milestones
|
// CreateMilestones creates milestones
|
||||||
|
@ -980,5 +980,5 @@ func (g *GiteaLocalUploader) Finish() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
g.repo.Status = repo_model.RepositoryReady
|
g.repo.Status = repo_model.RepositoryReady
|
||||||
return models.UpdateRepositoryCols(g.repo, "status")
|
return repo_model.UpdateRepositoryCols(g.repo, "status")
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ func UpdateAddress(m *repo_model.Mirror, addr string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Repo.OriginalURL = addr
|
m.Repo.OriginalURL = addr
|
||||||
return models.UpdateRepositoryCols(m.Repo, "original_url")
|
return repo_model.UpdateRepositoryCols(m.Repo, "original_url")
|
||||||
}
|
}
|
||||||
|
|
||||||
// mirrorSyncResult contains information of a updated reference.
|
// mirrorSyncResult contains information of a updated reference.
|
||||||
|
@ -476,7 +476,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = models.UpdateRepositoryUpdatedTime(m.RepoID, commitDate); err != nil {
|
if err = repo_model.UpdateRepositoryUpdatedTime(m.RepoID, commitDate); err != nil {
|
||||||
log.Error("Update repository 'updated_unix' [%d]: %v", m.RepoID, err)
|
log.Error("Update repository 'updated_unix' [%d]: %v", m.RepoID, err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -539,7 +539,7 @@ func checkAndUpdateEmptyRepository(m *repo_model.Mirror, gitRepo *git.Repository
|
||||||
}
|
}
|
||||||
m.Repo.IsEmpty = false
|
m.Repo.IsEmpty = false
|
||||||
// Update the is empty and default_branch columns
|
// Update the is empty and default_branch columns
|
||||||
if err := models.UpdateRepositoryCols(m.Repo, "default_branch", "is_empty"); err != nil {
|
if err := repo_model.UpdateRepositoryCols(m.Repo, "default_branch", "is_empty"); err != nil {
|
||||||
log.Error("Failed to update default branch of repository %-v. Error: %v", m.Repo, err)
|
log.Error("Failed to update default branch of repository %-v. Error: %v", m.Repo, err)
|
||||||
desc := fmt.Sprintf("Failed to uupdate default branch of repository '%s': %v", m.Repo.RepoPath(), err)
|
desc := fmt.Sprintf("Failed to uupdate default branch of repository '%s': %v", m.Repo.RepoPath(), err)
|
||||||
if err = admin_model.CreateRepositoryNotice(desc); err != nil {
|
if err = admin_model.CreateRepositoryNotice(desc); err != nil {
|
||||||
|
|
|
@ -28,7 +28,7 @@ import (
|
||||||
// AdoptRepository adopts pre-existing repository files for the user/organization.
|
// AdoptRepository adopts pre-existing repository files for the user/organization.
|
||||||
func AdoptRepository(doer, u *user_model.User, opts models.CreateRepoOptions) (*repo_model.Repository, error) {
|
func AdoptRepository(doer, u *user_model.User, opts models.CreateRepoOptions) (*repo_model.Repository, error) {
|
||||||
if !doer.IsAdmin && !u.CanCreateRepo() {
|
if !doer.IsAdmin && !u.CanCreateRepo() {
|
||||||
return nil, models.ErrReachLimitOfRepo{
|
return nil, repo_model.ErrReachLimitOfRepo{
|
||||||
Limit: u.MaxRepoCreation,
|
Limit: u.MaxRepoCreation,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,7 +188,7 @@ func adoptRepository(ctx context.Context, repoPath string, u *user_model.User, r
|
||||||
|
|
||||||
// DeleteUnadoptedRepository deletes unadopted repository files from the filesystem
|
// DeleteUnadoptedRepository deletes unadopted repository files from the filesystem
|
||||||
func DeleteUnadoptedRepository(doer, u *user_model.User, repoName string) error {
|
func DeleteUnadoptedRepository(doer, u *user_model.User, repoName string) error {
|
||||||
if err := models.IsUsableRepoName(repoName); err != nil {
|
if err := repo_model.IsUsableRepoName(repoName); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ func DeleteUnadoptedRepository(doer, u *user_model.User, repoName string) error
|
||||||
if exist, err := repo_model.IsRepositoryExist(u, repoName); err != nil {
|
if exist, err := repo_model.IsRepositoryExist(u, repoName); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if exist {
|
} else if exist {
|
||||||
return models.ErrRepoAlreadyExist{
|
return repo_model.ErrRepoAlreadyExist{
|
||||||
Uname: u.Name,
|
Uname: u.Name,
|
||||||
Name: repoName,
|
Name: repoName,
|
||||||
}
|
}
|
||||||
|
@ -312,7 +312,7 @@ func ListUnadoptedRepositories(query string, opts *db.ListOptions) ([]string, in
|
||||||
return filepath.SkipDir
|
return filepath.SkipDir
|
||||||
}
|
}
|
||||||
name = name[:len(name)-4]
|
name = name[:len(name)-4]
|
||||||
if models.IsUsableRepoName(name) != nil || strings.ToLower(name) != name || !globRepo.Match(name) {
|
if repo_model.IsUsableRepoName(name) != nil || strings.ToLower(name) != name || !globRepo.Match(name) {
|
||||||
return filepath.SkipDir
|
return filepath.SkipDir
|
||||||
}
|
}
|
||||||
if count < end {
|
if count < end {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package models
|
package repository
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -11,38 +11,18 @@ import (
|
||||||
"image/png"
|
"image/png"
|
||||||
"io"
|
"io"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/modules/avatar"
|
"code.gitea.io/gitea/modules/avatar"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
|
||||||
"code.gitea.io/gitea/modules/storage"
|
"code.gitea.io/gitea/modules/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RemoveRandomAvatars removes the randomly generated avatars that were created for repositories
|
// UploadAvatar saves custom avatar for repository.
|
||||||
func RemoveRandomAvatars(ctx context.Context) error {
|
|
||||||
return db.GetEngine(db.DefaultContext).
|
|
||||||
Where("id > 0").BufferSize(setting.Database.IterateBufferSize).
|
|
||||||
Iterate(new(repo_model.Repository),
|
|
||||||
func(idx int, bean interface{}) error {
|
|
||||||
repository := bean.(*repo_model.Repository)
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return db.ErrCancelledf("before random avatars removed for %s", repository.FullName())
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
stringifiedID := strconv.FormatInt(repository.ID, 10)
|
|
||||||
if repository.Avatar == stringifiedID {
|
|
||||||
return DeleteRepoAvatar(repository)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// UploadRepoAvatar saves custom avatar for repository.
|
|
||||||
// FIXME: split uploads to different subdirs in case we have massive number of repos.
|
// FIXME: split uploads to different subdirs in case we have massive number of repos.
|
||||||
func UploadRepoAvatar(repo *repo_model.Repository, data []byte) error {
|
func UploadAvatar(repo *repo_model.Repository, data []byte) error {
|
||||||
m, err := avatar.Prepare(data)
|
m, err := avatar.Prepare(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -64,7 +44,7 @@ func UploadRepoAvatar(repo *repo_model.Repository, data []byte) error {
|
||||||
// Users can upload the same image to other repo - prefix it with ID
|
// Users can upload the same image to other repo - prefix it with ID
|
||||||
// Then repo will be removed - only it avatar file will be removed
|
// Then repo will be removed - only it avatar file will be removed
|
||||||
repo.Avatar = newAvatar
|
repo.Avatar = newAvatar
|
||||||
if _, err := db.GetEngine(ctx).ID(repo.ID).Cols("avatar").Update(repo); err != nil {
|
if err := repo_model.UpdateRepositoryColsCtx(ctx, repo, "avatar"); err != nil {
|
||||||
return fmt.Errorf("UploadAvatar: Update repository avatar: %v", err)
|
return fmt.Errorf("UploadAvatar: Update repository avatar: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,8 +66,8 @@ func UploadRepoAvatar(repo *repo_model.Repository, data []byte) error {
|
||||||
return committer.Commit()
|
return committer.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteRepoAvatar deletes the repos's custom avatar.
|
// DeleteAvatar deletes the repos's custom avatar.
|
||||||
func DeleteRepoAvatar(repo *repo_model.Repository) error {
|
func DeleteAvatar(repo *repo_model.Repository) error {
|
||||||
// Avatar not exists
|
// Avatar not exists
|
||||||
if len(repo.Avatar) == 0 {
|
if len(repo.Avatar) == 0 {
|
||||||
return nil
|
return nil
|
||||||
|
@ -103,7 +83,7 @@ func DeleteRepoAvatar(repo *repo_model.Repository) error {
|
||||||
defer committer.Close()
|
defer committer.Close()
|
||||||
|
|
||||||
repo.Avatar = ""
|
repo.Avatar = ""
|
||||||
if _, err := db.GetEngine(ctx).ID(repo.ID).Cols("avatar").Update(repo); err != nil {
|
if err := repo_model.UpdateRepositoryColsCtx(ctx, repo, "avatar"); err != nil {
|
||||||
return fmt.Errorf("DeleteAvatar: Update repository avatar: %v", err)
|
return fmt.Errorf("DeleteAvatar: Update repository avatar: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,3 +93,29 @@ func DeleteRepoAvatar(repo *repo_model.Repository) error {
|
||||||
|
|
||||||
return committer.Commit()
|
return committer.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RemoveRandomAvatars removes the randomly generated avatars that were created for repositories
|
||||||
|
func RemoveRandomAvatars(ctx context.Context) error {
|
||||||
|
return repo_model.IterateRepository(func(repository *repo_model.Repository) error {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return db.ErrCancelledf("before random avatars removed for %s", repository.FullName())
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
stringifiedID := strconv.FormatInt(repository.ID, 10)
|
||||||
|
if repository.Avatar == stringifiedID {
|
||||||
|
return DeleteAvatar(repository)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// generateAvatar generates the avatar from a template repository
|
||||||
|
func generateAvatar(ctx context.Context, templateRepo, generateRepo *repo_model.Repository) error {
|
||||||
|
generateRepo.Avatar = strings.Replace(templateRepo.Avatar, strconv.FormatInt(templateRepo.ID, 10), strconv.FormatInt(generateRepo.ID, 10), 1)
|
||||||
|
if _, err := storage.Copy(storage.RepoAvatars, generateRepo.CustomAvatarRelativePath(), storage.RepoAvatars, templateRepo.CustomAvatarRelativePath()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return repo_model.UpdateRepositoryColsCtx(ctx, generateRepo, "avatar")
|
||||||
|
}
|
64
services/repository/avatar_test.go
Normal file
64
services/repository/avatar_test.go
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
// Copyright 2021 The Gitea 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 repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/md5"
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"image/png"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUploadAvatar(t *testing.T) {
|
||||||
|
// Generate image
|
||||||
|
myImage := image.NewRGBA(image.Rect(0, 0, 1, 1))
|
||||||
|
var buff bytes.Buffer
|
||||||
|
png.Encode(&buff, myImage)
|
||||||
|
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}).(*repo_model.Repository)
|
||||||
|
|
||||||
|
err := UploadAvatar(repo, buff.Bytes())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, fmt.Sprintf("%d-%x", 10, md5.Sum(buff.Bytes())), repo.Avatar)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUploadBigAvatar(t *testing.T) {
|
||||||
|
// Generate BIG image
|
||||||
|
myImage := image.NewRGBA(image.Rect(0, 0, 5000, 1))
|
||||||
|
var buff bytes.Buffer
|
||||||
|
png.Encode(&buff, myImage)
|
||||||
|
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}).(*repo_model.Repository)
|
||||||
|
|
||||||
|
err := UploadAvatar(repo, buff.Bytes())
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteAvatar(t *testing.T) {
|
||||||
|
// Generate image
|
||||||
|
myImage := image.NewRGBA(image.Rect(0, 0, 1, 1))
|
||||||
|
var buff bytes.Buffer
|
||||||
|
png.Encode(&buff, myImage)
|
||||||
|
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}).(*repo_model.Repository)
|
||||||
|
|
||||||
|
err := UploadAvatar(repo, buff.Bytes())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = DeleteAvatar(repo)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, "", repo.Avatar)
|
||||||
|
}
|
|
@ -22,9 +22,16 @@ import (
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ForkRepoOptions contains the fork repository options
|
||||||
|
type ForkRepoOptions struct {
|
||||||
|
BaseRepo *repo_model.Repository
|
||||||
|
Name string
|
||||||
|
Description string
|
||||||
|
}
|
||||||
|
|
||||||
// ForkRepository forks a repository
|
// ForkRepository forks a repository
|
||||||
func ForkRepository(doer, owner *user_model.User, opts models.ForkRepoOptions) (_ *repo_model.Repository, err error) {
|
func ForkRepository(doer, owner *user_model.User, opts ForkRepoOptions) (_ *repo_model.Repository, err error) {
|
||||||
forkedRepo, err := models.GetUserFork(opts.BaseRepo.ID, owner.ID)
|
forkedRepo, err := repo_model.GetUserFork(opts.BaseRepo.ID, owner.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ func TestForkRepository(t *testing.T) {
|
||||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 13}).(*user_model.User)
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 13}).(*user_model.User)
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}).(*repo_model.Repository)
|
||||||
|
|
||||||
fork, err := ForkRepository(user, user, models.ForkRepoOptions{
|
fork, err := ForkRepository(user, user, ForkRepoOptions{
|
||||||
BaseRepo: repo,
|
BaseRepo: repo,
|
||||||
Name: "test",
|
Name: "test",
|
||||||
Description: "test",
|
Description: "test",
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
repo_module "code.gitea.io/gitea/modules/repository"
|
repo_module "code.gitea.io/gitea/modules/repository"
|
||||||
|
|
||||||
|
@ -50,3 +51,36 @@ func SyncRepositoryHooks(ctx context.Context) error {
|
||||||
log.Trace("Finished: SyncRepositoryHooks")
|
log.Trace("Finished: SyncRepositoryHooks")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GenerateGitHooks generates git hooks from a template repository
|
||||||
|
func GenerateGitHooks(ctx context.Context, templateRepo, generateRepo *repo_model.Repository) error {
|
||||||
|
generateGitRepo, err := git.OpenRepository(generateRepo.RepoPath())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer generateGitRepo.Close()
|
||||||
|
|
||||||
|
templateGitRepo, err := git.OpenRepository(templateRepo.RepoPath())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer templateGitRepo.Close()
|
||||||
|
|
||||||
|
templateHooks, err := templateGitRepo.Hooks()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, templateHook := range templateHooks {
|
||||||
|
generateHook, err := generateGitRepo.GetHook(templateHook.Name())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
generateHook.Content = templateHook.Content
|
||||||
|
if err := generateHook.Update(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -166,7 +166,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Update the is empty and default_branch columns
|
// Update the is empty and default_branch columns
|
||||||
if err := models.UpdateRepositoryCols(repo, "default_branch", "is_empty"); err != nil {
|
if err := repo_model.UpdateRepositoryCols(repo, "default_branch", "is_empty"); err != nil {
|
||||||
return fmt.Errorf("UpdateRepositoryCols: %v", err)
|
return fmt.Errorf("UpdateRepositoryCols: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -227,7 +227,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Even if user delete a branch on a repository which he didn't watch, he will be watch that.
|
// Even if user delete a branch on a repository which he didn't watch, he will be watch that.
|
||||||
if err = models.WatchIfAuto(opts.PusherID, repo.ID, true); err != nil {
|
if err = repo_model.WatchIfAuto(opts.PusherID, repo.ID, true); err != nil {
|
||||||
log.Warn("Fail to perform auto watch on user %v for repo %v: %v", opts.PusherID, repo.ID, err)
|
log.Warn("Fail to perform auto watch on user %v for repo %v: %v", opts.PusherID, repo.ID, err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -239,7 +239,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change repository last updated time.
|
// Change repository last updated time.
|
||||||
if err := models.UpdateRepositoryUpdatedTime(repo.ID, time.Now()); err != nil {
|
if err := repo_model.UpdateRepositoryUpdatedTime(repo.ID, time.Now()); err != nil {
|
||||||
return fmt.Errorf("UpdateRepositoryUpdatedTime: %v", err)
|
return fmt.Errorf("UpdateRepositoryUpdatedTime: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ import (
|
||||||
// GenerateRepository generates a repository from a template
|
// GenerateRepository generates a repository from a template
|
||||||
func GenerateRepository(doer, owner *user_model.User, templateRepo *repo_model.Repository, opts models.GenerateRepoOptions) (_ *repo_model.Repository, err error) {
|
func GenerateRepository(doer, owner *user_model.User, templateRepo *repo_model.Repository, opts models.GenerateRepoOptions) (_ *repo_model.Repository, err error) {
|
||||||
if !doer.IsAdmin && !owner.CanCreateRepo() {
|
if !doer.IsAdmin && !owner.CanCreateRepo() {
|
||||||
return nil, models.ErrReachLimitOfRepo{
|
return nil, repo_model.ErrReachLimitOfRepo{
|
||||||
Limit: owner.MaxRepoCreation,
|
Limit: owner.MaxRepoCreation,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,14 +40,14 @@ func GenerateRepository(doer, owner *user_model.User, templateRepo *repo_model.R
|
||||||
|
|
||||||
// Topics
|
// Topics
|
||||||
if opts.Topics {
|
if opts.Topics {
|
||||||
if err = models.GenerateTopics(ctx, templateRepo, generateRepo); err != nil {
|
if err = repo_model.GenerateTopics(ctx, templateRepo, generateRepo); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Git Hooks
|
// Git Hooks
|
||||||
if opts.GitHooks {
|
if opts.GitHooks {
|
||||||
if err = models.GenerateGitHooks(ctx, templateRepo, generateRepo); err != nil {
|
if err = GenerateGitHooks(ctx, templateRepo, generateRepo); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ func GenerateRepository(doer, owner *user_model.User, templateRepo *repo_model.R
|
||||||
|
|
||||||
// Avatar
|
// Avatar
|
||||||
if opts.Avatar && len(templateRepo.Avatar) > 0 {
|
if opts.Avatar && len(templateRepo.Avatar) > 0 {
|
||||||
if err = models.GenerateAvatar(ctx, templateRepo, generateRepo); err != nil {
|
if err = generateAvatar(ctx, templateRepo, generateRepo); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -64,7 +64,7 @@ func ChangeRepositoryName(doer *user_model.User, repo *repo_model.Repository, ne
|
||||||
// local copy's origin accordingly.
|
// local copy's origin accordingly.
|
||||||
|
|
||||||
repoWorkingPool.CheckIn(fmt.Sprint(repo.ID))
|
repoWorkingPool.CheckIn(fmt.Sprint(repo.ID))
|
||||||
if err := models.ChangeRepositoryName(doer, repo, newRepoName); err != nil {
|
if err := repo_model.ChangeRepositoryName(doer, repo, newRepoName); err != nil {
|
||||||
repoWorkingPool.CheckOut(fmt.Sprint(repo.ID))
|
repoWorkingPool.CheckOut(fmt.Sprint(repo.ID))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,9 +27,9 @@ import (
|
||||||
|
|
||||||
func handleCreateError(owner *user_model.User, err error) error {
|
func handleCreateError(owner *user_model.User, err error) error {
|
||||||
switch {
|
switch {
|
||||||
case models.IsErrReachLimitOfRepo(err):
|
case repo_model.IsErrReachLimitOfRepo(err):
|
||||||
return fmt.Errorf("You have already reached your limit of %d repositories", owner.MaxCreationLimit())
|
return fmt.Errorf("You have already reached your limit of %d repositories", owner.MaxCreationLimit())
|
||||||
case models.IsErrRepoAlreadyExist(err):
|
case repo_model.IsErrRepoAlreadyExist(err):
|
||||||
return errors.New("The repository name is already used")
|
return errors.New("The repository name is already used")
|
||||||
case db.IsErrNameReserved(err):
|
case db.IsErrNameReserved(err):
|
||||||
return fmt.Errorf("The repository name '%s' is reserved", err.(db.ErrNameReserved).Name)
|
return fmt.Errorf("The repository name '%s' is reserved", err.(db.ErrNameReserved).Name)
|
||||||
|
@ -123,7 +123,7 @@ func runMigrateTask(t *models.Task) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if models.IsErrRepoAlreadyExist(err) {
|
if repo_model.IsErrRepoAlreadyExist(err) {
|
||||||
err = errors.New("The repository name is already used")
|
err = errors.New("The repository name is already used")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -375,7 +375,7 @@ func DeleteWikiPage(doer *user_model.User, repo *repo_model.Repository, wikiName
|
||||||
|
|
||||||
// DeleteWiki removes the actual and local copy of repository wiki.
|
// DeleteWiki removes the actual and local copy of repository wiki.
|
||||||
func DeleteWiki(repo *repo_model.Repository) error {
|
func DeleteWiki(repo *repo_model.Repository) error {
|
||||||
if err := models.UpdateRepositoryUnits(repo, nil, []unit.Type{unit.TypeWiki}); err != nil {
|
if err := repo_model.UpdateRepositoryUnits(repo, nil, []unit.Type{unit.TypeWiki}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue