This commit is contained in:
@@ -5,18 +5,21 @@
|
||||
package issues
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/modules/container"
|
||||
"code.gitea.io/gitea/modules/label"
|
||||
"code.gitea.io/gitea/modules/optional"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"gitea.dev/models/db"
|
||||
"gitea.dev/modules/container"
|
||||
"gitea.dev/modules/label"
|
||||
"gitea.dev/modules/optional"
|
||||
"gitea.dev/modules/timeutil"
|
||||
"gitea.dev/modules/util"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
@@ -27,12 +30,6 @@ type ErrRepoLabelNotExist struct {
|
||||
RepoID int64
|
||||
}
|
||||
|
||||
// IsErrRepoLabelNotExist checks if an error is a RepoErrLabelNotExist.
|
||||
func IsErrRepoLabelNotExist(err error) bool {
|
||||
_, ok := err.(ErrRepoLabelNotExist)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrRepoLabelNotExist) Error() string {
|
||||
return fmt.Sprintf("label does not exist [label_id: %d, repo_id: %d]", err.LabelID, err.RepoID)
|
||||
}
|
||||
@@ -196,6 +193,42 @@ func (l *Label) ExclusiveScope() string {
|
||||
return l.Name[:lastIndex]
|
||||
}
|
||||
|
||||
// CompareLabelForDisplay compares labels for displaying them in dropdowns or lists.
|
||||
// Labels are grouped by their exclusive scope, and labels within the same scope
|
||||
// are sorted by their exclusive order, where unordered labels (order 0) come last.
|
||||
// Labels without a scope are listed first and everything else falls back to name order.
|
||||
func CompareLabelForDisplay(a, b *Label) int {
|
||||
scopeA, scopeB := a.ExclusiveScope(), b.ExclusiveScope()
|
||||
if scopeA != scopeB {
|
||||
if scopeA == "" {
|
||||
return -1
|
||||
}
|
||||
if scopeB == "" {
|
||||
return 1
|
||||
}
|
||||
return strings.Compare(scopeA, scopeB)
|
||||
}
|
||||
if scopeA != "" {
|
||||
orderA, orderB := a.ExclusiveOrder, b.ExclusiveOrder
|
||||
if orderA <= 0 {
|
||||
orderA = math.MaxInt
|
||||
}
|
||||
if orderB <= 0 {
|
||||
orderB = math.MaxInt
|
||||
}
|
||||
if orderA != orderB {
|
||||
return cmp.Compare(orderA, orderB)
|
||||
}
|
||||
}
|
||||
return strings.Compare(a.Name, b.Name)
|
||||
}
|
||||
|
||||
// SortLabelsForDisplay sorts labels in place for displaying them in dropdowns or lists,
|
||||
// grouping them by their exclusive scope and respecting the exclusive order within each scope.
|
||||
func SortLabelsForDisplay(labels []*Label) {
|
||||
slices.SortStableFunc(labels, CompareLabelForDisplay)
|
||||
}
|
||||
|
||||
// NewLabel creates a new label
|
||||
func NewLabel(ctx context.Context, l *Label) error {
|
||||
color, err := label.NormalizeColor(l.Color)
|
||||
@@ -312,6 +345,18 @@ func GetLabelInRepoByName(ctx context.Context, repoID int64, labelName string) (
|
||||
return l, nil
|
||||
}
|
||||
|
||||
// GetLabelInRepoOrOrgByID returns the label with labelID scoped to the repo, falling back to the
|
||||
// repo's owning organization when ownerIsOrg is set. It returns ErrRepoLabelNotExist /
|
||||
// ErrOrgLabelNotExist when the label is in neither scope, so a foreign-but-existing label ID is
|
||||
// indistinguishable from a nonexistent one (no cross-repo enumeration oracle).
|
||||
func GetLabelInRepoOrOrgByID(ctx context.Context, repoID, ownerID int64, ownerIsOrg bool, labelID int64) (*Label, error) {
|
||||
label, err := GetLabelInRepoByID(ctx, repoID, labelID)
|
||||
if err != nil && errors.Is(err, util.ErrNotExist) && ownerIsOrg {
|
||||
return GetLabelInOrgByID(ctx, ownerID, labelID)
|
||||
}
|
||||
return label, err
|
||||
}
|
||||
|
||||
// GetLabelInRepoByID returns a label by ID in given repository.
|
||||
func GetLabelInRepoByID(ctx context.Context, repoID, labelID int64) (*Label, error) {
|
||||
if labelID <= 0 || repoID <= 0 {
|
||||
@@ -396,7 +441,7 @@ func GetLabelsByRepoID(ctx context.Context, repoID int64, sortType string, listO
|
||||
}
|
||||
|
||||
if listOptions.Page > 0 {
|
||||
sess = db.SetSessionPagination(sess, &listOptions)
|
||||
db.SetSessionPagination(sess, &listOptions)
|
||||
}
|
||||
|
||||
return labels, sess.Find(&labels)
|
||||
@@ -471,7 +516,7 @@ func GetLabelsByOrgID(ctx context.Context, orgID int64, sortType string, listOpt
|
||||
}
|
||||
|
||||
if listOptions.Page > 0 {
|
||||
sess = db.SetSessionPagination(sess, &listOptions)
|
||||
db.SetSessionPagination(sess, &listOptions)
|
||||
}
|
||||
|
||||
return labels, sess.Find(&labels)
|
||||
|
||||
Reference in New Issue
Block a user