@@ -7,12 +7,12 @@ package issues
7
7
import (
8
8
"context"
9
9
"fmt"
10
- "regexp"
11
10
"strconv"
12
11
"strings"
13
12
14
13
"code.gitea.io/gitea/models/db"
15
14
user_model "code.gitea.io/gitea/models/user"
15
+ "code.gitea.io/gitea/modules/label"
16
16
"code.gitea.io/gitea/modules/timeutil"
17
17
"code.gitea.io/gitea/modules/util"
18
18
@@ -78,9 +78,6 @@ func (err ErrLabelNotExist) Unwrap() error {
78
78
return util .ErrNotExist
79
79
}
80
80
81
- // LabelColorPattern is a regexp witch can validate LabelColor
82
- var LabelColorPattern = regexp .MustCompile ("^#?(?:[0-9a-fA-F]{6}|[0-9a-fA-F]{3})$" )
83
-
84
81
// Label represents a label of repository for issues.
85
82
type Label struct {
86
83
ID int64 `xorm:"pk autoincr"`
@@ -109,35 +106,35 @@ func init() {
109
106
}
110
107
111
108
// CalOpenIssues sets the number of open issues of a label based on the already stored number of closed issues.
112
- func (label * Label ) CalOpenIssues () {
113
- label .NumOpenIssues = label .NumIssues - label .NumClosedIssues
109
+ func (l * Label ) CalOpenIssues () {
110
+ l .NumOpenIssues = l .NumIssues - l .NumClosedIssues
114
111
}
115
112
116
113
// CalOpenOrgIssues calculates the open issues of a label for a specific repo
117
- func (label * Label ) CalOpenOrgIssues (ctx context.Context , repoID , labelID int64 ) {
114
+ func (l * Label ) CalOpenOrgIssues (ctx context.Context , repoID , labelID int64 ) {
118
115
counts , _ := CountIssuesByRepo (ctx , & IssuesOptions {
119
116
RepoID : repoID ,
120
117
LabelIDs : []int64 {labelID },
121
118
IsClosed : util .OptionalBoolFalse ,
122
119
})
123
120
124
121
for _ , count := range counts {
125
- label .NumOpenRepoIssues += count
122
+ l .NumOpenRepoIssues += count
126
123
}
127
124
}
128
125
129
126
// LoadSelectedLabelsAfterClick calculates the set of selected labels when a label is clicked
130
- func (label * Label ) LoadSelectedLabelsAfterClick (currentSelectedLabels []int64 , currentSelectedExclusiveScopes []string ) {
127
+ func (l * Label ) LoadSelectedLabelsAfterClick (currentSelectedLabels []int64 , currentSelectedExclusiveScopes []string ) {
131
128
var labelQuerySlice []string
132
129
labelSelected := false
133
- labelID := strconv .FormatInt (label .ID , 10 )
134
- labelScope := label .ExclusiveScope ()
130
+ labelID := strconv .FormatInt (l .ID , 10 )
131
+ labelScope := l .ExclusiveScope ()
135
132
for i , s := range currentSelectedLabels {
136
- if s == label .ID {
133
+ if s == l .ID {
137
134
labelSelected = true
138
- } else if - s == label .ID {
135
+ } else if - s == l .ID {
139
136
labelSelected = true
140
- label .IsExcluded = true
137
+ l .IsExcluded = true
141
138
} else if s != 0 {
142
139
// Exclude other labels in the same scope from selection
143
140
if s < 0 || labelScope == "" || labelScope != currentSelectedExclusiveScopes [i ] {
@@ -148,23 +145,23 @@ func (label *Label) LoadSelectedLabelsAfterClick(currentSelectedLabels []int64,
148
145
if ! labelSelected {
149
146
labelQuerySlice = append (labelQuerySlice , labelID )
150
147
}
151
- label .IsSelected = labelSelected
152
- label .QueryString = strings .Join (labelQuerySlice , "," )
148
+ l .IsSelected = labelSelected
149
+ l .QueryString = strings .Join (labelQuerySlice , "," )
153
150
}
154
151
155
152
// BelongsToOrg returns true if label is an organization label
156
- func (label * Label ) BelongsToOrg () bool {
157
- return label .OrgID > 0
153
+ func (l * Label ) BelongsToOrg () bool {
154
+ return l .OrgID > 0
158
155
}
159
156
160
157
// BelongsToRepo returns true if label is a repository label
161
- func (label * Label ) BelongsToRepo () bool {
162
- return label .RepoID > 0
158
+ func (l * Label ) BelongsToRepo () bool {
159
+ return l .RepoID > 0
163
160
}
164
161
165
162
// Get color as RGB values in 0..255 range
166
- func (label * Label ) ColorRGB () (float64 , float64 , float64 , error ) {
167
- color , err := strconv .ParseUint (label .Color [1 :], 16 , 64 )
163
+ func (l * Label ) ColorRGB () (float64 , float64 , float64 , error ) {
164
+ color , err := strconv .ParseUint (l .Color [1 :], 16 , 64 )
168
165
if err != nil {
169
166
return 0 , 0 , 0 , err
170
167
}
@@ -176,9 +173,9 @@ func (label *Label) ColorRGB() (float64, float64, float64, error) {
176
173
}
177
174
178
175
// Determine if label text should be light or dark to be readable on background color
179
- func (label * Label ) UseLightTextColor () bool {
180
- if strings .HasPrefix (label .Color , "#" ) {
181
- if r , g , b , err := label .ColorRGB (); err == nil {
176
+ func (l * Label ) UseLightTextColor () bool {
177
+ if strings .HasPrefix (l .Color , "#" ) {
178
+ if r , g , b , err := l .ColorRGB (); err == nil {
182
179
// Perceived brightness from: https://www.w3.org/TR/AERT/#color-contrast
183
180
// In the future WCAG 3 APCA may be a better solution
184
181
brightness := (0.299 * r + 0.587 * g + 0.114 * b ) / 255
@@ -190,40 +187,26 @@ func (label *Label) UseLightTextColor() bool {
190
187
}
191
188
192
189
// Return scope substring of label name, or empty string if none exists
193
- func (label * Label ) ExclusiveScope () string {
194
- if ! label .Exclusive {
190
+ func (l * Label ) ExclusiveScope () string {
191
+ if ! l .Exclusive {
195
192
return ""
196
193
}
197
- lastIndex := strings .LastIndex (label .Name , "/" )
198
- if lastIndex == - 1 || lastIndex == 0 || lastIndex == len (label .Name )- 1 {
194
+ lastIndex := strings .LastIndex (l .Name , "/" )
195
+ if lastIndex == - 1 || lastIndex == 0 || lastIndex == len (l .Name )- 1 {
199
196
return ""
200
197
}
201
- return label .Name [:lastIndex ]
198
+ return l .Name [:lastIndex ]
202
199
}
203
200
204
201
// NewLabel creates a new label
205
- func NewLabel (ctx context.Context , label * Label ) error {
206
- if ! LabelColorPattern .MatchString (label .Color ) {
207
- return fmt .Errorf ("bad color code: %s" , label .Color )
208
- }
209
-
210
- // normalize case
211
- label .Color = strings .ToLower (label .Color )
212
-
213
- // add leading hash
214
- if label .Color [0 ] != '#' {
215
- label .Color = "#" + label .Color
216
- }
217
-
218
- // convert 3-character shorthand into 6-character version
219
- if len (label .Color ) == 4 {
220
- r := label .Color [1 ]
221
- g := label .Color [2 ]
222
- b := label .Color [3 ]
223
- label .Color = fmt .Sprintf ("#%c%c%c%c%c%c" , r , r , g , g , b , b )
202
+ func NewLabel (ctx context.Context , l * Label ) error {
203
+ color , err := label .NormalizeColor (l .Color )
204
+ if err != nil {
205
+ return err
224
206
}
207
+ l .Color = color
225
208
226
- return db .Insert (ctx , label )
209
+ return db .Insert (ctx , l )
227
210
}
228
211
229
212
// NewLabels creates new labels
@@ -234,11 +217,14 @@ func NewLabels(labels ...*Label) error {
234
217
}
235
218
defer committer .Close ()
236
219
237
- for _ , label := range labels {
238
- if ! LabelColorPattern .MatchString (label .Color ) {
239
- return fmt .Errorf ("bad color code: %s" , label .Color )
220
+ for _ , l := range labels {
221
+ color , err := label .NormalizeColor (l .Color )
222
+ if err != nil {
223
+ return err
240
224
}
241
- if err := db .Insert (ctx , label ); err != nil {
225
+ l .Color = color
226
+
227
+ if err := db .Insert (ctx , l ); err != nil {
242
228
return err
243
229
}
244
230
}
@@ -247,15 +233,18 @@ func NewLabels(labels ...*Label) error {
247
233
248
234
// UpdateLabel updates label information.
249
235
func UpdateLabel (l * Label ) error {
250
- if ! LabelColorPattern .MatchString (l .Color ) {
251
- return fmt .Errorf ("bad color code: %s" , l .Color )
236
+ color , err := label .NormalizeColor (l .Color )
237
+ if err != nil {
238
+ return err
252
239
}
240
+ l .Color = color
241
+
253
242
return updateLabelCols (db .DefaultContext , l , "name" , "description" , "color" , "exclusive" )
254
243
}
255
244
256
245
// DeleteLabel delete a label
257
246
func DeleteLabel (id , labelID int64 ) error {
258
- label , err := GetLabelByID (db .DefaultContext , labelID )
247
+ l , err := GetLabelByID (db .DefaultContext , labelID )
259
248
if err != nil {
260
249
if IsErrLabelNotExist (err ) {
261
250
return nil
@@ -271,10 +260,10 @@ func DeleteLabel(id, labelID int64) error {
271
260
272
261
sess := db .GetEngine (ctx )
273
262
274
- if label .BelongsToOrg () && label .OrgID != id {
263
+ if l .BelongsToOrg () && l .OrgID != id {
275
264
return nil
276
265
}
277
- if label .BelongsToRepo () && label .RepoID != id {
266
+ if l .BelongsToRepo () && l .RepoID != id {
278
267
return nil
279
268
}
280
269
@@ -682,14 +671,14 @@ func newIssueLabels(ctx context.Context, issue *Issue, labels []*Label, doer *us
682
671
if err = issue .LoadRepo (ctx ); err != nil {
683
672
return err
684
673
}
685
- for _ , label := range labels {
674
+ for _ , l := range labels {
686
675
// Don't add already present labels and invalid labels
687
- if HasIssueLabel (ctx , issue .ID , label .ID ) ||
688
- (label .RepoID != issue .RepoID && label .OrgID != issue .Repo .OwnerID ) {
676
+ if HasIssueLabel (ctx , issue .ID , l .ID ) ||
677
+ (l .RepoID != issue .RepoID && l .OrgID != issue .Repo .OwnerID ) {
689
678
continue
690
679
}
691
680
692
- if err = newIssueLabel (ctx , issue , label , doer ); err != nil {
681
+ if err = newIssueLabel (ctx , issue , l , doer ); err != nil {
693
682
return fmt .Errorf ("newIssueLabel: %w" , err )
694
683
}
695
684
}
0 commit comments