mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 00:20:25 +08:00 
			
		
		
		
	Move some files into models' sub packages (#20262)
* Move some files into models' sub packages * Move functions * merge main branch * Fix check * fix check * Fix some tests * Fix lint * Fix lint * Revert lint changes * Fix error comments * Fix lint Co-authored-by: 6543 <6543@obermui.de>
This commit is contained in:
		@@ -3,7 +3,7 @@
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package models
 | 
			
		||||
package activities
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
@@ -211,21 +211,6 @@ func (a *Action) GetRepoLink() string {
 | 
			
		||||
	return path.Join(setting.AppSubURL, "/", url.PathEscape(a.GetRepoUserName()), url.PathEscape(a.GetRepoName()))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetRepositoryFromMatch returns a *repo_model.Repository from a username and repo strings
 | 
			
		||||
func GetRepositoryFromMatch(ownerName, repoName string) (*repo_model.Repository, error) {
 | 
			
		||||
	var err error
 | 
			
		||||
	refRepo, err := repo_model.GetRepositoryByOwnerAndName(ownerName, repoName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if repo_model.IsErrRepoNotExist(err) {
 | 
			
		||||
			log.Warn("Repository referenced in commit but does not exist: %v", err)
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		log.Error("repo_model.GetRepositoryByOwnerAndName: %v", err)
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return refRepo, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetCommentLink returns link to action comment.
 | 
			
		||||
func (a *Action) GetCommentLink() string {
 | 
			
		||||
	return a.getCommentLink(db.DefaultContext)
 | 
			
		||||
@@ -372,7 +357,8 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, error) {
 | 
			
		||||
	return actions, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func activityReadable(user, doer *user_model.User) bool {
 | 
			
		||||
// ActivityReadable return whether doer can read activities of user
 | 
			
		||||
func ActivityReadable(user, doer *user_model.User) bool {
 | 
			
		||||
	return !user.KeepActivityPrivate ||
 | 
			
		||||
		doer != nil && (doer.IsAdmin || user.ID == doer.ID)
 | 
			
		||||
}
 | 
			
		||||
@@ -602,3 +588,23 @@ func DeleteIssueActions(ctx context.Context, repoID, issueID int64) error {
 | 
			
		||||
		Delete(&Action{})
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CountActionCreatedUnixString count actions where created_unix is an empty string
 | 
			
		||||
func CountActionCreatedUnixString() (int64, error) {
 | 
			
		||||
	if setting.Database.UseSQLite3 {
 | 
			
		||||
		return db.GetEngine(db.DefaultContext).Where(`created_unix = ""`).Count(new(Action))
 | 
			
		||||
	}
 | 
			
		||||
	return 0, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FixActionCreatedUnixString set created_unix to zero if it is an empty string
 | 
			
		||||
func FixActionCreatedUnixString() (int64, error) {
 | 
			
		||||
	if setting.Database.UseSQLite3 {
 | 
			
		||||
		res, err := db.GetEngine(db.DefaultContext).Exec(`UPDATE action SET created_unix = 0 WHERE created_unix = ""`)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
		return res.RowsAffected()
 | 
			
		||||
	}
 | 
			
		||||
	return 0, nil
 | 
			
		||||
}
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package models
 | 
			
		||||
package activities
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
@@ -2,12 +2,13 @@
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package models
 | 
			
		||||
package activities_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"path"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	activities_model "code.gitea.io/gitea/models/activities"
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
@@ -21,7 +22,7 @@ func TestAction_GetRepoPath(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{})
 | 
			
		||||
	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
 | 
			
		||||
	action := &Action{RepoID: repo.ID}
 | 
			
		||||
	action := &activities_model.Action{RepoID: repo.ID}
 | 
			
		||||
	assert.Equal(t, path.Join(owner.Name, repo.Name), action.GetRepoPath())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -29,7 +30,7 @@ func TestAction_GetRepoLink(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{})
 | 
			
		||||
	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
 | 
			
		||||
	action := &Action{RepoID: repo.ID}
 | 
			
		||||
	action := &activities_model.Action{RepoID: repo.ID}
 | 
			
		||||
	setting.AppSubURL = "/suburl"
 | 
			
		||||
	expected := path.Join(setting.AppSubURL, owner.Name, repo.Name)
 | 
			
		||||
	assert.Equal(t, expected, action.GetRepoLink())
 | 
			
		||||
@@ -40,7 +41,7 @@ func TestGetFeeds(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
 | 
			
		||||
 | 
			
		||||
	actions, err := GetFeeds(db.DefaultContext, GetFeedsOptions{
 | 
			
		||||
	actions, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
 | 
			
		||||
		RequestedUser:   user,
 | 
			
		||||
		Actor:           user,
 | 
			
		||||
		IncludePrivate:  true,
 | 
			
		||||
@@ -53,7 +54,7 @@ func TestGetFeeds(t *testing.T) {
 | 
			
		||||
		assert.EqualValues(t, user.ID, actions[0].UserID)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	actions, err = GetFeeds(db.DefaultContext, GetFeedsOptions{
 | 
			
		||||
	actions, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
 | 
			
		||||
		RequestedUser:   user,
 | 
			
		||||
		Actor:           user,
 | 
			
		||||
		IncludePrivate:  false,
 | 
			
		||||
@@ -70,7 +71,7 @@ func TestGetFeedsForRepos(t *testing.T) {
 | 
			
		||||
	pubRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 8})
 | 
			
		||||
 | 
			
		||||
	// private repo & no login
 | 
			
		||||
	actions, err := GetFeeds(db.DefaultContext, GetFeedsOptions{
 | 
			
		||||
	actions, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
 | 
			
		||||
		RequestedRepo:  privRepo,
 | 
			
		||||
		IncludePrivate: true,
 | 
			
		||||
	})
 | 
			
		||||
@@ -78,7 +79,7 @@ func TestGetFeedsForRepos(t *testing.T) {
 | 
			
		||||
	assert.Len(t, actions, 0)
 | 
			
		||||
 | 
			
		||||
	// public repo & no login
 | 
			
		||||
	actions, err = GetFeeds(db.DefaultContext, GetFeedsOptions{
 | 
			
		||||
	actions, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
 | 
			
		||||
		RequestedRepo:  pubRepo,
 | 
			
		||||
		IncludePrivate: true,
 | 
			
		||||
	})
 | 
			
		||||
@@ -86,7 +87,7 @@ func TestGetFeedsForRepos(t *testing.T) {
 | 
			
		||||
	assert.Len(t, actions, 1)
 | 
			
		||||
 | 
			
		||||
	// private repo and login
 | 
			
		||||
	actions, err = GetFeeds(db.DefaultContext, GetFeedsOptions{
 | 
			
		||||
	actions, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
 | 
			
		||||
		RequestedRepo:  privRepo,
 | 
			
		||||
		IncludePrivate: true,
 | 
			
		||||
		Actor:          user,
 | 
			
		||||
@@ -95,7 +96,7 @@ func TestGetFeedsForRepos(t *testing.T) {
 | 
			
		||||
	assert.Len(t, actions, 1)
 | 
			
		||||
 | 
			
		||||
	// public repo & login
 | 
			
		||||
	actions, err = GetFeeds(db.DefaultContext, GetFeedsOptions{
 | 
			
		||||
	actions, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
 | 
			
		||||
		RequestedRepo:  pubRepo,
 | 
			
		||||
		IncludePrivate: true,
 | 
			
		||||
		Actor:          user,
 | 
			
		||||
@@ -110,7 +111,7 @@ func TestGetFeeds2(t *testing.T) {
 | 
			
		||||
	org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3})
 | 
			
		||||
	user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
 | 
			
		||||
 | 
			
		||||
	actions, err := GetFeeds(db.DefaultContext, GetFeedsOptions{
 | 
			
		||||
	actions, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
 | 
			
		||||
		RequestedUser:   org,
 | 
			
		||||
		Actor:           user,
 | 
			
		||||
		IncludePrivate:  true,
 | 
			
		||||
@@ -124,7 +125,7 @@ func TestGetFeeds2(t *testing.T) {
 | 
			
		||||
		assert.EqualValues(t, org.ID, actions[0].UserID)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	actions, err = GetFeeds(db.DefaultContext, GetFeedsOptions{
 | 
			
		||||
	actions, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
 | 
			
		||||
		RequestedUser:   org,
 | 
			
		||||
		Actor:           user,
 | 
			
		||||
		IncludePrivate:  false,
 | 
			
		||||
@@ -171,40 +172,40 @@ func TestActivityReadable(t *testing.T) {
 | 
			
		||||
		result: true,
 | 
			
		||||
	}}
 | 
			
		||||
	for _, test := range tt {
 | 
			
		||||
		assert.Equal(t, test.result, activityReadable(test.user, test.doer), test.desc)
 | 
			
		||||
		assert.Equal(t, test.result, activities_model.ActivityReadable(test.user, test.doer), test.desc)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestNotifyWatchers(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	action := &Action{
 | 
			
		||||
	action := &activities_model.Action{
 | 
			
		||||
		ActUserID: 8,
 | 
			
		||||
		RepoID:    1,
 | 
			
		||||
		OpType:    ActionStarRepo,
 | 
			
		||||
		OpType:    activities_model.ActionStarRepo,
 | 
			
		||||
	}
 | 
			
		||||
	assert.NoError(t, NotifyWatchers(action))
 | 
			
		||||
	assert.NoError(t, activities_model.NotifyWatchers(action))
 | 
			
		||||
 | 
			
		||||
	// One watchers are inactive, thus action is only created for user 8, 1, 4, 11
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &Action{
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &activities_model.Action{
 | 
			
		||||
		ActUserID: action.ActUserID,
 | 
			
		||||
		UserID:    8,
 | 
			
		||||
		RepoID:    action.RepoID,
 | 
			
		||||
		OpType:    action.OpType,
 | 
			
		||||
	})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &Action{
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &activities_model.Action{
 | 
			
		||||
		ActUserID: action.ActUserID,
 | 
			
		||||
		UserID:    1,
 | 
			
		||||
		RepoID:    action.RepoID,
 | 
			
		||||
		OpType:    action.OpType,
 | 
			
		||||
	})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &Action{
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &activities_model.Action{
 | 
			
		||||
		ActUserID: action.ActUserID,
 | 
			
		||||
		UserID:    4,
 | 
			
		||||
		RepoID:    action.RepoID,
 | 
			
		||||
		OpType:    action.OpType,
 | 
			
		||||
	})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &Action{
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &activities_model.Action{
 | 
			
		||||
		ActUserID: action.ActUserID,
 | 
			
		||||
		UserID:    11,
 | 
			
		||||
		RepoID:    action.RepoID,
 | 
			
		||||
@@ -215,12 +216,12 @@ func TestNotifyWatchers(t *testing.T) {
 | 
			
		||||
func TestGetFeedsCorrupted(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &Action{
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &activities_model.Action{
 | 
			
		||||
		ID:     8,
 | 
			
		||||
		RepoID: 1700,
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	actions, err := GetFeeds(db.DefaultContext, GetFeedsOptions{
 | 
			
		||||
	actions, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
 | 
			
		||||
		RequestedUser:  user,
 | 
			
		||||
		Actor:          user,
 | 
			
		||||
		IncludePrivate: true,
 | 
			
		||||
@@ -235,12 +236,12 @@ func TestConsistencyUpdateAction(t *testing.T) {
 | 
			
		||||
	}
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	id := 8
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &Action{
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &activities_model.Action{
 | 
			
		||||
		ID: int64(id),
 | 
			
		||||
	})
 | 
			
		||||
	_, err := db.GetEngine(db.DefaultContext).Exec(`UPDATE action SET created_unix = "" WHERE id = ?`, id)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	actions := make([]*Action, 0, 1)
 | 
			
		||||
	actions := make([]*activities_model.Action, 0, 1)
 | 
			
		||||
	//
 | 
			
		||||
	// XORM returns an error when created_unix is a string
 | 
			
		||||
	//
 | 
			
		||||
@@ -251,17 +252,17 @@ func TestConsistencyUpdateAction(t *testing.T) {
 | 
			
		||||
	//
 | 
			
		||||
	// Get rid of incorrectly set created_unix
 | 
			
		||||
	//
 | 
			
		||||
	count, err := CountActionCreatedUnixString()
 | 
			
		||||
	count, err := activities_model.CountActionCreatedUnixString()
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.EqualValues(t, 1, count)
 | 
			
		||||
	count, err = FixActionCreatedUnixString()
 | 
			
		||||
	count, err = activities_model.FixActionCreatedUnixString()
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.EqualValues(t, 1, count)
 | 
			
		||||
 | 
			
		||||
	count, err = CountActionCreatedUnixString()
 | 
			
		||||
	count, err = activities_model.CountActionCreatedUnixString()
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.EqualValues(t, 0, count)
 | 
			
		||||
	count, err = FixActionCreatedUnixString()
 | 
			
		||||
	count, err = activities_model.FixActionCreatedUnixString()
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.EqualValues(t, 0, count)
 | 
			
		||||
 | 
			
		||||
@@ -269,5 +270,5 @@ func TestConsistencyUpdateAction(t *testing.T) {
 | 
			
		||||
	// XORM must be happy now
 | 
			
		||||
	//
 | 
			
		||||
	assert.NoError(t, db.GetEngine(db.DefaultContext).Where("id = ?", id).Find(&actions))
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &Action{})
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &activities_model.Action{})
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								models/activities/main_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								models/activities/main_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
// Copyright 2020 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 activities_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
 | 
			
		||||
	_ "code.gitea.io/gitea/models"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestMain(m *testing.M) {
 | 
			
		||||
	unittest.MainTest(m, &unittest.TestOptions{
 | 
			
		||||
		GiteaRootPath: filepath.Join("..", ".."),
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package models
 | 
			
		||||
package activities
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
@@ -13,6 +13,7 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	issues_model "code.gitea.io/gitea/models/issues"
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	access_model "code.gitea.io/gitea/models/perm/access"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	"code.gitea.io/gitea/models/unit"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
@@ -267,10 +268,10 @@ func createOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, n
 | 
			
		||||
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if issue.IsPull && !CheckRepoUnitUser(ctx, issue.Repo, user, unit.TypePullRequests) {
 | 
			
		||||
		if issue.IsPull && !access_model.CheckRepoUnitUser(ctx, issue.Repo, user, unit.TypePullRequests) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if !issue.IsPull && !CheckRepoUnitUser(ctx, issue.Repo, user, unit.TypeIssues) {
 | 
			
		||||
		if !issue.IsPull && !access_model.CheckRepoUnitUser(ctx, issue.Repo, user, unit.TypeIssues) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -2,11 +2,12 @@
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package models
 | 
			
		||||
package activities_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	activities_model "code.gitea.io/gitea/models/activities"
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	issues_model "code.gitea.io/gitea/models/issues"
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
@@ -19,22 +20,22 @@ func TestCreateOrUpdateIssueNotifications(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1})
 | 
			
		||||
 | 
			
		||||
	assert.NoError(t, CreateOrUpdateIssueNotifications(issue.ID, 0, 2, 0))
 | 
			
		||||
	assert.NoError(t, activities_model.CreateOrUpdateIssueNotifications(issue.ID, 0, 2, 0))
 | 
			
		||||
 | 
			
		||||
	// User 9 is inactive, thus notifications for user 1 and 4 are created
 | 
			
		||||
	notf := unittest.AssertExistsAndLoadBean(t, &Notification{UserID: 1, IssueID: issue.ID})
 | 
			
		||||
	assert.Equal(t, NotificationStatusUnread, notf.Status)
 | 
			
		||||
	notf := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{UserID: 1, IssueID: issue.ID})
 | 
			
		||||
	assert.Equal(t, activities_model.NotificationStatusUnread, notf.Status)
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &issues_model.Issue{ID: issue.ID})
 | 
			
		||||
 | 
			
		||||
	notf = unittest.AssertExistsAndLoadBean(t, &Notification{UserID: 4, IssueID: issue.ID})
 | 
			
		||||
	assert.Equal(t, NotificationStatusUnread, notf.Status)
 | 
			
		||||
	notf = unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{UserID: 4, IssueID: issue.ID})
 | 
			
		||||
	assert.Equal(t, activities_model.NotificationStatusUnread, notf.Status)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestNotificationsForUser(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
 | 
			
		||||
	statuses := []NotificationStatus{NotificationStatusRead, NotificationStatusUnread}
 | 
			
		||||
	notfs, err := NotificationsForUser(db.DefaultContext, user, statuses, 1, 10)
 | 
			
		||||
	statuses := []activities_model.NotificationStatus{activities_model.NotificationStatusRead, activities_model.NotificationStatusUnread}
 | 
			
		||||
	notfs, err := activities_model.NotificationsForUser(db.DefaultContext, user, statuses, 1, 10)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	if assert.Len(t, notfs, 3) {
 | 
			
		||||
		assert.EqualValues(t, 5, notfs[0].ID)
 | 
			
		||||
@@ -48,7 +49,7 @@ func TestNotificationsForUser(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
func TestNotification_GetRepo(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	notf := unittest.AssertExistsAndLoadBean(t, &Notification{RepoID: 1})
 | 
			
		||||
	notf := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{RepoID: 1})
 | 
			
		||||
	repo, err := notf.GetRepo()
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, repo, notf.Repository)
 | 
			
		||||
@@ -57,7 +58,7 @@ func TestNotification_GetRepo(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
func TestNotification_GetIssue(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	notf := unittest.AssertExistsAndLoadBean(t, &Notification{RepoID: 1})
 | 
			
		||||
	notf := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{RepoID: 1})
 | 
			
		||||
	issue, err := notf.GetIssue()
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, issue, notf.Issue)
 | 
			
		||||
@@ -67,11 +68,11 @@ func TestNotification_GetIssue(t *testing.T) {
 | 
			
		||||
func TestGetNotificationCount(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
 | 
			
		||||
	cnt, err := GetNotificationCount(db.DefaultContext, user, NotificationStatusRead)
 | 
			
		||||
	cnt, err := activities_model.GetNotificationCount(db.DefaultContext, user, activities_model.NotificationStatusRead)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.EqualValues(t, 0, cnt)
 | 
			
		||||
 | 
			
		||||
	cnt, err = GetNotificationCount(db.DefaultContext, user, NotificationStatusUnread)
 | 
			
		||||
	cnt, err = activities_model.GetNotificationCount(db.DefaultContext, user, activities_model.NotificationStatusUnread)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.EqualValues(t, 1, cnt)
 | 
			
		||||
}
 | 
			
		||||
@@ -80,15 +81,15 @@ func TestSetNotificationStatus(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
 | 
			
		||||
	notf := unittest.AssertExistsAndLoadBean(t,
 | 
			
		||||
		&Notification{UserID: user.ID, Status: NotificationStatusRead})
 | 
			
		||||
	_, err := SetNotificationStatus(notf.ID, user, NotificationStatusPinned)
 | 
			
		||||
		&activities_model.Notification{UserID: user.ID, Status: activities_model.NotificationStatusRead})
 | 
			
		||||
	_, err := activities_model.SetNotificationStatus(notf.ID, user, activities_model.NotificationStatusPinned)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t,
 | 
			
		||||
		&Notification{ID: notf.ID, Status: NotificationStatusPinned})
 | 
			
		||||
		&activities_model.Notification{ID: notf.ID, Status: activities_model.NotificationStatusPinned})
 | 
			
		||||
 | 
			
		||||
	_, err = SetNotificationStatus(1, user, NotificationStatusRead)
 | 
			
		||||
	_, err = activities_model.SetNotificationStatus(1, user, activities_model.NotificationStatusRead)
 | 
			
		||||
	assert.Error(t, err)
 | 
			
		||||
	_, err = SetNotificationStatus(unittest.NonexistentID, user, NotificationStatusRead)
 | 
			
		||||
	_, err = activities_model.SetNotificationStatus(unittest.NonexistentID, user, activities_model.NotificationStatusRead)
 | 
			
		||||
	assert.Error(t, err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -96,16 +97,16 @@ func TestUpdateNotificationStatuses(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
 | 
			
		||||
	notfUnread := unittest.AssertExistsAndLoadBean(t,
 | 
			
		||||
		&Notification{UserID: user.ID, Status: NotificationStatusUnread})
 | 
			
		||||
		&activities_model.Notification{UserID: user.ID, Status: activities_model.NotificationStatusUnread})
 | 
			
		||||
	notfRead := unittest.AssertExistsAndLoadBean(t,
 | 
			
		||||
		&Notification{UserID: user.ID, Status: NotificationStatusRead})
 | 
			
		||||
		&activities_model.Notification{UserID: user.ID, Status: activities_model.NotificationStatusRead})
 | 
			
		||||
	notfPinned := unittest.AssertExistsAndLoadBean(t,
 | 
			
		||||
		&Notification{UserID: user.ID, Status: NotificationStatusPinned})
 | 
			
		||||
	assert.NoError(t, UpdateNotificationStatuses(user, NotificationStatusUnread, NotificationStatusRead))
 | 
			
		||||
		&activities_model.Notification{UserID: user.ID, Status: activities_model.NotificationStatusPinned})
 | 
			
		||||
	assert.NoError(t, activities_model.UpdateNotificationStatuses(user, activities_model.NotificationStatusUnread, activities_model.NotificationStatusRead))
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t,
 | 
			
		||||
		&Notification{ID: notfUnread.ID, Status: NotificationStatusRead})
 | 
			
		||||
		&activities_model.Notification{ID: notfUnread.ID, Status: activities_model.NotificationStatusRead})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t,
 | 
			
		||||
		&Notification{ID: notfRead.ID, Status: NotificationStatusRead})
 | 
			
		||||
		&activities_model.Notification{ID: notfRead.ID, Status: activities_model.NotificationStatusRead})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t,
 | 
			
		||||
		&Notification{ID: notfPinned.ID, Status: NotificationStatusPinned})
 | 
			
		||||
		&activities_model.Notification{ID: notfPinned.ID, Status: activities_model.NotificationStatusPinned})
 | 
			
		||||
}
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package models
 | 
			
		||||
package activities
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
@@ -39,7 +39,7 @@ type ActivityStats struct {
 | 
			
		||||
	ClosedIssues                issues_model.IssueList
 | 
			
		||||
	ClosedIssueAuthorCount      int64
 | 
			
		||||
	UnresolvedIssues            issues_model.IssueList
 | 
			
		||||
	PublishedReleases           []*Release
 | 
			
		||||
	PublishedReleases           []*repo_model.Release
 | 
			
		||||
	PublishedReleaseAuthorCount int64
 | 
			
		||||
	Code                        *git.CodeActivityStats
 | 
			
		||||
}
 | 
			
		||||
@@ -344,7 +344,7 @@ func (stats *ActivityStats) FillReleases(repoID int64, fromTime time.Time) error
 | 
			
		||||
	// Published releases list
 | 
			
		||||
	sess := releasesForActivityStatement(repoID, fromTime)
 | 
			
		||||
	sess.OrderBy("release.created_unix DESC")
 | 
			
		||||
	stats.PublishedReleases = make([]*Release, 0)
 | 
			
		||||
	stats.PublishedReleases = make([]*repo_model.Release, 0)
 | 
			
		||||
	if err = sess.Find(&stats.PublishedReleases); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package models
 | 
			
		||||
package activities
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	asymkey_model "code.gitea.io/gitea/models/asymkey"
 | 
			
		||||
@@ -101,7 +101,7 @@ func GetStatistic() (stats Statistic) {
 | 
			
		||||
	stats.Counter.Oauth = 0
 | 
			
		||||
	stats.Counter.Follow, _ = e.Count(new(user_model.Follow))
 | 
			
		||||
	stats.Counter.Mirror, _ = e.Count(new(repo_model.Mirror))
 | 
			
		||||
	stats.Counter.Release, _ = e.Count(new(Release))
 | 
			
		||||
	stats.Counter.Release, _ = e.Count(new(repo_model.Release))
 | 
			
		||||
	stats.Counter.AuthSource = auth.CountSources()
 | 
			
		||||
	stats.Counter.Webhook, _ = e.Count(new(webhook.Webhook))
 | 
			
		||||
	stats.Counter.Milestone, _ = e.Count(new(issues_model.Milestone))
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.package models
 | 
			
		||||
 | 
			
		||||
package models
 | 
			
		||||
package activities
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
@@ -31,7 +31,7 @@ func GetUserHeatmapDataByUserTeam(user *user_model.User, team *organization.Team
 | 
			
		||||
func getUserHeatmapData(user *user_model.User, team *organization.Team, doer *user_model.User) ([]*UserHeatmapData, error) {
 | 
			
		||||
	hdata := make([]*UserHeatmapData, 0)
 | 
			
		||||
 | 
			
		||||
	if !activityReadable(user, doer) {
 | 
			
		||||
	if !ActivityReadable(user, doer) {
 | 
			
		||||
		return hdata, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -2,13 +2,14 @@
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.package models
 | 
			
		||||
 | 
			
		||||
package models
 | 
			
		||||
package activities_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"testing"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	activities_model "code.gitea.io/gitea/models/activities"
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
@@ -73,7 +74,7 @@ func TestGetUserHeatmapDataByUser(t *testing.T) {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// get the action for comparison
 | 
			
		||||
		actions, err := GetFeeds(db.DefaultContext, GetFeedsOptions{
 | 
			
		||||
		actions, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
 | 
			
		||||
			RequestedUser:   user,
 | 
			
		||||
			Actor:           doer,
 | 
			
		||||
			IncludePrivate:  true,
 | 
			
		||||
@@ -83,7 +84,7 @@ func TestGetUserHeatmapDataByUser(t *testing.T) {
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
		// Get the heatmap and compare
 | 
			
		||||
		heatmap, err := GetUserHeatmapDataByUser(user, doer)
 | 
			
		||||
		heatmap, err := activities_model.GetUserHeatmapDataByUser(user, doer)
 | 
			
		||||
		var contributions int
 | 
			
		||||
		for _, hm := range heatmap {
 | 
			
		||||
			contributions += int(hm.Contributions)
 | 
			
		||||
@@ -2,18 +2,21 @@
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package admin
 | 
			
		||||
package admin_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
 | 
			
		||||
	_ "code.gitea.io/gitea/models"
 | 
			
		||||
	_ "code.gitea.io/gitea/models/activities"
 | 
			
		||||
	_ "code.gitea.io/gitea/models/perm/access"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestMain(m *testing.M) {
 | 
			
		||||
	unittest.MainTest(m, &unittest.TestOptions{
 | 
			
		||||
		GiteaRootPath: filepath.Join("..", ".."),
 | 
			
		||||
		FixtureFiles:  []string{"notice.yml"},
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,11 +2,12 @@
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package admin
 | 
			
		||||
package admin_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/admin"
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
 | 
			
		||||
@@ -14,8 +15,8 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestNotice_TrStr(t *testing.T) {
 | 
			
		||||
	notice := &Notice{
 | 
			
		||||
		Type:        NoticeRepository,
 | 
			
		||||
	notice := &admin.Notice{
 | 
			
		||||
		Type:        admin.NoticeRepository,
 | 
			
		||||
		Description: "test description",
 | 
			
		||||
	}
 | 
			
		||||
	assert.Equal(t, "admin.notices.type_1", notice.TrStr())
 | 
			
		||||
@@ -24,24 +25,24 @@ func TestNotice_TrStr(t *testing.T) {
 | 
			
		||||
func TestCreateNotice(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	noticeBean := &Notice{
 | 
			
		||||
		Type:        NoticeRepository,
 | 
			
		||||
	noticeBean := &admin.Notice{
 | 
			
		||||
		Type:        admin.NoticeRepository,
 | 
			
		||||
		Description: "test description",
 | 
			
		||||
	}
 | 
			
		||||
	unittest.AssertNotExistsBean(t, noticeBean)
 | 
			
		||||
	assert.NoError(t, CreateNotice(db.DefaultContext, noticeBean.Type, noticeBean.Description))
 | 
			
		||||
	assert.NoError(t, admin.CreateNotice(db.DefaultContext, noticeBean.Type, noticeBean.Description))
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, noticeBean)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCreateRepositoryNotice(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	noticeBean := &Notice{
 | 
			
		||||
		Type:        NoticeRepository,
 | 
			
		||||
	noticeBean := &admin.Notice{
 | 
			
		||||
		Type:        admin.NoticeRepository,
 | 
			
		||||
		Description: "test description",
 | 
			
		||||
	}
 | 
			
		||||
	unittest.AssertNotExistsBean(t, noticeBean)
 | 
			
		||||
	assert.NoError(t, CreateRepositoryNotice(noticeBean.Description))
 | 
			
		||||
	assert.NoError(t, admin.CreateRepositoryNotice(noticeBean.Description))
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, noticeBean)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -49,20 +50,20 @@ func TestCreateRepositoryNotice(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
func TestCountNotices(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	assert.Equal(t, int64(3), CountNotices())
 | 
			
		||||
	assert.Equal(t, int64(3), admin.CountNotices())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestNotices(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	notices, err := Notices(1, 2)
 | 
			
		||||
	notices, err := admin.Notices(1, 2)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	if assert.Len(t, notices, 2) {
 | 
			
		||||
		assert.Equal(t, int64(3), notices[0].ID)
 | 
			
		||||
		assert.Equal(t, int64(2), notices[1].ID)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	notices, err = Notices(2, 2)
 | 
			
		||||
	notices, err = admin.Notices(2, 2)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	if assert.Len(t, notices, 1) {
 | 
			
		||||
		assert.Equal(t, int64(1), notices[0].ID)
 | 
			
		||||
@@ -72,45 +73,45 @@ func TestNotices(t *testing.T) {
 | 
			
		||||
func TestDeleteNotice(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &Notice{ID: 3})
 | 
			
		||||
	assert.NoError(t, DeleteNotice(3))
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &Notice{ID: 3})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 3})
 | 
			
		||||
	assert.NoError(t, admin.DeleteNotice(3))
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &admin.Notice{ID: 3})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDeleteNotices(t *testing.T) {
 | 
			
		||||
	// delete a non-empty range
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &Notice{ID: 1})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &Notice{ID: 2})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &Notice{ID: 3})
 | 
			
		||||
	assert.NoError(t, DeleteNotices(1, 2))
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &Notice{ID: 1})
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &Notice{ID: 2})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &Notice{ID: 3})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 1})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 2})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 3})
 | 
			
		||||
	assert.NoError(t, admin.DeleteNotices(1, 2))
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &admin.Notice{ID: 1})
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &admin.Notice{ID: 2})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 3})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDeleteNotices2(t *testing.T) {
 | 
			
		||||
	// delete an empty range
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &Notice{ID: 1})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &Notice{ID: 2})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &Notice{ID: 3})
 | 
			
		||||
	assert.NoError(t, DeleteNotices(3, 2))
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &Notice{ID: 1})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &Notice{ID: 2})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &Notice{ID: 3})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 1})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 2})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 3})
 | 
			
		||||
	assert.NoError(t, admin.DeleteNotices(3, 2))
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 1})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 2})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 3})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDeleteNoticesByIDs(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &Notice{ID: 1})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &Notice{ID: 2})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &Notice{ID: 3})
 | 
			
		||||
	assert.NoError(t, DeleteNoticesByIDs([]int64{1, 3}))
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &Notice{ID: 1})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &Notice{ID: 2})
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &Notice{ID: 3})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 1})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 2})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 3})
 | 
			
		||||
	assert.NoError(t, admin.DeleteNoticesByIDs([]int64{1, 3}))
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &admin.Notice{ID: 1})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &admin.Notice{ID: 2})
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &admin.Notice{ID: 3})
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package models
 | 
			
		||||
package admin
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
@@ -2,24 +2,22 @@
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package auth
 | 
			
		||||
package auth_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
 | 
			
		||||
	_ "code.gitea.io/gitea/models"
 | 
			
		||||
	_ "code.gitea.io/gitea/models/activities"
 | 
			
		||||
	_ "code.gitea.io/gitea/models/auth"
 | 
			
		||||
	_ "code.gitea.io/gitea/models/perm/access"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestMain(m *testing.M) {
 | 
			
		||||
	unittest.MainTest(m, &unittest.TestOptions{
 | 
			
		||||
		GiteaRootPath: filepath.Join("..", ".."),
 | 
			
		||||
		FixtureFiles: []string{
 | 
			
		||||
			"login_source.yml",
 | 
			
		||||
			"oauth2_application.yml",
 | 
			
		||||
			"oauth2_authorization_code.yml",
 | 
			
		||||
			"oauth2_grant.yml",
 | 
			
		||||
			"webauthn_credential.yml",
 | 
			
		||||
		},
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,11 +2,12 @@
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package auth
 | 
			
		||||
package auth_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	auth_model "code.gitea.io/gitea/models/auth"
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
 | 
			
		||||
@@ -17,23 +18,23 @@ import (
 | 
			
		||||
 | 
			
		||||
func TestOAuth2Application_GenerateClientSecret(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	app := unittest.AssertExistsAndLoadBean(t, &OAuth2Application{ID: 1})
 | 
			
		||||
	app := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1})
 | 
			
		||||
	secret, err := app.GenerateClientSecret()
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.True(t, len(secret) > 0)
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &OAuth2Application{ID: 1, ClientSecret: app.ClientSecret})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1, ClientSecret: app.ClientSecret})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func BenchmarkOAuth2Application_GenerateClientSecret(b *testing.B) {
 | 
			
		||||
	assert.NoError(b, unittest.PrepareTestDatabase())
 | 
			
		||||
	app := unittest.AssertExistsAndLoadBean(b, &OAuth2Application{ID: 1})
 | 
			
		||||
	app := unittest.AssertExistsAndLoadBean(b, &auth_model.OAuth2Application{ID: 1})
 | 
			
		||||
	for i := 0; i < b.N; i++ {
 | 
			
		||||
		_, _ = app.GenerateClientSecret()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestOAuth2Application_ContainsRedirectURI(t *testing.T) {
 | 
			
		||||
	app := &OAuth2Application{
 | 
			
		||||
	app := &auth_model.OAuth2Application{
 | 
			
		||||
		RedirectURIs: []string{"a", "b", "c"},
 | 
			
		||||
	}
 | 
			
		||||
	assert.True(t, app.ContainsRedirectURI("a"))
 | 
			
		||||
@@ -44,7 +45,7 @@ func TestOAuth2Application_ContainsRedirectURI(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
func TestOAuth2Application_ValidateClientSecret(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	app := unittest.AssertExistsAndLoadBean(t, &OAuth2Application{ID: 1})
 | 
			
		||||
	app := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1})
 | 
			
		||||
	secret, err := app.GenerateClientSecret()
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.True(t, app.ValidateClientSecret([]byte(secret)))
 | 
			
		||||
@@ -53,31 +54,31 @@ func TestOAuth2Application_ValidateClientSecret(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
func TestGetOAuth2ApplicationByClientID(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	app, err := GetOAuth2ApplicationByClientID(db.DefaultContext, "da7da3ba-9a13-4167-856f-3899de0b0138")
 | 
			
		||||
	app, err := auth_model.GetOAuth2ApplicationByClientID(db.DefaultContext, "da7da3ba-9a13-4167-856f-3899de0b0138")
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, "da7da3ba-9a13-4167-856f-3899de0b0138", app.ClientID)
 | 
			
		||||
 | 
			
		||||
	app, err = GetOAuth2ApplicationByClientID(db.DefaultContext, "invalid client id")
 | 
			
		||||
	app, err = auth_model.GetOAuth2ApplicationByClientID(db.DefaultContext, "invalid client id")
 | 
			
		||||
	assert.Error(t, err)
 | 
			
		||||
	assert.Nil(t, app)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCreateOAuth2Application(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	app, err := CreateOAuth2Application(db.DefaultContext, CreateOAuth2ApplicationOptions{Name: "newapp", UserID: 1})
 | 
			
		||||
	app, err := auth_model.CreateOAuth2Application(db.DefaultContext, auth_model.CreateOAuth2ApplicationOptions{Name: "newapp", UserID: 1})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, "newapp", app.Name)
 | 
			
		||||
	assert.Len(t, app.ClientID, 36)
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &OAuth2Application{Name: "newapp"})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{Name: "newapp"})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestOAuth2Application_TableName(t *testing.T) {
 | 
			
		||||
	assert.Equal(t, "oauth2_application", new(OAuth2Application).TableName())
 | 
			
		||||
	assert.Equal(t, "oauth2_application", new(auth_model.OAuth2Application).TableName())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestOAuth2Application_GetGrantByUserID(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	app := unittest.AssertExistsAndLoadBean(t, &OAuth2Application{ID: 1})
 | 
			
		||||
	app := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1})
 | 
			
		||||
	grant, err := app.GetGrantByUserID(db.DefaultContext, 1)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, int64(1), grant.UserID)
 | 
			
		||||
@@ -89,7 +90,7 @@ func TestOAuth2Application_GetGrantByUserID(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
func TestOAuth2Application_CreateGrant(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	app := unittest.AssertExistsAndLoadBean(t, &OAuth2Application{ID: 1})
 | 
			
		||||
	app := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1})
 | 
			
		||||
	grant, err := app.CreateGrant(db.DefaultContext, 2, "")
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.NotNil(t, grant)
 | 
			
		||||
@@ -102,26 +103,26 @@ func TestOAuth2Application_CreateGrant(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
func TestGetOAuth2GrantByID(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	grant, err := GetOAuth2GrantByID(db.DefaultContext, 1)
 | 
			
		||||
	grant, err := auth_model.GetOAuth2GrantByID(db.DefaultContext, 1)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, int64(1), grant.ID)
 | 
			
		||||
 | 
			
		||||
	grant, err = GetOAuth2GrantByID(db.DefaultContext, 34923458)
 | 
			
		||||
	grant, err = auth_model.GetOAuth2GrantByID(db.DefaultContext, 34923458)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Nil(t, grant)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestOAuth2Grant_IncreaseCounter(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	grant := unittest.AssertExistsAndLoadBean(t, &OAuth2Grant{ID: 1, Counter: 1})
 | 
			
		||||
	grant := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Grant{ID: 1, Counter: 1})
 | 
			
		||||
	assert.NoError(t, grant.IncreaseCounter(db.DefaultContext))
 | 
			
		||||
	assert.Equal(t, int64(2), grant.Counter)
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &OAuth2Grant{ID: 1, Counter: 2})
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Grant{ID: 1, Counter: 2})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestOAuth2Grant_ScopeContains(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	grant := unittest.AssertExistsAndLoadBean(t, &OAuth2Grant{ID: 1, Scope: "openid profile"})
 | 
			
		||||
	grant := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Grant{ID: 1, Scope: "openid profile"})
 | 
			
		||||
	assert.True(t, grant.ScopeContains("openid"))
 | 
			
		||||
	assert.True(t, grant.ScopeContains("profile"))
 | 
			
		||||
	assert.False(t, grant.ScopeContains("profil"))
 | 
			
		||||
@@ -130,7 +131,7 @@ func TestOAuth2Grant_ScopeContains(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
func TestOAuth2Grant_GenerateNewAuthorizationCode(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	grant := unittest.AssertExistsAndLoadBean(t, &OAuth2Grant{ID: 1})
 | 
			
		||||
	grant := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Grant{ID: 1})
 | 
			
		||||
	code, err := grant.GenerateNewAuthorizationCode(db.DefaultContext, "https://example2.com/callback", "CjvyTLSdR47G5zYenDA-eDWW4lRrO8yvjcWwbD_deOg", "S256")
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.NotNil(t, code)
 | 
			
		||||
@@ -138,46 +139,46 @@ func TestOAuth2Grant_GenerateNewAuthorizationCode(t *testing.T) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestOAuth2Grant_TableName(t *testing.T) {
 | 
			
		||||
	assert.Equal(t, "oauth2_grant", new(OAuth2Grant).TableName())
 | 
			
		||||
	assert.Equal(t, "oauth2_grant", new(auth_model.OAuth2Grant).TableName())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetOAuth2GrantsByUserID(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	result, err := GetOAuth2GrantsByUserID(db.DefaultContext, 1)
 | 
			
		||||
	result, err := auth_model.GetOAuth2GrantsByUserID(db.DefaultContext, 1)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, result, 1)
 | 
			
		||||
	assert.Equal(t, int64(1), result[0].ID)
 | 
			
		||||
	assert.Equal(t, result[0].ApplicationID, result[0].Application.ID)
 | 
			
		||||
 | 
			
		||||
	result, err = GetOAuth2GrantsByUserID(db.DefaultContext, 34134)
 | 
			
		||||
	result, err = auth_model.GetOAuth2GrantsByUserID(db.DefaultContext, 34134)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Empty(t, result)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRevokeOAuth2Grant(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	assert.NoError(t, RevokeOAuth2Grant(db.DefaultContext, 1, 1))
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &OAuth2Grant{ID: 1, UserID: 1})
 | 
			
		||||
	assert.NoError(t, auth_model.RevokeOAuth2Grant(db.DefaultContext, 1, 1))
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &auth_model.OAuth2Grant{ID: 1, UserID: 1})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//////////////////// Authorization Code
 | 
			
		||||
 | 
			
		||||
func TestGetOAuth2AuthorizationByCode(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	code, err := GetOAuth2AuthorizationByCode(db.DefaultContext, "authcode")
 | 
			
		||||
	code, err := auth_model.GetOAuth2AuthorizationByCode(db.DefaultContext, "authcode")
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.NotNil(t, code)
 | 
			
		||||
	assert.Equal(t, "authcode", code.Code)
 | 
			
		||||
	assert.Equal(t, int64(1), code.ID)
 | 
			
		||||
 | 
			
		||||
	code, err = GetOAuth2AuthorizationByCode(db.DefaultContext, "does not exist")
 | 
			
		||||
	code, err = auth_model.GetOAuth2AuthorizationByCode(db.DefaultContext, "does not exist")
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Nil(t, code)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestOAuth2AuthorizationCode_ValidateCodeChallenge(t *testing.T) {
 | 
			
		||||
	// test plain
 | 
			
		||||
	code := &OAuth2AuthorizationCode{
 | 
			
		||||
	code := &auth_model.OAuth2AuthorizationCode{
 | 
			
		||||
		CodeChallengeMethod: "plain",
 | 
			
		||||
		CodeChallenge:       "test123",
 | 
			
		||||
	}
 | 
			
		||||
@@ -185,7 +186,7 @@ func TestOAuth2AuthorizationCode_ValidateCodeChallenge(t *testing.T) {
 | 
			
		||||
	assert.False(t, code.ValidateCodeChallenge("ierwgjoergjio"))
 | 
			
		||||
 | 
			
		||||
	// test S256
 | 
			
		||||
	code = &OAuth2AuthorizationCode{
 | 
			
		||||
	code = &auth_model.OAuth2AuthorizationCode{
 | 
			
		||||
		CodeChallengeMethod: "S256",
 | 
			
		||||
		CodeChallenge:       "CjvyTLSdR47G5zYenDA-eDWW4lRrO8yvjcWwbD_deOg",
 | 
			
		||||
	}
 | 
			
		||||
@@ -193,14 +194,14 @@ func TestOAuth2AuthorizationCode_ValidateCodeChallenge(t *testing.T) {
 | 
			
		||||
	assert.False(t, code.ValidateCodeChallenge("wiogjerogorewngoenrgoiuenorg"))
 | 
			
		||||
 | 
			
		||||
	// test unknown
 | 
			
		||||
	code = &OAuth2AuthorizationCode{
 | 
			
		||||
	code = &auth_model.OAuth2AuthorizationCode{
 | 
			
		||||
		CodeChallengeMethod: "monkey",
 | 
			
		||||
		CodeChallenge:       "foiwgjioriogeiogjerger",
 | 
			
		||||
	}
 | 
			
		||||
	assert.False(t, code.ValidateCodeChallenge("foiwgjioriogeiogjerger"))
 | 
			
		||||
 | 
			
		||||
	// test no code challenge
 | 
			
		||||
	code = &OAuth2AuthorizationCode{
 | 
			
		||||
	code = &auth_model.OAuth2AuthorizationCode{
 | 
			
		||||
		CodeChallengeMethod: "",
 | 
			
		||||
		CodeChallenge:       "foierjiogerogerg",
 | 
			
		||||
	}
 | 
			
		||||
@@ -208,7 +209,7 @@ func TestOAuth2AuthorizationCode_ValidateCodeChallenge(t *testing.T) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestOAuth2AuthorizationCode_GenerateRedirectURI(t *testing.T) {
 | 
			
		||||
	code := &OAuth2AuthorizationCode{
 | 
			
		||||
	code := &auth_model.OAuth2AuthorizationCode{
 | 
			
		||||
		RedirectURI: "https://example.com/callback",
 | 
			
		||||
		Code:        "thecode",
 | 
			
		||||
	}
 | 
			
		||||
@@ -224,11 +225,11 @@ func TestOAuth2AuthorizationCode_GenerateRedirectURI(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
func TestOAuth2AuthorizationCode_Invalidate(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	code := unittest.AssertExistsAndLoadBean(t, &OAuth2AuthorizationCode{Code: "authcode"})
 | 
			
		||||
	code := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2AuthorizationCode{Code: "authcode"})
 | 
			
		||||
	assert.NoError(t, code.Invalidate(db.DefaultContext))
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &OAuth2AuthorizationCode{Code: "authcode"})
 | 
			
		||||
	unittest.AssertNotExistsBean(t, &auth_model.OAuth2AuthorizationCode{Code: "authcode"})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestOAuth2AuthorizationCode_TableName(t *testing.T) {
 | 
			
		||||
	assert.Equal(t, "oauth2_authorization_code", new(OAuth2AuthorizationCode).TableName())
 | 
			
		||||
	assert.Equal(t, "oauth2_authorization_code", new(auth_model.OAuth2AuthorizationCode).TableName())
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,12 +2,13 @@
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package auth
 | 
			
		||||
package auth_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"strings"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	auth_model "code.gitea.io/gitea/models/auth"
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
	"code.gitea.io/gitea/modules/json"
 | 
			
		||||
@@ -37,13 +38,13 @@ func (source *TestSource) ToDB() ([]byte, error) {
 | 
			
		||||
func TestDumpAuthSource(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	authSourceSchema, err := db.TableInfo(new(Source))
 | 
			
		||||
	authSourceSchema, err := db.TableInfo(new(auth_model.Source))
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
	RegisterTypeConfig(OAuth2, new(TestSource))
 | 
			
		||||
	auth_model.RegisterTypeConfig(auth_model.OAuth2, new(TestSource))
 | 
			
		||||
 | 
			
		||||
	CreateSource(&Source{
 | 
			
		||||
		Type:     OAuth2,
 | 
			
		||||
	auth_model.CreateSource(&auth_model.Source{
 | 
			
		||||
		Type:     auth_model.OAuth2,
 | 
			
		||||
		Name:     "TestSource",
 | 
			
		||||
		IsActive: false,
 | 
			
		||||
		Cfg: &TestSource{
 | 
			
		||||
 
 | 
			
		||||
@@ -3,14 +3,13 @@
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package models
 | 
			
		||||
package auth
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/subtle"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/auth"
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/modules/base"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
@@ -21,6 +20,34 @@ import (
 | 
			
		||||
	lru "github.com/hashicorp/golang-lru"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ErrAccessTokenNotExist represents a "AccessTokenNotExist" kind of error.
 | 
			
		||||
type ErrAccessTokenNotExist struct {
 | 
			
		||||
	Token string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrAccessTokenNotExist checks if an error is a ErrAccessTokenNotExist.
 | 
			
		||||
func IsErrAccessTokenNotExist(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrAccessTokenNotExist)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrAccessTokenNotExist) Error() string {
 | 
			
		||||
	return fmt.Sprintf("access token does not exist [sha: %s]", err.Token)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrAccessTokenEmpty represents a "AccessTokenEmpty" kind of error.
 | 
			
		||||
type ErrAccessTokenEmpty struct{}
 | 
			
		||||
 | 
			
		||||
// IsErrAccessTokenEmpty checks if an error is a ErrAccessTokenEmpty.
 | 
			
		||||
func IsErrAccessTokenEmpty(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrAccessTokenEmpty)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrAccessTokenEmpty) Error() string {
 | 
			
		||||
	return "access token is empty"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var successfulAccessTokenCache *lru.Cache
 | 
			
		||||
 | 
			
		||||
// AccessToken represents a personal access token.
 | 
			
		||||
@@ -68,7 +95,7 @@ func NewAccessToken(t *AccessToken) error {
 | 
			
		||||
	}
 | 
			
		||||
	t.TokenSalt = salt
 | 
			
		||||
	t.Token = base.EncodeSha1(gouuid.New().String())
 | 
			
		||||
	t.TokenHash = auth.HashToken(t.Token, t.TokenSalt)
 | 
			
		||||
	t.TokenHash = HashToken(t.Token, t.TokenSalt)
 | 
			
		||||
	t.TokenLastEight = t.Token[len(t.Token)-8:]
 | 
			
		||||
	_, err = db.GetEngine(db.DefaultContext).Insert(t)
 | 
			
		||||
	return err
 | 
			
		||||
@@ -130,7 +157,7 @@ func GetAccessTokenBySHA(token string) (*AccessToken, error) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, t := range tokens {
 | 
			
		||||
		tempHash := auth.HashToken(token, t.TokenSalt)
 | 
			
		||||
		tempHash := HashToken(token, t.TokenSalt)
 | 
			
		||||
		if subtle.ConstantTimeCompare([]byte(t.TokenHash), []byte(tempHash)) == 1 {
 | 
			
		||||
			if successfulAccessTokenCache != nil {
 | 
			
		||||
				successfulAccessTokenCache.Add(token, t.ID)
 | 
			
		||||
@@ -2,11 +2,12 @@
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package models
 | 
			
		||||
package auth_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	auth_model "code.gitea.io/gitea/models/auth"
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
@@ -14,77 +15,77 @@ import (
 | 
			
		||||
 | 
			
		||||
func TestNewAccessToken(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	token := &AccessToken{
 | 
			
		||||
	token := &auth_model.AccessToken{
 | 
			
		||||
		UID:  3,
 | 
			
		||||
		Name: "Token C",
 | 
			
		||||
	}
 | 
			
		||||
	assert.NoError(t, NewAccessToken(token))
 | 
			
		||||
	assert.NoError(t, auth_model.NewAccessToken(token))
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, token)
 | 
			
		||||
 | 
			
		||||
	invalidToken := &AccessToken{
 | 
			
		||||
	invalidToken := &auth_model.AccessToken{
 | 
			
		||||
		ID:   token.ID, // duplicate
 | 
			
		||||
		UID:  2,
 | 
			
		||||
		Name: "Token F",
 | 
			
		||||
	}
 | 
			
		||||
	assert.Error(t, NewAccessToken(invalidToken))
 | 
			
		||||
	assert.Error(t, auth_model.NewAccessToken(invalidToken))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAccessTokenByNameExists(t *testing.T) {
 | 
			
		||||
	name := "Token Gitea"
 | 
			
		||||
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	token := &AccessToken{
 | 
			
		||||
	token := &auth_model.AccessToken{
 | 
			
		||||
		UID:  3,
 | 
			
		||||
		Name: name,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check to make sure it doesn't exists already
 | 
			
		||||
	exist, err := AccessTokenByNameExists(token)
 | 
			
		||||
	exist, err := auth_model.AccessTokenByNameExists(token)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.False(t, exist)
 | 
			
		||||
 | 
			
		||||
	// Save it to the database
 | 
			
		||||
	assert.NoError(t, NewAccessToken(token))
 | 
			
		||||
	assert.NoError(t, auth_model.NewAccessToken(token))
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, token)
 | 
			
		||||
 | 
			
		||||
	// This token must be found by name in the DB now
 | 
			
		||||
	exist, err = AccessTokenByNameExists(token)
 | 
			
		||||
	exist, err = auth_model.AccessTokenByNameExists(token)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.True(t, exist)
 | 
			
		||||
 | 
			
		||||
	user4Token := &AccessToken{
 | 
			
		||||
	user4Token := &auth_model.AccessToken{
 | 
			
		||||
		UID:  4,
 | 
			
		||||
		Name: name,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Name matches but different user ID, this shouldn't exists in the
 | 
			
		||||
	// database
 | 
			
		||||
	exist, err = AccessTokenByNameExists(user4Token)
 | 
			
		||||
	exist, err = auth_model.AccessTokenByNameExists(user4Token)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.False(t, exist)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetAccessTokenBySHA(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	token, err := GetAccessTokenBySHA("d2c6c1ba3890b309189a8e618c72a162e4efbf36")
 | 
			
		||||
	token, err := auth_model.GetAccessTokenBySHA("d2c6c1ba3890b309189a8e618c72a162e4efbf36")
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, int64(1), token.UID)
 | 
			
		||||
	assert.Equal(t, "Token A", token.Name)
 | 
			
		||||
	assert.Equal(t, "2b3668e11cb82d3af8c6e4524fc7841297668f5008d1626f0ad3417e9fa39af84c268248b78c481daa7e5dc437784003494f", token.TokenHash)
 | 
			
		||||
	assert.Equal(t, "e4efbf36", token.TokenLastEight)
 | 
			
		||||
 | 
			
		||||
	_, err = GetAccessTokenBySHA("notahash")
 | 
			
		||||
	_, err = auth_model.GetAccessTokenBySHA("notahash")
 | 
			
		||||
	assert.Error(t, err)
 | 
			
		||||
	assert.True(t, IsErrAccessTokenNotExist(err))
 | 
			
		||||
	assert.True(t, auth_model.IsErrAccessTokenNotExist(err))
 | 
			
		||||
 | 
			
		||||
	_, err = GetAccessTokenBySHA("")
 | 
			
		||||
	_, err = auth_model.GetAccessTokenBySHA("")
 | 
			
		||||
	assert.Error(t, err)
 | 
			
		||||
	assert.True(t, IsErrAccessTokenEmpty(err))
 | 
			
		||||
	assert.True(t, auth_model.IsErrAccessTokenEmpty(err))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestListAccessTokens(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	tokens, err := ListAccessTokens(ListAccessTokensOptions{UserID: 1})
 | 
			
		||||
	tokens, err := auth_model.ListAccessTokens(auth_model.ListAccessTokensOptions{UserID: 1})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	if assert.Len(t, tokens, 2) {
 | 
			
		||||
		assert.Equal(t, int64(1), tokens[0].UID)
 | 
			
		||||
@@ -93,39 +94,39 @@ func TestListAccessTokens(t *testing.T) {
 | 
			
		||||
		assert.Contains(t, []string{tokens[0].Name, tokens[1].Name}, "Token B")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tokens, err = ListAccessTokens(ListAccessTokensOptions{UserID: 2})
 | 
			
		||||
	tokens, err = auth_model.ListAccessTokens(auth_model.ListAccessTokensOptions{UserID: 2})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	if assert.Len(t, tokens, 1) {
 | 
			
		||||
		assert.Equal(t, int64(2), tokens[0].UID)
 | 
			
		||||
		assert.Equal(t, "Token A", tokens[0].Name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	tokens, err = ListAccessTokens(ListAccessTokensOptions{UserID: 100})
 | 
			
		||||
	tokens, err = auth_model.ListAccessTokens(auth_model.ListAccessTokensOptions{UserID: 100})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Empty(t, tokens)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestUpdateAccessToken(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	token, err := GetAccessTokenBySHA("4c6f36e6cf498e2a448662f915d932c09c5a146c")
 | 
			
		||||
	token, err := auth_model.GetAccessTokenBySHA("4c6f36e6cf498e2a448662f915d932c09c5a146c")
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	token.Name = "Token Z"
 | 
			
		||||
 | 
			
		||||
	assert.NoError(t, UpdateAccessToken(token))
 | 
			
		||||
	assert.NoError(t, auth_model.UpdateAccessToken(token))
 | 
			
		||||
	unittest.AssertExistsAndLoadBean(t, token)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDeleteAccessTokenByID(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	token, err := GetAccessTokenBySHA("4c6f36e6cf498e2a448662f915d932c09c5a146c")
 | 
			
		||||
	token, err := auth_model.GetAccessTokenBySHA("4c6f36e6cf498e2a448662f915d932c09c5a146c")
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, int64(1), token.UID)
 | 
			
		||||
 | 
			
		||||
	assert.NoError(t, DeleteAccessTokenByID(token.ID, 1))
 | 
			
		||||
	assert.NoError(t, auth_model.DeleteAccessTokenByID(token.ID, 1))
 | 
			
		||||
	unittest.AssertNotExistsBean(t, token)
 | 
			
		||||
 | 
			
		||||
	err = DeleteAccessTokenByID(100, 100)
 | 
			
		||||
	err = auth_model.DeleteAccessTokenByID(100, 100)
 | 
			
		||||
	assert.Error(t, err)
 | 
			
		||||
	assert.True(t, IsErrAccessTokenNotExist(err))
 | 
			
		||||
	assert.True(t, auth_model.IsErrAccessTokenNotExist(err))
 | 
			
		||||
}
 | 
			
		||||
@@ -2,11 +2,12 @@
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package auth
 | 
			
		||||
package auth_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	auth_model "code.gitea.io/gitea/models/auth"
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
 | 
			
		||||
	"github.com/duo-labs/webauthn/webauthn"
 | 
			
		||||
@@ -16,51 +17,51 @@ import (
 | 
			
		||||
func TestGetWebAuthnCredentialByID(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	res, err := GetWebAuthnCredentialByID(1)
 | 
			
		||||
	res, err := auth_model.GetWebAuthnCredentialByID(1)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, "WebAuthn credential", res.Name)
 | 
			
		||||
 | 
			
		||||
	_, err = GetWebAuthnCredentialByID(342432)
 | 
			
		||||
	_, err = auth_model.GetWebAuthnCredentialByID(342432)
 | 
			
		||||
	assert.Error(t, err)
 | 
			
		||||
	assert.True(t, IsErrWebAuthnCredentialNotExist(err))
 | 
			
		||||
	assert.True(t, auth_model.IsErrWebAuthnCredentialNotExist(err))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetWebAuthnCredentialsByUID(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	res, err := GetWebAuthnCredentialsByUID(32)
 | 
			
		||||
	res, err := auth_model.GetWebAuthnCredentialsByUID(32)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Len(t, res, 1)
 | 
			
		||||
	assert.Equal(t, "WebAuthn credential", res[0].Name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestWebAuthnCredential_TableName(t *testing.T) {
 | 
			
		||||
	assert.Equal(t, "webauthn_credential", WebAuthnCredential{}.TableName())
 | 
			
		||||
	assert.Equal(t, "webauthn_credential", auth_model.WebAuthnCredential{}.TableName())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestWebAuthnCredential_UpdateSignCount(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	cred := unittest.AssertExistsAndLoadBean(t, &WebAuthnCredential{ID: 1})
 | 
			
		||||
	cred := unittest.AssertExistsAndLoadBean(t, &auth_model.WebAuthnCredential{ID: 1})
 | 
			
		||||
	cred.SignCount = 1
 | 
			
		||||
	assert.NoError(t, cred.UpdateSignCount())
 | 
			
		||||
	unittest.AssertExistsIf(t, true, &WebAuthnCredential{ID: 1, SignCount: 1})
 | 
			
		||||
	unittest.AssertExistsIf(t, true, &auth_model.WebAuthnCredential{ID: 1, SignCount: 1})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestWebAuthnCredential_UpdateLargeCounter(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
	cred := unittest.AssertExistsAndLoadBean(t, &WebAuthnCredential{ID: 1})
 | 
			
		||||
	cred := unittest.AssertExistsAndLoadBean(t, &auth_model.WebAuthnCredential{ID: 1})
 | 
			
		||||
	cred.SignCount = 0xffffffff
 | 
			
		||||
	assert.NoError(t, cred.UpdateSignCount())
 | 
			
		||||
	unittest.AssertExistsIf(t, true, &WebAuthnCredential{ID: 1, SignCount: 0xffffffff})
 | 
			
		||||
	unittest.AssertExistsIf(t, true, &auth_model.WebAuthnCredential{ID: 1, SignCount: 0xffffffff})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestCreateCredential(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	res, err := CreateCredential(1, "WebAuthn Created Credential", &webauthn.Credential{ID: []byte("Test")})
 | 
			
		||||
	res, err := auth_model.CreateCredential(1, "WebAuthn Created Credential", &webauthn.Credential{ID: []byte("Test")})
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.Equal(t, "WebAuthn Created Credential", res.Name)
 | 
			
		||||
	assert.Equal(t, []byte("Test"), res.CredentialID)
 | 
			
		||||
 | 
			
		||||
	unittest.AssertExistsIf(t, true, &WebAuthnCredential{Name: "WebAuthn Created Credential", UserID: 1})
 | 
			
		||||
	unittest.AssertExistsIf(t, true, &auth_model.WebAuthnCredential{Name: "WebAuthn Created Credential", UserID: 1})
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,56 +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 (
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/builder"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// CountNullArchivedRepository counts the number of repositories with is_archived is null
 | 
			
		||||
func CountNullArchivedRepository() (int64, error) {
 | 
			
		||||
	return db.GetEngine(db.DefaultContext).Where(builder.IsNull{"is_archived"}).Count(new(repo_model.Repository))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FixNullArchivedRepository sets is_archived to false where it is null
 | 
			
		||||
func FixNullArchivedRepository() (int64, error) {
 | 
			
		||||
	return db.GetEngine(db.DefaultContext).Where(builder.IsNull{"is_archived"}).Cols("is_archived").NoAutoTime().Update(&repo_model.Repository{
 | 
			
		||||
		IsArchived: false,
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CountWrongUserType count OrgUser who have wrong type
 | 
			
		||||
func CountWrongUserType() (int64, error) {
 | 
			
		||||
	return db.GetEngine(db.DefaultContext).Where(builder.Eq{"type": 0}.And(builder.Neq{"num_teams": 0})).Count(new(user_model.User))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FixWrongUserType fix OrgUser who have wrong type
 | 
			
		||||
func FixWrongUserType() (int64, error) {
 | 
			
		||||
	return db.GetEngine(db.DefaultContext).Where(builder.Eq{"type": 0}.And(builder.Neq{"num_teams": 0})).Cols("type").NoAutoTime().Update(&user_model.User{Type: 1})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CountActionCreatedUnixString count actions where created_unix is an empty string
 | 
			
		||||
func CountActionCreatedUnixString() (int64, error) {
 | 
			
		||||
	if setting.Database.UseSQLite3 {
 | 
			
		||||
		return db.GetEngine(db.DefaultContext).Where(`created_unix = ""`).Count(new(Action))
 | 
			
		||||
	}
 | 
			
		||||
	return 0, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FixActionCreatedUnixString set created_unix to zero if it is an empty string
 | 
			
		||||
func FixActionCreatedUnixString() (int64, error) {
 | 
			
		||||
	if setting.Database.UseSQLite3 {
 | 
			
		||||
		res, err := db.GetEngine(db.DefaultContext).Exec(`UPDATE action SET created_unix = 0 WHERE created_unix = ""`)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return 0, err
 | 
			
		||||
		}
 | 
			
		||||
		return res.RowsAffected()
 | 
			
		||||
	}
 | 
			
		||||
	return 0, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										203
									
								
								models/error.go
									
									
									
									
									
								
							
							
						
						
									
										203
									
								
								models/error.go
									
									
									
									
									
								
							@@ -57,93 +57,6 @@ func (err ErrUserOwnPackages) Error() string {
 | 
			
		||||
	return fmt.Sprintf("user still has ownership of packages [uid: %d]", err.UID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//  __      __.__ __   .__
 | 
			
		||||
// /  \    /  \__|  | _|__|
 | 
			
		||||
// \   \/\/   /  |  |/ /  |
 | 
			
		||||
//  \        /|  |    <|  |
 | 
			
		||||
//   \__/\  / |__|__|_ \__|
 | 
			
		||||
//        \/          \/
 | 
			
		||||
 | 
			
		||||
// ErrWikiAlreadyExist represents a "WikiAlreadyExist" kind of error.
 | 
			
		||||
type ErrWikiAlreadyExist struct {
 | 
			
		||||
	Title string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrWikiAlreadyExist checks if an error is an ErrWikiAlreadyExist.
 | 
			
		||||
func IsErrWikiAlreadyExist(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrWikiAlreadyExist)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrWikiAlreadyExist) Error() string {
 | 
			
		||||
	return fmt.Sprintf("wiki page already exists [title: %s]", err.Title)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrWikiReservedName represents a reserved name error.
 | 
			
		||||
type ErrWikiReservedName struct {
 | 
			
		||||
	Title string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrWikiReservedName checks if an error is an ErrWikiReservedName.
 | 
			
		||||
func IsErrWikiReservedName(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrWikiReservedName)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrWikiReservedName) Error() string {
 | 
			
		||||
	return fmt.Sprintf("wiki title is reserved: %s", err.Title)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrWikiInvalidFileName represents an invalid wiki file name.
 | 
			
		||||
type ErrWikiInvalidFileName struct {
 | 
			
		||||
	FileName string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrWikiInvalidFileName checks if an error is an ErrWikiInvalidFileName.
 | 
			
		||||
func IsErrWikiInvalidFileName(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrWikiInvalidFileName)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrWikiInvalidFileName) Error() string {
 | 
			
		||||
	return fmt.Sprintf("Invalid wiki filename: %s", err.FileName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//    _____                                   ___________     __
 | 
			
		||||
//   /  _  \   ____  ____  ____   ______ _____\__    ___/___ |  | __ ____   ____
 | 
			
		||||
//  /  /_\  \_/ ___\/ ___\/ __ \ /  ___//  ___/ |    | /  _ \|  |/ // __ \ /    \
 | 
			
		||||
// /    |    \  \__\  \__\  ___/ \___ \ \___ \  |    |(  <_> )    <\  ___/|   |  \
 | 
			
		||||
// \____|__  /\___  >___  >___  >____  >____  > |____| \____/|__|_ \\___  >___|  /
 | 
			
		||||
//         \/     \/    \/    \/     \/     \/                    \/    \/     \/
 | 
			
		||||
 | 
			
		||||
// ErrAccessTokenNotExist represents a "AccessTokenNotExist" kind of error.
 | 
			
		||||
type ErrAccessTokenNotExist struct {
 | 
			
		||||
	Token string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrAccessTokenNotExist checks if an error is a ErrAccessTokenNotExist.
 | 
			
		||||
func IsErrAccessTokenNotExist(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrAccessTokenNotExist)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrAccessTokenNotExist) Error() string {
 | 
			
		||||
	return fmt.Sprintf("access token does not exist [sha: %s]", err.Token)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrAccessTokenEmpty represents a "AccessTokenEmpty" kind of error.
 | 
			
		||||
type ErrAccessTokenEmpty struct{}
 | 
			
		||||
 | 
			
		||||
// IsErrAccessTokenEmpty checks if an error is a ErrAccessTokenEmpty.
 | 
			
		||||
func IsErrAccessTokenEmpty(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrAccessTokenEmpty)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrAccessTokenEmpty) Error() string {
 | 
			
		||||
	return "access token is empty"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrNoPendingRepoTransfer is an error type for repositories without a pending
 | 
			
		||||
// transfer request
 | 
			
		||||
type ErrNoPendingRepoTransfer struct {
 | 
			
		||||
@@ -178,23 +91,6 @@ func (err ErrRepoTransferInProgress) Error() string {
 | 
			
		||||
	return fmt.Sprintf("repository is already being transferred [uname: %s, name: %s]", err.Uname, err.Name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrForkAlreadyExist represents a "ForkAlreadyExist" kind of error.
 | 
			
		||||
type ErrForkAlreadyExist struct {
 | 
			
		||||
	Uname    string
 | 
			
		||||
	RepoName string
 | 
			
		||||
	ForkName string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrForkAlreadyExist checks if an error is an ErrForkAlreadyExist.
 | 
			
		||||
func IsErrForkAlreadyExist(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrForkAlreadyExist)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrInvalidCloneAddr represents a "InvalidCloneAddr" kind of error.
 | 
			
		||||
type ErrInvalidCloneAddr struct {
 | 
			
		||||
	Host               string
 | 
			
		||||
@@ -243,37 +139,6 @@ func (err ErrUpdateTaskNotExist) Error() string {
 | 
			
		||||
	return fmt.Sprintf("update task does not exist [uuid: %s]", err.UUID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrReleaseAlreadyExist represents a "ReleaseAlreadyExist" kind of error.
 | 
			
		||||
type ErrReleaseAlreadyExist struct {
 | 
			
		||||
	TagName string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrReleaseAlreadyExist checks if an error is a ErrReleaseAlreadyExist.
 | 
			
		||||
func IsErrReleaseAlreadyExist(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrReleaseAlreadyExist)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrReleaseAlreadyExist) Error() string {
 | 
			
		||||
	return fmt.Sprintf("release tag already exist [tag_name: %s]", err.TagName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrReleaseNotExist represents a "ReleaseNotExist" kind of error.
 | 
			
		||||
type ErrReleaseNotExist struct {
 | 
			
		||||
	ID      int64
 | 
			
		||||
	TagName string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrReleaseNotExist checks if an error is a ErrReleaseNotExist.
 | 
			
		||||
func IsErrReleaseNotExist(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrReleaseNotExist)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrReleaseNotExist) Error() string {
 | 
			
		||||
	return fmt.Sprintf("release tag does not exist [id: %d, tag_name: %s]", err.ID, err.TagName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrInvalidTagName represents a "InvalidTagName" kind of error.
 | 
			
		||||
type ErrInvalidTagName struct {
 | 
			
		||||
	TagName string
 | 
			
		||||
@@ -657,71 +522,3 @@ func (err ErrPullRequestHasMerged) Error() string {
 | 
			
		||||
	return fmt.Sprintf("pull request has merged [id: %d, issue_id: %d, head_repo_id: %d, base_repo_id: %d, head_branch: %s, base_branch: %s]",
 | 
			
		||||
		err.ID, err.IssueID, err.HeadRepoID, err.BaseRepoID, err.HeadBranch, err.BaseBranch)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//  _________ __                                __         .__
 | 
			
		||||
//  /   _____//  |_  ____ ________  _  _______ _/  |_  ____ |  |__
 | 
			
		||||
//  \_____  \\   __\/  _ \\____ \ \/ \/ /\__  \\   __\/ ___\|  |  \
 | 
			
		||||
//  /        \|  | (  <_> )  |_> >     /  / __ \|  | \  \___|   Y  \
 | 
			
		||||
//  /_______  /|__|  \____/|   __/ \/\_/  (____  /__|  \___  >___|  /
 | 
			
		||||
// \/             |__|                \/          \/     \/
 | 
			
		||||
 | 
			
		||||
// ErrStopwatchNotExist represents a "Stopwatch Not Exist" kind of error.
 | 
			
		||||
type ErrStopwatchNotExist struct {
 | 
			
		||||
	ID int64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrStopwatchNotExist checks if an error is a ErrStopwatchNotExist.
 | 
			
		||||
func IsErrStopwatchNotExist(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrStopwatchNotExist)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrStopwatchNotExist) Error() string {
 | 
			
		||||
	return fmt.Sprintf("stopwatch does not exist [id: %d]", err.ID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ___________                     __              .______________.__
 | 
			
		||||
// \__    ___/___________    ____ |  | __ ____   __| _/\__    ___/|__| _____   ____
 | 
			
		||||
// |    |  \_  __ \__  \ _/ ___\|  |/ // __ \ / __ |   |    |   |  |/     \_/ __ \
 | 
			
		||||
// |    |   |  | \// __ \\  \___|    <\  ___// /_/ |   |    |   |  |  Y Y  \  ___/
 | 
			
		||||
// |____|   |__|  (____  /\___  >__|_ \\___  >____ |   |____|   |__|__|_|  /\___  >
 | 
			
		||||
// \/     \/     \/    \/     \/                     \/     \/
 | 
			
		||||
 | 
			
		||||
// ErrTrackedTimeNotExist represents a "TrackedTime Not Exist" kind of error.
 | 
			
		||||
type ErrTrackedTimeNotExist struct {
 | 
			
		||||
	ID int64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrTrackedTimeNotExist checks if an error is a ErrTrackedTimeNotExist.
 | 
			
		||||
func IsErrTrackedTimeNotExist(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrTrackedTimeNotExist)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrTrackedTimeNotExist) Error() string {
 | 
			
		||||
	return fmt.Sprintf("tracked time does not exist [id: %d]", err.ID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//  ____ ___        .__                    .___
 | 
			
		||||
// |    |   \______ |  |   _________     __| _/
 | 
			
		||||
// |    |   /\____ \|  |  /  _ \__  \   / __ |
 | 
			
		||||
// |    |  / |  |_> >  |_(  <_> ) __ \_/ /_/ |
 | 
			
		||||
// |______/  |   __/|____/\____(____  /\____ |
 | 
			
		||||
//           |__|                   \/      \/
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
// ErrUploadNotExist represents a "UploadNotExist" kind of error.
 | 
			
		||||
type ErrUploadNotExist struct {
 | 
			
		||||
	ID   int64
 | 
			
		||||
	UUID string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrUploadNotExist checks if an error is a ErrUploadNotExist.
 | 
			
		||||
func IsErrUploadNotExist(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrUploadNotExist)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrUploadNotExist) Error() string {
 | 
			
		||||
	return fmt.Sprintf("attachment does not exist [id: %d, uuid: %s]", err.ID, err.UUID)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@ package models
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	activities_model "code.gitea.io/gitea/models/activities"
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
@@ -28,7 +29,7 @@ func TestFixturesAreConsistent(t *testing.T) {
 | 
			
		||||
		&user_model.User{},
 | 
			
		||||
		&repo_model.Repository{},
 | 
			
		||||
		&organization.Team{},
 | 
			
		||||
		&Action{})
 | 
			
		||||
		&activities_model.Action{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestMain(m *testing.M) {
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ import (
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	issues_model "code.gitea.io/gitea/models/issues"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	"code.gitea.io/gitea/modules/structs"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -154,7 +155,7 @@ func InsertPullRequests(prs ...*issues_model.PullRequest) error {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// InsertReleases migrates release
 | 
			
		||||
func InsertReleases(rels ...*Release) error {
 | 
			
		||||
func InsertReleases(rels ...*repo_model.Release) error {
 | 
			
		||||
	ctx, committer, err := db.TxContext()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
@@ -191,7 +192,7 @@ func UpdateMigrationsByType(tp structs.GitServiceType, externalUserID string, us
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := UpdateReleasesMigrationsByType(tp, externalUserID, userID); err != nil {
 | 
			
		||||
	if err := repo_model.UpdateReleasesMigrationsByType(tp, externalUserID, userID); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -149,7 +149,7 @@ func TestMigrate_InsertReleases(t *testing.T) {
 | 
			
		||||
	a := &repo_model.Attachment{
 | 
			
		||||
		UUID: "a0eebc91-9c0c-4ef7-bb6e-6bb9bd380a12",
 | 
			
		||||
	}
 | 
			
		||||
	r := &Release{
 | 
			
		||||
	r := &repo_model.Release{
 | 
			
		||||
		Attachments: []*repo_model.Attachment{a},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -8,79 +8,13 @@ package models
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	access_model "code.gitea.io/gitea/models/perm/access"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	"code.gitea.io/gitea/models/unit"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/builder"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// MinimalOrg represents a simple orgnization with only needed columns
 | 
			
		||||
type MinimalOrg = organization.Organization
 | 
			
		||||
 | 
			
		||||
// GetUserOrgsList returns one user's all orgs list
 | 
			
		||||
func GetUserOrgsList(user *user_model.User) ([]*MinimalOrg, error) {
 | 
			
		||||
	schema, err := db.TableInfo(new(user_model.User))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	outputCols := []string{
 | 
			
		||||
		"id",
 | 
			
		||||
		"name",
 | 
			
		||||
		"full_name",
 | 
			
		||||
		"visibility",
 | 
			
		||||
		"avatar",
 | 
			
		||||
		"avatar_email",
 | 
			
		||||
		"use_custom_avatar",
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	groupByCols := &strings.Builder{}
 | 
			
		||||
	for _, col := range outputCols {
 | 
			
		||||
		fmt.Fprintf(groupByCols, "`%s`.%s,", schema.Name, col)
 | 
			
		||||
	}
 | 
			
		||||
	groupByStr := groupByCols.String()
 | 
			
		||||
	groupByStr = groupByStr[0 : len(groupByStr)-1]
 | 
			
		||||
 | 
			
		||||
	sess := db.GetEngine(db.DefaultContext)
 | 
			
		||||
	sess = sess.Select(groupByStr+", count(distinct repo_id) as org_count").
 | 
			
		||||
		Table("user").
 | 
			
		||||
		Join("INNER", "team", "`team`.org_id = `user`.id").
 | 
			
		||||
		Join("INNER", "team_user", "`team`.id = `team_user`.team_id").
 | 
			
		||||
		Join("LEFT", builder.
 | 
			
		||||
			Select("id as repo_id, owner_id as repo_owner_id").
 | 
			
		||||
			From("repository").
 | 
			
		||||
			Where(repo_model.AccessibleRepositoryCondition(user, unit.TypeInvalid)), "`repository`.repo_owner_id = `team`.org_id").
 | 
			
		||||
		Where("`team_user`.uid = ?", user.ID).
 | 
			
		||||
		GroupBy(groupByStr)
 | 
			
		||||
 | 
			
		||||
	type OrgCount struct {
 | 
			
		||||
		organization.Organization `xorm:"extends"`
 | 
			
		||||
		OrgCount                  int
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	orgCounts := make([]*OrgCount, 0, 10)
 | 
			
		||||
 | 
			
		||||
	if err := sess.
 | 
			
		||||
		Asc("`user`.name").
 | 
			
		||||
		Find(&orgCounts); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	orgs := make([]*MinimalOrg, len(orgCounts))
 | 
			
		||||
	for i, orgCount := range orgCounts {
 | 
			
		||||
		orgCount.Organization.NumRepos = orgCount.OrgCount
 | 
			
		||||
		orgs[i] = &orgCount.Organization
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return orgs, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func removeOrgUser(ctx context.Context, orgID, userID int64) error {
 | 
			
		||||
	ou := new(organization.OrgUser)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -25,12 +25,12 @@ import (
 | 
			
		||||
	"xorm.io/builder"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func addRepository(ctx context.Context, t *organization.Team, repo *repo_model.Repository) (err error) {
 | 
			
		||||
func AddRepository(ctx context.Context, t *organization.Team, repo *repo_model.Repository) (err error) {
 | 
			
		||||
	if err = organization.AddTeamRepo(ctx, t.OrgID, t.ID, repo.ID); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err = db.GetEngine(ctx).Incr("num_repos").ID(t.ID).Update(new(organization.Team)); err != nil {
 | 
			
		||||
	if err = organization.IncrTeamRepoNum(ctx, t.ID); err != nil {
 | 
			
		||||
		return fmt.Errorf("update team: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -58,16 +58,15 @@ func addRepository(ctx context.Context, t *organization.Team, repo *repo_model.R
 | 
			
		||||
// addAllRepositories adds all repositories to the team.
 | 
			
		||||
// If the team already has some repositories they will be left unchanged.
 | 
			
		||||
func addAllRepositories(ctx context.Context, t *organization.Team) error {
 | 
			
		||||
	var orgRepos []repo_model.Repository
 | 
			
		||||
	e := db.GetEngine(ctx)
 | 
			
		||||
	if err := e.Where("owner_id = ?", t.OrgID).Find(&orgRepos); err != nil {
 | 
			
		||||
	orgRepos, err := organization.GetOrgRepositories(ctx, t.OrgID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("get org repos: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, repo := range orgRepos {
 | 
			
		||||
		if !organization.HasTeamRepo(ctx, t.OrgID, t.ID, repo.ID) {
 | 
			
		||||
			if err := addRepository(ctx, t, &repo); err != nil {
 | 
			
		||||
				return fmt.Errorf("addRepository: %v", err)
 | 
			
		||||
			if err := AddRepository(ctx, t, repo); err != nil {
 | 
			
		||||
				return fmt.Errorf("AddRepository: %v", err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -90,27 +89,6 @@ func AddAllRepositories(t *organization.Team) (err error) {
 | 
			
		||||
	return committer.Commit()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddRepository adds new repository to team of organization.
 | 
			
		||||
func AddRepository(t *organization.Team, repo *repo_model.Repository) (err error) {
 | 
			
		||||
	if repo.OwnerID != t.OrgID {
 | 
			
		||||
		return errors.New("Repository does not belong to organization")
 | 
			
		||||
	} else if HasRepository(t, repo.ID) {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx, committer, err := db.TxContext()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer committer.Close()
 | 
			
		||||
 | 
			
		||||
	if err = addRepository(ctx, t, repo); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return committer.Commit()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RemoveAllRepositories removes all repositories from team and recalculates access
 | 
			
		||||
func RemoveAllRepositories(t *organization.Team) (err error) {
 | 
			
		||||
	if t.IncludesAllRepositories {
 | 
			
		||||
 
 | 
			
		||||
@@ -68,25 +68,6 @@ func TestTeam_HasRepository(t *testing.T) {
 | 
			
		||||
	test(2, 5, false)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestTeam_AddRepository(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	testSuccess := func(teamID, repoID int64) {
 | 
			
		||||
		team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID})
 | 
			
		||||
		repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID})
 | 
			
		||||
		assert.NoError(t, AddRepository(team, repo))
 | 
			
		||||
		unittest.AssertExistsAndLoadBean(t, &organization.TeamRepo{TeamID: teamID, RepoID: repoID})
 | 
			
		||||
		unittest.CheckConsistencyFor(t, &organization.Team{ID: teamID}, &repo_model.Repository{ID: repoID})
 | 
			
		||||
	}
 | 
			
		||||
	testSuccess(2, 3)
 | 
			
		||||
	testSuccess(2, 5)
 | 
			
		||||
 | 
			
		||||
	team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 1})
 | 
			
		||||
	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
 | 
			
		||||
	assert.Error(t, AddRepository(team, repo))
 | 
			
		||||
	unittest.CheckConsistencyFor(t, &organization.Team{ID: 1}, &repo_model.Repository{ID: 1})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestTeam_RemoveRepository(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										78
									
								
								models/organization/mini_org.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								models/organization/mini_org.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
			
		||||
// Copyright 2022 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 organization
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"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"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/builder"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// MinimalOrg represents a simple organization with only the needed columns
 | 
			
		||||
type MinimalOrg = Organization
 | 
			
		||||
 | 
			
		||||
// GetUserOrgsList returns all organizations the given user has access to
 | 
			
		||||
func GetUserOrgsList(user *user_model.User) ([]*MinimalOrg, error) {
 | 
			
		||||
	schema, err := db.TableInfo(new(user_model.User))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	outputCols := []string{
 | 
			
		||||
		"id",
 | 
			
		||||
		"name",
 | 
			
		||||
		"full_name",
 | 
			
		||||
		"visibility",
 | 
			
		||||
		"avatar",
 | 
			
		||||
		"avatar_email",
 | 
			
		||||
		"use_custom_avatar",
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	groupByCols := &strings.Builder{}
 | 
			
		||||
	for _, col := range outputCols {
 | 
			
		||||
		fmt.Fprintf(groupByCols, "`%s`.%s,", schema.Name, col)
 | 
			
		||||
	}
 | 
			
		||||
	groupByStr := groupByCols.String()
 | 
			
		||||
	groupByStr = groupByStr[0 : len(groupByStr)-1]
 | 
			
		||||
 | 
			
		||||
	sess := db.GetEngine(db.DefaultContext)
 | 
			
		||||
	sess = sess.Select(groupByStr+", count(distinct repo_id) as org_count").
 | 
			
		||||
		Table("user").
 | 
			
		||||
		Join("INNER", "team", "`team`.org_id = `user`.id").
 | 
			
		||||
		Join("INNER", "team_user", "`team`.id = `team_user`.team_id").
 | 
			
		||||
		Join("LEFT", builder.
 | 
			
		||||
			Select("id as repo_id, owner_id as repo_owner_id").
 | 
			
		||||
			From("repository").
 | 
			
		||||
			Where(repo_model.AccessibleRepositoryCondition(user, unit.TypeInvalid)), "`repository`.repo_owner_id = `team`.org_id").
 | 
			
		||||
		Where("`team_user`.uid = ?", user.ID).
 | 
			
		||||
		GroupBy(groupByStr)
 | 
			
		||||
 | 
			
		||||
	type OrgCount struct {
 | 
			
		||||
		Organization `xorm:"extends"`
 | 
			
		||||
		OrgCount     int
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	orgCounts := make([]*OrgCount, 0, 10)
 | 
			
		||||
 | 
			
		||||
	if err := sess.
 | 
			
		||||
		Asc("`user`.name").
 | 
			
		||||
		Find(&orgCounts); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	orgs := make([]*MinimalOrg, len(orgCounts))
 | 
			
		||||
	for i, orgCount := range orgCounts {
 | 
			
		||||
		orgCount.Organization.NumRepos = orgCount.OrgCount
 | 
			
		||||
		orgs[i] = &orgCount.Organization
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return orgs, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										18
									
								
								models/organization/org_repo.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								models/organization/org_repo.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
// Copyright 2022 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 organization
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// GetOrgRepositories get repos belonging to the given organization
 | 
			
		||||
func GetOrgRepositories(ctx context.Context, orgID int64) ([]*repo_model.Repository, error) {
 | 
			
		||||
	var orgRepos []*repo_model.Repository
 | 
			
		||||
	return orgRepos, db.GetEngine(ctx).Where("owner_id = ?", orgID).Find(&orgRepos)
 | 
			
		||||
}
 | 
			
		||||
@@ -359,3 +359,9 @@ func GetRepoTeams(ctx context.Context, repo *repo_model.Repository) (teams []*Te
 | 
			
		||||
		OrderBy("CASE WHEN name LIKE '" + OwnerTeamName + "' THEN '' ELSE name END").
 | 
			
		||||
		Find(&teams)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IncrTeamRepoNum increases the number of repos for the given team by 1
 | 
			
		||||
func IncrTeamRepoNum(ctx context.Context, teamID int64) error {
 | 
			
		||||
	_, err := db.GetEngine(ctx).Incr("num_repos").ID(teamID).Update(new(Team))
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,13 +7,10 @@ package access_test
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models"
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	perm_model "code.gitea.io/gitea/models/perm"
 | 
			
		||||
	access_model "code.gitea.io/gitea/models/perm/access"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	"code.gitea.io/gitea/models/unit"
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
 | 
			
		||||
@@ -128,249 +125,3 @@ func TestRepository_RecalculateAccesses2(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.False(t, has)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRepoPermissionPublicNonOrgRepo(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	// public non-organization repo
 | 
			
		||||
	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
 | 
			
		||||
	assert.NoError(t, repo.LoadUnits(db.DefaultContext))
 | 
			
		||||
 | 
			
		||||
	// plain user
 | 
			
		||||
	user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
 | 
			
		||||
	perm, err := access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	for _, unit := range repo.Units {
 | 
			
		||||
		assert.True(t, perm.CanRead(unit.Type))
 | 
			
		||||
		assert.False(t, perm.CanWrite(unit.Type))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// change to collaborator
 | 
			
		||||
	assert.NoError(t, models.AddCollaborator(repo, user))
 | 
			
		||||
	perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	for _, unit := range repo.Units {
 | 
			
		||||
		assert.True(t, perm.CanRead(unit.Type))
 | 
			
		||||
		assert.True(t, perm.CanWrite(unit.Type))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// collaborator
 | 
			
		||||
	collaborator := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
 | 
			
		||||
	perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, collaborator)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	for _, unit := range repo.Units {
 | 
			
		||||
		assert.True(t, perm.CanRead(unit.Type))
 | 
			
		||||
		assert.True(t, perm.CanWrite(unit.Type))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// owner
 | 
			
		||||
	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
 | 
			
		||||
	perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, owner)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	for _, unit := range repo.Units {
 | 
			
		||||
		assert.True(t, perm.CanRead(unit.Type))
 | 
			
		||||
		assert.True(t, perm.CanWrite(unit.Type))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// admin
 | 
			
		||||
	admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
 | 
			
		||||
	perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, admin)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	for _, unit := range repo.Units {
 | 
			
		||||
		assert.True(t, perm.CanRead(unit.Type))
 | 
			
		||||
		assert.True(t, perm.CanWrite(unit.Type))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	// private non-organization repo
 | 
			
		||||
	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
 | 
			
		||||
	assert.NoError(t, repo.LoadUnits(db.DefaultContext))
 | 
			
		||||
 | 
			
		||||
	// plain user
 | 
			
		||||
	user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
 | 
			
		||||
	perm, err := access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	for _, unit := range repo.Units {
 | 
			
		||||
		assert.False(t, perm.CanRead(unit.Type))
 | 
			
		||||
		assert.False(t, perm.CanWrite(unit.Type))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// change to collaborator to default write access
 | 
			
		||||
	assert.NoError(t, models.AddCollaborator(repo, user))
 | 
			
		||||
	perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	for _, unit := range repo.Units {
 | 
			
		||||
		assert.True(t, perm.CanRead(unit.Type))
 | 
			
		||||
		assert.True(t, perm.CanWrite(unit.Type))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, user.ID, perm_model.AccessModeRead))
 | 
			
		||||
	perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	for _, unit := range repo.Units {
 | 
			
		||||
		assert.True(t, perm.CanRead(unit.Type))
 | 
			
		||||
		assert.False(t, perm.CanWrite(unit.Type))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// owner
 | 
			
		||||
	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
 | 
			
		||||
	perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, owner)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	for _, unit := range repo.Units {
 | 
			
		||||
		assert.True(t, perm.CanRead(unit.Type))
 | 
			
		||||
		assert.True(t, perm.CanWrite(unit.Type))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// admin
 | 
			
		||||
	admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
 | 
			
		||||
	perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, admin)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	for _, unit := range repo.Units {
 | 
			
		||||
		assert.True(t, perm.CanRead(unit.Type))
 | 
			
		||||
		assert.True(t, perm.CanWrite(unit.Type))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRepoPermissionPublicOrgRepo(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	// public organization repo
 | 
			
		||||
	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 32})
 | 
			
		||||
	assert.NoError(t, repo.LoadUnits(db.DefaultContext))
 | 
			
		||||
 | 
			
		||||
	// plain user
 | 
			
		||||
	user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
 | 
			
		||||
	perm, err := access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	for _, unit := range repo.Units {
 | 
			
		||||
		assert.True(t, perm.CanRead(unit.Type))
 | 
			
		||||
		assert.False(t, perm.CanWrite(unit.Type))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// change to collaborator to default write access
 | 
			
		||||
	assert.NoError(t, models.AddCollaborator(repo, user))
 | 
			
		||||
	perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	for _, unit := range repo.Units {
 | 
			
		||||
		assert.True(t, perm.CanRead(unit.Type))
 | 
			
		||||
		assert.True(t, perm.CanWrite(unit.Type))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, user.ID, perm_model.AccessModeRead))
 | 
			
		||||
	perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	for _, unit := range repo.Units {
 | 
			
		||||
		assert.True(t, perm.CanRead(unit.Type))
 | 
			
		||||
		assert.False(t, perm.CanWrite(unit.Type))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// org member team owner
 | 
			
		||||
	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
 | 
			
		||||
	perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, owner)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	for _, unit := range repo.Units {
 | 
			
		||||
		assert.True(t, perm.CanRead(unit.Type))
 | 
			
		||||
		assert.True(t, perm.CanWrite(unit.Type))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// org member team tester
 | 
			
		||||
	member := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15})
 | 
			
		||||
	perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, member)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	for _, unit := range repo.Units {
 | 
			
		||||
		assert.True(t, perm.CanRead(unit.Type))
 | 
			
		||||
	}
 | 
			
		||||
	assert.True(t, perm.CanWrite(unit.TypeIssues))
 | 
			
		||||
	assert.False(t, perm.CanWrite(unit.TypeCode))
 | 
			
		||||
 | 
			
		||||
	// admin
 | 
			
		||||
	admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
 | 
			
		||||
	perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, admin)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	for _, unit := range repo.Units {
 | 
			
		||||
		assert.True(t, perm.CanRead(unit.Type))
 | 
			
		||||
		assert.True(t, perm.CanWrite(unit.Type))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRepoPermissionPrivateOrgRepo(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	// private organization repo
 | 
			
		||||
	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 24})
 | 
			
		||||
	assert.NoError(t, repo.LoadUnits(db.DefaultContext))
 | 
			
		||||
 | 
			
		||||
	// plain user
 | 
			
		||||
	user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
 | 
			
		||||
	perm, err := access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	for _, unit := range repo.Units {
 | 
			
		||||
		assert.False(t, perm.CanRead(unit.Type))
 | 
			
		||||
		assert.False(t, perm.CanWrite(unit.Type))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// change to collaborator to default write access
 | 
			
		||||
	assert.NoError(t, models.AddCollaborator(repo, user))
 | 
			
		||||
	perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	for _, unit := range repo.Units {
 | 
			
		||||
		assert.True(t, perm.CanRead(unit.Type))
 | 
			
		||||
		assert.True(t, perm.CanWrite(unit.Type))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, user.ID, perm_model.AccessModeRead))
 | 
			
		||||
	perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	for _, unit := range repo.Units {
 | 
			
		||||
		assert.True(t, perm.CanRead(unit.Type))
 | 
			
		||||
		assert.False(t, perm.CanWrite(unit.Type))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// org member team owner
 | 
			
		||||
	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15})
 | 
			
		||||
	perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, owner)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	for _, unit := range repo.Units {
 | 
			
		||||
		assert.True(t, perm.CanRead(unit.Type))
 | 
			
		||||
		assert.True(t, perm.CanWrite(unit.Type))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// update team information and then check permission
 | 
			
		||||
	team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 5})
 | 
			
		||||
	err = organization.UpdateTeamUnits(team, nil)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, owner)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	for _, unit := range repo.Units {
 | 
			
		||||
		assert.True(t, perm.CanRead(unit.Type))
 | 
			
		||||
		assert.True(t, perm.CanWrite(unit.Type))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// org member team tester
 | 
			
		||||
	tester := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
 | 
			
		||||
	perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, tester)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.True(t, perm.CanWrite(unit.TypeIssues))
 | 
			
		||||
	assert.False(t, perm.CanWrite(unit.TypeCode))
 | 
			
		||||
	assert.False(t, perm.CanRead(unit.TypeCode))
 | 
			
		||||
 | 
			
		||||
	// org member team reviewer
 | 
			
		||||
	reviewer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 20})
 | 
			
		||||
	perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, reviewer)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.False(t, perm.CanRead(unit.TypeIssues))
 | 
			
		||||
	assert.False(t, perm.CanWrite(unit.TypeCode))
 | 
			
		||||
	assert.True(t, perm.CanRead(unit.TypeCode))
 | 
			
		||||
 | 
			
		||||
	// admin
 | 
			
		||||
	admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
 | 
			
		||||
	perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, admin)
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	for _, unit := range repo.Units {
 | 
			
		||||
		assert.True(t, perm.CanRead(unit.Type))
 | 
			
		||||
		assert.True(t, perm.CanWrite(unit.Type))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -430,3 +430,17 @@ func IsRepoReader(ctx context.Context, repo *repo_model.Repository, userID int64
 | 
			
		||||
	}
 | 
			
		||||
	return db.GetEngine(ctx).Where("repo_id = ? AND user_id = ? AND mode >= ?", repo.ID, userID, perm_model.AccessModeRead).Get(&Access{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CheckRepoUnitUser check whether user could visit the unit of this repository
 | 
			
		||||
func CheckRepoUnitUser(ctx context.Context, repo *repo_model.Repository, user *user_model.User, unitType unit.Type) bool {
 | 
			
		||||
	if user != nil && user.IsAdmin {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	perm, err := GetUserRepoPermission(ctx, repo, user)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Error("GetUserRepoPermission: %w", err)
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return perm.CanRead(unitType)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										169
									
								
								models/repo.go
									
									
									
									
									
								
							
							
						
						
									
										169
									
								
								models/repo.go
									
									
									
									
									
								
							@@ -12,13 +12,13 @@ import (
 | 
			
		||||
 | 
			
		||||
	_ "image/jpeg" // Needed for jpeg support
 | 
			
		||||
 | 
			
		||||
	activities_model "code.gitea.io/gitea/models/activities"
 | 
			
		||||
	admin_model "code.gitea.io/gitea/models/admin"
 | 
			
		||||
	asymkey_model "code.gitea.io/gitea/models/asymkey"
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	git_model "code.gitea.io/gitea/models/git"
 | 
			
		||||
	issues_model "code.gitea.io/gitea/models/issues"
 | 
			
		||||
	"code.gitea.io/gitea/models/organization"
 | 
			
		||||
	"code.gitea.io/gitea/models/perm"
 | 
			
		||||
	access_model "code.gitea.io/gitea/models/perm/access"
 | 
			
		||||
	project_model "code.gitea.io/gitea/models/project"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
@@ -27,10 +27,7 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/models/webhook"
 | 
			
		||||
	"code.gitea.io/gitea/modules/lfs"
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
	"code.gitea.io/gitea/modules/storage"
 | 
			
		||||
	api "code.gitea.io/gitea/modules/structs"
 | 
			
		||||
	"code.gitea.io/gitea/modules/util"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/builder"
 | 
			
		||||
)
 | 
			
		||||
@@ -40,162 +37,6 @@ func NewRepoContext() {
 | 
			
		||||
	unit.LoadUnitConfig()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CheckRepoUnitUser check whether user could visit the unit of this repository
 | 
			
		||||
func CheckRepoUnitUser(ctx context.Context, repo *repo_model.Repository, user *user_model.User, unitType unit.Type) bool {
 | 
			
		||||
	if user != nil && user.IsAdmin {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	perm, err := access_model.GetUserRepoPermission(ctx, repo, user)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Error("GetUserRepoPermission(): %v", err)
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return perm.CanRead(unitType)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreateRepoOptions contains the create repository options
 | 
			
		||||
type CreateRepoOptions struct {
 | 
			
		||||
	Name           string
 | 
			
		||||
	Description    string
 | 
			
		||||
	OriginalURL    string
 | 
			
		||||
	GitServiceType api.GitServiceType
 | 
			
		||||
	Gitignores     string
 | 
			
		||||
	IssueLabels    string
 | 
			
		||||
	License        string
 | 
			
		||||
	Readme         string
 | 
			
		||||
	DefaultBranch  string
 | 
			
		||||
	IsPrivate      bool
 | 
			
		||||
	IsMirror       bool
 | 
			
		||||
	IsTemplate     bool
 | 
			
		||||
	AutoInit       bool
 | 
			
		||||
	Status         repo_model.RepositoryStatus
 | 
			
		||||
	TrustModel     repo_model.TrustModelType
 | 
			
		||||
	MirrorInterval string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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) {
 | 
			
		||||
	if err = repo_model.IsUsableRepoName(repo.Name); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	has, err := repo_model.IsRepositoryExist(ctx, u, repo.Name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("IsRepositoryExist: %v", err)
 | 
			
		||||
	} else if has {
 | 
			
		||||
		return repo_model.ErrRepoAlreadyExist{
 | 
			
		||||
			Uname: u.Name,
 | 
			
		||||
			Name:  repo.Name,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	repoPath := repo_model.RepoPath(u.Name, repo.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 {
 | 
			
		||||
		log.Error("Files already exist in %s and we are not going to adopt or delete.", repoPath)
 | 
			
		||||
		return repo_model.ErrRepoFilesAlreadyExist{
 | 
			
		||||
			Uname: u.Name,
 | 
			
		||||
			Name:  repo.Name,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = db.Insert(ctx, repo); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err = repo_model.DeleteRedirect(ctx, u.ID, repo.Name); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// insert units for repo
 | 
			
		||||
	units := make([]repo_model.RepoUnit, 0, len(unit.DefaultRepoUnits))
 | 
			
		||||
	for _, tp := range unit.DefaultRepoUnits {
 | 
			
		||||
		if tp == unit.TypeIssues {
 | 
			
		||||
			units = append(units, repo_model.RepoUnit{
 | 
			
		||||
				RepoID: repo.ID,
 | 
			
		||||
				Type:   tp,
 | 
			
		||||
				Config: &repo_model.IssuesConfig{
 | 
			
		||||
					EnableTimetracker:                setting.Service.DefaultEnableTimetracking,
 | 
			
		||||
					AllowOnlyContributorsToTrackTime: setting.Service.DefaultAllowOnlyContributorsToTrackTime,
 | 
			
		||||
					EnableDependencies:               setting.Service.DefaultEnableDependencies,
 | 
			
		||||
				},
 | 
			
		||||
			})
 | 
			
		||||
		} else if tp == unit.TypePullRequests {
 | 
			
		||||
			units = append(units, repo_model.RepoUnit{
 | 
			
		||||
				RepoID: repo.ID,
 | 
			
		||||
				Type:   tp,
 | 
			
		||||
				Config: &repo_model.PullRequestsConfig{AllowMerge: true, AllowRebase: true, AllowRebaseMerge: true, AllowSquash: true, DefaultMergeStyle: repo_model.MergeStyle(setting.Repository.PullRequest.DefaultMergeStyle), AllowRebaseUpdate: true},
 | 
			
		||||
			})
 | 
			
		||||
		} else {
 | 
			
		||||
			units = append(units, repo_model.RepoUnit{
 | 
			
		||||
				RepoID: repo.ID,
 | 
			
		||||
				Type:   tp,
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = db.Insert(ctx, units); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Remember visibility preference.
 | 
			
		||||
	u.LastRepoVisibility = repo.IsPrivate
 | 
			
		||||
	if err = user_model.UpdateUserCols(ctx, u, "last_repo_visibility"); err != nil {
 | 
			
		||||
		return fmt.Errorf("updateUser: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err = db.GetEngine(ctx).Incr("num_repos").ID(u.ID).Update(new(user_model.User)); err != nil {
 | 
			
		||||
		return fmt.Errorf("increment user total_repos: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	u.NumRepos++
 | 
			
		||||
 | 
			
		||||
	// Give access to all members in teams with access to all repositories.
 | 
			
		||||
	if u.IsOrganization() {
 | 
			
		||||
		teams, err := organization.FindOrgTeams(ctx, u.ID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return fmt.Errorf("loadTeams: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
		for _, t := range teams {
 | 
			
		||||
			if t.IncludesAllRepositories {
 | 
			
		||||
				if err := addRepository(ctx, t, repo); err != nil {
 | 
			
		||||
					return fmt.Errorf("addRepository: %v", err)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if isAdmin, err := access_model.IsUserRepoAdmin(ctx, repo, doer); err != nil {
 | 
			
		||||
			return fmt.Errorf("IsUserRepoAdminCtx: %v", err)
 | 
			
		||||
		} else if !isAdmin {
 | 
			
		||||
			// Make creator repo admin if it wasn't assigned automatically
 | 
			
		||||
			if err = addCollaborator(ctx, repo, doer); err != nil {
 | 
			
		||||
				return fmt.Errorf("AddCollaborator: %v", err)
 | 
			
		||||
			}
 | 
			
		||||
			if err = repo_model.ChangeCollaborationAccessModeCtx(ctx, repo, doer.ID, perm.AccessModeAdmin); err != nil {
 | 
			
		||||
				return fmt.Errorf("ChangeCollaborationAccessMode: %v", err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else if err = access_model.RecalculateAccesses(ctx, repo); err != nil {
 | 
			
		||||
		// Organization automatically called this in addRepository method.
 | 
			
		||||
		return fmt.Errorf("recalculateAccesses: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if setting.Service.AutoWatchNewRepos {
 | 
			
		||||
		if err = repo_model.WatchRepo(ctx, doer.ID, repo.ID, true); err != nil {
 | 
			
		||||
			return fmt.Errorf("watchRepo: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = webhook.CopyDefaultWebhooksToRepo(ctx, repo.ID); err != nil {
 | 
			
		||||
		return fmt.Errorf("copyDefaultWebhooksToRepo: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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)
 | 
			
		||||
func DeleteRepository(doer *user_model.User, uid, repoID int64) error {
 | 
			
		||||
@@ -279,7 +120,7 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error {
 | 
			
		||||
 | 
			
		||||
	if err := db.DeleteBeans(ctx,
 | 
			
		||||
		&access_model.Access{RepoID: repo.ID},
 | 
			
		||||
		&Action{RepoID: repo.ID},
 | 
			
		||||
		&activities_model.Action{RepoID: repo.ID},
 | 
			
		||||
		&repo_model.Collaboration{RepoID: repoID},
 | 
			
		||||
		&issues_model.Comment{RefRepoID: repoID},
 | 
			
		||||
		&git_model.CommitStatus{RepoID: repoID},
 | 
			
		||||
@@ -289,16 +130,16 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error {
 | 
			
		||||
		&repo_model.LanguageStat{RepoID: repoID},
 | 
			
		||||
		&issues_model.Milestone{RepoID: repoID},
 | 
			
		||||
		&repo_model.Mirror{RepoID: repoID},
 | 
			
		||||
		&Notification{RepoID: repoID},
 | 
			
		||||
		&activities_model.Notification{RepoID: repoID},
 | 
			
		||||
		&git_model.ProtectedBranch{RepoID: repoID},
 | 
			
		||||
		&git_model.ProtectedTag{RepoID: repoID},
 | 
			
		||||
		&repo_model.PushMirror{RepoID: repoID},
 | 
			
		||||
		&Release{RepoID: repoID},
 | 
			
		||||
		&repo_model.Release{RepoID: repoID},
 | 
			
		||||
		&repo_model.RepoIndexerStatus{RepoID: repoID},
 | 
			
		||||
		&repo_model.Redirect{RedirectRepoID: repoID},
 | 
			
		||||
		&repo_model.RepoUnit{RepoID: repoID},
 | 
			
		||||
		&repo_model.Star{RepoID: repoID},
 | 
			
		||||
		&Task{RepoID: repoID},
 | 
			
		||||
		&admin_model.Task{RepoID: repoID},
 | 
			
		||||
		&repo_model.Watch{RepoID: repoID},
 | 
			
		||||
		&webhook.Webhook{RepoID: repoID},
 | 
			
		||||
	); err != nil {
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package models
 | 
			
		||||
package repo
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
@@ -14,7 +14,6 @@ import (
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
	"code.gitea.io/gitea/modules/structs"
 | 
			
		||||
	"code.gitea.io/gitea/modules/timeutil"
 | 
			
		||||
@@ -23,14 +22,45 @@ import (
 | 
			
		||||
	"xorm.io/builder"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ErrReleaseAlreadyExist represents a "ReleaseAlreadyExist" kind of error.
 | 
			
		||||
type ErrReleaseAlreadyExist struct {
 | 
			
		||||
	TagName string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrReleaseAlreadyExist checks if an error is a ErrReleaseAlreadyExist.
 | 
			
		||||
func IsErrReleaseAlreadyExist(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrReleaseAlreadyExist)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrReleaseAlreadyExist) Error() string {
 | 
			
		||||
	return fmt.Sprintf("release tag already exist [tag_name: %s]", err.TagName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrReleaseNotExist represents a "ReleaseNotExist" kind of error.
 | 
			
		||||
type ErrReleaseNotExist struct {
 | 
			
		||||
	ID      int64
 | 
			
		||||
	TagName string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrReleaseNotExist checks if an error is a ErrReleaseNotExist.
 | 
			
		||||
func IsErrReleaseNotExist(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrReleaseNotExist)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrReleaseNotExist) Error() string {
 | 
			
		||||
	return fmt.Sprintf("release tag does not exist [id: %d, tag_name: %s]", err.ID, err.TagName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Release represents a release of repository.
 | 
			
		||||
type Release struct {
 | 
			
		||||
	ID               int64                  `xorm:"pk autoincr"`
 | 
			
		||||
	RepoID           int64                  `xorm:"INDEX UNIQUE(n)"`
 | 
			
		||||
	Repo             *repo_model.Repository `xorm:"-"`
 | 
			
		||||
	PublisherID      int64                  `xorm:"INDEX"`
 | 
			
		||||
	Publisher        *user_model.User       `xorm:"-"`
 | 
			
		||||
	TagName          string                 `xorm:"INDEX UNIQUE(n)"`
 | 
			
		||||
	ID               int64            `xorm:"pk autoincr"`
 | 
			
		||||
	RepoID           int64            `xorm:"INDEX UNIQUE(n)"`
 | 
			
		||||
	Repo             *Repository      `xorm:"-"`
 | 
			
		||||
	PublisherID      int64            `xorm:"INDEX"`
 | 
			
		||||
	Publisher        *user_model.User `xorm:"-"`
 | 
			
		||||
	TagName          string           `xorm:"INDEX UNIQUE(n)"`
 | 
			
		||||
	OriginalAuthor   string
 | 
			
		||||
	OriginalAuthorID int64 `xorm:"index"`
 | 
			
		||||
	LowerTagName     string
 | 
			
		||||
@@ -38,14 +68,14 @@ type Release struct {
 | 
			
		||||
	Title            string
 | 
			
		||||
	Sha1             string `xorm:"VARCHAR(40)"`
 | 
			
		||||
	NumCommits       int64
 | 
			
		||||
	NumCommitsBehind int64                    `xorm:"-"`
 | 
			
		||||
	Note             string                   `xorm:"TEXT"`
 | 
			
		||||
	RenderedNote     string                   `xorm:"-"`
 | 
			
		||||
	IsDraft          bool                     `xorm:"NOT NULL DEFAULT false"`
 | 
			
		||||
	IsPrerelease     bool                     `xorm:"NOT NULL DEFAULT false"`
 | 
			
		||||
	IsTag            bool                     `xorm:"NOT NULL DEFAULT false"`
 | 
			
		||||
	Attachments      []*repo_model.Attachment `xorm:"-"`
 | 
			
		||||
	CreatedUnix      timeutil.TimeStamp       `xorm:"INDEX"`
 | 
			
		||||
	NumCommitsBehind int64              `xorm:"-"`
 | 
			
		||||
	Note             string             `xorm:"TEXT"`
 | 
			
		||||
	RenderedNote     string             `xorm:"-"`
 | 
			
		||||
	IsDraft          bool               `xorm:"NOT NULL DEFAULT false"`
 | 
			
		||||
	IsPrerelease     bool               `xorm:"NOT NULL DEFAULT false"`
 | 
			
		||||
	IsTag            bool               `xorm:"NOT NULL DEFAULT false"`
 | 
			
		||||
	Attachments      []*Attachment      `xorm:"-"`
 | 
			
		||||
	CreatedUnix      timeutil.TimeStamp `xorm:"INDEX"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
@@ -55,7 +85,7 @@ func init() {
 | 
			
		||||
func (r *Release) loadAttributes(ctx context.Context) error {
 | 
			
		||||
	var err error
 | 
			
		||||
	if r.Repo == nil {
 | 
			
		||||
		r.Repo, err = repo_model.GetRepositoryByIDCtx(ctx, r.RepoID)
 | 
			
		||||
		r.Repo, err = GetRepositoryByIDCtx(ctx, r.RepoID)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
@@ -116,7 +146,7 @@ func UpdateRelease(ctx context.Context, rel *Release) error {
 | 
			
		||||
// AddReleaseAttachments adds a release attachments
 | 
			
		||||
func AddReleaseAttachments(ctx context.Context, releaseID int64, attachmentUUIDs []string) (err error) {
 | 
			
		||||
	// Check attachments
 | 
			
		||||
	attachments, err := repo_model.GetAttachmentsByUUIDs(ctx, attachmentUUIDs)
 | 
			
		||||
	attachments, err := GetAttachmentsByUUIDs(ctx, attachmentUUIDs)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("GetAttachmentsByUUIDs [uuids: %v]: %v", attachmentUUIDs, err)
 | 
			
		||||
	}
 | 
			
		||||
@@ -279,9 +309,9 @@ func GetReleaseAttachments(ctx context.Context, rels ...*Release) (err error) {
 | 
			
		||||
 | 
			
		||||
	// Sort
 | 
			
		||||
	sortedRels := releaseMetaSearch{ID: make([]int64, len(rels)), Rel: make([]*Release, len(rels))}
 | 
			
		||||
	var attachments []*repo_model.Attachment
 | 
			
		||||
	var attachments []*Attachment
 | 
			
		||||
	for index, element := range rels {
 | 
			
		||||
		element.Attachments = []*repo_model.Attachment{}
 | 
			
		||||
		element.Attachments = []*Attachment{}
 | 
			
		||||
		sortedRels.ID[index] = element.ID
 | 
			
		||||
		sortedRels.Rel[index] = element
 | 
			
		||||
	}
 | 
			
		||||
@@ -291,7 +321,7 @@ func GetReleaseAttachments(ctx context.Context, rels ...*Release) (err error) {
 | 
			
		||||
	err = db.GetEngine(ctx).
 | 
			
		||||
		Asc("release_id", "name").
 | 
			
		||||
		In("release_id", sortedRels.ID).
 | 
			
		||||
		Find(&attachments, repo_model.Attachment{})
 | 
			
		||||
		Find(&attachments, Attachment{})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
@@ -354,7 +384,7 @@ func UpdateReleasesMigrationsByType(gitServiceType structs.GitServiceType, origi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PushUpdateDeleteTagsContext updates a number of delete tags with context
 | 
			
		||||
func PushUpdateDeleteTagsContext(ctx context.Context, repo *repo_model.Repository, tags []string) error {
 | 
			
		||||
func PushUpdateDeleteTagsContext(ctx context.Context, repo *Repository, tags []string) error {
 | 
			
		||||
	if len(tags) == 0 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
@@ -384,7 +414,7 @@ func PushUpdateDeleteTagsContext(ctx context.Context, repo *repo_model.Repositor
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PushUpdateDeleteTag must be called for any push actions to delete tag
 | 
			
		||||
func PushUpdateDeleteTag(repo *repo_model.Repository, tagName string) error {
 | 
			
		||||
func PushUpdateDeleteTag(repo *Repository, tagName string) error {
 | 
			
		||||
	rel, err := GetRelease(repo.ID, tagName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if IsErrReleaseNotExist(err) {
 | 
			
		||||
@@ -409,7 +439,7 @@ func PushUpdateDeleteTag(repo *repo_model.Repository, tagName string) error {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SaveOrUpdateTag must be called for any push actions to add tag
 | 
			
		||||
func SaveOrUpdateTag(repo *repo_model.Repository, newRel *Release) error {
 | 
			
		||||
func SaveOrUpdateTag(repo *Repository, newRel *Release) error {
 | 
			
		||||
	rel, err := GetRelease(repo.ID, newRel.TagName)
 | 
			
		||||
	if err != nil && !IsErrReleaseNotExist(err) {
 | 
			
		||||
		return fmt.Errorf("GetRelease: %v", err)
 | 
			
		||||
@@ -23,6 +23,8 @@ import (
 | 
			
		||||
	api "code.gitea.io/gitea/modules/structs"
 | 
			
		||||
	"code.gitea.io/gitea/modules/timeutil"
 | 
			
		||||
	"code.gitea.io/gitea/modules/util"
 | 
			
		||||
 | 
			
		||||
	"xorm.io/builder"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ErrUserDoesNotHaveAccessToRepo represets an error where the user doesn't has access to a given repo.
 | 
			
		||||
@@ -784,3 +786,15 @@ func UpdateRepoIssueNumbers(ctx context.Context, repoID int64, isPull, isClosed
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CountNullArchivedRepository counts the number of repositories with is_archived is null
 | 
			
		||||
func CountNullArchivedRepository() (int64, error) {
 | 
			
		||||
	return db.GetEngine(db.DefaultContext).Where(builder.IsNull{"is_archived"}).Count(new(Repository))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FixNullArchivedRepository sets is_archived to false where it is null
 | 
			
		||||
func FixNullArchivedRepository() (int64, error) {
 | 
			
		||||
	return db.GetEngine(db.DefaultContext).Where(builder.IsNull{"is_archived"}).Cols("is_archived").NoAutoTime().Update(&Repository{
 | 
			
		||||
		IsArchived: false,
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package models
 | 
			
		||||
package repo
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
@@ -20,13 +20,21 @@ import (
 | 
			
		||||
	gouuid "github.com/google/uuid"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//  ____ ___        .__                    .___ ___________.___.__
 | 
			
		||||
// |    |   \______ |  |   _________     __| _/ \_   _____/|   |  |   ____   ______
 | 
			
		||||
// |    |   /\____ \|  |  /  _ \__  \   / __ |   |    __)  |   |  | _/ __ \ /  ___/
 | 
			
		||||
// |    |  / |  |_> >  |_(  <_> ) __ \_/ /_/ |   |     \   |   |  |_\  ___/ \___ \
 | 
			
		||||
// |______/  |   __/|____/\____(____  /\____ |   \___  /   |___|____/\___  >____  >
 | 
			
		||||
//           |__|                   \/      \/       \/                  \/     \/
 | 
			
		||||
//
 | 
			
		||||
// ErrUploadNotExist represents a "UploadNotExist" kind of error.
 | 
			
		||||
type ErrUploadNotExist struct {
 | 
			
		||||
	ID   int64
 | 
			
		||||
	UUID string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrUploadNotExist checks if an error is a ErrUploadNotExist.
 | 
			
		||||
func IsErrUploadNotExist(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrUploadNotExist)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrUploadNotExist) Error() string {
 | 
			
		||||
	return fmt.Sprintf("attachment does not exist [id: %d, uuid: %s]", err.ID, err.UUID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Upload represent a uploaded file to a repo to be deleted when moved
 | 
			
		||||
type Upload struct {
 | 
			
		||||
@@ -6,6 +6,7 @@
 | 
			
		||||
package repo
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
@@ -14,6 +15,51 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/modules/util"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ErrWikiAlreadyExist represents a "WikiAlreadyExist" kind of error.
 | 
			
		||||
type ErrWikiAlreadyExist struct {
 | 
			
		||||
	Title string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrWikiAlreadyExist checks if an error is an ErrWikiAlreadyExist.
 | 
			
		||||
func IsErrWikiAlreadyExist(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrWikiAlreadyExist)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrWikiAlreadyExist) Error() string {
 | 
			
		||||
	return fmt.Sprintf("wiki page already exists [title: %s]", err.Title)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrWikiReservedName represents a reserved name error.
 | 
			
		||||
type ErrWikiReservedName struct {
 | 
			
		||||
	Title string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrWikiReservedName checks if an error is an ErrWikiReservedName.
 | 
			
		||||
func IsErrWikiReservedName(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrWikiReservedName)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrWikiReservedName) Error() string {
 | 
			
		||||
	return fmt.Sprintf("wiki title is reserved: %s", err.Title)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrWikiInvalidFileName represents an invalid wiki file name.
 | 
			
		||||
type ErrWikiInvalidFileName struct {
 | 
			
		||||
	FileName string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsErrWikiInvalidFileName checks if an error is an ErrWikiInvalidFileName.
 | 
			
		||||
func IsErrWikiInvalidFileName(err error) bool {
 | 
			
		||||
	_, ok := err.(ErrWikiInvalidFileName)
 | 
			
		||||
	return ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err ErrWikiInvalidFileName) Error() string {
 | 
			
		||||
	return fmt.Sprintf("Invalid wiki filename: %s", err.FileName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WikiCloneLink returns clone URLs of repository wiki.
 | 
			
		||||
func (repo *Repository) WikiCloneLink() *CloneLink {
 | 
			
		||||
	return repo.cloneLink(true)
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,6 @@ import (
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	issues_model "code.gitea.io/gitea/models/issues"
 | 
			
		||||
	"code.gitea.io/gitea/models/perm"
 | 
			
		||||
	access_model "code.gitea.io/gitea/models/perm/access"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
@@ -19,42 +18,6 @@ import (
 | 
			
		||||
	"xorm.io/builder"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func addCollaborator(ctx context.Context, repo *repo_model.Repository, u *user_model.User) error {
 | 
			
		||||
	collaboration := &repo_model.Collaboration{
 | 
			
		||||
		RepoID: repo.ID,
 | 
			
		||||
		UserID: u.ID,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	has, err := db.GetByBean(ctx, collaboration)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	} else if has {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	collaboration.Mode = perm.AccessModeWrite
 | 
			
		||||
 | 
			
		||||
	if err = db.Insert(ctx, collaboration); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return access_model.RecalculateUserAccess(ctx, repo, u.ID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddCollaborator adds new collaboration to a repository with default access mode.
 | 
			
		||||
func AddCollaborator(repo *repo_model.Repository, u *user_model.User) error {
 | 
			
		||||
	ctx, committer, err := db.TxContext()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer committer.Close()
 | 
			
		||||
 | 
			
		||||
	if err := addCollaborator(ctx, repo, u); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return committer.Commit()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeleteCollaboration removes collaboration relation between the user and repository.
 | 
			
		||||
func DeleteCollaboration(repo *repo_model.Repository, uid int64) (err error) {
 | 
			
		||||
	collaboration := &repo_model.Collaboration{
 | 
			
		||||
 
 | 
			
		||||
@@ -10,26 +10,10 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
			
		||||
	"code.gitea.io/gitea/models/unittest"
 | 
			
		||||
	user_model "code.gitea.io/gitea/models/user"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestRepository_AddCollaborator(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	testSuccess := func(repoID, userID int64) {
 | 
			
		||||
		repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID})
 | 
			
		||||
		assert.NoError(t, repo.GetOwner(db.DefaultContext))
 | 
			
		||||
		user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID})
 | 
			
		||||
		assert.NoError(t, AddCollaborator(repo, user))
 | 
			
		||||
		unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repoID}, &user_model.User{ID: userID})
 | 
			
		||||
	}
 | 
			
		||||
	testSuccess(1, 4)
 | 
			
		||||
	testSuccess(1, 4)
 | 
			
		||||
	testSuccess(3, 4)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRepository_DeleteCollaboration(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, unittest.PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -327,8 +327,8 @@ func TransferOwnership(doer *user_model.User, newOwnerName string, repo *repo_mo
 | 
			
		||||
		}
 | 
			
		||||
		for _, t := range teams {
 | 
			
		||||
			if t.IncludesAllRepositories {
 | 
			
		||||
				if err := addRepository(ctx, t, repo); err != nil {
 | 
			
		||||
					return fmt.Errorf("addRepository: %v", err)
 | 
			
		||||
				if err := AddRepository(ctx, t, repo); err != nil {
 | 
			
		||||
					return fmt.Errorf("AddRepository: %v", err)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@ import (
 | 
			
		||||
 | 
			
		||||
	_ "image/jpeg" // Needed for jpeg support
 | 
			
		||||
 | 
			
		||||
	activities_model "code.gitea.io/gitea/models/activities"
 | 
			
		||||
	asymkey_model "code.gitea.io/gitea/models/asymkey"
 | 
			
		||||
	auth_model "code.gitea.io/gitea/models/auth"
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
@@ -70,14 +71,14 @@ func DeleteUser(ctx context.Context, u *user_model.User, purge bool) (err error)
 | 
			
		||||
	// ***** END: Follow *****
 | 
			
		||||
 | 
			
		||||
	if err = db.DeleteBeans(ctx,
 | 
			
		||||
		&AccessToken{UID: u.ID},
 | 
			
		||||
		&auth_model.AccessToken{UID: u.ID},
 | 
			
		||||
		&repo_model.Collaboration{UserID: u.ID},
 | 
			
		||||
		&access_model.Access{UserID: u.ID},
 | 
			
		||||
		&repo_model.Watch{UserID: u.ID},
 | 
			
		||||
		&repo_model.Star{UID: u.ID},
 | 
			
		||||
		&user_model.Follow{UserID: u.ID},
 | 
			
		||||
		&user_model.Follow{FollowID: u.ID},
 | 
			
		||||
		&Action{UserID: u.ID},
 | 
			
		||||
		&activities_model.Action{UserID: u.ID},
 | 
			
		||||
		&issues_model.IssueUser{UID: u.ID},
 | 
			
		||||
		&user_model.EmailAddress{UID: u.ID},
 | 
			
		||||
		&user_model.UserOpenID{UID: u.ID},
 | 
			
		||||
 
 | 
			
		||||
@@ -1317,6 +1317,16 @@ func IsUserVisibleToViewer(ctx context.Context, u, viewer *User) bool {
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CountWrongUserType count OrgUser who have wrong type
 | 
			
		||||
func CountWrongUserType() (int64, error) {
 | 
			
		||||
	return db.GetEngine(db.DefaultContext).Where(builder.Eq{"type": 0}.And(builder.Neq{"num_teams": 0})).Count(new(User))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FixWrongUserType fix OrgUser who have wrong type
 | 
			
		||||
func FixWrongUserType() (int64, error) {
 | 
			
		||||
	return db.GetEngine(db.DefaultContext).Where(builder.Eq{"type": 0}.And(builder.Neq{"num_teams": 0})).Cols("type").NoAutoTime().Update(&User{Type: 1})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func GetOrderByName() string {
 | 
			
		||||
	if setting.UI.DefaultShowFullName {
 | 
			
		||||
		return "full_name, name"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								models/user/user_update.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								models/user/user_update.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
// Copyright 2022 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 user
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models/db"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func IncrUserRepoNum(ctx context.Context, userID int64) error {
 | 
			
		||||
	_, err := db.GetEngine(ctx).Incr("num_repos").ID(userID).Update(new(User))
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user