1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
// GoToSocial
// Copyright (C) GoToSocial Authors admin@gotosocial.org
// SPDX-License-Identifier: AGPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package util
import (
"fmt"
"net/url"
"strings"
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
)
// PageableResponseParams models the parameters to pass to PackagePageableResponse.
//
// The given items will be provided in the paged response.
//
// The other values are all used to create the Link header so that callers know
// which endpoint to query next and previously in order to do paging.
type PageableResponseParams struct {
Items []interface{} // Sorted slice of items (statuses, notifications, etc)
Path string // path to use for next/prev queries in the link header
NextMaxIDKey string // key to use for the next max id query param in the link header, defaults to 'max_id'
NextMaxIDValue string // value to use for next max id
PrevMinIDKey string // key to use for the prev min id query param in the link header, defaults to 'min_id'
PrevMinIDValue string // value to use for prev min id
Limit int // limit number of entries to return
ExtraQueryParams []string // any extra query parameters to provide in the link header, should be in the format 'example=value'
}
// PackagePageableResponse is a convenience function for returning
// a bunch of pageable items (notifications, statuses, etc), as well
// as a Link header to inform callers of where to find next/prev items.
func PackagePageableResponse(params PageableResponseParams) (*apimodel.PageableResponse, gtserror.WithCode) {
// Set default paging values, if
// they weren't set by the caller.
if params.NextMaxIDKey == "" {
params.NextMaxIDKey = "max_id"
}
if params.PrevMinIDKey == "" {
params.PrevMinIDKey = "min_id"
}
var (
protocol = config.GetProtocol()
host = config.GetHost()
nextLink string
prevLink string
linkHeaderParts = make([]string, 0, 2)
)
// Parse next link.
if params.NextMaxIDValue != "" {
nextRaw := params.NextMaxIDKey + "=" + params.NextMaxIDValue
if params.Limit != 0 {
nextRaw = fmt.Sprintf("limit=%d&", params.Limit) + nextRaw
}
for _, p := range params.ExtraQueryParams {
nextRaw += "&" + p
}
nextLink = func() string {
u := &url.URL{
Scheme: protocol,
Host: host,
Path: params.Path,
RawQuery: nextRaw,
}
return u.String()
}()
linkHeaderParts = append(linkHeaderParts, `<`+nextLink+`>; rel="next"`)
}
// Parse prev link.
if params.PrevMinIDValue != "" {
prevRaw := params.PrevMinIDKey + "=" + params.PrevMinIDValue
if params.Limit != 0 {
prevRaw = fmt.Sprintf("limit=%d&", params.Limit) + prevRaw
}
for _, p := range params.ExtraQueryParams {
prevRaw = prevRaw + "&" + p
}
prevLink = func() string {
u := &url.URL{
Scheme: protocol,
Host: host,
Path: params.Path,
RawQuery: prevRaw,
}
return u.String()
}()
linkHeaderParts = append(linkHeaderParts, `<`+prevLink+`>; rel="prev"`)
}
return &apimodel.PageableResponse{
Items: params.Items,
LinkHeader: strings.Join(linkHeaderParts, ", "),
NextLink: nextLink,
PrevLink: prevLink,
}, nil
}
// EmptyPageableResponse just returns an empty
// PageableResponse with no link header or items.
func EmptyPageableResponse() *apimodel.PageableResponse {
return &apimodel.PageableResponse{
Items: []interface{}{},
}
}
|