@@ -32,6 +32,87 @@ import (
3232 issue_service "code.gitea.io/gitea/services/issue"
3333)
3434
35+ // parseIssueIsClosed parses the "state" query parameter and returns the corresponding isClosed option
36+ func parseIssueIsClosed (ctx * context.APIContext ) optional.Option [bool ] {
37+ switch ctx .FormString ("state" ) {
38+ case "closed" :
39+ return optional .Some (true )
40+ case "all" :
41+ return optional .None [bool ]()
42+ default :
43+ return optional .Some (false )
44+ }
45+ }
46+
47+ // parseIssueIsPull parses the "type" query parameter and returns the corresponding isPull option
48+ func parseIssueIsPull (ctx * context.APIContext ) optional.Option [bool ] {
49+ switch ctx .FormString ("type" ) {
50+ case "pulls" :
51+ return optional .Some (true )
52+ case "issues" :
53+ return optional .Some (false )
54+ default :
55+ return optional .None [bool ]()
56+ }
57+ }
58+
59+ // buildSearchIssuesRepoIDs builds the list of repository IDs for issue search based on query parameters.
60+ // It returns repoIDs, allPublic flag, and any error that occurred.
61+ func buildSearchIssuesRepoIDs (ctx * context.APIContext ) ([]int64 , bool , error ) {
62+ var repoIDs []int64
63+ var allPublic bool
64+
65+ opts := repo_model.SearchRepoOptions {
66+ Private : false ,
67+ AllPublic : true ,
68+ TopicOnly : false ,
69+ Collaborate : optional .None [bool ](),
70+ // This needs to be a column that is not nil in fixtures or
71+ // MySQL will return different results when sorting by null in some cases
72+ OrderBy : db .SearchOrderByAlphabetically ,
73+ Actor : ctx .Doer ,
74+ }
75+ if ctx .IsSigned {
76+ opts .Private = ! ctx .PublicOnly
77+ opts .AllLimited = true
78+ }
79+ if ctx .FormString ("owner" ) != "" {
80+ owner , err := user_model .GetUserByName (ctx , ctx .FormString ("owner" ))
81+ if err != nil {
82+ return nil , false , err
83+ }
84+ opts .OwnerID = owner .ID
85+ opts .AllLimited = false
86+ opts .AllPublic = false
87+ opts .Collaborate = optional .Some (false )
88+ }
89+ if ctx .FormString ("team" ) != "" {
90+ if ctx .FormString ("owner" ) == "" {
91+ return nil , false , fmt .Errorf ("owner organisation is required for filtering on team" )
92+ }
93+ team , err := organization .GetTeam (ctx , opts .OwnerID , ctx .FormString ("team" ))
94+ if err != nil {
95+ return nil , false , err
96+ }
97+ opts .TeamID = team .ID
98+ }
99+
100+ if opts .AllPublic {
101+ allPublic = true
102+ opts .AllPublic = false // set it false to avoid returning too many repos, we could filter by indexer
103+ }
104+ repoIDs , _ , err := repo_model .SearchRepositoryIDs (ctx , opts )
105+ if err != nil {
106+ return nil , false , err
107+ }
108+ if len (repoIDs ) == 0 {
109+ // no repos found, don't let the indexer return all repos
110+ repoIDs = []int64 {0 }
111+ }
112+
113+ return repoIDs , allPublic , nil
114+ }
115+
35116// SearchIssues searches for issues across the repositories that the user has access to
36117func SearchIssues (ctx * context.APIContext ) {
37118 // swagger:operation GET /repos/issues/search issue issueSearchIssues
@@ -136,97 +217,28 @@ func SearchIssues(ctx *context.APIContext) {
136217 return
137218 }
138219
139- var isClosed optional.Option [bool ]
140- switch ctx .FormString ("state" ) {
141- case "closed" :
142- isClosed = optional .Some (true )
143- case "all" :
144- isClosed = optional .None [bool ]()
145- default :
146- isClosed = optional .Some (false )
147- }
148-
149- var (
150- repoIDs []int64
151- allPublic bool
152- )
153- {
154- // find repos user can access (for issue search)
155- opts := repo_model.SearchRepoOptions {
156- Private : false ,
157- AllPublic : true ,
158- TopicOnly : false ,
159- Collaborate : optional .None [bool ](),
160- // This needs to be a column that is not nil in fixtures or
161- // MySQL will return different results when sorting by null in some cases
162- OrderBy : db .SearchOrderByAlphabetically ,
163- Actor : ctx .Doer ,
164- }
165- if ctx .IsSigned {
166- opts .Private = ! ctx .PublicOnly
167- opts .AllLimited = true
168- }
169- if ctx .FormString ("owner" ) != "" {
170- owner , err := user_model .GetUserByName (ctx , ctx .FormString ("owner" ))
171- if err != nil {
172- if user_model .IsErrUserNotExist (err ) {
173- ctx .APIError (http .StatusBadRequest , err )
174- } else {
175- ctx .APIErrorInternal (err )
176- }
177- return
178- }
179- opts .OwnerID = owner .ID
180- opts .AllLimited = false
181- opts .AllPublic = false
182- opts .Collaborate = optional .Some (false )
183- }
184- if ctx .FormString ("team" ) != "" {
185- if ctx .FormString ("owner" ) == "" {
186- ctx .APIError (http .StatusBadRequest , "Owner organisation is required for filtering on team" )
187- return
188- }
189- team , err := organization .GetTeam (ctx , opts .OwnerID , ctx .FormString ("team" ))
190- if err != nil {
191- if organization .IsErrTeamNotExist (err ) {
192- ctx .APIError (http .StatusBadRequest , err )
193- } else {
194- ctx .APIErrorInternal (err )
195- }
196- return
197- }
198- opts .TeamID = team .ID
199- }
220+ isClosed := parseIssueIsClosed (ctx )
200221
201- if opts .AllPublic {
202- allPublic = true
203- opts .AllPublic = false // set it false to avoid returning too many repos, we could filter by indexer
204- }
205- repoIDs , _ , err = repo_model .SearchRepositoryIDs (ctx , opts )
206- if err != nil {
222+ repoIDs , allPublic , err := buildSearchIssuesRepoIDs (ctx )
223+ if err != nil {
224+ if user_model .IsErrUserNotExist (err ) {
225+ ctx .APIError (http .StatusBadRequest , err )
226+ } else if organization .IsErrTeamNotExist (err ) {
227+ ctx .APIError (http .StatusBadRequest , err )
228+ } else if err .Error () == "owner organisation is required for filtering on team" {
229+ ctx .APIError (http .StatusBadRequest , err )
230+ } else {
207231 ctx .APIErrorInternal (err )
208- return
209- }
210- if len (repoIDs ) == 0 {
211- // no repos found, don't let the indexer return all repos
212- repoIDs = []int64 {0 }
213232 }
233+ return
214234 }
215235
216236 keyword := ctx .FormTrim ("q" )
217237 if strings .IndexByte (keyword , 0 ) >= 0 {
218238 keyword = ""
219239 }
220240
221- var isPull optional.Option [bool ]
222- switch ctx .FormString ("type" ) {
223- case "pulls" :
224- isPull = optional .Some (true )
225- case "issues" :
226- isPull = optional .Some (false )
227- default :
228- isPull = optional .None [bool ]()
229- }
241+ isPull := parseIssueIsPull (ctx )
230242
231243 var includedAnyLabels []int64
232244 {
0 commit comments