• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / reporting / 732508278

pending completion
732508278

Pull #87

gitlab-ci

Fabio Tranchitella
refac: rename internal search end-point to `/tenants/{tenant_id}/devices/search`
Pull Request #87: MEN-5930: index device deployment objects

331 of 402 new or added lines in 12 files covered. (82.34%)

135 existing lines in 5 files now uncovered.

2196 of 2600 relevant lines covered (84.46%)

17.72 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.13
/api/http/management_devices.go
1
// Copyright 2022 Northern.tech AS
2
//
3
//    Licensed under the Apache License, Version 2.0 (the "License");
4
//    you may not use this file except in compliance with the License.
5
//    You may obtain a copy of the License at
6
//
7
//        http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//    Unless required by applicable law or agreed to in writing, software
10
//    distributed under the License is distributed on an "AS IS" BASIS,
11
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//    See the License for the specific language governing permissions and
13
//    limitations under the License.
14

15
package http
16

17
import (
18
        "context"
19
        "net/http"
20
        "os"
21
        "strconv"
22
        "strings"
23

24
        "github.com/gin-gonic/gin"
25
        "github.com/pkg/errors"
26

27
        "github.com/mendersoftware/go-lib-micro/identity"
28
        "github.com/mendersoftware/go-lib-micro/rbac"
29
        "github.com/mendersoftware/go-lib-micro/rest.utils"
30

31
        "github.com/mendersoftware/reporting/model"
32
)
33

34
type attributes struct {
35
        Limit      int         `json:"limit"`
36
        Count      int         `json:"count"`
37
        Attributes []attribute `json:"attributes"`
38
}
39

40
type attribute struct {
41
        Name  string `json:"name"`
42
        Scope string `json:"scope"`
43
}
44

45
func (mc *ManagementController) AggregateDevices(c *gin.Context) {
10✔
46
        ctx := c.Request.Context()
10✔
47

10✔
48
        params, err := parseAggregateParams(ctx, c)
10✔
49
        if err != nil {
14✔
50
                rest.RenderError(c,
4✔
51
                        http.StatusBadRequest,
4✔
52
                        errors.Wrap(err, "malformed request body"),
4✔
53
                )
4✔
54
                return
4✔
55
        }
4✔
56

57
        res, err := mc.reporting.AggregateDevices(ctx, params)
6✔
58
        if err != nil {
8✔
59
                rest.RenderError(c,
2✔
60
                        http.StatusInternalServerError,
2✔
61
                        err,
2✔
62
                )
2✔
63
                return
2✔
64
        }
2✔
65

66
        c.JSON(http.StatusOK, res)
4✔
67
}
68

69
func parseAggregateParams(ctx context.Context, c *gin.Context) (*model.AggregateParams, error) {
10✔
70
        var aggregateParams model.AggregateParams
10✔
71

10✔
72
        err := c.ShouldBindJSON(&aggregateParams)
10✔
73
        if err != nil {
12✔
74
                return nil, err
2✔
75
        }
2✔
76

77
        if id := identity.FromContext(ctx); id != nil {
16✔
78
                aggregateParams.TenantID = id.Tenant
8✔
79
        } else {
8✔
NEW
80
                return nil, errors.New("missing tenant ID from the context")
×
NEW
81
        }
×
82

83
        if scope := rbac.ExtractScopeFromHeader(c.Request); scope != nil {
8✔
NEW
84
                aggregateParams.Groups = scope.DeviceGroups
×
NEW
85
        }
×
86

87
        if err := aggregateParams.Validate(); err != nil {
10✔
88
                return nil, err
2✔
89
        }
2✔
90

91
        return &aggregateParams, nil
6✔
92
}
93

94
func (mc *ManagementController) DeviceAttrs(c *gin.Context) {
10✔
95
        ctx := c.Request.Context()
10✔
96

10✔
97
        var tenantID string
10✔
98
        if id := identity.FromContext(ctx); id != nil && id.Tenant != "" {
18✔
99
                tenantID = id.Tenant
8✔
100
        } else {
10✔
101
                rest.RenderError(c,
2✔
102
                        http.StatusBadRequest,
2✔
103
                        errors.New("missing tenant ID from the context"),
2✔
104
                )
2✔
105
                return
2✔
106
        }
2✔
107

108
        mapping, err := mc.reporting.GetMapping(ctx, tenantID)
8✔
109
        if err != nil {
10✔
110
                rest.RenderError(c,
2✔
111
                        http.StatusInternalServerError,
2✔
112
                        errors.Wrap(err, "failed to retrieve the mapping"),
2✔
113
                )
2✔
114
                return
2✔
115
        } else if mapping == nil {
10✔
116
                mapping = &model.Mapping{}
2✔
117
        }
2✔
118

119
        attributesList := make([]attribute, 0, len(mapping.Inventory))
6✔
120
        for _, attr := range mapping.Inventory {
10✔
121
                parts := strings.SplitN(attr, string(os.PathSeparator), 2)
4✔
122
                attributesList = append(attributesList, attribute{
4✔
123
                        Name:  parts[1],
4✔
124
                        Scope: parts[0],
4✔
125
                })
4✔
126
        }
4✔
127
        res := &attributes{
6✔
128
                Limit:      model.MaxMappingInventoryAttributes,
6✔
129
                Count:      len(mapping.Inventory),
6✔
130
                Attributes: attributesList,
6✔
131
        }
6✔
132

6✔
133
        c.JSON(http.StatusOK, res)
6✔
134
}
135

136
func (mc *ManagementController) SearchDevices(c *gin.Context) {
21✔
137
        ctx := c.Request.Context()
21✔
138
        params, err := parseSearchParams(ctx, c)
21✔
139
        if err != nil {
25✔
140
                rest.RenderError(c,
4✔
141
                        http.StatusBadRequest,
4✔
142
                        errors.Wrap(err, "malformed request body"),
4✔
143
                )
4✔
144
                return
4✔
145
        }
4✔
146

147
        res, total, err := mc.reporting.SearchDevices(ctx, params)
17✔
148
        if err != nil {
19✔
149
                rest.RenderError(c,
2✔
150
                        http.StatusInternalServerError,
2✔
151
                        err,
2✔
152
                )
2✔
153
                return
2✔
154
        }
2✔
155

156
        pageLinkHdrs(c, params.Page, params.PerPage, total)
15✔
157

15✔
158
        c.Header(hdrTotalCount, strconv.Itoa(total))
15✔
159
        c.JSON(http.StatusOK, res)
15✔
160
}
161

162
func parseSearchParams(ctx context.Context, c *gin.Context) (*model.SearchParams, error) {
37✔
163
        var searchParams model.SearchParams
37✔
164

37✔
165
        err := c.ShouldBindJSON(&searchParams)
37✔
166
        if err != nil {
39✔
167
                return nil, err
2✔
168
        }
2✔
169

170
        if id := identity.FromContext(ctx); id != nil {
70✔
171
                searchParams.TenantID = id.Tenant
35✔
172
        } else {
35✔
NEW
173
                return nil, errors.New("missing tenant ID from the context")
×
NEW
174
        }
×
175

176
        if scope := rbac.ExtractScopeFromHeader(c.Request); scope != nil {
37✔
177
                searchParams.Groups = scope.DeviceGroups
2✔
178
        }
2✔
179

180
        if searchParams.PerPage <= 0 {
62✔
181
                searchParams.PerPage = ParamPerPageDefault
27✔
182
        }
27✔
183
        if searchParams.Page <= 0 {
62✔
184
                searchParams.Page = ParamPageDefault
27✔
185
        }
27✔
186

187
        if err := searchParams.Validate(); err != nil {
39✔
188
                return nil, err
4✔
189
        }
4✔
190

191
        return &searchParams, nil
31✔
192
}
193

NEW
194
func (mc *ManagementController) SearchDeviceAttrs(c *gin.Context) {
×
NEW
195
        ctx := c.Request.Context()
×
NEW
196

×
NEW
197
        id := identity.FromContext(ctx)
×
NEW
198
        res, err := mc.reporting.GetSearchableInvAttrs(ctx, id.Tenant)
×
NEW
199
        if err != nil {
×
NEW
200
                rest.RenderError(c,
×
NEW
201
                        http.StatusInternalServerError,
×
NEW
202
                        err,
×
NEW
203
                )
×
NEW
204
                return
×
NEW
205
        }
×
206

NEW
207
        c.JSON(http.StatusOK, res)
×
208
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc