diff --git a/go.mod b/go.mod index 6f1dac602..23736cdac 100644 --- a/go.mod +++ b/go.mod @@ -72,3 +72,5 @@ replace github.com/bradfitz/gomemcache => github.com/themihai/gomemcache v0.0.0- // Required for Alertmanager replace github.com/hashicorp/consul => github.com/hashicorp/consul v1.8.1 + +replace github.com/grafana-tools/sdk => github.com/colega/grafana-tools-sdk v0.0.0-20220323154849-711bca56d13f diff --git a/go.sum b/go.sum index 4c7c8525d..116f1e7c8 100644 --- a/go.sum +++ b/go.sum @@ -416,6 +416,8 @@ github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/colega/grafana-tools-sdk v0.0.0-20220323154849-711bca56d13f h1:Mc/WpMhT0pzDD5zGjhge7PiO7nkrMME4GuGS1y4HGwk= +github.com/colega/grafana-tools-sdk v0.0.0-20220323154849-711bca56d13f/go.mod h1:AHHlOEv1+GGQ3ktHMlhuTUwo3zljV3QJbC0+8o2kn+4= github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= @@ -1160,8 +1162,6 @@ github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoA github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gosimple/slug v1.1.1 h1:fRu/digW+NMwBIP+RmviTK97Ho/bEj/C9swrCspN3D4= github.com/gosimple/slug v1.1.1/go.mod h1:ER78kgg1Mv0NQGlXiDe57DpCyfbNywXXZ9mIorhxAf0= -github.com/grafana-tools/sdk v0.0.0-20220203092117-edae16afa87b h1:R9LID2XreyUOQfJ/NKLGuYOF4/Wz6ljmYFAhlOaHVQ4= -github.com/grafana-tools/sdk v0.0.0-20220203092117-edae16afa87b/go.mod h1:AHHlOEv1+GGQ3ktHMlhuTUwo3zljV3QJbC0+8o2kn+4= github.com/grafana/dskit v0.0.0-20210818123532-6645f87e9e12/go.mod h1:QaNAQaCSFOtG/NHf6Jd/zh67H25kkrVCq36U61Y2Mhw= github.com/grafana/dskit v0.0.0-20210819132858-471020752967/go.mod h1:uF46UNN1/feB1egpq8UGbBBKvJjGgZauW7pcVbeFLLM= github.com/grafana/dskit v0.0.0-20211021180445-3bd016e9d7f1/go.mod h1:uPG2nyK4CtgNDmWv7qyzYcdI+S90kHHRWvHnBtEMBXM= diff --git a/vendor/github.com/grafana-tools/sdk/board.go b/vendor/github.com/grafana-tools/sdk/board.go index da8edf1fe..2e8fdafc9 100644 --- a/vendor/github.com/grafana-tools/sdk/board.go +++ b/vendor/github.com/grafana-tools/sdk/board.go @@ -79,24 +79,24 @@ type ( List []TemplateVar `json:"list"` } TemplateVar struct { - Name string `json:"name"` - Type string `json:"type"` - Auto bool `json:"auto,omitempty"` - AutoCount *int `json:"auto_count,omitempty"` - Datasource *string `json:"datasource"` - Refresh BoolInt `json:"refresh"` - Options []Option `json:"options"` - IncludeAll bool `json:"includeAll"` - AllFormat string `json:"allFormat"` - AllValue string `json:"allValue"` - Multi bool `json:"multi"` - MultiFormat string `json:"multiFormat"` - Query interface{} `json:"query"` - Regex string `json:"regex"` - Current Current `json:"current"` - Label string `json:"label"` - Hide uint8 `json:"hide"` - Sort int `json:"sort"` + Name string `json:"name"` + Type string `json:"type"` + Auto bool `json:"auto,omitempty"` + AutoCount *int `json:"auto_count,omitempty"` + Datasource *DatasourceRef `json:"datasource"` + Refresh BoolInt `json:"refresh"` + Options []Option `json:"options"` + IncludeAll bool `json:"includeAll"` + AllFormat string `json:"allFormat"` + AllValue string `json:"allValue"` + Multi bool `json:"multi"` + MultiFormat string `json:"multiFormat"` + Query interface{} `json:"query"` + Regex string `json:"regex"` + Current Current `json:"current"` + Label string `json:"label"` + Hide uint8 `json:"hide"` + Sort int `json:"sort"` } // for templateVar Option struct { @@ -111,23 +111,23 @@ type ( Value interface{} `json:"value"` // TODO select more precise type } Annotation struct { - Name string `json:"name"` - Datasource *string `json:"datasource"` - ShowLine bool `json:"showLine"` - IconColor string `json:"iconColor"` - LineColor string `json:"lineColor"` - IconSize uint `json:"iconSize"` - Enable bool `json:"enable"` - Query string `json:"query"` - Expr string `json:"expr"` - Step string `json:"step"` - TextField string `json:"textField"` - TextFormat string `json:"textFormat"` - TitleFormat string `json:"titleFormat"` - TagsField string `json:"tagsField"` - Tags []string `json:"tags"` - TagKeys string `json:"tagKeys"` - Type string `json:"type"` + Name string `json:"name"` + Datasource *DatasourceRef `json:"datasource"` + ShowLine bool `json:"showLine"` + IconColor string `json:"iconColor"` + LineColor string `json:"lineColor"` + IconSize uint `json:"iconSize"` + Enable bool `json:"enable"` + Query string `json:"query"` + Expr string `json:"expr"` + Step string `json:"step"` + TextField string `json:"textField"` + TextFormat string `json:"textFormat"` + TitleFormat string `json:"titleFormat"` + TagsField string `json:"tagsField"` + Tags []string `json:"tags"` + TagKeys string `json:"tagKeys"` + Type string `json:"type"` } // Link represents link to another dashboard or external weblink Link struct { diff --git a/vendor/github.com/grafana-tools/sdk/datasource.go b/vendor/github.com/grafana-tools/sdk/datasource.go index fe582fd23..c08ee3cff 100644 --- a/vendor/github.com/grafana-tools/sdk/datasource.go +++ b/vendor/github.com/grafana-tools/sdk/datasource.go @@ -1,5 +1,9 @@ package sdk +import ( + "encoding/json" +) + /* Copyright 2016 Alexander I.Grafov Copyright 2016-2019 The Grafana SDK authors @@ -24,14 +28,17 @@ package sdk type Datasource struct { ID uint `json:"id"` OrgID uint `json:"orgId"` + UID string `json:"uid"` Name string `json:"name"` Type string `json:"type"` + TypeLogoURL string `json:"typeLogoUrl"` Access string `json:"access"` // direct or proxy URL string `json:"url"` Password *string `json:"password,omitempty"` User *string `json:"user,omitempty"` Database *string `json:"database,omitempty"` BasicAuth *bool `json:"basicAuth,omitempty"` + ReadOnly *bool `json:"readOnly,omitempty"` BasicAuthUser *string `json:"basicAuthUser,omitempty"` BasicAuthPassword *string `json:"basicAuthPassword,omitempty"` IsDefault bool `json:"isDefault"` @@ -52,3 +59,37 @@ type DatasourceType struct { ServiceName string `json:"serviceName"` Type string `json:"type"` } + +// DatasourceRef is used to reference a datasource from panels, queries, etc. +type DatasourceRef struct { + // Type describes the type of the datasource, like "prometheus", "graphite", etc. + // Datasources of the same type should support same queries. + // If Type is empty in an unmarshaled DatasourceRef, check the LegacyName field. + Type string `json:"type"` + // UID is the uid of the specific datasource this references to. + UID string `json:"UID"` + // LegacyName is the old way of referencing a datasource by its name, replaced in Grafana v8.4.3 by Type and UID referencing. + // If datasource is encoded as a string, then it's unmarshaled into this LegacyName field (Type and UID will be empty). + // If LegacyName is not empty, then this DatasourceRef will be marshaled as a string, ignoring the values of Type and UID. + LegacyName string `json:"-"` +} + +func (ref DatasourceRef) MarshalJSON() ([]byte, error) { + if ref.LegacyName != "" { + return json.Marshal(ref.LegacyName) + } + type plain DatasourceRef + return json.Marshal(plain(ref)) +} + +func (ref *DatasourceRef) UnmarshalJSON(data []byte) error { + type plain DatasourceRef + err := json.Unmarshal(data, (*plain)(ref)) + if err != nil { + if err := json.Unmarshal(data, &ref.LegacyName); err == nil { + // We could check here if it's `-- Mixed --` and in that case set ref.Type="mixed". + return nil + } + } + return err +} diff --git a/vendor/github.com/grafana-tools/sdk/folder-permissions.go b/vendor/github.com/grafana-tools/sdk/folder-permissions.go new file mode 100644 index 000000000..c80451a60 --- /dev/null +++ b/vendor/github.com/grafana-tools/sdk/folder-permissions.go @@ -0,0 +1,46 @@ +package sdk + +/* + Copyright 2016 Alexander I.Grafov + Copyright 2016-2022 The Grafana SDK authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + ॐ तारे तुत्तारे तुरे स्व +*/ + +type PermissionType uint + +const PermissionView = PermissionType(1) +const PermissionEdit = PermissionType(2) +const PermissionAdmin = PermissionType(4) + +type FolderPermission struct { + Id uint `json:"id"` + FolderId uint `json:"folderId"` + Created string `json:"created"` + Updated string `json:"updated"` + UserId uint `json:"userId,omitempty"` + UserLogin string `json:"userLogin,omitempty"` + UserEmail string `json:"userEmail,omitempty"` + TeamId uint `json:"teamId,omitempty"` + Team string `json:"team,omitempty"` + Role string `json:"role,omitempty"` + Permission PermissionType `json:"permission"` + PermissionName string `json:"permissionName"` + Uid string `json:"uid,omitempty"` + Title string `json:"title,omitempty"` + Slug string `json:"slug,omitempty"` + IsFolder bool `json:"isFolder"` + Url string `json:"url,omitempty"` +} diff --git a/vendor/github.com/grafana-tools/sdk/panel.go b/vendor/github.com/grafana-tools/sdk/panel.go index 552c058cd..34479bd6f 100644 --- a/vendor/github.com/grafana-tools/sdk/panel.go +++ b/vendor/github.com/grafana-tools/sdk/panel.go @@ -66,9 +66,9 @@ type ( } panelType int8 CommonPanel struct { - Datasource *string `json:"datasource,omitempty"` // metrics - Editable bool `json:"editable"` - Error bool `json:"error"` + Datasource *DatasourceRef `json:"datasource,omitempty"` // metrics + Editable bool `json:"editable"` + Error bool `json:"error"` GridPos struct { H *int `json:"h,omitempty"` W *int `json:"w,omitempty"` @@ -373,8 +373,8 @@ type ( FieldConfigDefaults struct { Unit string `json:"unit"` Decimals *int `json:"decimals,omitempty"` - Min *int `json:"min,omitempty"` - Max *int `json:"max,omitempty"` + Min *float64 `json:"min,omitempty"` + Max *float64 `json:"max,omitempty"` Color FieldConfigColor `json:"color"` Thresholds Thresholds `json:"thresholds"` Custom FieldConfigCustom `json:"custom"` @@ -419,8 +419,8 @@ type ( Steps []ThresholdStep `json:"steps"` } ThresholdStep struct { - Color string `json:"color"` - Value *int `json:"value"` + Color string `json:"color"` + Value *float64 `json:"value"` } FieldConfigColor struct { Mode string `json:"mode"` @@ -549,9 +549,9 @@ type ( // for an any panel type Target struct { - RefID string `json:"refId"` - Datasource string `json:"datasource,omitempty"` - Hide bool `json:"hide,omitempty"` + RefID string `json:"refId"` + Datasource *DatasourceRef `json:"datasource,omitempty"` + Hide bool `json:"hide,omitempty"` // For PostgreSQL Table string `json:"table,omitempty"` @@ -942,7 +942,7 @@ func (p *Panel) RepeatDatasourcesForEachTarget(dsNames ...string) { for _, ds := range dsNames { newTarget := target newTarget.RefID = refID - newTarget.Datasource = ds + newTarget.Datasource = &DatasourceRef{LegacyName: ds} refID = incRefID(refID) *targets = append(*targets, newTarget) } @@ -973,13 +973,13 @@ func (p *Panel) RepeatTargetsForDatasources(dsNames ...string) { lenTargets := len(*targets) for i, name := range dsNames { if i < lenTargets { - (*targets)[i].Datasource = name + (*targets)[i].Datasource = &DatasourceRef{LegacyName: name} lastRefID = (*targets)[i].RefID } else { newTarget := (*targets)[i%lenTargets] lastRefID = incRefID(lastRefID) newTarget.RefID = lastRefID - newTarget.Datasource = name + newTarget.Datasource = &DatasourceRef{LegacyName: name} *targets = append(*targets, newTarget) } } diff --git a/vendor/github.com/grafana-tools/sdk/rest-dashboard.go b/vendor/github.com/grafana-tools/sdk/rest-dashboard.go index 653844c8c..06963ef1d 100644 --- a/vendor/github.com/grafana-tools/sdk/rest-dashboard.go +++ b/vendor/github.com/grafana-tools/sdk/rest-dashboard.go @@ -116,6 +116,38 @@ func (r *Client) GetDashboardBySlug(ctx context.Context, slug string) (Board, Bo return r.getDashboard(ctx, path) } +// DashboardVersion represents a response from /api/dashboards/id/:dashboardId/versions API +type DashboardVersion struct { + ID uint `json:"id"` + DashboardID uint `json:"dashboardId"` + ParentVersion uint `json:"parentVersion"` + RestoredFrom uint `json:"restoredFrom"` + Version uint `json:"version"` + Created time.Time `json:"created"` + CreatedBy string `json:"createdBy"` + Message string `json:"message"` +} + +// GetDashboardVersionsByDashboardID reflects /api/dashboards/id/:dashboardId/versions API call +func (r *Client) GetDashboardVersionsByDashboardID(ctx context.Context, dashboardID uint, params ...QueryParam) ([]DashboardVersion, error) { + var ( + raw []byte + code int + err error + ) + + if raw, code, err = r.get(ctx, fmt.Sprintf("api/dashboards/id/%d/versions", dashboardID), queryParams(params...)); err != nil { + return nil, err + } + if code != 200 { + return nil, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } + var versions []DashboardVersion + err = json.Unmarshal(raw, &versions) + + return versions, err +} + // getDashboard loads a dashboard from Grafana instance along with metadata for a dashboard. // For dashboards from a filesystem set "file/" prefix for slug. By default dashboards from // a database assumed. Database dashboards may have "db/" prefix or may have not, it will @@ -396,8 +428,34 @@ type ( SearchParam func(*url.Values) // SearchParamType is a type accepted by SearchType func. SearchParamType string + // QueryParam is a type for specifying arbitrary API parameters + QueryParam func(*url.Values) ) +// queryParams returns url.Values built from multiple QueryParam +func queryParams(params ...QueryParam) url.Values { + u := url.URL{} + q := u.Query() + for _, p := range params { + p(&q) + } + return q +} + +// QueryParamStart sets `start` parameter +func QueryParamStart(start uint) QueryParam { + return func(v *url.Values) { + v.Set("start", strconv.Itoa(int(start))) + } +} + +// QueryParamLimit sets `limit` parameter +func QueryParamLimit(limit uint) QueryParam { + return func(v *url.Values) { + v.Set("limit", strconv.Itoa(int(limit))) + } +} + // Search entities to be used with SearchType(). const ( SearchTypeFolder SearchParamType = "dash-folder" diff --git a/vendor/github.com/grafana-tools/sdk/rest-folder-permissions.go b/vendor/github.com/grafana-tools/sdk/rest-folder-permissions.go new file mode 100644 index 000000000..962a28408 --- /dev/null +++ b/vendor/github.com/grafana-tools/sdk/rest-folder-permissions.go @@ -0,0 +1,74 @@ +package sdk + +/* + Copyright 2016 Alexander I.Grafov + Copyright 2016-2022 The Grafana SDK authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + ॐ तारे तुत्तारे तुरे स्व +*/ + +import ( + "context" + "encoding/json" + "fmt" +) + +// https://grafana.com/docs/grafana/latest/http_api/folder_permissions/ + +// GetFolderPermissions gets permissions for a folder. +// Reflects GET /api/folders/:uid/permissions API call. +func (r *Client) GetFolderPermissions(ctx context.Context, folderUID string) ([]FolderPermission, error) { + var ( + raw []byte + fs []FolderPermission + code int + err error + ) + if raw, code, err = r.get(ctx, fmt.Sprintf("api/folders/%s/permissions", folderUID), nil); err != nil { + return nil, err + } + if code != 200 { + return nil, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } + err = json.Unmarshal(raw, &fs) + return fs, err +} + +// UpdateFolderPermissions update folders permission +// Reflects PUT /api/folders/:uid/permissions API call. +func (r *Client) UpdateFolderPermissions(ctx context.Context, folderUID string, up ...FolderPermission) (StatusMessage, error) { + var ( + raw []byte + rf StatusMessage + code int + err error + ) + request := struct { + Items []FolderPermission `json:"items"` + }{ + Items: up, + } + if raw, err = json.Marshal(request); err != nil { + return rf, err + } + if raw, code, err = r.post(ctx, fmt.Sprintf("api/folders/%s/permissions", folderUID), nil, raw); err != nil { + return rf, err + } + if code != 200 { + return rf, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } + err = json.Unmarshal(raw, &rf) + return rf, err +} diff --git a/vendor/github.com/grafana-tools/sdk/rest-team.go b/vendor/github.com/grafana-tools/sdk/rest-team.go new file mode 100644 index 000000000..6f555e6f8 --- /dev/null +++ b/vendor/github.com/grafana-tools/sdk/rest-team.go @@ -0,0 +1,299 @@ +package sdk + +/* + Copyright 2016 Alexander I.Grafov + Copyright 2016-2022 The Grafana SDK authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + ॐ तारे तुत्तारे तुरे स्व +*/ + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "net/url" + "strconv" +) + +// SearchTeams search teams with optional parameters. +// Reflects GET /api/teams/search API call. +func (r *Client) SearchTeams(ctx context.Context, params ...SearchTeamParams) (PageTeams, error) { + var ( + raw []byte + pageTeams PageTeams + code int + err error + requestParams = make(url.Values) + ) + + for _, p := range params { + p(requestParams) + } + + if raw, code, err = r.get(ctx, "api/teams/search", requestParams); err != nil { + return pageTeams, err + } + if code != 200 { + return pageTeams, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } + dec := json.NewDecoder(bytes.NewReader(raw)) + dec.UseNumber() + if err := dec.Decode(&pageTeams); err != nil { + return pageTeams, fmt.Errorf("unmarshal teams: %s\n%s", err, raw) + } + return pageTeams, err +} + +func (r *Client) GetTeamByName(ctx context.Context, name string) (Team, error) { + var ( + team Team + err error + ) + search, err := r.SearchTeams(ctx, WithTeam(name)) + if err != nil { + return team, err + } + if len(search.Teams) == 0 { + return Team{}, TeamNotFound + } + + return search.Teams[0], nil +} + +// GetTeam gets an team by ID. +// Reflects GET /api/teams/:id API call. +func (r *Client) GetTeam(ctx context.Context, id uint) (Team, error) { + var ( + raw []byte + team Team + code int + err error + ) + if raw, code, err = r.get(ctx, fmt.Sprintf("api/teams/%d", id), nil); err != nil { + return team, err + } + if code != 200 { + return team, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } + dec := json.NewDecoder(bytes.NewReader(raw)) + dec.UseNumber() + if err := dec.Decode(&team); err != nil { + return team, fmt.Errorf("unmarshal team: %s\n%s", err, raw) + } + return team, err +} + +// CreateTeam creates a new team. +// Reflects POST /api/teams API call. +func (r *Client) CreateTeam(ctx context.Context, t Team) (StatusMessage, error) { + var ( + raw []byte + resp StatusMessage + err error + ) + if raw, err = json.Marshal(t); err != nil { + return StatusMessage{}, err + } + if raw, _, err = r.post(ctx, "api/teams", nil, raw); err != nil { + return StatusMessage{}, err + } + if err = json.Unmarshal(raw, &resp); err != nil { + return StatusMessage{}, err + } + return resp, nil +} + +// UpdateTeam updates a team. +// Reflects PUT /api/teams/:id API call. +func (r *Client) UpdateTeam(ctx context.Context, id uint, t Team) (StatusMessage, error) { + var ( + raw []byte + resp StatusMessage + err error + ) + if raw, err = json.Marshal(t); err != nil { + return StatusMessage{}, err + } + if raw, _, err = r.put(ctx, fmt.Sprintf("api/teams/%d", id), nil, raw); err != nil { + return StatusMessage{}, err + } + if err = json.Unmarshal(raw, &resp); err != nil { + return StatusMessage{}, err + } + return resp, nil +} + +// DeleteTeam deletes a team. +// Reflects DELETE /api/teams/:id API call. +func (r *Client) DeleteTeam(ctx context.Context, id uint) (StatusMessage, error) { + var ( + raw []byte + resp StatusMessage + err error + ) + if raw, _, err = r.delete(ctx, fmt.Sprintf("api/teams/%d", id)); err != nil { + return StatusMessage{}, err + } + if err = json.Unmarshal(raw, &resp); err != nil { + return StatusMessage{}, err + } + return resp, nil +} + +// GetTeamMembers gets the members of a team by id. +// Reflects GET /api/teams/:teamId/members API call. +func (r *Client) GetTeamMembers(ctx context.Context, teamId uint) ([]TeamMember, error) { + var ( + raw []byte + teamMembers []TeamMember + code int + err error + ) + if raw, code, err = r.get(ctx, fmt.Sprintf("api/teams/%d/members", teamId), nil); err != nil { + return teamMembers, err + } + if code != 200 { + return teamMembers, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } + dec := json.NewDecoder(bytes.NewReader(raw)) + dec.UseNumber() + if err := dec.Decode(&teamMembers); err != nil { + return teamMembers, fmt.Errorf("unmarshal team: %s\n%s", err, raw) + } + return teamMembers, err +} + +// AddTeamMember adds a member to a team. +// Reflects POST /api/teams/:teamId/members API call. +func (r *Client) AddTeamMember(ctx context.Context, teamId uint, userId uint) (StatusMessage, error) { + var ( + raw []byte + resp StatusMessage + err error + ) + if raw, err = json.Marshal(struct { + UserId uint `json:"userId"` + }{ + UserId: userId, + }); err != nil { + return StatusMessage{}, err + } + if raw, _, err = r.post(ctx, fmt.Sprintf("api/teams/%d/members", teamId), nil, raw); err != nil { + return StatusMessage{}, err + } + if err = json.Unmarshal(raw, &resp); err != nil { + return StatusMessage{}, err + } + return resp, nil +} + +// DeleteTeamMember removes a ream member from a team by id. +// Reflects DELETE /api/teams/:teamId/:userId API call. +func (r *Client) DeleteTeamMember(ctx context.Context, teamId uint, userId uint) (StatusMessage, error) { + var ( + raw []byte + resp StatusMessage + err error + ) + if raw, _, err = r.delete(ctx, fmt.Sprintf("api/teams/%d/members/%d", teamId, userId)); err != nil { + return StatusMessage{}, err + } + if err = json.Unmarshal(raw, &resp); err != nil { + return StatusMessage{}, err + } + return resp, nil +} + +// GetTeamPreferences gets the preferences for a team by id. +// Reflects GET /api/teams/:teamId/preferences API call. +func (r *Client) GetTeamPreferences(ctx context.Context, teamId uint) (TeamPreferences, error) { + var ( + raw []byte + teamPreferences TeamPreferences + code int + err error + ) + if raw, code, err = r.get(ctx, fmt.Sprintf("api/teams/%d/preferences", teamId), nil); err != nil { + return teamPreferences, err + } + if code != 200 { + return teamPreferences, fmt.Errorf("HTTP error %d: returns %s", code, raw) + } + dec := json.NewDecoder(bytes.NewReader(raw)) + dec.UseNumber() + if err := dec.Decode(&teamPreferences); err != nil { + return teamPreferences, fmt.Errorf("unmarshal team: %s\n%s", err, raw) + } + return teamPreferences, err +} + +// UpdateTeamPreferences updates the preferences for a team by id. +// Reflects PUT /api/teams/:teamId/preferences API call. +func (r *Client) UpdateTeamPreferences(ctx context.Context, teamId uint, tp TeamPreferences) (StatusMessage, error) { + var ( + raw []byte + resp StatusMessage + err error + ) + if raw, err = json.Marshal(tp); err != nil { + return StatusMessage{}, err + } + if raw, _, err = r.put(ctx, fmt.Sprintf("api/teams/%d/preferences", teamId), nil, raw); err != nil { + return StatusMessage{}, err + } + if err = json.Unmarshal(raw, &resp); err != nil { + return StatusMessage{}, err + } + return resp, nil +} + +// TeamNotFound is an error returned if the given team was not found. +var TeamNotFound = fmt.Errorf("team not found") + +// SearchTeamParams is the type for all options implementing query parameters +// perpage optional. default 1000 +// page optional. default 1 +// http://docs.grafana.org/http_api/team/#search-teams +// http://docs.grafana.org/http_api/team/#search-teams-with-paging +type SearchTeamParams func(values url.Values) + +// WithQuery adds a query parameter +func WithQuery(query string) SearchTeamParams { + return func(v url.Values) { + v.Set("query", query) + } +} + +// WithPagesize adds a page size query parameter +func WithPagesize(size uint) SearchTeamParams { + return func(v url.Values) { + v.Set("perpage", strconv.FormatUint(uint64(size),10)) + } +} + +// WithPage adds a page number query parameter +func WithPage(page uint) SearchTeamParams { + return func(v url.Values) { + v.Set("page", strconv.FormatUint(uint64(page),10)) + } +} + +// WithTeam adds a query parameter +func WithTeam(team string) SearchTeamParams { + return func(v url.Values) { + v.Set("team", team) + } +} \ No newline at end of file diff --git a/vendor/github.com/grafana-tools/sdk/team.go b/vendor/github.com/grafana-tools/sdk/team.go new file mode 100644 index 000000000..5c50e1e59 --- /dev/null +++ b/vendor/github.com/grafana-tools/sdk/team.go @@ -0,0 +1,51 @@ +package sdk + +/* + Copyright 2016 Alexander I.Grafov + Copyright 2016-2022 The Grafana SDK authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + ॐ तारे तुत्तारे तुरे स्व +*/ + +type Team struct { + ID uint `json:"id"` + Name string `json:"name"` + Email string `json:"email"` + OrgID uint `json:"orgId"` + Created string `json:"created"` + Updated string `json:"updated"` +} + +type PageTeams struct { + TotalCount int `json:"totalCount"` + Teams []Team `json:"teams"` + Page int `json:"page"` + PerPage int `json:"perPage"` +} + +type TeamMember struct { + OrgId uint `json:"orgId"` + TeamId uint `json:"teamId"` + UserId uint `json:"userId"` + Email string `json:"email"` + Login string `json:"login"` + AvatarUrl string `json:"avatarUrl"` +} + +type TeamPreferences struct { + Theme string `json:"theme"` + HomeDashboardId int `json:"homeDashboardId"` + Timezone string `json:"timezone"` +} diff --git a/vendor/modules.txt b/vendor/modules.txt index cf1d8e5ef..62bef95c1 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -450,7 +450,7 @@ github.com/googleapis/gax-go/v2/apierror/internal/proto github.com/gorilla/mux # github.com/gosimple/slug v1.1.1 github.com/gosimple/slug -# github.com/grafana-tools/sdk v0.0.0-20220203092117-edae16afa87b +# github.com/grafana-tools/sdk v0.0.0-20220203092117-edae16afa87b => github.com/colega/grafana-tools-sdk v0.0.0-20220323154849-711bca56d13f ## explicit github.com/grafana-tools/sdk # github.com/grafana/dskit v0.0.0-20211103155626-4e784973d341 @@ -1169,3 +1169,4 @@ rsc.io/binaryregexp/syntax # github.com/gocql/gocql => github.com/grafana/gocql v0.0.0-20200605141915-ba5dc39ece85 # github.com/bradfitz/gomemcache => github.com/themihai/gomemcache v0.0.0-20180902122335-24332e2d58ab # github.com/hashicorp/consul => github.com/hashicorp/consul v1.8.1 +# github.com/grafana-tools/sdk => github.com/colega/grafana-tools-sdk v0.0.0-20220323154849-711bca56d13f