@@ -7,12 +7,12 @@ package issues
77import (
88 "context"
99 "fmt"
10- "regexp"
1110 "strconv"
1211 "strings"
1312
1413 "code.gitea.io/gitea/models/db"
1514 user_model "code.gitea.io/gitea/models/user"
15+ "code.gitea.io/gitea/modules/label"
1616 "code.gitea.io/gitea/modules/timeutil"
1717 "code.gitea.io/gitea/modules/util"
1818
@@ -78,9 +78,6 @@ func (err ErrLabelNotExist) Unwrap() error {
7878 return util .ErrNotExist
7979}
8080
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-
8481// Label represents a label of repository for issues.
8582type Label struct {
8683 ID int64 `xorm:"pk autoincr"`
@@ -109,35 +106,35 @@ func init() {
109106}
110107
111108// 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
114111}
115112
116113// 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 ) {
118115 counts , _ := CountIssuesByRepo (ctx , & IssuesOptions {
119116 RepoID : repoID ,
120117 LabelIDs : []int64 {labelID },
121118 IsClosed : util .OptionalBoolFalse ,
122119 })
123120
124121 for _ , count := range counts {
125- label .NumOpenRepoIssues += count
122+ l .NumOpenRepoIssues += count
126123 }
127124}
128125
129126// 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 ) {
131128 var labelQuerySlice []string
132129 labelSelected := false
133- labelID := strconv .FormatInt (label .ID , 10 )
134- labelScope := label .ExclusiveScope ()
130+ labelID := strconv .FormatInt (l .ID , 10 )
131+ labelScope := l .ExclusiveScope ()
135132 for i , s := range currentSelectedLabels {
136- if s == label .ID {
133+ if s == l .ID {
137134 labelSelected = true
138- } else if - s == label .ID {
135+ } else if - s == l .ID {
139136 labelSelected = true
140- label .IsExcluded = true
137+ l .IsExcluded = true
141138 } else if s != 0 {
142139 // Exclude other labels in the same scope from selection
143140 if s < 0 || labelScope == "" || labelScope != currentSelectedExclusiveScopes [i ] {
@@ -148,23 +145,23 @@ func (label *Label) LoadSelectedLabelsAfterClick(currentSelectedLabels []int64,
148145 if ! labelSelected {
149146 labelQuerySlice = append (labelQuerySlice , labelID )
150147 }
151- label .IsSelected = labelSelected
152- label .QueryString = strings .Join (labelQuerySlice , "," )
148+ l .IsSelected = labelSelected
149+ l .QueryString = strings .Join (labelQuerySlice , "," )
153150}
154151
155152// 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
158155}
159156
160157// 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
163160}
164161
165162// 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 )
168165 if err != nil {
169166 return 0 , 0 , 0 , err
170167 }
@@ -176,9 +173,9 @@ func (label *Label) ColorRGB() (float64, float64, float64, error) {
176173}
177174
178175// 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 {
182179 // Perceived brightness from: https://www.w3.org/TR/AERT/#color-contrast
183180 // In the future WCAG 3 APCA may be a better solution
184181 brightness := (0.299 * r + 0.587 * g + 0.114 * b ) / 255
@@ -190,40 +187,26 @@ func (label *Label) UseLightTextColor() bool {
190187}
191188
192189// 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 {
195192 return ""
196193 }
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 {
199196 return ""
200197 }
201- return label .Name [:lastIndex ]
198+ return l .Name [:lastIndex ]
202199}
203200
204201// 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
224206 }
207+ l .Color = color
225208
226- return db .Insert (ctx , label )
209+ return db .Insert (ctx , l )
227210}
228211
229212// NewLabels creates new labels
@@ -234,11 +217,14 @@ func NewLabels(labels ...*Label) error {
234217 }
235218 defer committer .Close ()
236219
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
240224 }
241- if err := db .Insert (ctx , label ); err != nil {
225+ l .Color = color
226+
227+ if err := db .Insert (ctx , l ); err != nil {
242228 return err
243229 }
244230 }
@@ -247,15 +233,18 @@ func NewLabels(labels ...*Label) error {
247233
248234// UpdateLabel updates label information.
249235func 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
252239 }
240+ l .Color = color
241+
253242 return updateLabelCols (db .DefaultContext , l , "name" , "description" , "color" , "exclusive" )
254243}
255244
256245// DeleteLabel delete a label
257246func DeleteLabel (id , labelID int64 ) error {
258- label , err := GetLabelByID (db .DefaultContext , labelID )
247+ l , err := GetLabelByID (db .DefaultContext , labelID )
259248 if err != nil {
260249 if IsErrLabelNotExist (err ) {
261250 return nil
@@ -271,10 +260,10 @@ func DeleteLabel(id, labelID int64) error {
271260
272261 sess := db .GetEngine (ctx )
273262
274- if label .BelongsToOrg () && label .OrgID != id {
263+ if l .BelongsToOrg () && l .OrgID != id {
275264 return nil
276265 }
277- if label .BelongsToRepo () && label .RepoID != id {
266+ if l .BelongsToRepo () && l .RepoID != id {
278267 return nil
279268 }
280269
@@ -682,14 +671,14 @@ func newIssueLabels(ctx context.Context, issue *Issue, labels []*Label, doer *us
682671 if err = issue .LoadRepo (ctx ); err != nil {
683672 return err
684673 }
685- for _ , label := range labels {
674+ for _ , l := range labels {
686675 // 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 ) {
689678 continue
690679 }
691680
692- if err = newIssueLabel (ctx , issue , label , doer ); err != nil {
681+ if err = newIssueLabel (ctx , issue , l , doer ); err != nil {
693682 return fmt .Errorf ("newIssueLabel: %w" , err )
694683 }
695684 }
0 commit comments