Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit7c6c486

Browse files
committed
Merge branch 'main' of github.com:/coder/coder into dk/system-notifications-lib
2 parents0f29293 +dd80958 commit7c6c486

File tree

36 files changed

+3345
-111
lines changed

36 files changed

+3345
-111
lines changed

‎agent/proto/agent_drpc_old.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package proto
2+
3+
import (
4+
"context"
5+
6+
"storj.io/drpc"
7+
)
8+
9+
// DRPCAgentClient20 is the Agent API at v2.0. Notably, it is missing GetAnnouncementBanners, but
10+
// is useful when you want to be maximally compatible with Coderd Release Versions from 2.9+
11+
typeDRPCAgentClient20interface {
12+
DRPCConn() drpc.Conn
13+
14+
GetManifest(ctx context.Context,in*GetManifestRequest) (*Manifest,error)
15+
GetServiceBanner(ctx context.Context,in*GetServiceBannerRequest) (*ServiceBanner,error)
16+
UpdateStats(ctx context.Context,in*UpdateStatsRequest) (*UpdateStatsResponse,error)
17+
UpdateLifecycle(ctx context.Context,in*UpdateLifecycleRequest) (*Lifecycle,error)
18+
BatchUpdateAppHealths(ctx context.Context,in*BatchUpdateAppHealthRequest) (*BatchUpdateAppHealthResponse,error)
19+
UpdateStartup(ctx context.Context,in*UpdateStartupRequest) (*Startup,error)
20+
BatchUpdateMetadata(ctx context.Context,in*BatchUpdateMetadataRequest) (*BatchUpdateMetadataResponse,error)
21+
BatchCreateLogs(ctx context.Context,in*BatchCreateLogsRequest) (*BatchCreateLogsResponse,error)
22+
}
23+
24+
// DRPCAgentClient21 is the Agent API at v2.1. It is useful if you want to be maximally compatible
25+
// with Coderd Release Versions from 2.12+
26+
typeDRPCAgentClient21interface {
27+
DRPCConn() drpc.Conn
28+
29+
GetManifest(ctx context.Context,in*GetManifestRequest) (*Manifest,error)
30+
GetServiceBanner(ctx context.Context,in*GetServiceBannerRequest) (*ServiceBanner,error)
31+
UpdateStats(ctx context.Context,in*UpdateStatsRequest) (*UpdateStatsResponse,error)
32+
UpdateLifecycle(ctx context.Context,in*UpdateLifecycleRequest) (*Lifecycle,error)
33+
BatchUpdateAppHealths(ctx context.Context,in*BatchUpdateAppHealthRequest) (*BatchUpdateAppHealthResponse,error)
34+
UpdateStartup(ctx context.Context,in*UpdateStartupRequest) (*Startup,error)
35+
BatchUpdateMetadata(ctx context.Context,in*BatchUpdateMetadataRequest) (*BatchUpdateMetadataResponse,error)
36+
BatchCreateLogs(ctx context.Context,in*BatchCreateLogsRequest) (*BatchCreateLogsResponse,error)
37+
GetAnnouncementBanners(ctx context.Context,in*GetAnnouncementBannersRequest) (*GetAnnouncementBannersResponse,error)
38+
}

‎coderd/httpapi/queryparams.go

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package httpapi
22

33
import (
4+
"database/sql"
45
"errors"
56
"fmt"
67
"net/url"
@@ -104,6 +105,27 @@ func (p *QueryParamParser) PositiveInt32(vals url.Values, def int32, queryParam
104105
returnv
105106
}
106107

108+
// NullableBoolean will return a null sql value if no input is provided.
109+
// SQLc still uses sql.NullBool rather than the generic type. So converting from
110+
// the generic type is required.
111+
func (p*QueryParamParser)NullableBoolean(vals url.Values,def sql.NullBool,queryParamstring) sql.NullBool {
112+
v,err:=parseNullableQueryParam[bool](p,vals,strconv.ParseBool, sql.Null[bool]{
113+
V:def.Bool,
114+
Valid:def.Valid,
115+
},queryParam)
116+
iferr!=nil {
117+
p.Errors=append(p.Errors, codersdk.ValidationError{
118+
Field:queryParam,
119+
Detail:fmt.Sprintf("Query param %q must be a valid boolean: %s",queryParam,err.Error()),
120+
})
121+
}
122+
123+
return sql.NullBool{
124+
Bool:v.V,
125+
Valid:v.Valid,
126+
}
127+
}
128+
107129
func (p*QueryParamParser)Boolean(vals url.Values,defbool,queryParamstring)bool {
108130
v,err:=parseQueryParam(p,vals,strconv.ParseBool,def,queryParam)
109131
iferr!=nil {
@@ -294,9 +316,34 @@ func ParseCustomList[T any](parser *QueryParamParser, vals url.Values, def []T,
294316
returnv
295317
}
296318

319+
funcparseNullableQueryParam[Tany](parser*QueryParamParser,vals url.Values,parsefunc(vstring) (T,error),def sql.Null[T],queryParamstring) (sql.Null[T],error) {
320+
setParse:=parseSingle(parser,parse,def.V,queryParam)
321+
returnparseQueryParamSet[sql.Null[T]](parser,vals,func(set []string) (sql.Null[T],error) {
322+
iflen(set)==0 {
323+
return sql.Null[T]{
324+
Valid:false,
325+
},nil
326+
}
327+
328+
value,err:=setParse(set)
329+
iferr!=nil {
330+
return sql.Null[T]{},err
331+
}
332+
return sql.Null[T]{
333+
V:value,
334+
Valid:true,
335+
},nil
336+
},def,queryParam)
337+
}
338+
297339
// parseQueryParam expects just 1 value set for the given query param.
298340
funcparseQueryParam[Tany](parser*QueryParamParser,vals url.Values,parsefunc(vstring) (T,error),defT,queryParamstring) (T,error) {
299-
setParse:=func(set []string) (T,error) {
341+
setParse:=parseSingle(parser,parse,def,queryParam)
342+
returnparseQueryParamSet(parser,vals,setParse,def,queryParam)
343+
}
344+
345+
funcparseSingle[Tany](parser*QueryParamParser,parsefunc(vstring) (T,error),defT,queryParamstring)func(set []string) (T,error) {
346+
returnfunc(set []string) (T,error) {
300347
iflen(set)>1 {
301348
// Set as a parser.Error rather than return an error.
302349
// Returned errors are errors from the passed in `parse` function, and
@@ -311,7 +358,6 @@ func parseQueryParam[T any](parser *QueryParamParser, vals url.Values, parse fun
311358
}
312359
returnparse(set[0])
313360
}
314-
returnparseQueryParamSet(parser,vals,setParse,def,queryParam)
315361
}
316362

317363
funcparseQueryParamSet[Tany](parser*QueryParamParser,vals url.Values,parsefunc(set []string) (T,error),defT,queryParamstring) (T,error) {

‎coderd/httpapi/queryparams_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package httpapi_test
22

33
import (
4+
"database/sql"
45
"fmt"
56
"net/http"
67
"net/url"
@@ -220,6 +221,65 @@ func TestParseQueryParams(t *testing.T) {
220221
testQueryParams(t,expParams,parser,parser.Boolean)
221222
})
222223

224+
t.Run("NullableBoolean",func(t*testing.T) {
225+
t.Parallel()
226+
expParams:= []queryParamTestCase[sql.NullBool]{
227+
{
228+
QueryParam:"valid_true",
229+
Value:"true",
230+
Expected: sql.NullBool{
231+
Bool:true,
232+
Valid:true,
233+
},
234+
},
235+
{
236+
QueryParam:"no_value_true_def",
237+
NoSet:true,
238+
Default: sql.NullBool{
239+
Bool:true,
240+
Valid:true,
241+
},
242+
Expected: sql.NullBool{
243+
Bool:true,
244+
Valid:true,
245+
},
246+
},
247+
{
248+
QueryParam:"no_value",
249+
NoSet:true,
250+
Expected: sql.NullBool{
251+
Bool:false,
252+
Valid:false,
253+
},
254+
},
255+
256+
{
257+
QueryParam:"invalid_boolean",
258+
Value:"yes",
259+
Expected: sql.NullBool{
260+
Bool:false,
261+
Valid:false,
262+
},
263+
ExpectedErrorContains:"must be a valid boolean",
264+
},
265+
{
266+
QueryParam:"unexpected_list",
267+
Values: []string{"true","false"},
268+
ExpectedErrorContains:multipleValuesError,
269+
// Expected value is a bit strange, but the error is raised
270+
// in the parser, not as a parse failure. Maybe this should be
271+
// fixed, but is how it is done atm.
272+
Expected: sql.NullBool{
273+
Bool:false,
274+
Valid:true,
275+
},
276+
},
277+
}
278+
279+
parser:=httpapi.NewQueryParamParser()
280+
testQueryParams(t,expParams,parser,parser.NullableBoolean)
281+
})
282+
223283
t.Run("Int",func(t*testing.T) {
224284
t.Parallel()
225285
expParams:= []queryParamTestCase[int]{

‎coderd/searchquery/search.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,52 @@ func Workspaces(query string, page codersdk.Pagination, agentInactiveDisconnectT
184184
returnfilter,parser.Errors
185185
}
186186

187+
funcTemplates(ctx context.Context,db database.Store,querystring) (database.GetTemplatesWithFilterParams, []codersdk.ValidationError) {
188+
// Always lowercase for all searches.
189+
query=strings.ToLower(query)
190+
values,errors:=searchTerms(query,func(termstring,values url.Values)error {
191+
// Default to the template name
192+
values.Add("name",term)
193+
returnnil
194+
})
195+
iflen(errors)>0 {
196+
return database.GetTemplatesWithFilterParams{},errors
197+
}
198+
199+
parser:=httpapi.NewQueryParamParser()
200+
filter:= database.GetTemplatesWithFilterParams{
201+
Deleted:parser.Boolean(values,false,"deleted"),
202+
// TODO: Should name be a fuzzy search?
203+
ExactName:parser.String(values,"","name"),
204+
IDs:parser.UUIDs(values, []uuid.UUID{},"ids"),
205+
Deprecated:parser.NullableBoolean(values, sql.NullBool{},"deprecated"),
206+
}
207+
208+
// Convert the "organization" parameter to an organization uuid. This can require
209+
// a database lookup.
210+
organizationArg:=parser.String(values,"","organization")
211+
iforganizationArg!="" {
212+
organizationID,err:=uuid.Parse(organizationArg)
213+
iferr==nil {
214+
filter.OrganizationID=organizationID
215+
}else {
216+
// Organization could be a name
217+
organization,err:=db.GetOrganizationByName(ctx,organizationArg)
218+
iferr!=nil {
219+
parser.Errors=append(parser.Errors, codersdk.ValidationError{
220+
Field:"organization",
221+
Detail:fmt.Sprintf("Organization %q either does not exist, or you are unauthorized to view it",organizationArg),
222+
})
223+
}else {
224+
filter.OrganizationID=organization.ID
225+
}
226+
}
227+
}
228+
229+
parser.ErrorExcessParams(values)
230+
returnfilter,parser.Errors
231+
}
232+
187233
funcsearchTerms(querystring,defaultKeyfunc(termstring,values url.Values)error) (url.Values, []codersdk.ValidationError) {
188234
searchValues:=make(url.Values)
189235

‎coderd/searchquery/search_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"testing"
99
"time"
1010

11+
"github.com/google/uuid"
1112
"github.com/stretchr/testify/assert"
1213
"github.com/stretchr/testify/require"
1314

@@ -454,3 +455,45 @@ func TestSearchUsers(t *testing.T) {
454455
})
455456
}
456457
}
458+
459+
funcTestSearchTemplates(t*testing.T) {
460+
t.Parallel()
461+
testCases:= []struct {
462+
Namestring
463+
Querystring
464+
Expected database.GetTemplatesWithFilterParams
465+
ExpectedErrorContainsstring
466+
}{
467+
{
468+
Name:"Empty",
469+
Query:"",
470+
Expected: database.GetTemplatesWithFilterParams{},
471+
},
472+
}
473+
474+
for_,c:=rangetestCases {
475+
c:=c
476+
t.Run(c.Name,func(t*testing.T) {
477+
t.Parallel()
478+
// Do not use a real database, this is only used for an
479+
// organization lookup.
480+
db:=dbmem.New()
481+
values,errs:=searchquery.Templates(context.Background(),db,c.Query)
482+
ifc.ExpectedErrorContains!="" {
483+
require.True(t,len(errs)>0,"expect some errors")
484+
vars strings.Builder
485+
for_,err:=rangeerrs {
486+
_,_=s.WriteString(fmt.Sprintf("%s: %s\n",err.Field,err.Detail))
487+
}
488+
require.Contains(t,s.String(),c.ExpectedErrorContains)
489+
}else {
490+
require.Len(t,errs,0,"expected no error")
491+
ifc.Expected.IDs==nil {
492+
// Nil and length 0 are the same
493+
c.Expected.IDs= []uuid.UUID{}
494+
}
495+
require.Equal(t,c.Expected,values,"expected values")
496+
}
497+
})
498+
}
499+
}

‎coderd/templates.go

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/coder/coder/v2/coderd/rbac"
2222
"github.com/coder/coder/v2/coderd/rbac/policy"
2323
"github.com/coder/coder/v2/coderd/schedule"
24+
"github.com/coder/coder/v2/coderd/searchquery"
2425
"github.com/coder/coder/v2/coderd/telemetry"
2526
"github.com/coder/coder/v2/coderd/util/ptr"
2627
"github.com/coder/coder/v2/coderd/workspacestats"
@@ -457,20 +458,12 @@ func (api *API) fetchTemplates(mutate func(r *http.Request, arg *database.GetTem
457458
returnfunc(rw http.ResponseWriter,r*http.Request) {
458459
ctx:=r.Context()
459460

460-
p:=httpapi.NewQueryParamParser()
461-
values:=r.URL.Query()
462-
463-
deprecated:= sql.NullBool{}
464-
ifvalues.Has("deprecated") {
465-
deprecated= sql.NullBool{
466-
Bool:p.Boolean(values,false,"deprecated"),
467-
Valid:true,
468-
}
469-
}
470-
iflen(p.Errors)>0 {
461+
queryStr:=r.URL.Query().Get("q")
462+
filter,errs:=searchquery.Templates(ctx,api.Database,queryStr)
463+
iflen(errs)>0 {
471464
httpapi.Write(ctx,rw,http.StatusBadRequest, codersdk.Response{
472-
Message:"Invalidquery params.",
473-
Validations:p.Errors,
465+
Message:"Invalidtemplate search query.",
466+
Validations:errs,
474467
})
475468
return
476469
}
@@ -484,9 +477,7 @@ func (api *API) fetchTemplates(mutate func(r *http.Request, arg *database.GetTem
484477
return
485478
}
486479

487-
args:= database.GetTemplatesWithFilterParams{
488-
Deprecated:deprecated,
489-
}
480+
args:=filter
490481
ifmutate!=nil {
491482
mutate(r,&args)
492483
}

‎coderd/templates_test.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,9 @@ func TestTemplatesByOrganization(t *testing.T) {
420420

421421
ctx:=testutil.Context(t,testutil.WaitLong)
422422

423-
templates,err:=client.TemplatesByOrganization(ctx,user.OrganizationID)
423+
templates,err:=client.Templates(ctx, codersdk.TemplateFilter{
424+
OrganizationID:user.OrganizationID,
425+
})
424426
require.NoError(t,err)
425427
require.Len(t,templates,1)
426428
})
@@ -440,7 +442,7 @@ func TestTemplatesByOrganization(t *testing.T) {
440442
require.Len(t,templates,2)
441443

442444
// Listing all should match
443-
templates,err=client.Templates(ctx)
445+
templates,err=client.Templates(ctx, codersdk.TemplateFilter{})
444446
require.NoError(t,err)
445447
require.Len(t,templates,2)
446448

@@ -473,12 +475,19 @@ func TestTemplatesByOrganization(t *testing.T) {
473475
ctx:=testutil.Context(t,testutil.WaitLong)
474476

475477
// All 4 are viewable by the owner
476-
templates,err:=client.Templates(ctx)
478+
templates,err:=client.Templates(ctx, codersdk.TemplateFilter{})
477479
require.NoError(t,err)
478480
require.Len(t,templates,4)
479481

482+
// View a single organization from the owner
483+
templates,err=client.Templates(ctx, codersdk.TemplateFilter{
484+
OrganizationID:owner.OrganizationID,
485+
})
486+
require.NoError(t,err)
487+
require.Len(t,templates,2)
488+
480489
// Only 2 are viewable by the org user
481-
templates,err=user.Templates(ctx)
490+
templates,err=user.Templates(ctx, codersdk.TemplateFilter{})
482491
require.NoError(t,err)
483492
require.Len(t,templates,2)
484493
for_,tmpl:=rangetemplates {

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp