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

mendersoftware / mender-server / 1863989307

11 Jun 2025 08:38AM UTC coverage: 66.403% (+0.7%) from 65.731%
1863989307

Pull #720

gitlab-ci

mzedel
test(gui): made e2e tests work with changed tenant token expansion

Signed-off-by: Manuel Zedel <manuel.zedel@northern.tech>
Pull Request #720: MEN-8411 - billing/ organization split

29581 of 44548 relevant lines covered (66.4%)

1.45 hits per line

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

54.29
/backend/pkg/rest_utils/paging.go
1
// Copyright 2024 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 rest_utils
16

17
import (
18
        "errors"
19
        "fmt"
20
        "math"
21
        "net/url"
22
        "strconv"
23
        "strings"
24

25
        "github.com/ant0ine/go-json-rest/rest"
26

27
        micro_strings "github.com/mendersoftware/mender-server/pkg/strings"
28
)
29

30
// pagination constants
31
const (
32
        PageName       = "page"
33
        PerPageName    = "per_page"
34
        PageMin        = 1
35
        PageDefault    = 1
36
        PerPageMin     = 1
37
        PerPageMax     = 500
38
        PerPageDefault = 20
39
        LinkHdr        = "Link"
40
        LinkTmpl       = "<%s>; rel=\"%s\""
41
        LinkPrev       = "prev"
42
        LinkNext       = "next"
43
        LinkFirst      = "first"
44
        DefaultScheme  = "http"
45
)
46

47
// error msgs
48
func MsgQueryParmInvalid(name string) string {
1✔
49
        return fmt.Sprintf("Can't parse param %s", name)
1✔
50
}
1✔
51

52
func MsgQueryParmMissing(name string) string {
×
53
        return fmt.Sprintf("Missing required param %s", name)
×
54
}
×
55

56
func MsgQueryParmLimit(name string) string {
×
57
        return fmt.Sprintf("Param %s is out of bounds", name)
×
58
}
×
59

60
func MsgQueryParmOneOf(name string, allowed []string) string {
×
61
        return fmt.Sprintf("Param %s must be one of %v", name, allowed)
×
62
}
×
63

64
// query param parsing/validation
65
func ParseQueryParmUInt(
66
        r *rest.Request,
67
        name string,
68
        required bool,
69
        min, max, def uint64,
70
) (uint64, error) {
2✔
71
        strVal := r.URL.Query().Get(name)
2✔
72

2✔
73
        if strVal == "" {
4✔
74
                if required {
2✔
75
                        return 0, errors.New(MsgQueryParmMissing(name))
×
76
                } else {
2✔
77
                        return def, nil
2✔
78
                }
2✔
79
        }
80

81
        uintVal, err := strconv.ParseUint(strVal, 10, 32)
2✔
82
        if err != nil {
3✔
83
                return 0, errors.New(MsgQueryParmInvalid(name))
1✔
84
        }
1✔
85

86
        if uintVal < min || uintVal > max {
2✔
87
                return 0, errors.New(MsgQueryParmLimit(name))
×
88
        }
×
89

90
        return uintVal, nil
2✔
91
}
92

93
func ParseQueryParmBool(r *rest.Request, name string, required bool, def *bool) (*bool, error) {
×
94
        strVal := r.URL.Query().Get(name)
×
95

×
96
        if strVal == "" {
×
97
                if required {
×
98
                        return nil, errors.New(MsgQueryParmMissing(name))
×
99
                } else {
×
100
                        return def, nil
×
101
                }
×
102
        }
103

104
        boolVal, err := strconv.ParseBool(strVal)
×
105
        if err != nil {
×
106
                return nil, errors.New(MsgQueryParmInvalid(name))
×
107
        }
×
108

109
        return &boolVal, nil
×
110
}
111

112
func ParseQueryParmStr(
113
        r *rest.Request,
114
        name string,
115
        required bool,
116
        allowed []string,
117
) (string, error) {
×
118
        val := r.URL.Query().Get(name)
×
119

×
120
        if val == "" {
×
121
                if required {
×
122
                        return "", errors.New(MsgQueryParmMissing(name))
×
123
                }
×
124
        } else {
×
125
                if allowed != nil && !micro_strings.ContainsString(val, allowed) {
×
126
                        return "", errors.New(MsgQueryParmOneOf(name, allowed))
×
127
                }
×
128
        }
129

130
        return val, nil
×
131
}
132

133
// pagination helpers
134
func ParsePagination(r *rest.Request) (uint64, uint64, error) {
2✔
135
        page, err := ParseQueryParmUInt(r, PageName, false, PageMin, math.MaxUint64, PageDefault)
2✔
136
        if err != nil {
3✔
137
                return 0, 0, err
1✔
138
        }
1✔
139

140
        per_page, err := ParseQueryParmUInt(
2✔
141
                r,
2✔
142
                PerPageName,
2✔
143
                false,
2✔
144
                PerPageMin,
2✔
145
                PerPageMax,
2✔
146
                PerPageDefault,
2✔
147
        )
2✔
148
        if err != nil {
3✔
149
                return 0, 0, err
1✔
150
        }
1✔
151

152
        return page, per_page, nil
2✔
153
}
154

155
func MakePageLinkHdrs(r *rest.Request, page, per_page uint64, has_next bool) []string {
2✔
156
        var links []string
2✔
157
        if page > 1 {
4✔
158
                links = append(links, MakeLink(LinkPrev, r, page-1, per_page))
2✔
159
        }
2✔
160

161
        if has_next {
4✔
162
                links = append(links, MakeLink(LinkNext, r, page+1, per_page))
2✔
163
        }
2✔
164

165
        links = append(links, MakeLink(LinkFirst, r, 1, per_page))
2✔
166
        return links
2✔
167
}
168

169
// MakeLink creates a relative URL for insertion in the link header URL field.
170
func MakeLink(link_type string, r *rest.Request, page, per_page uint64) string {
2✔
171
        q := r.URL.Query()
2✔
172
        q.Set(PageName, strconv.Itoa(int(page)))
2✔
173
        q.Set(PerPageName, strconv.Itoa(int(per_page)))
2✔
174
        url := url.URL{
2✔
175
                Path:     r.URL.Path,
2✔
176
                RawPath:  r.URL.RawPath,
2✔
177
                RawQuery: q.Encode(),
2✔
178
                Fragment: r.URL.Fragment,
2✔
179
        }
2✔
180

2✔
181
        return fmt.Sprintf(LinkTmpl, url.String(), link_type)
2✔
182
}
2✔
183

184
// build URL using request 'r' and template, replace path params with
185
// elements from 'params' using lexical match as in strings.Replace()
186
func BuildURL(r *rest.Request, template string, params map[string]string) *url.URL {
×
187
        url := r.BaseUrl()
×
188

×
189
        path := template
×
190
        for k, v := range params {
×
191
                path = strings.Replace(path, k, v, -1)
×
192
        }
×
193
        url.Path = path
×
194

×
195
        return url
×
196
}
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