summaryrefslogtreecommitdiffstats
path: root/models
diff options
context:
space:
mode:
authorLunny Xiao <xiaolunwen@gmail.com>2023-11-24 11:49:41 +0800
committerGitHub <noreply@github.com>2023-11-24 03:49:41 +0000
commitdf1e7d0067bb39913eb681ccc920649884fb1938 (patch)
tree2419feab5c28658adb7f71878df646bdc9bdc50e /models
parentd24a8223ce1e47a0c9b103aae07f67c3112ca048 (diff)
downloadgitea-df1e7d0067bb39913eb681ccc920649884fb1938.tar.gz
gitea-df1e7d0067bb39913eb681ccc920649884fb1938.zip
Use db.Find instead of writing methods for every object (#28084)
For those simple objects, it's unnecessary to write the find and count methods again and again.
Diffstat (limited to 'models')
-rw-r--r--models/actions/artifact.go50
-rw-r--r--models/actions/run.go4
-rw-r--r--models/actions/run_job_list.go16
-rw-r--r--models/actions/run_list.go16
-rw-r--r--models/actions/runner.go23
-rw-r--r--models/actions/schedule_list.go16
-rw-r--r--models/actions/schedule_spec_list.go19
-rw-r--r--models/actions/task_list.go17
-rw-r--r--models/actions/variable.go11
-rw-r--r--models/activities/notification.go207
-rw-r--r--models/activities/notification_test.go23
-rw-r--r--models/activities/statistic.go4
-rw-r--r--models/asymkey/ssh_key.go63
-rw-r--r--models/asymkey/ssh_key_commit_verification.go5
-rw-r--r--models/asymkey/ssh_key_deploy.go22
-rw-r--r--models/auth/access_token.go37
-rw-r--r--models/auth/access_token_test.go6
-rw-r--r--models/auth/oauth2.go28
-rw-r--r--models/auth/oauth2_list.go32
-rw-r--r--models/auth/source.go20
-rw-r--r--models/db/context.go5
-rw-r--r--models/db/list.go80
-rw-r--r--models/db/list_test.go13
-rw-r--r--models/issues/comment.go2
-rw-r--r--models/organization/org.go21
-rw-r--r--models/organization/org_test.go8
-rw-r--r--models/project/project.go25
-rw-r--r--models/project/project_test.go6
-rw-r--r--models/secret/secret.go18
-rw-r--r--models/user/external_login_user.go36
-rw-r--r--models/webhook/webhook.go23
-rw-r--r--models/webhook/webhook_test.go8
32 files changed, 369 insertions, 495 deletions
diff --git a/models/actions/artifact.go b/models/actions/artifact.go
index 849a90fd10..42bd9c23cb 100644
--- a/models/actions/artifact.go
+++ b/models/actions/artifact.go
@@ -14,6 +14,8 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
+
+ "xorm.io/builder"
)
// ArtifactStatus is the status of an artifact, uploading, expired or need-delete
@@ -108,29 +110,37 @@ func UpdateArtifactByID(ctx context.Context, id int64, art *ActionArtifact) erro
return err
}
-// ListArtifactsByRunID returns all artifacts of a run
-func ListArtifactsByRunID(ctx context.Context, runID int64) ([]*ActionArtifact, error) {
- arts := make([]*ActionArtifact, 0, 10)
- return arts, db.GetEngine(ctx).Where("run_id=?", runID).Find(&arts)
+type FindArtifactsOptions struct {
+ db.ListOptions
+ RepoID int64
+ RunID int64
+ ArtifactName string
+ Status int
}
-// ListArtifactsByRunIDAndArtifactName returns an artifacts of a run by artifact name
-func ListArtifactsByRunIDAndArtifactName(ctx context.Context, runID int64, artifactName string) ([]*ActionArtifact, error) {
- arts := make([]*ActionArtifact, 0, 10)
- return arts, db.GetEngine(ctx).Where("run_id=? AND artifact_name=?", runID, artifactName).Find(&arts)
-}
+func (opts FindArtifactsOptions) ToConds() builder.Cond {
+ cond := builder.NewCond()
+ if opts.RepoID > 0 {
+ cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
+ }
+ if opts.RunID > 0 {
+ cond = cond.And(builder.Eq{"run_id": opts.RunID})
+ }
+ if opts.ArtifactName != "" {
+ cond = cond.And(builder.Eq{"artifact_name": opts.ArtifactName})
+ }
+ if opts.Status > 0 {
+ cond = cond.And(builder.Eq{"status": opts.Status})
+ }
-// ListUploadedArtifactsByRunID returns all uploaded artifacts of a run
-func ListUploadedArtifactsByRunID(ctx context.Context, runID int64) ([]*ActionArtifact, error) {
- arts := make([]*ActionArtifact, 0, 10)
- return arts, db.GetEngine(ctx).Where("run_id=? AND status=?", runID, ArtifactStatusUploadConfirmed).Find(&arts)
+ return cond
}
// ActionArtifactMeta is the meta data of an artifact
type ActionArtifactMeta struct {
ArtifactName string
FileSize int64
- Status int64
+ Status ArtifactStatus
}
// ListUploadedArtifactsMeta returns all uploaded artifacts meta of a run
@@ -143,18 +153,6 @@ func ListUploadedArtifactsMeta(ctx context.Context, runID int64) ([]*ActionArtif
Find(&arts)
}
-// ListArtifactsByRepoID returns all artifacts of a repo
-func ListArtifactsByRepoID(ctx context.Context, repoID int64) ([]*ActionArtifact, error) {
- arts := make([]*ActionArtifact, 0, 10)
- return arts, db.GetEngine(ctx).Where("repo_id=?", repoID).Find(&arts)
-}
-
-// ListArtifactsByRunIDAndName returns artifacts by name of a run
-func ListArtifactsByRunIDAndName(ctx context.Context, runID int64, name string) ([]*ActionArtifact, error) {
- arts := make([]*ActionArtifact, 0, 10)
- return arts, db.GetEngine(ctx).Where("run_id=? AND artifact_name=?", runID, name).Find(&arts)
-}
-
// ListNeedExpiredArtifacts returns all need expired artifacts but not deleted
func ListNeedExpiredArtifacts(ctx context.Context) ([]*ActionArtifact, error) {
arts := make([]*ActionArtifact, 0, 10)
diff --git a/models/actions/run.go b/models/actions/run.go
index 8078613fb8..4656aa22a2 100644
--- a/models/actions/run.go
+++ b/models/actions/run.go
@@ -170,7 +170,7 @@ func updateRepoRunsNumbers(ctx context.Context, repo *repo_model.Repository) err
// CancelRunningJobs cancels all running and waiting jobs associated with a specific workflow.
func CancelRunningJobs(ctx context.Context, repoID int64, ref, workflowID string) error {
// Find all runs in the specified repository, reference, and workflow with statuses 'Running' or 'Waiting'.
- runs, total, err := FindRuns(ctx, FindRunOptions{
+ runs, total, err := db.FindAndCount[ActionRun](ctx, FindRunOptions{
RepoID: repoID,
Ref: ref,
WorkflowID: workflowID,
@@ -188,7 +188,7 @@ func CancelRunningJobs(ctx context.Context, repoID int64, ref, workflowID string
// Iterate over each found run and cancel its associated jobs.
for _, run := range runs {
// Find all jobs associated with the current run.
- jobs, _, err := FindRunJobs(ctx, FindRunJobOptions{
+ jobs, err := db.Find[ActionRunJob](ctx, FindRunJobOptions{
RunID: run.ID,
})
if err != nil {
diff --git a/models/actions/run_job_list.go b/models/actions/run_job_list.go
index a166396694..6ea6cb9d3b 100644
--- a/models/actions/run_job_list.go
+++ b/models/actions/run_job_list.go
@@ -61,7 +61,7 @@ type FindRunJobOptions struct {
UpdatedBefore timeutil.TimeStamp
}
-func (opts FindRunJobOptions) toConds() builder.Cond {
+func (opts FindRunJobOptions) ToConds() builder.Cond {
cond := builder.NewCond()
if opts.RunID > 0 {
cond = cond.And(builder.Eq{"run_id": opts.RunID})
@@ -83,17 +83,3 @@ func (opts FindRunJobOptions) toConds() builder.Cond {
}
return cond
}
-
-func FindRunJobs(ctx context.Context, opts FindRunJobOptions) (ActionJobList, int64, error) {
- e := db.GetEngine(ctx).Where(opts.toConds())
- if opts.PageSize > 0 && opts.Page >= 1 {
- e.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
- }
- var tasks ActionJobList
- total, err := e.FindAndCount(&tasks)
- return tasks, total, err
-}
-
-func CountRunJobs(ctx context.Context, opts FindRunJobOptions) (int64, error) {
- return db.GetEngine(ctx).Where(opts.toConds()).Count(new(ActionRunJob))
-}
diff --git a/models/actions/run_list.go b/models/actions/run_list.go
index cd053ea7b5..375c46221b 100644
--- a/models/actions/run_list.go
+++ b/models/actions/run_list.go
@@ -75,7 +75,7 @@ type FindRunOptions struct {
Status []Status
}
-func (opts FindRunOptions) toConds() builder.Cond {
+func (opts FindRunOptions) ToConds() builder.Cond {
cond := builder.NewCond()
if opts.RepoID > 0 {
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
@@ -101,18 +101,8 @@ func (opts FindRunOptions) toConds() builder.Cond {
return cond
}
-func FindRuns(ctx context.Context, opts FindRunOptions) (RunList, int64, error) {
- e := db.GetEngine(ctx).Where(opts.toConds())
- if opts.PageSize > 0 && opts.Page >= 1 {
- e.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
- }
- var runs RunList
- total, err := e.Desc("id").FindAndCount(&runs)
- return runs, total, err
-}
-
-func CountRuns(ctx context.Context, opts FindRunOptions) (int64, error) {
- return db.GetEngine(ctx).Where(opts.toConds()).Count(new(ActionRun))
+func (opts FindRunOptions) ToOrders() string {
+ return "`id` DESC"
}
type StatusInfo struct {
diff --git a/models/actions/runner.go b/models/actions/runner.go
index 2c092c2b4a..717b770800 100644
--- a/models/actions/runner.go
+++ b/models/actions/runner.go
@@ -156,7 +156,7 @@ type FindRunnerOptions struct {
WithAvailable bool // not only runners belong to, but also runners can be used
}
-func (opts FindRunnerOptions) toCond() builder.Cond {
+func (opts FindRunnerOptions) ToConds() builder.Cond {
cond := builder.NewCond()
if opts.RepoID > 0 {
@@ -181,7 +181,7 @@ func (opts FindRunnerOptions) toCond() builder.Cond {
return cond
}
-func (opts FindRunnerOptions) toOrder() string {
+func (opts FindRunnerOptions) ToOrders() string {
switch opts.Sort {
case "online":
return "last_online DESC"
@@ -199,22 +199,6 @@ func (opts FindRunnerOptions) toOrder() string {
return "last_online DESC"
}
-func CountRunners(ctx context.Context, opts FindRunnerOptions) (int64, error) {
- return db.GetEngine(ctx).
- Where(opts.toCond()).
- Count(ActionRunner{})
-}
-
-func FindRunners(ctx context.Context, opts FindRunnerOptions) (runners RunnerList, err error) {
- sess := db.GetEngine(ctx).
- Where(opts.toCond()).
- OrderBy(opts.toOrder())
- if opts.Page > 0 {
- sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
- }
- return runners, sess.Find(&runners)
-}
-
// GetRunnerByUUID returns a runner via uuid
func GetRunnerByUUID(ctx context.Context, uuid string) (*ActionRunner, error) {
var runner ActionRunner
@@ -263,8 +247,7 @@ func DeleteRunner(ctx context.Context, id int64) error {
// CreateRunner creates new runner.
func CreateRunner(ctx context.Context, t *ActionRunner) error {
- _, err := db.GetEngine(ctx).Insert(t)
- return err
+ return db.Insert(ctx, t)
}
func CountRunnersWithoutBelongingOwner(ctx context.Context) (int64, error) {
diff --git a/models/actions/schedule_list.go b/models/actions/schedule_list.go
index ddd9a1321e..b806550b87 100644
--- a/models/actions/schedule_list.go
+++ b/models/actions/schedule_list.go
@@ -67,7 +67,7 @@ type FindScheduleOptions struct {
OwnerID int64
}
-func (opts FindScheduleOptions) toConds() builder.Cond {
+func (opts FindScheduleOptions) ToConds() builder.Cond {
cond := builder.NewCond()
if opts.RepoID > 0 {
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
@@ -79,16 +79,6 @@ func (opts FindScheduleOptions) toConds() builder.Cond {
return cond
}
-func FindSchedules(ctx context.Context, opts FindScheduleOptions) (ScheduleList, int64, error) {
- e := db.GetEngine(ctx).Where(opts.toConds())
- if !opts.ListAll && opts.PageSize > 0 && opts.Page >= 1 {
- e.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
- }
- var schedules ScheduleList
- total, err := e.Desc("id").FindAndCount(&schedules)
- return schedules, total, err
-}
-
-func CountSchedules(ctx context.Context, opts FindScheduleOptions) (int64, error) {
- return db.GetEngine(ctx).Where(opts.toConds()).Count(new(ActionSchedule))
+func (opts FindScheduleOptions) ToOrders() string {
+ return "`id` DESC"
}
diff --git a/models/actions/schedule_spec_list.go b/models/actions/schedule_spec_list.go
index 6bf91cf819..e9ae268a6e 100644
--- a/models/actions/schedule_spec_list.go
+++ b/models/actions/schedule_spec_list.go
@@ -71,7 +71,7 @@ type FindSpecOptions struct {
Next int64
}
-func (opts FindSpecOptions) toConds() builder.Cond {
+func (opts FindSpecOptions) ToConds() builder.Cond {
cond := builder.NewCond()
if opts.RepoID > 0 {
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
@@ -84,23 +84,18 @@ func (opts FindSpecOptions) toConds() builder.Cond {
return cond
}
+func (opts FindSpecOptions) ToOrders() string {
+ return "`id` DESC"
+}
+
func FindSpecs(ctx context.Context, opts FindSpecOptions) (SpecList, int64, error) {
- e := db.GetEngine(ctx).Where(opts.toConds())
- if opts.PageSize > 0 && opts.Page >= 1 {
- e.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
- }
- var specs SpecList
- total, err := e.Desc("id").FindAndCount(&specs)
+ specs, total, err := db.FindAndCount[ActionScheduleSpec](ctx, opts)
if err != nil {
return nil, 0, err
}
- if err := specs.LoadSchedules(ctx); err != nil {
+ if err := SpecList(specs).LoadSchedules(ctx); err != nil {
return nil, 0, err
}
return specs, total, nil
}
-
-func CountSpecs(ctx context.Context, opts FindSpecOptions) (int64, error) {
- return db.GetEngine(ctx).Where(opts.toConds()).Count(new(ActionScheduleSpec))
-}
diff --git a/models/actions/task_list.go b/models/actions/task_list.go
index 1f6b16772b..b07d00b8db 100644
--- a/models/actions/task_list.go
+++ b/models/actions/task_list.go
@@ -62,7 +62,7 @@ type FindTaskOptions struct {
IDOrderDesc bool
}
-func (opts FindTaskOptions) toConds() builder.Cond {
+func (opts FindTaskOptions) ToConds() builder.Cond {
cond := builder.NewCond()
if opts.RepoID > 0 {
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
@@ -88,18 +88,9 @@ func (opts FindTaskOptions) toConds() builder.Cond {
return cond
}
-func FindTasks(ctx context.Context, opts FindTaskOptions) (TaskList, error) {
- e := db.GetEngine(ctx).Where(opts.toConds())
- if opts.PageSize > 0 && opts.Page >= 1 {
- e.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
- }
+func (opts FindTaskOptions) ToOrders() string {
if opts.IDOrderDesc {
- e.OrderBy("id DESC")
+ return "`id` DESC"
}
- var tasks TaskList
- return tasks, e.Find(&tasks)
-}
-
-func CountTasks(ctx context.Context, opts FindTaskOptions) (int64, error) {
- return db.GetEngine(ctx).Where(opts.toConds()).Count(new(ActionTask))
+ return ""
}
diff --git a/models/actions/variable.go b/models/actions/variable.go
index e0bb59ccbe..030b7bae92 100644
--- a/models/actions/variable.go
+++ b/models/actions/variable.go
@@ -56,7 +56,7 @@ type FindVariablesOpts struct {
RepoID int64
}
-func (opts *FindVariablesOpts) toConds() builder.Cond {
+func (opts FindVariablesOpts) ToConds() builder.Cond {
cond := builder.NewCond()
if opts.OwnerID > 0 {
cond = cond.And(builder.Eq{"owner_id": opts.OwnerID})
@@ -67,15 +67,6 @@ func (opts *FindVariablesOpts) toConds() builder.Cond {
return cond
}
-func FindVariables(ctx context.Context, opts FindVariablesOpts) ([]*ActionVariable, error) {
- var variables []*ActionVariable
- sess := db.GetEngine(ctx)
- if opts.PageSize != 0 {
- sess = db.SetSessionPagination(sess, &opts.ListOptions)
- }
- return variables, sess.Where(opts.toConds()).Find(&variables)
-}
-
func GetVariableByID(ctx context.Context, variableID int64) (*ActionVariable, error) {
var variable ActionVariable
has, err := db.GetEngine(ctx).Where("id=?", variableID).Get(&variable)
diff --git a/models/activities/notification.go b/models/activities/notification.go
index 7c794564b6..230bcdd6e8 100644
--- a/models/activities/notification.go
+++ b/models/activities/notification.go
@@ -22,7 +22,6 @@ import (
"code.gitea.io/gitea/modules/timeutil"
"xorm.io/builder"
- "xorm.io/xorm"
)
type (
@@ -93,7 +92,7 @@ type FindNotificationOptions struct {
}
// ToCond will convert each condition into a xorm-Cond
-func (opts *FindNotificationOptions) ToCond() builder.Cond {
+func (opts FindNotificationOptions) ToConds() builder.Cond {
cond := builder.NewCond()
if opts.UserID != 0 {
cond = cond.And(builder.Eq{"notification.user_id": opts.UserID})
@@ -105,7 +104,11 @@ func (opts *FindNotificationOptions) ToCond() builder.Cond {
cond = cond.And(builder.Eq{"notification.issue_id": opts.IssueID})
}
if len(opts.Status) > 0 {
- cond = cond.And(builder.In("notification.status", opts.Status))
+ if len(opts.Status) == 1 {
+ cond = cond.And(builder.Eq{"notification.status": opts.Status[0]})
+ } else {
+ cond = cond.And(builder.In("notification.status", opts.Status))
+ }
}
if len(opts.Source) > 0 {
cond = cond.And(builder.In("notification.source", opts.Source))
@@ -119,24 +122,8 @@ func (opts *FindNotificationOptions) ToCond() builder.Cond {
return cond
}
-// ToSession will convert the given options to a xorm Session by using the conditions from ToCond and joining with issue table if required
-func (opts *FindNotificationOptions) ToSession(ctx context.Context) *xorm.Session {
- sess := db.GetEngine(ctx).Where(opts.ToCond())
- if opts.Page != 0 {
- sess = db.SetSessionPagination(sess, opts)
- }
- return sess
-}
-
-// GetNotifications returns all notifications that fit to the given options.
-func GetNotifications(ctx context.Context, options *FindNotificationOptions) (nl NotificationList, err error) {
- err = options.ToSession(ctx).OrderBy("notification.updated_unix DESC").Find(&nl)
- return nl, err
-}
-
-// CountNotifications count all notifications that fit to the given options and ignore pagination.
-func CountNotifications(ctx context.Context, opts *FindNotificationOptions) (int64, error) {
- return db.GetEngine(ctx).Where(opts.ToCond()).Count(&Notification{})
+func (opts FindNotificationOptions) ToOrders() string {
+ return "notification.updated_unix DESC"
}
// CreateRepoTransferNotification creates notification for the user a repository was transferred to
@@ -192,7 +179,9 @@ func CreateOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, n
func createOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, notificationAuthorID, receiverID int64) error {
// init
var toNotify container.Set[int64]
- notifications, err := getNotificationsByIssueID(ctx, issueID)
+ notifications, err := db.Find[Notification](ctx, FindNotificationOptions{
+ IssueID: issueID,
+ })
if err != nil {
return err
}
@@ -273,23 +262,6 @@ func createOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, n
return nil
}
-func getNotificationsByIssueID(ctx context.Context, issueID int64) (notifications []*Notification, err error) {
- err = db.GetEngine(ctx).
- Where("issue_id = ?", issueID).
- Find(&notifications)
- return notifications, err
-}
-
-func notificationExists(notifications []*Notification, issueID, userID int64) bool {
- for _, notification := range notifications {
- if notification.IssueID == issueID && notification.UserID == userID {
- return true
- }
- }
-
- return false
-}
-
func createIssueNotification(ctx context.Context, userID int64, issue *issues_model.Issue, commentID, updatedByID int64) error {
notification := &Notification{
UserID: userID,
@@ -341,35 +313,6 @@ func GetIssueNotification(ctx context.Context, userID, issueID int64) (*Notifica
return notification, err
}
-// NotificationsForUser returns notifications for a given user and status
-func NotificationsForUser(ctx context.Context, user *user_model.User, statuses []NotificationStatus, page, perPage int) (notifications NotificationList, err error) {
- if len(statuses) == 0 {
- return nil, nil
- }
-
- sess := db.GetEngine(ctx).
- Where("user_id = ?", user.ID).
- In("status", statuses).
- OrderBy("updated_unix DESC")
-
- if page > 0 && perPage > 0 {
- sess.Limit(perPage, (page-1)*perPage)
- }
-
- err = sess.Find(&notifications)
- return notifications, err
-}
-
-// CountUnread count unread notifications for a user
-func CountUnread(ctx context.Context, userID int64) int64 {
- exist, err := db.GetEngine(ctx).Where("user_id = ?", userID).And("status = ?", NotificationStatusUnread).Count(new(Notification))
- if err != nil {
- log.Error("countUnread", err)
- return 0
- }
- return exist
-}
-
// LoadAttributes load Repo Issue User and Comment if not loaded
func (n *Notification) LoadAttributes(ctx context.Context) (err error) {
if err = n.loadRepo(ctx); err != nil {
@@ -481,17 +424,47 @@ func (n *Notification) APIURL() string {
return setting.AppURL + "api/v1/notifications/threads/" + strconv.FormatInt(n.ID, 10)
}
+func notificationExists(notifications []*Notification, issueID, userID int64) bool {
+ for _, notification := range notifications {
+ if notification.IssueID == issueID && notification.UserID == userID {
+ return true
+ }
+ }
+
+ return false
+}
+
+// UserIDCount is a simple coalition of UserID and Count
+type UserIDCount struct {
+ UserID int64
+ Count int64
+}
+
+// GetUIDsAndNotificationCounts between the two provided times
+func GetUIDsAndNotificationCounts(ctx context.Context, since, until timeutil.TimeStamp) ([]UserIDCount, error) {
+ sql := `SELECT user_id, count(*) AS count FROM notification ` +
+ `WHERE user_id IN (SELECT user_id FROM notification WHERE updated_unix >= ? AND ` +
+ `updated_unix < ?) AND status = ? GROUP BY user_id`
+ var res []UserIDCount
+ return res, db.GetEngine(ctx).SQL(sql, since, until, NotificationStatusUnread).Find(&res)
+}
+
// NotificationList contains a list of notifications
type NotificationList []*Notification
// LoadAttributes load Repo Issue User and Comment if not loaded
func (nl NotificationList) LoadAttributes(ctx context.Context) error {
- var err error
- for i := 0; i < len(nl); i++ {
- err = nl[i].LoadAttributes(ctx)
- if err != nil && !issues_model.IsErrCommentNotExist(err) {
- return err
- }
+ if _, _, err := nl.LoadRepos(ctx); err != nil {
+ return err
+ }
+ if _, err := nl.LoadIssues(ctx); err != nil {
+ return err
+ }
+ if _, err := nl.LoadUsers(ctx); err != nil {
+ return err
+ }
+ if _, err := nl.LoadComments(ctx); err != nil {
+ return err
}
return nil
}
@@ -665,6 +638,68 @@ func (nl NotificationList) getPendingCommentIDs() []int64 {
return ids.Values()
}
+func (nl NotificationList) getUserIDs() []int64 {
+ ids := make(container.Set[int64], len(nl))
+ for _, notification := range nl {
+ if notification.UserID == 0 || notification.User != nil {
+ continue
+ }
+ ids.Add(notification.UserID)
+ }
+ return ids.Values()
+}
+
+// LoadUsers loads users from database
+func (nl NotificationList) LoadUsers(ctx context.Context) ([]int, error) {
+ if len(nl) == 0 {
+ return []int{}, nil
+ }
+
+ userIDs := nl.getUserIDs()
+ users := make(map[int64]*user_model.User, len(userIDs))
+ left := len(userIDs)
+ for left > 0 {
+ limit := db.DefaultMaxInSize
+ if left < limit {
+ limit = left
+ }
+ rows, err := db.GetEngine(ctx).
+ In("id", userIDs[:limit]).
+ Rows(new(user_model.User))
+ if err != nil {
+ return nil, err
+ }
+
+ for rows.Next() {
+ var user user_model.User
+ err = rows.Scan(&user)
+ if err != nil {
+ rows.Close()
+ return nil, err
+ }
+
+ users[user.ID] = &user
+ }
+ _ = rows.Close()
+
+ left -= limit
+ userIDs = userIDs[limit:]
+ }
+
+ failures := []int{}
+ for i, notification := range nl {
+ if notification.UserID > 0 && notification.User == nil && users[notification.UserID] != nil {
+ notification.User = users[notification.UserID]
+ if notification.User == nil {
+ log.Error("Notification[%d]: UserID[%d] failed to load", notification.ID, notification.UserID)
+ failures = append(failures, i)
+ continue
+ }
+ }
+ }
+ return failures, nil
+}
+
// LoadComments loads comments from database
func (nl NotificationList) LoadComments(ctx context.Context) ([]int, error) {
if len(nl) == 0 {
@@ -717,30 +752,6 @@ func (nl NotificationList) LoadComments(ctx context.Context) ([]int, error) {
return failures, nil
}
-// GetNotificationCount returns the notification count for user
-func GetNotificationCount(ctx context.Context, user *user_model.User, status NotificationStatus) (count int64, err error) {
- count, err = db.GetEngine(ctx).
- Where("user_id = ?", user.ID).
- And("status = ?", status).
- Count(&Notification{})
- return count, err
-}
-
-// UserIDCount is a simple coalition of UserID and Count
-type UserIDCount struct {
- UserID int64
- Count int64
-}
-
-// GetUIDsAndNotificationCounts between the two provided times
-func GetUIDsAndNotificationCounts(ctx context.Context, since, until timeutil.TimeStamp) ([]UserIDCount, error) {
- sql := `SELECT user_id, count(*) AS count FROM notification ` +
- `WHERE user_id IN (SELECT user_id FROM notification WHERE updated_unix >= ? AND ` +
- `updated_unix < ?) AND status = ? GROUP BY user_id`
- var res []UserIDCount
- return res, db.GetEngine(ctx).SQL(sql, since, until, NotificationStatusUnread).Find(&res)
-}
-
// SetIssueReadBy sets issue to be read by given user.
func SetIssueReadBy(ctx context.Context, issueID, userID int64) error {
if err := issues_model.UpdateIssueUserByRead(ctx, userID, issueID); err != nil {
diff --git a/models/activities/notification_test.go b/models/activities/notification_test.go
index b90ce70536..52f0eacba1 100644
--- a/models/activities/notification_test.go
+++ b/models/activities/notification_test.go
@@ -34,8 +34,13 @@ func TestCreateOrUpdateIssueNotifications(t *testing.T) {
func TestNotificationsForUser(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
- statuses := []activities_model.NotificationStatus{activities_model.NotificationStatusRead, activities_model.NotificationStatusUnread}
- notfs, err := activities_model.NotificationsForUser(db.DefaultContext, user, statuses, 1, 10)
+ notfs, err := db.Find[activities_model.Notification](db.DefaultContext, activities_model.FindNotificationOptions{
+ UserID: user.ID,
+ Status: []activities_model.NotificationStatus{
+ activities_model.NotificationStatusRead,
+ activities_model.NotificationStatusUnread,
+ },
+ })
assert.NoError(t, err)
if assert.Len(t, notfs, 3) {
assert.EqualValues(t, 5, notfs[0].ID)
@@ -68,11 +73,21 @@ 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 := activities_model.GetNotificationCount(db.DefaultContext, user, activities_model.NotificationStatusRead)
+ cnt, err := db.Count[activities_model.Notification](db.DefaultContext, activities_model.FindNotificationOptions{
+ UserID: user.ID,
+ Status: []activities_model.NotificationStatus{
+ activities_model.NotificationStatusRead,
+ },
+ })
assert.NoError(t, err)
assert.EqualValues(t, 0, cnt)
- cnt, err = activities_model.GetNotificationCount(db.DefaultContext, user, activities_model.NotificationStatusUnread)
+ cnt, err = db.Count[activities_model.Notification](db.DefaultContext, activities_model.FindNotificationOptions{
+ UserID: user.ID,
+ Status: []activities_model.NotificationStatus{
+ activities_model.NotificationStatusUnread,
+ },
+ })
assert.NoError(t, err)
assert.EqualValues(t, 1, cnt)
}
diff --git a/models/activities/statistic.go b/models/activities/statistic.go
index e9dab6fc10..fe5f7d0872 100644
--- a/models/activities/statistic.go
+++ b/models/activities/statistic.go
@@ -52,7 +52,7 @@ type IssueByRepositoryCount struct {
func GetStatistic(ctx context.Context) (stats Statistic) {
e := db.GetEngine(ctx)
stats.Counter.User = user_model.CountUsers(ctx, nil)
- stats.Counter.Org, _ = organization.CountOrgs(ctx, organization.FindOrgOptions{IncludePrivate: true})
+ stats.Counter.Org, _ = db.Count[organization.Organization](ctx, organization.FindOrgOptions{IncludePrivate: true})
stats.Counter.PublicKey, _ = e.Count(new(asymkey_model.PublicKey))
stats.Counter.Repo, _ = repo_model.CountRepositories(ctx, repo_model.CountRepositoryOptions{})
stats.Counter.Watch, _ = e.Count(new(repo_model.Watch))
@@ -102,7 +102,7 @@ func GetStatistic(ctx context.Context) (stats Statistic) {
stats.Counter.Follow, _ = e.Count(new(user_model.Follow))
stats.Counter.Mirror, _ = e.Count(new(repo_model.Mirror))
stats.Counter.Release, _ = e.Count(new(repo_model.Release))
- stats.Counter.AuthSource = auth.CountSources(ctx, auth.FindSourcesOptions{})
+ stats.Counter.AuthSource, _ = db.Count[auth.Source](ctx, auth.FindSourcesOptions{})
stats.Counter.Webhook, _ = e.Count(new(webhook.Webhook))
stats.Counter.Milestone, _ = e.Count(new(issues_model.Milestone))
stats.Counter.Label, _ = e.Count(new(issues_model.Label))
diff --git a/models/asymkey/ssh_key.go b/models/asymkey/ssh_key.go
index f36738fb3d..552f2ffd69 100644
--- a/models/asymkey/ssh_key.go
+++ b/models/asymkey/ssh_key.go
@@ -179,45 +179,33 @@ func SearchPublicKeyByContentExact(ctx context.Context, content string) (*Public
return key, nil
}
-// SearchPublicKey returns a list of public keys matching the provided arguments.
-func SearchPublicKey(ctx context.Context, uid int64, fingerprint string) ([]*PublicKey, error) {
- keys := make([]*PublicKey, 0, 5)
+type FindPublicKeyOptions struct {
+ db.ListOptions
+ OwnerID int64
+ Fingerprint string
+ KeyTypes []KeyType
+ NotKeytype KeyType
+ LoginSourceID int64
+}
+
+func (opts FindPublicKeyOptions) ToConds() builder.Cond {
cond := builder.NewCond()
- if uid != 0 {
- cond = cond.And(builder.Eq{"owner_id": uid})
+ if opts.OwnerID > 0 {
+ cond = cond.And(builder.Eq{"owner_id": opts.OwnerID})
}
- if fingerprint != "" {
- cond = cond.And(builder.Eq{"fingerprint": fingerprint})
+ if opts.Fingerprint != "" {
+ cond = cond.And(builder.Eq{"fingerprint": opts.Fingerprint})
}
- return keys, db.GetEngine(ctx).Where(cond).Find(&keys)
-}
-
-// ListPublicKeys returns a list of public keys belongs to given user.
-func ListPublicKeys(ctx context.Context, uid int64, listOptions db.ListOptions) ([]*PublicKey, error) {
- sess := db.GetEngine(ctx).Where("owner_id = ? AND type != ?", uid, KeyTypePrincipal)
- if listOptions.Page != 0 {
- sess = db.SetSessionPagination(sess, &listOptions)
-
- keys := make([]*PublicKey, 0, listOptions.PageSize)
- return keys, sess.Find(&keys)
+ if len(opts.KeyTypes) > 0 {
+ cond = cond.And(builder.In("type", opts.KeyTypes))
}
-
- keys := make([]*PublicKey, 0, 5)
- return keys, sess.Find(&keys)
-}
-
-// CountPublicKeys count public keys a user has
-func CountPublicKeys(ctx context.Context, userID int64) (int64, error) {
- sess := db.GetEngine(ctx).Where("owner_id = ? AND type != ?", userID, KeyTypePrincipal)
- return sess.Count(&PublicKey{})
-}
-
-// ListPublicKeysBySource returns a list of synchronized public keys for a given user and login source.
-func ListPublicKeysBySource(ctx context.Context, uid, authSourceID int64) ([]*PublicKey, error) {
- keys := make([]*PublicKey, 0, 5)
- return keys, db.GetEngine(ctx).
- Where("owner_id = ? AND login_source_id = ?", uid, authSourceID).
- Find(&keys)
+ if opts.NotKeytype > 0 {
+ cond = cond.And(builder.Neq{"type": opts.NotKeytype})
+ }
+ if opts.LoginSourceID > 0 {
+ cond = cond.And(builder.Eq{"login_source_id": opts.LoginSourceID})
+ }
+ return cond
}
// UpdatePublicKeyUpdated updates public key use time.
@@ -394,7 +382,10 @@ func SynchronizePublicKeys(ctx context.Context, usr *user_model.User, s *auth.So
// Get Public Keys from DB with current LDAP source
var giteaKeys []string
- keys, err := ListPublicKeysBySource(ctx, usr.ID, s.ID)
+ keys, err := db.Find[PublicKey](ctx, FindPublicKeyOptions{
+ OwnerID: usr.ID,
+ LoginSourceID: s.ID,
+ })
if err != nil {
log.Error("synchronizePublicKeys[%s]: Error listing Public SSH Keys for user %s: %v", s.Name, usr.Name, err)
}
diff --git a/models/asymkey/ssh_key_commit_verification.go b/models/asymkey/ssh_key_commit_verification.go
index a61f0663b1..27c6df3578 100644
--- a/models/asymkey/ssh_key_commit_verification.go
+++ b/models/asymkey/ssh_key_commit_verification.go
@@ -21,7 +21,10 @@ import (
func ParseCommitWithSSHSignature(ctx context.Context, c *git.Commit, committer *user_model.User) *CommitVerification {
// Now try to associate the signature with the committer, if present
if committer.ID != 0 {
- keys, err := ListPublicKeys(ctx, committer.ID, db.ListOptions{})
+ keys, err := db.Find[PublicKey](ctx, FindPublicKeyOptions{
+ OwnerID: committer.ID,
+ NotKeytype: KeyTypePrincipal,
+ })
if err != nil { // Skipping failed to get ssh keys of user
log.Error("ListPublicKeys: %v", err)
return &CommitVerification{
diff --git a/models/asymkey/ssh_key_deploy.go b/models/asymkey/ssh_key_deploy.go
index e347604bcd..8f9f454051 100644
--- a/models/asymkey/ssh_key_deploy.go
+++ b/models/asymkey/ssh_key_deploy.go
@@ -210,7 +210,7 @@ type ListDeployKeysOptions struct {
Fingerprint string
}
-func (opt ListDeployKeysOptions) toCond() builder.Cond {
+func (opt ListDeployKeysOptions) ToConds() builder.Cond {
cond := builder.NewCond()
if opt.RepoID != 0 {
cond = cond.And(builder.Eq{"repo_id": opt.RepoID})
@@ -223,23 +223,3 @@ func (opt ListDeployKeysOptions) toCond() builder.Cond {
}
return cond
}
-
-// ListDeployKeys returns a list of deploy keys matching the provided arguments.
-func ListDeployKeys(ctx context.Context, opts *ListDeployKeysOptions) ([]*DeployKey, error) {
- sess := db.GetEngine(ctx).Where(opts.toCond())
-
- if opts.Page != 0 {
- sess = db.SetSessionPagination(sess, opts)
-
- keys := make([]*DeployKey, 0, opts.PageSize)
- return keys, sess.Find(&keys)
- }
-
- keys := make([]*DeployKey, 0, 5)
- return keys, sess.Find(&keys)
-}
-
-// CountDeployKeys returns count deploy keys matching the provided arguments.
-func CountDeployKeys(ctx context.Context, opts *ListDeployKeysOptions) (int64, error) {
- return db.GetEngine(ctx).Where(opts.toCond()).Count(&DeployKey{})
-}
diff --git a/models/auth/access_token.go b/models/auth/access_token.go
index 8abcc622bc..63331b4841 100644
--- a/models/auth/access_token.go
+++ b/models/auth/access_token.go
@@ -17,6 +17,7 @@ import (
"code.gitea.io/gitea/modules/util"
lru "github.com/hashicorp/golang-lru/v2"
+ "xorm.io/builder"
)
// ErrAccessTokenNotExist represents a "AccessTokenNotExist" kind of error.
@@ -201,25 +202,18 @@ type ListAccessTokensOptions struct {
UserID int64
}
-// ListAccessTokens returns a list of access tokens belongs to given user.
-func ListAccessTokens(ctx context.Context, opts ListAccessTokensOptions) ([]*AccessToken, error) {
- sess := db.GetEngine(ctx).Where("uid=?", opts.UserID)
-
- if len(opts.Name) != 0 {
- sess = sess.Where("name=?", opts.Name)
- }
-
- sess = sess.Desc("created_unix")
-
- if opts.Page != 0 {
- sess = db.SetSessionPagination(sess, &opts)
-
- tokens := make([]*AccessToken, 0, opts.PageSize)
- return tokens, sess.Find(&tokens)
+func (opts ListAccessTokensOptions) ToConds() builder.Cond {
+ cond := builder.NewCond()
+ // user id is required, otherwise it will return all result which maybe a possible bug
+ cond = cond.And(builder.Eq{"uid": opts.UserID})
+ if len(opts.Name) > 0 {
+ cond = cond.And(builder.Eq{"name": opts.Name})
}
+ return cond
+}
- tokens := make([]*AccessToken, 0, 5)
- return tokens, sess.Find(&tokens)
+func (opts ListAccessTokensOptions) ToOrders() string {
+ return "created_unix DESC"
}
// UpdateAccessToken updates information of access token.
@@ -228,15 +222,6 @@ func UpdateAccessToken(ctx context.Context, t *AccessToken) error {
return err
}
-// CountAccessTokens count access tokens belongs to given user by options
-func CountAccessTokens(ctx context.Context, opts ListAccessTokensOptions) (int64, error) {
- sess := db.GetEngine(ctx).Where("uid=?", opts.UserID)
- if len(opts.Name) != 0 {
- sess = sess.Where("name=?", opts.Name)
- }
- return sess.Count(&AccessToken{})
-}
-
// DeleteAccessTokenByID deletes access token by given ID.
func DeleteAccessTokenByID(ctx context.Context, id, userID int64) error {
cnt, err := db.GetEngine(ctx).ID(id).Delete(&AccessToken{
diff --git a/models/auth/access_token_test.go b/models/auth/access_token_test.go
index 72c937ffd6..4360f1a214 100644
--- a/models/auth/access_token_test.go
+++ b/models/auth/access_token_test.go
@@ -85,7 +85,7 @@ func TestGetAccessTokenBySHA(t *testing.T) {
func TestListAccessTokens(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- tokens, err := auth_model.ListAccessTokens(db.DefaultContext, auth_model.ListAccessTokensOptions{UserID: 1})
+ tokens, err := db.Find[auth_model.AccessToken](db.DefaultContext, auth_model.ListAccessTokensOptions{UserID: 1})
assert.NoError(t, err)
if assert.Len(t, tokens, 2) {
assert.Equal(t, int64(1), tokens[0].UID)
@@ -94,14 +94,14 @@ func TestListAccessTokens(t *testing.T) {
assert.Contains(t, []string{tokens[0].Name, tokens[1].Name}, "Token B")
}
- tokens, err = auth_model.ListAccessTokens(db.DefaultContext, auth_model.ListAccessTokensOptions{UserID: 2})
+ tokens, err = db.Find[auth_model.AccessToken](db.DefaultContext, 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 = auth_model.ListAccessTokens(db.DefaultContext, auth_model.ListAccessTokensOptions{UserID: 100})
+ tokens, err = db.Find[auth_model.AccessToken](db.DefaultContext, auth_model.ListAccessTokensOptions{UserID: 100})
assert.NoError(t, err)
assert.Empty(t, tokens)
}
diff --git a/models/auth/oauth2.go b/models/auth/oauth2.go
index 76a4e9d835..9d53fffc78 100644
--- a/models/auth/oauth2.go
+++ b/models/auth/oauth2.go
@@ -5,6 +5,7 @@ package auth
import (
"context"
+ "crypto/sha256"
"encoding/base32"
"encoding/base64"
"fmt"
@@ -19,7 +20,6 @@ import (
"code.gitea.io/gitea/modules/util"
uuid "github.com/google/uuid"
- "github.com/minio/sha256-simd"
"golang.org/x/crypto/bcrypt"
"xorm.io/builder"
"xorm.io/xorm"
@@ -243,13 +243,6 @@ func GetOAuth2ApplicationByID(ctx context.Context, id int64) (app *OAuth2Applica
return app, nil
}
-// GetOAuth2ApplicationsByUserID returns all oauth2 applications owned by the user
-func GetOAuth2ApplicationsByUserID(ctx context.Context, userID int64) (apps []*OAuth2Application, err error) {
- apps = make([]*OAuth2Application, 0)
- err = db.GetEngine(ctx).Where("uid = ?", userID).Find(&apps)
- return apps, err
-}
-
// CreateOAuth2ApplicationOptions holds options to create an oauth2 application
type CreateOAuth2ApplicationOptions struct {
Name string
@@ -372,25 +365,6 @@ func DeleteOAuth2Application(ctx context.Context, id, userid int64) error {
return committer.Commit()
}
-// ListOAuth2Applications returns a list of oauth2 applications belongs to given user.
-func ListOAuth2Applications(ctx context.Context, uid int64, listOptions db.ListOptions) ([]*OAuth2Application, int64, error) {
- sess := db.GetEngine(ctx).
- Where("uid=?", uid).
- Desc("id")
-
- if listOptions.Page != 0 {
- sess = db.SetSessionPagination(sess, &listOptions)
-
- apps := make([]*OAuth2Application, 0, listOptions.PageSize)
- total, err := sess.FindAndCount(&apps)
- return apps, total, err
- }
-
- apps := make([]*OAuth2Application, 0, 5)
- total, err := sess.FindAndCount(&apps)
- return apps, total, err
-}
-
//////////////////////////////////////////////////////
// OAuth2AuthorizationCode is a code to obtain an access token in combination with the client secret once. It has a limited lifetime.
diff --git a/models/auth/oauth2_list.go b/models/auth/oauth2_list.go
new file mode 100644
index 0000000000..c55f10b3c8
--- /dev/null
+++ b/models/auth/oauth2_list.go
@@ -0,0 +1,32 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package auth
+
+import (
+ "code.gitea.io/gitea/models/db"
+
+ "xorm.io/builder"
+)
+
+type FindOAuth2ApplicationsOptions struct {
+ db.ListOptions
+ // OwnerID is the user id or org id of the owner of the application
+ OwnerID int64
+ // find global applications, if true, then OwnerID will be igonred
+ IsGlobal bool
+}
+
+func (opts FindOAuth2ApplicationsOptions) ToConds() builder.Cond {
+ conds := builder.NewCond()
+ if opts.IsGlobal {
+ conds = conds.And(builder.Eq{"uid": 0})
+ } else if opts.OwnerID != 0 {
+ conds = conds.And(builder.Eq{"uid": opts.OwnerID})
+ }
+ return conds
+}
+
+func (opts FindOAuth2ApplicationsOptions) ToOrders() string {
+ return "id DESC"
+}
diff --git a/models/auth/source.go b/models/auth/source.go
index 5f2781c808..5e77afddc3 100644
--- a/models/auth/source.go
+++ b/models/auth/source.go
@@ -242,6 +242,7 @@ func CreateSource(ctx context.Context, source *Source) error {
}
type FindSourcesOptions struct {
+ db.ListOptions
IsActive util.OptionalBool
LoginType Type
}
@@ -257,27 +258,22 @@ func (opts FindSourcesOptions) ToConds() builder.Cond {
return conds
}
-// FindSources returns a slice of login sources found in DB according to given conditions.
-func FindSources(ctx context.Context, opts FindSourcesOptions) ([]*Source, error) {
- auths := make([]*Source, 0, 6)
- return auths, db.GetEngine(ctx).Where(opts.ToConds()).Find(&auths)
-}
-
// IsSSPIEnabled returns true if there is at least one activated login
// source of type LoginSSPI
func IsSSPIEnabled(ctx context.Context) bool {
if !db.HasEngine {
return false
}
- sources, err := FindSources(ctx, FindSourcesOptions{
+
+ exist, err := db.Exists[Source](ctx, FindSourcesOptions{
IsActive: util.OptionalBoolTrue,
LoginType: SSPI,
})
if err != nil {
- log.Error("ActiveSources: %v", err)
+ log.Error("Active SSPI Sources: %v", err)
return false
}
- return len(sources) > 0
+ return exist
}
// GetSourceByID returns login source by given ID.
@@ -346,12 +342,6 @@ func UpdateSource(ctx context.Context, source *Source) error {
return err
}
-// CountSources returns number of login sources.
-func CountSources(ctx context.Context, opts FindSourcesOptions) int64 {
- count, _ := db.GetEngine(ctx).Where(opts.ToConds()).Count(new(Source))
- return count
-}
-
// ErrSourceNotExist represents a "SourceNotExist" kind of error.
type ErrSourceNotExist struct {
ID int64
diff --git a/models/db/context.go b/models/db/context.go
index 521857fae8..45765ef7d3 100644
--- a/models/db/context.go
+++ b/models/db/context.go
@@ -264,3 +264,8 @@ func inTransaction(ctx context.Context) (*xorm.Session, bool) {
return nil, false
}
}
+
+func Exists[T any](ctx context.Context, opts FindOptions) (bool, error) {
+ var bean T
+ return GetEngine(ctx).Where(opts.ToConds()).Exist(&bean)
+}
diff --git a/models/db/list.go b/models/db/list.go
index 9fb4d0741f..b2f932e89b 100644
--- a/models/db/list.go
+++ b/models/db/list.go
@@ -14,7 +14,8 @@ import (
const (
// DefaultMaxInSize represents default variables number on IN () in SQL
- DefaultMaxInSize = 50
+ DefaultMaxInSize = 50
+ defaultFindSliceSize = 10
)
// Paginator is the base for different ListOptions types
@@ -52,7 +53,12 @@ type ListOptions struct {
ListAll bool // if true, then PageSize and Page will not be taken
}
-var _ Paginator = &ListOptions{}
+var ListOptionsAll = ListOptions{ListAll: true}
+
+var (
+ _ Paginator = &ListOptions{}
+ _ FindOptions = ListOptions{}
+)
// GetSkipTake returns the skip and take values
func (opts *ListOptions) GetSkipTake() (skip, take int) {
@@ -67,8 +73,16 @@ func (opts *ListOptions) GetStartEnd() (start, end int) {
return start, end
}
+func (opts ListOptions) GetPage() int {
+ return opts.Page
+}
+
+func (opts ListOptions) GetPageSize() int {
+ return opts.PageSize
+}
+
// IsListAll indicates PageSize and Page will be ignored
-func (opts *ListOptions) IsListAll() bool {
+func (opts ListOptions) IsListAll() bool {
return opts.ListAll
}
@@ -85,6 +99,10 @@ func (opts *ListOptions) SetDefaultValues() {
}
}
+func (opts ListOptions) ToConds() builder.Cond {
+ return builder.NewCond()
+}
+
// AbsoluteListOptions absolute options to paginate results
type AbsoluteListOptions struct {
skip int
@@ -124,29 +142,63 @@ func (opts *AbsoluteListOptions) GetStartEnd() (start, end int) {
// FindOptions represents a find options
type FindOptions interface {
- Paginator
+ GetPage() int
+ GetPageSize() int
+ IsListAll() bool
ToConds() builder.Cond
}
+type FindOptionsOrder interface {
+ ToOrders() string
+}
+
// Find represents a common find function which accept an options interface
-func Find[T any](ctx context.Context, opts FindOptions, objects *[]T) error {
+func Find[T any](ctx context.Context, opts FindOptions) ([]*T, error) {
sess := GetEngine(ctx).Where(opts.ToConds())
- if !opts.IsListAll() {
- sess.Limit(opts.GetSkipTake())
+ page, pageSize := opts.GetPage(), opts.GetPageSize()
+ if !opts.IsListAll() && pageSize > 0 && page >= 1 {
+ sess.Limit(pageSize, (page-1)*pageSize)
+ }
+ if newOpt, ok := opts.(FindOptionsOrder); ok && newOpt.ToOrders() != "" {
+ sess.OrderBy(newOpt.ToOrders())
+ }
+
+ findPageSize := defaultFindSliceSize
+ if pageSize > 0 {
+ findPageSize = pageSize
+ }
+ objects := make([]*T, 0, findPageSize)
+ if err := sess.Find(&objects); err != nil {
+ return nil, err
}
- return sess.Find(objects)
+ return objects, nil
}
// Count represents a common count function which accept an options interface
-func Count[T any](ctx context.Context, opts FindOptions, object T) (int64, error) {
- return GetEngine(ctx).Where(opts.ToConds()).Count(object)
+func Count[T any](ctx context.Context, opts FindOptions) (int64, error) {
+ var object T
+ return GetEngine(ctx).Where(opts.ToConds()).Count(&object)
}
// FindAndCount represents a common findandcount function which accept an options interface
-func FindAndCount[T any](ctx context.Context, opts FindOptions, objects *[]T) (int64, error) {
+func FindAndCount[T any](ctx context.Context, opts FindOptions) ([]*T, int64, error) {
sess := GetEngine(ctx).Where(opts.ToConds())
- if !opts.IsListAll() {
- sess.Limit(opts.GetSkipTake())
+ page, pageSize := opts.GetPage(), opts.GetPageSize()
+ if !opts.IsListAll() && pageSize > 0 && page >= 1 {
+ sess.Limit(pageSize, (page-1)*pageSize)
+ }
+ if newOpt, ok := opts.(FindOptionsOrder); ok && newOpt.ToOrders() != "" {
+ sess.OrderBy(newOpt.ToOrders())
+ }
+
+ findPageSize := defaultFindSliceSize
+ if pageSize > 0 {
+ findPageSize = pageSize
+ }
+ objects := make([]*T, 0, findPageSize)
+ cnt, err := sess.FindAndCount(&objects)
+ if err != nil {
+ return nil, 0, err
}
- return sess.FindAndCount(objects)
+ return objects, cnt, nil
}
diff --git a/models/db/list_test.go b/models/db/list_test.go
index b923dc9c22..45194611f8 100644
--- a/models/db/list_test.go
+++ b/models/db/list_test.go
@@ -18,11 +18,11 @@ type mockListOptions struct {
db.ListOptions
}
-func (opts *mockListOptions) IsListAll() bool {
+func (opts mockListOptions) IsListAll() bool {
return true
}
-func (opts *mockListOptions) ToConds() builder.Cond {
+func (opts mockListOptions) ToConds() builder.Cond {
return builder.NewCond()
}
@@ -37,17 +37,16 @@ func TestFind(t *testing.T) {
assert.NotEmpty(t, repoUnitCount)
opts := mockListOptions{}
- var repoUnits []repo_model.RepoUnit
- err = db.Find(db.DefaultContext, &opts, &repoUnits)
+ repoUnits, err := db.Find[repo_model.RepoUnit](db.DefaultContext, opts)
assert.NoError(t, err)
assert.Len(t, repoUnits, repoUnitCount)
- cnt, err := db.Count(db.DefaultContext, &opts, new(repo_model.RepoUnit))
+ cnt, err := db.Count[repo_model.RepoUnit](db.DefaultContext, opts)
assert.NoError(t, err)
assert.EqualValues(t, repoUnitCount, cnt)
- repoUnits = make([]repo_model.RepoUnit, 0, 10)
- newCnt, err := db.FindAndCount(db.DefaultContext, &opts, &repoUnits)
+ repoUnits, newCnt, err := db.FindAndCount[repo_model.RepoUnit](db.DefaultContext, opts)
assert.NoError(t, err)
assert.EqualValues(t, cnt, newCnt)
+ assert.Len(t, repoUnits, repoUnitCount)
}
diff --git a/models/issues/comment.go b/models/issues/comment.go
index 7fd07867df..a59fa570af 100644
--- a/models/issues/comment.go
+++ b/models/issues/comment.go
@@ -1027,7 +1027,7 @@ type FindCommentsOptions struct {
}
// ToConds implements FindOptions interface
-func (opts *FindCommentsOptions) ToConds() builder.Cond {
+func (opts FindCommentsOptions) ToConds() builder.Cond {
cond := builder.NewCond()
if opts.RepoID > 0 {
cond = cond.And(builder.Eq{"issue.repo_id": opts.RepoID})
diff --git a/models/organization/org.go b/models/organization/org.go
index 07091194eb..23a4e2f96a 100644
--- a/models/organization/org.go
+++ b/models/organization/org.go
@@ -456,7 +456,7 @@ func queryUserOrgIDs(userID int64, includePrivate bool) *builder.Builder {
return builder.Select("org_id").From("org_user").Where(cond)
}
-func (opts FindOrgOptions) toConds() builder.Cond {
+func (opts FindOrgOptions) ToConds() builder.Cond {
var cond builder.Cond = builder.Eq{"`user`.`type`": user_model.UserTypeOrganization}
if opts.UserID > 0 {
cond = cond.And(builder.In("`user`.`id`", queryUserOrgIDs(opts.UserID, opts.IncludePrivate)))
@@ -467,23 +467,8 @@ func (opts FindOrgOptions) toConds() builder.Cond {
return cond
}
-// FindOrgs returns a list of organizations according given conditions
-func FindOrgs(ctx context.Context, opts FindOrgOptions) ([]*Organization, error) {
- orgs := make([]*Organization, 0, 10)
- sess := db.GetEngine(ctx).
- Where(opts.toConds()).
- Asc("`user`.name")
- if opts.Page > 0 && opts.PageSize > 0 {
- sess.Limit(opts.PageSize, opts.PageSize*(opts.Page-1))
- }
- return orgs, sess.Find(&orgs)
-}
-
-// CountOrgs returns total count organizations according options
-func CountOrgs(ctx context.Context, opts FindOrgOptions) (int64, error) {
- return db.GetEngine(ctx).
- Where(opts.toConds()).
- Count(new(Organization))
+func (opts FindOrgOptions) ToOrders() string {
+ return "`user`.name ASC"
}
// HasOrgOrUserVisible tells if the given user can see the given org or user
diff --git a/models/organization/org_test.go b/models/organization/org_test.go
index aa72fc467e..5e40dd4190 100644
--- a/models/organization/org_test.go
+++ b/models/organization/org_test.go
@@ -131,7 +131,7 @@ func TestCountOrganizations(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
expected, err := db.GetEngine(db.DefaultContext).Where("type=?", user_model.UserTypeOrganization).Count(&organization.Organization{})
assert.NoError(t, err)
- cnt, err := organization.CountOrgs(db.DefaultContext, organization.FindOrgOptions{IncludePrivate: true})
+ cnt, err := db.Count[organization.Organization](db.DefaultContext, organization.FindOrgOptions{IncludePrivate: true})
assert.NoError(t, err)
assert.Equal(t, expected, cnt)
}
@@ -183,7 +183,7 @@ func TestIsPublicMembership(t *testing.T) {
func TestFindOrgs(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- orgs, err := organization.FindOrgs(db.DefaultContext, organization.FindOrgOptions{
+ orgs, err := db.Find[organization.Organization](db.DefaultContext, organization.FindOrgOptions{
UserID: 4,
IncludePrivate: true,
})
@@ -192,14 +192,14 @@ func TestFindOrgs(t *testing.T) {
assert.EqualValues(t, 3, orgs[0].ID)
}
- orgs, err = organization.FindOrgs(db.DefaultContext, organization.FindOrgOptions{
+ orgs, err = db.Find[organization.Organization](db.DefaultContext, organization.FindOrgOptions{
UserID: 4,
IncludePrivate: false,
})
assert.NoError(t, err)
assert.Len(t, orgs, 0)
- total, err := organization.CountOrgs(db.DefaultContext, organization.FindOrgOptions{
+ total, err := db.Count[organization.Organization](db.DefaultContext, organization.FindOrgOptions{
UserID: 4,
IncludePrivate: true,
})
diff --git a/models/project/project.go b/models/project/project.go
index 3a1bfe1dbd..becfcbea1e 100644
--- a/models/project/project.go
+++ b/models/project/project.go
@@ -192,16 +192,16 @@ func IsTypeValid(p Type) bool {
// SearchOptions are options for GetProjects
type SearchOptions struct {
+ db.ListOptions
OwnerID int64
RepoID int64
- Page int
IsClosed util.OptionalBool
OrderBy db.SearchOrderBy
Type Type
Title string
}
-func (opts *SearchOptions) toConds() builder.Cond {
+func (opts SearchOptions) ToConds() builder.Cond {
cond := builder.NewCond()
if opts.RepoID > 0 {
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
@@ -226,9 +226,8 @@ func (opts *SearchOptions) toConds() builder.Cond {
return cond
}
-// CountProjects counts projects
-func CountProjects(ctx context.Context, opts SearchOptions) (int64, error) {
- return db.GetEngine(ctx).Where(opts.toConds()).Count(new(Project))
+func (opts SearchOptions) ToOrders() string {
+ return opts.OrderBy.String()
}
func GetSearchOrderByBySortType(sortType string) db.SearchOrderBy {
@@ -244,22 +243,6 @@ func GetSearchOrderByBySortType(sortType string) db.SearchOrderBy {
}
}
-// FindProjects returns a list of all projects that have been created in the repository
-func FindProjects(ctx context.Context, opts SearchOptions) ([]*Project, int64, error) {
- e := db.GetEngine(ctx).Where(opts.toConds())
- if opts.OrderBy.String() != "" {
- e = e.OrderBy(opts.OrderBy.String())
- }
- projects := make([]*Project, 0, setting.UI.IssuePagingNum)
-
- if opts.Page > 0 {
- e = e.Limit(setting.UI.IssuePagingNum, (opts.Page-1)*setting.UI.IssuePagingNum)
- }
-
- count, err := e.FindAndCount(&projects)
- return projects, count, err
-}
-
// NewProject creates a new Project
func NewProject(ctx context.Context, p *Project) error {
if !IsBoardTypeValid(p.BoardType) {
diff --git a/models/project/project_test.go b/models/project/project_test.go
index 6b5bd5b371..7a37c1faf2 100644
--- a/models/project/project_test.go
+++ b/models/project/project_test.go
@@ -34,13 +34,13 @@ func TestIsProjectTypeValid(t *testing.T) {
func TestGetProjects(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- projects, _, err := FindProjects(db.DefaultContext, SearchOptions{RepoID: 1})
+ projects, err := db.Find[Project](db.DefaultContext, SearchOptions{RepoID: 1})
assert.NoError(t, err)
// 1 value for this repo exists in the fixtures
assert.Len(t, projects, 1)
- projects, _, err = FindProjects(db.DefaultContext, SearchOptions{RepoID: 3})
+ projects, err = db.Find[Project](db.DefaultContext, SearchOptions{RepoID: 3})
assert.NoError(t, err)
// 1 value for this repo exists in the fixtures
@@ -109,7 +109,7 @@ func TestProjectsSort(t *testing.T) {
}
for _, tt := range tests {
- projects, count, err := FindProjects(db.DefaultContext, SearchOptions{
+ projects, count, err := db.FindAndCount[Project](db.DefaultContext, SearchOptions{
OrderBy: GetSearchOrderByBySortType(tt.sortType),
})
assert.NoError(t, err)
diff --git a/models/secret/secret.go b/models/secret/secret.go
index 8df46b6c38..41e860d7f6 100644
--- a/models/secret/secret.go
+++ b/models/secret/secret.go
@@ -78,7 +78,7 @@ type FindSecretsOptions struct {
Name string
}
-func (opts *FindSecretsOptions) toConds() builder.Cond {
+func (opts FindSecretsOptions) ToConds() builder.Cond {
cond := builder.NewCond()
if opts.OwnerID > 0 {
cond = cond.And(builder.Eq{"owner_id": opts.OwnerID})
@@ -96,22 +96,6 @@ func (opts *FindSecretsOptions) toConds() builder.Cond {
return cond
}
-func FindSecrets(ctx context.Context, opts FindSecretsOptions) ([]*Secret, error) {
- var secrets []*Secret
- sess := db.GetEngine(ctx)
- if opts.PageSize != 0 {
- sess = db.SetSessionPagination(sess, &opts.ListOptions)
- }
- return secrets, sess.
- Where(opts.toConds()).
- Find(&secrets)
-}
-
-// CountSecrets counts the secrets
-func CountSecrets(ctx context.Context, opts *FindSecretsOptions) (int64, error) {
- return db.GetEngine(ctx).Where(opts.toConds()).Count(new(Secret))
-}
-
// UpdateSecret changes org or user reop secret.
func UpdateSecret(ctx context.Context, secretID int64, data string) error {
encrypted, err := secret_module.EncryptSecret(setting.SecretKey, data)
diff --git a/models/user/external_login_user.go b/models/user/external_login_user.go
index 4121c5d89f..0db702f225 100644
--- a/models/user/external_login_user.go
+++ b/models/user/external_login_user.go
@@ -96,19 +96,6 @@ func GetExternalLogin(ctx context.Context, externalLoginUser *ExternalLoginUser)
return db.GetEngine(ctx).Get(externalLoginUser)
}
-// ListAccountLinks returns a map with the ExternalLoginUser and its LoginSource
-func ListAccountLinks(ctx context.Context, user *User) ([]*ExternalLoginUser, error) {
- externalAccounts := make([]*ExternalLoginUser, 0, 5)
- err := db.GetEngine(ctx).Where("user_id=?", user.ID).
- Desc("login_source_id").
- Find(&externalAccounts)
- if err != nil {
- return nil, err
- }
-
- return externalAccounts, nil
-}
-
// LinkExternalToUser link the external user to the user
func LinkExternalToUser(ctx context.Context, user *User, externalLoginUser *ExternalLoginUser) error {
has, err := db.GetEngine(ctx).Where("external_id=? AND login_source_id=?", externalLoginUser.ExternalID, externalLoginUser.LoginSourceID).
@@ -173,28 +160,23 @@ func UpdateExternalUserByExternalID(ctx context.Context, external *ExternalLogin
// FindExternalUserOptions represents an options to find external users
type FindExternalUserOptions struct {
+ db.ListOptions
Provider string
- Limit int
- Start int
+ UserID int64
+ OrderBy string
}
-func (opts FindExternalUserOptions) toConds() builder.Cond {
+func (opts FindExternalUserOptions) ToConds() builder.Cond {
cond := builder.NewCond()
if len(opts.Provider) > 0 {
cond = cond.And(builder.Eq{"provider": opts.Provider})
}
+ if opts.UserID > 0 {
+ cond = cond.And(builder.Eq{"user_id": opts.UserID})
+ }
return cond
}
-// FindExternalUsersByProvider represents external users via provider
-func FindExternalUsersByProvider(ctx context.Context, opts FindExternalUserOptions) ([]ExternalLoginUser, error) {
- var users []ExternalLoginUser
- err := db.GetEngine(ctx).Where(opts.toConds()).
- Limit(opts.Limit, opts.Start).
- OrderBy("login_source_id ASC, external_id ASC").
- Find(&users)
- if err != nil {
- return nil, err
- }
- return users, nil
+func (opts FindExternalUserOptions) ToOrders() string {
+ return opts.OrderBy
}
diff --git a/models/webhook/webhook.go b/models/webhook/webhook.go
index b28cea6a9c..408023507a 100644
--- a/models/webhook/webhook.go
+++ b/models/webhook/webhook.go
@@ -435,7 +435,7 @@ type ListWebhookOptions struct {
IsActive util.OptionalBool
}
-func (opts *ListWebhookOptions) toCond() builder.Cond {
+func (opts ListWebhookOptions) ToConds() builder.Cond {
cond := builder.NewCond()
if opts.RepoID != 0 {
cond = cond.And(builder.Eq{"webhook.repo_id": opts.RepoID})
@@ -449,27 +449,6 @@ func (opts *ListWebhookOptions) toCond() builder.Cond {
return cond
}
-// ListWebhooksByOpts return webhooks based on options
-func ListWebhooksByOpts(ctx context.Context, opts *ListWebhookOptions) ([]*Webhook, error) {
- sess := db.GetEngine(ctx).Where(opts.toCond())
-
- if opts.Page != 0 {
- sess = db.SetSessionPagination(sess, opts)
- webhooks := make([]*Webhook, 0, opts.PageSize)
- err := sess.Find(&webhooks)
- return webhooks, err
- }
-
- webhooks := make([]*Webhook, 0, 10)
- err := sess.Find(&webhooks)
- return webhooks, err
-}
-
-// CountWebhooksByOpts count webhooks based on options and ignore pagination
-func CountWebhooksByOpts(ctx context.Context, opts *ListWebhookOptions) (int64, error) {
- return db.GetEngine(ctx).Where(opts.toCond()).Count(&Webhook{})
-}
-
// UpdateWebhook updates information of webhook.
func UpdateWebhook(ctx context.Context, w *Webhook) error {
_, err := db.GetEngine(ctx).ID(w.ID).AllCols().Update(w)
diff --git a/models/webhook/webhook_test.go b/models/webhook/webhook_test.go
index 6a01fdd75f..694fd7a873 100644
--- a/models/webhook/webhook_test.go
+++ b/models/webhook/webhook_test.go
@@ -123,7 +123,7 @@ func TestGetWebhookByOwnerID(t *testing.T) {
func TestGetActiveWebhooksByRepoID(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- hooks, err := ListWebhooksByOpts(db.DefaultContext, &ListWebhookOptions{RepoID: 1, IsActive: util.OptionalBoolTrue})
+ hooks, err := db.Find[Webhook](db.DefaultContext, ListWebhookOptions{RepoID: 1, IsActive: util.OptionalBoolTrue})
assert.NoError(t, err)
if assert.Len(t, hooks, 1) {
assert.Equal(t, int64(1), hooks[0].ID)
@@ -133,7 +133,7 @@ func TestGetActiveWebhooksByRepoID(t *testing.T) {
func TestGetWebhooksByRepoID(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- hooks, err := ListWebhooksByOpts(db.DefaultContext, &ListWebhookOptions{RepoID: 1})
+ hooks, err := db.Find[Webhook](db.DefaultContext, ListWebhookOptions{RepoID: 1})
assert.NoError(t, err)
if assert.Len(t, hooks, 2) {
assert.Equal(t, int64(1), hooks[0].ID)
@@ -143,7 +143,7 @@ func TestGetWebhooksByRepoID(t *testing.T) {
func TestGetActiveWebhooksByOwnerID(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- hooks, err := ListWebhooksByOpts(db.DefaultContext, &ListWebhookOptions{OwnerID: 3, IsActive: util.OptionalBoolTrue})
+ hooks, err := db.Find[Webhook](db.DefaultContext, ListWebhookOptions{OwnerID: 3, IsActive: util.OptionalBoolTrue})
assert.NoError(t, err)
if assert.Len(t, hooks, 1) {
assert.Equal(t, int64(3), hooks[0].ID)
@@ -153,7 +153,7 @@ func TestGetActiveWebhooksByOwnerID(t *testing.T) {
func TestGetWebhooksByOwnerID(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- hooks, err := ListWebhooksByOpts(db.DefaultContext, &ListWebhookOptions{OwnerID: 3})
+ hooks, err := db.Find[Webhook](db.DefaultContext, ListWebhookOptions{OwnerID: 3})
assert.NoError(t, err)
if assert.Len(t, hooks, 1) {
assert.Equal(t, int64(3), hooks[0].ID)