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

mendersoftware / mender-server / 1833359013

23 May 2025 01:25PM UTC coverage: 66.318% (+0.5%) from 65.861%
1833359013

Pull #674

gitlab-ci

mzedel
fix(gui): prevented device tag editor to be shown when no tags exist

- this is to reduce confusion about tags defined async to the current session not being visible

Ticket: ME-528
Signed-off-by: Manuel Zedel <manuel.zedel@northern.tech>
Pull Request #674: ME-529, ME-528 - adjustments to device tag editing

29554 of 44564 relevant lines covered (66.32%)

1.45 hits per line

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

12.6
/backend/pkg/rest.utils/paging.go
1
// Copyright 2023 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
16

17
import (
18
        "fmt"
19
        "net/http"
20
        "net/url"
21
        "strconv"
22

23
        "github.com/pkg/errors"
24
)
25

26
const (
27
        PerPageDefault = 20
28
        PerPageMax     = 500
29

30
        pageQueryParam    = "page"
31
        perPageQueryParam = "per_page"
32
)
33

34
var (
35
        ErrPerPageLimit = errors.Errorf(
36
                `parameter "per_page" above limit (max: %d)`, PerPageMax,
37
        )
38
)
39

40
// ParsePagingParameters parses the paging parameters from the URL query
41
// string and returns the parsed page, per_page or a parsing error respectively.
42
func ParsePagingParameters(r *http.Request) (int64, int64, error) {
2✔
43
        q := r.URL.Query()
2✔
44
        var (
2✔
45
                err     error
2✔
46
                page    int64
2✔
47
                perPage int64
2✔
48
        )
2✔
49
        qPage := q.Get(pageQueryParam)
2✔
50
        if qPage == "" {
4✔
51
                page = 1
2✔
52
        } else {
2✔
53
                page, err = strconv.ParseInt(qPage, 10, 64)
×
54
                if err != nil {
×
55
                        return -1, -1, errors.Errorf(
×
56
                                "invalid page query: \"%s\"",
×
57
                                qPage,
×
58
                        )
×
59
                } else if page < 1 {
×
60
                        return -1, -1, errors.New("invalid page query: " +
×
61
                                "value must be a non-zero positive integer",
×
62
                        )
×
63
                }
×
64
        }
65

66
        qPerPage := q.Get(perPageQueryParam)
2✔
67
        if qPerPage == "" {
4✔
68
                perPage = PerPageDefault
2✔
69
        } else {
2✔
70
                perPage, err = strconv.ParseInt(qPerPage, 10, 64)
×
71
                if err != nil {
×
72
                        return -1, -1, errors.Errorf(
×
73
                                "invalid per_page query: \"%s\"",
×
74
                                qPerPage,
×
75
                        )
×
76
                } else if perPage < 1 {
×
77
                        return -1, -1, errors.New("invalid per_page query: " +
×
78
                                "value must be a non-zero positive integer",
×
79
                        )
×
80
                } else if perPage > PerPageMax {
×
81
                        return page, perPage, ErrPerPageLimit
×
82
                }
×
83
        }
84
        return page, perPage, nil
2✔
85
}
86

87
type PagingHints struct {
88
        // TotalCount provides the total count of elements available,
89
        // if provided adds another link to the last page available.
90
        TotalCount *int64
91

92
        // HasNext instructs adding the "next" link header. This option
93
        // has no effect if TotalCount is given.
94
        HasNext *bool
95

96
        // Pagination parameters
97
        Page, PerPage *int64
98
}
99

100
func NewPagingHints() *PagingHints {
×
101
        return new(PagingHints)
×
102
}
×
103

104
func (h *PagingHints) SetTotalCount(totalCount int64) *PagingHints {
×
105
        h.TotalCount = &totalCount
×
106
        return h
×
107
}
×
108

109
func (h *PagingHints) SetHasNext(hasNext bool) *PagingHints {
×
110
        h.HasNext = &hasNext
×
111
        return h
×
112
}
×
113

114
func (h *PagingHints) SetPage(page int64) *PagingHints {
×
115
        h.Page = &page
×
116
        return h
×
117
}
×
118

119
func (h *PagingHints) SetPerPage(perPage int64) *PagingHints {
×
120
        h.PerPage = &perPage
×
121
        return h
×
122
}
×
123

124
func MakePagingHeaders(r *http.Request, hints ...*PagingHints) ([]string, error) {
×
125
        // Parse hints
×
126
        hint := new(PagingHints)
×
127
        for _, h := range hints {
×
128
                if h == nil {
×
129
                        continue
×
130
                }
131
                if h.HasNext != nil {
×
132
                        hint.HasNext = h.HasNext
×
133
                }
×
134
                if h.TotalCount != nil {
×
135
                        hint.TotalCount = h.TotalCount
×
136
                }
×
137
                if h.Page != nil {
×
138
                        hint.Page = h.Page
×
139
                }
×
140
                if h.PerPage != nil {
×
141
                        hint.PerPage = h.PerPage
×
142
                }
×
143
        }
144
        if hint.Page == nil || hint.PerPage == nil {
×
145
                page, perPage, err := ParsePagingParameters(r)
×
146
                if err != nil {
×
147
                        return nil, err
×
148
                }
×
149
                hint.Page, hint.PerPage = &page, &perPage
×
150
        }
151
        locationURL := url.URL{
×
152
                Path:     r.URL.Path,
×
153
                RawQuery: r.URL.RawQuery,
×
154
                Fragment: r.URL.Fragment,
×
155
        }
×
156
        q := locationURL.Query()
×
157
        // Ensure per_page is set
×
158
        q.Set(perPageQueryParam, strconv.FormatInt(*hint.PerPage, 10))
×
159
        links := make([]string, 0, 4)
×
160
        q.Set(pageQueryParam, "1")
×
161
        locationURL.RawQuery = q.Encode()
×
162
        links = append(links, fmt.Sprintf(
×
163
                "<%s>; rel=\"first\"", locationURL.String(),
×
164
        ))
×
165
        if (*hint.Page) > 1 {
×
166
                q.Set(pageQueryParam, strconv.FormatInt(*hint.Page-1, 10))
×
167
                locationURL.RawQuery = q.Encode()
×
168
                links = append(links, fmt.Sprintf(
×
169
                        "<%s>; rel=\"prev\"", locationURL.String(),
×
170
                ))
×
171
        }
×
172

173
        // TotalCount takes precedence over HasNext
174
        if hint.TotalCount != nil && *hint.TotalCount > 0 {
×
175
                lastPage := (*hint.TotalCount-1) / *hint.PerPage + 1
×
176
                if *hint.Page < lastPage {
×
177
                        // Add "next" link
×
178
                        q.Set(pageQueryParam, strconv.FormatUint(uint64(*hint.Page)+1, 10))
×
179
                        locationURL.RawQuery = q.Encode()
×
180
                        links = append(links, fmt.Sprintf(
×
181
                                "<%s>; rel=\"next\"", locationURL.String(),
×
182
                        ))
×
183
                }
×
184
                // Add "last" link
185
                q.Set(pageQueryParam, strconv.FormatInt(lastPage, 10))
×
186
                locationURL.RawQuery = q.Encode()
×
187
                links = append(links, fmt.Sprintf(
×
188
                        "<%s>; rel=\"last\"", locationURL.String(),
×
189
                ))
×
190
        } else if hint.HasNext != nil && *hint.HasNext {
×
191
                q.Set(pageQueryParam, strconv.FormatUint(uint64(*hint.Page)+1, 10))
×
192
                locationURL.RawQuery = q.Encode()
×
193
                links = append(links, fmt.Sprintf(
×
194
                        "<%s>; rel=\"next\"", locationURL.String(),
×
195
                ))
×
196
        }
×
197

198
        return links, nil
×
199
}
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