Fix incorrect snippet queries (and generify some utilities)
This commit is contained in:
parent
06781b3b16
commit
5427092708
7
go.mod
7
go.mod
|
@ -44,7 +44,7 @@ require (
|
|||
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dlclark/regexp2 v1.4.0 // indirect
|
||||
github.com/evanw/esbuild v0.21.4 // indirect
|
||||
github.com/evanw/esbuild v0.21.4
|
||||
github.com/huandu/xstrings v1.3.2 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
|
@ -59,11 +59,10 @@ require (
|
|||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/teambition/rrule-go v1.7.2 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
golang.org/x/net v0.6.0 // indirect
|
||||
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 // indirect
|
||||
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/sys v0.5.0 // indirect
|
||||
golang.org/x/text v0.7.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
|
|
14
go.sum
14
go.sum
|
@ -117,8 +117,8 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ
|
|||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
|
@ -282,8 +282,6 @@ github.com/teacat/noire v1.1.0/go.mod h1:cetGlnqr+9yKJcFgRgYXOWJY66XIrrjUsGBwNlN
|
|||
github.com/teambition/rrule-go v1.7.2 h1:goEajFWYydfCgavn2m/3w5U+1b3PGqPUHx/fFSVfTy0=
|
||||
github.com/teambition/rrule-go v1.7.2/go.mod h1:mBJ1Ht5uboJ6jexKdNUJg2NcwP8uUMNvStWXlJD3MvU=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/wellington/go-libsass v0.9.2 h1:6Ims04UDdBs6/CGSVK5JC8FNikR5ssrsMMKE/uaO5Q8=
|
||||
github.com/wellington/go-libsass v0.9.2/go.mod h1:mxgxgam0N0E+NAUMHLcu20Ccfc3mVpDkyrLDayqfiTs=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/yuin/goldmark v1.3.6/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE=
|
||||
|
@ -310,6 +308,8 @@ golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL
|
|||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
|
||||
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d h1:RNPAfi2nHY7C2srAV8A49jpsYr0ADedCk1wq6fTMTvs=
|
||||
|
@ -339,8 +339,6 @@ golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -350,8 +348,8 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc=
|
||||
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -402,8 +400,6 @@ golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtn
|
|||
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
|
|
|
@ -129,7 +129,7 @@ func FetchEmbed(ctx context.Context, urlStr string, httpClient *http.Client, max
|
|||
filename := ""
|
||||
u, err := url.Parse(urlStr)
|
||||
if err == nil {
|
||||
lastSlash := utils.IntMax(strings.LastIndex(u.Path, "/"), 0)
|
||||
lastSlash := utils.Max(strings.LastIndex(u.Path, "/"), 0)
|
||||
filename = u.Path[lastSlash:]
|
||||
}
|
||||
result := Embed{
|
||||
|
|
|
@ -99,16 +99,19 @@ func FetchSnippets(
|
|||
TRUE
|
||||
`,
|
||||
)
|
||||
allIDs := make([]int, 0, len(q.IDs)+len(tagSnippetIDs)+len(projectSnippetIDs))
|
||||
allIDs = append(allIDs, q.IDs...)
|
||||
allIDs = append(allIDs, tagSnippetIDs...)
|
||||
allIDs = append(allIDs, projectSnippetIDs...)
|
||||
if len(allIDs) > 0 && len(q.OwnerIDs) > 0 {
|
||||
qb.Add(`AND (snippet.id = ANY ($?) OR snippet.owner_id = ANY ($?))`, allIDs, q.OwnerIDs)
|
||||
allSnippetIDs := make([]int, 0, len(q.IDs)+len(tagSnippetIDs)+len(projectSnippetIDs))
|
||||
allSnippetIDs = append(allSnippetIDs, q.IDs...)
|
||||
allSnippetIDs = append(allSnippetIDs, tagSnippetIDs...)
|
||||
allSnippetIDs = append(allSnippetIDs, projectSnippetIDs...)
|
||||
if len(allSnippetIDs) == 0 {
|
||||
// We already managed to filter out all snippets, and all further
|
||||
// parts of this query are more filters, so we can just fail everything
|
||||
// else from right here.
|
||||
qb.Add(`AND FALSE`)
|
||||
} else if len(q.OwnerIDs) > 0 {
|
||||
qb.Add(`AND (snippet.id = ANY ($?) OR snippet.owner_id = ANY ($?))`, allSnippetIDs, q.OwnerIDs)
|
||||
} else {
|
||||
if len(allIDs) > 0 {
|
||||
qb.Add(`AND snippet.id = ANY ($?)`, allIDs)
|
||||
}
|
||||
qb.Add(`AND snippet.id = ANY ($?)`, allSnippetIDs)
|
||||
if len(q.OwnerIDs) > 0 {
|
||||
qb.Add(`AND snippet.owner_id = ANY ($?)`, q.OwnerIDs)
|
||||
}
|
||||
|
|
|
@ -289,7 +289,7 @@ func seedProject(ctx context.Context, tx pgx.Tx, input models.Project, owners []
|
|||
input.ForumEnabled, input.BlogEnabled,
|
||||
utils.OrDefault(input.DateCreated, time.Now()),
|
||||
)
|
||||
latestProjectId = utils.IntMax(latestProjectId, project.ID)
|
||||
latestProjectId = utils.Max(latestProjectId, project.ID)
|
||||
|
||||
// Create forum (even if unused)
|
||||
forum := db.MustQueryOne[models.Subforum](ctx, tx,
|
||||
|
|
|
@ -117,7 +117,7 @@
|
|||
<legend>Owners</legend>
|
||||
<div class="pa3">
|
||||
<div class="flex">
|
||||
<input class="flex-grow-1 no-border bl bt bb br-0" id="owner_name" type="text" placeholder="Enter a username" />
|
||||
<input class="flex-grow-1 no-border bl bt bb br-0" id="owner_name" type="text" placeholder="Enter another owner's username" />
|
||||
<button class="flex no-padding no-border pa3 bt br bb bl-0 also-focus" id="owner_add"><span class="flex w1">{{ svg "add" }}</span></button>
|
||||
</div>
|
||||
<div id="owners_error" class="f6"></div>
|
||||
|
@ -163,11 +163,13 @@
|
|||
</legend>
|
||||
<div class="pa3 input-group">
|
||||
<div id="links" class="flex flex-column g3 relative">
|
||||
<div>Primary Links</div>
|
||||
<div>Secondary Links</div>
|
||||
</div>
|
||||
<template id="link_row">
|
||||
<div class="link_row w-100 flex flex-row items-center" data-tmpl="root">
|
||||
<span class="link_handle svgicon pr3 pointer grab" onmousedown="startLinkDrag(event)">{{ svg "draggable" }}</span>
|
||||
<input data-tmpl="nameInput" class="link_name mr3 w4" type="text" placeholder="Name" />
|
||||
<input data-tmpl="nameInput" class="link_name mr3 w5" type="text" placeholder="Name" />
|
||||
<input data-tmpl="urlInput" class="link_url flex-grow-1" type="url" placeholder="Link" />
|
||||
<a class="delete_link svgicon link--normal pl3 f3" href="javascript:;" onclick="deleteLink(event)">{{ svg "delete" }}</a>
|
||||
</div>
|
||||
|
|
|
@ -44,7 +44,7 @@ func getTwitchUsersByLogin(ctx context.Context, logins []string) ([]twitchUser,
|
|||
for i := 0; i < numChunks; i++ {
|
||||
query := url.Values{}
|
||||
query.Add("first", "100")
|
||||
for _, login := range logins[i*100 : utils.IntMin((i+1)*100, len(logins))] {
|
||||
for _, login := range logins[i*100 : utils.Min((i+1)*100, len(logins))] {
|
||||
query.Add("login", login)
|
||||
}
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", buildUrl("/users", query.Encode()), nil)
|
||||
|
@ -94,7 +94,7 @@ func getStreamStatus(ctx context.Context, twitchIDs []string) ([]streamStatus, e
|
|||
for i := 0; i < numChunks; i++ {
|
||||
query := url.Values{}
|
||||
query.Add("first", "100")
|
||||
for _, tid := range twitchIDs[i*100 : utils.IntMin((i+1)*100, len(twitchIDs))] {
|
||||
for _, tid := range twitchIDs[i*100 : utils.Min((i+1)*100, len(twitchIDs))] {
|
||||
query.Add("user_id", tid)
|
||||
}
|
||||
req, err := http.NewRequestWithContext(ctx, "GET", buildUrl("/streams", query.Encode()), nil)
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"time"
|
||||
|
||||
"git.handmade.network/hmn/hmn/src/oops"
|
||||
"golang.org/x/exp/constraints"
|
||||
)
|
||||
|
||||
// Returns the provided value, or a default value if the input was zero.
|
||||
|
@ -37,29 +38,26 @@ func Must1[T any](v T, err error) T {
|
|||
return v
|
||||
}
|
||||
|
||||
func IntMin(a, b int) int {
|
||||
func Min[T constraints.Ordered](a, b T) T {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func IntMax(a, b int) int {
|
||||
func Max[T constraints.Ordered](a, b T) T {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func IntClamp(min, t, max int) int {
|
||||
return IntMax(min, IntMin(t, max))
|
||||
func Clamp[T constraints.Ordered](min, t, max T) T {
|
||||
return Max(min, Min(t, max))
|
||||
}
|
||||
|
||||
func Int64Max(a, b int64) int64 {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
func ClampSlice[T any](s []T, max int) []T {
|
||||
return s[:Min(len(s), max)]
|
||||
}
|
||||
|
||||
func DurationRoundUp(d time.Duration, interval time.Duration) time.Duration {
|
||||
|
@ -67,7 +65,7 @@ func DurationRoundUp(d time.Duration, interval time.Duration) time.Duration {
|
|||
}
|
||||
|
||||
func NumPages(numThings, thingsPerPage int) int {
|
||||
return IntMax(int(math.Ceil(float64(numThings)/float64(thingsPerPage))), 1)
|
||||
return Max(int(math.Ceil(float64(numThings)/float64(thingsPerPage))), 1)
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -102,8 +102,8 @@ func BlogIndex(c *RequestContext) ResponseData {
|
|||
|
||||
FirstUrl: c.UrlContext.BuildBlog(1),
|
||||
LastUrl: c.UrlContext.BuildBlog(numPages),
|
||||
PreviousUrl: c.UrlContext.BuildBlog(utils.IntClamp(1, page-1, numPages)),
|
||||
NextUrl: c.UrlContext.BuildBlog(utils.IntClamp(1, page+1, numPages)),
|
||||
PreviousUrl: c.UrlContext.BuildBlog(utils.Clamp(1, page-1, numPages)),
|
||||
NextUrl: c.UrlContext.BuildBlog(utils.Clamp(1, page+1, numPages)),
|
||||
},
|
||||
|
||||
ShowContent: len(entries) <= 5,
|
||||
|
|
|
@ -53,8 +53,8 @@ func Feed(c *RequestContext) ResponseData {
|
|||
|
||||
FirstUrl: hmnurl.BuildFeed(),
|
||||
LastUrl: hmnurl.BuildFeedWithPage(numPages),
|
||||
NextUrl: hmnurl.BuildFeedWithPage(utils.IntClamp(1, page+1, numPages)),
|
||||
PreviousUrl: hmnurl.BuildFeedWithPage(utils.IntClamp(1, page-1, numPages)),
|
||||
NextUrl: hmnurl.BuildFeedWithPage(utils.Clamp(1, page+1, numPages)),
|
||||
PreviousUrl: hmnurl.BuildFeedWithPage(utils.Clamp(1, page-1, numPages)),
|
||||
}
|
||||
|
||||
posts, err := fetchAllPosts(c, (page-1)*feedPostsPerPage, feedPostsPerPage)
|
||||
|
|
|
@ -198,8 +198,8 @@ func Forum(c *RequestContext) ResponseData {
|
|||
|
||||
FirstUrl: c.UrlContext.BuildForum(currentSubforumSlugs, 1),
|
||||
LastUrl: c.UrlContext.BuildForum(currentSubforumSlugs, numPages),
|
||||
NextUrl: c.UrlContext.BuildForum(currentSubforumSlugs, utils.IntClamp(1, page+1, numPages)),
|
||||
PreviousUrl: c.UrlContext.BuildForum(currentSubforumSlugs, utils.IntClamp(1, page-1, numPages)),
|
||||
NextUrl: c.UrlContext.BuildForum(currentSubforumSlugs, utils.Clamp(1, page+1, numPages)),
|
||||
PreviousUrl: c.UrlContext.BuildForum(currentSubforumSlugs, utils.Clamp(1, page-1, numPages)),
|
||||
},
|
||||
Subforums: subforums,
|
||||
}, c.Perf)
|
||||
|
@ -375,8 +375,8 @@ func ForumThread(c *RequestContext) ResponseData {
|
|||
|
||||
FirstUrl: c.UrlContext.BuildForumThread(currentSubforumSlugs, thread.ID, thread.Title, 1),
|
||||
LastUrl: c.UrlContext.BuildForumThread(currentSubforumSlugs, thread.ID, thread.Title, numPages),
|
||||
NextUrl: c.UrlContext.BuildForumThread(currentSubforumSlugs, thread.ID, thread.Title, utils.IntClamp(1, page+1, numPages)),
|
||||
PreviousUrl: c.UrlContext.BuildForumThread(currentSubforumSlugs, thread.ID, thread.Title, utils.IntClamp(1, page-1, numPages)),
|
||||
NextUrl: c.UrlContext.BuildForumThread(currentSubforumSlugs, thread.ID, thread.Title, utils.Clamp(1, page+1, numPages)),
|
||||
PreviousUrl: c.UrlContext.BuildForumThread(currentSubforumSlugs, thread.ID, thread.Title, utils.Clamp(1, page-1, numPages)),
|
||||
}
|
||||
|
||||
postsAndStuff, err := hmndata.FetchPosts(c, c.Conn, c.CurrentUser, hmndata.PostsQuery{
|
||||
|
|
|
@ -117,7 +117,7 @@ func csrfMiddleware(h Handler) Handler {
|
|||
func securityTimerMiddleware(duration time.Duration, h Handler) Handler {
|
||||
// NOTE(asaf): Will make sure that the request takes at least `duration` to finish. Adds a 10% random duration.
|
||||
return func(c *RequestContext) ResponseData {
|
||||
additionalDuration := time.Duration(rand.Int63n(utils.Int64Max(1, int64(duration)/10)))
|
||||
additionalDuration := time.Duration(rand.Int63n(utils.Max(1, int64(duration)/10)))
|
||||
timer := time.NewTimer(duration + additionalDuration)
|
||||
res := h(c)
|
||||
select {
|
||||
|
|
|
@ -16,7 +16,7 @@ func getPageInfo(
|
|||
totalPages int,
|
||||
ok bool,
|
||||
) {
|
||||
totalPages = utils.IntMax(1, int(math.Ceil(float64(totalItems)/float64(itemsPerPage))))
|
||||
totalPages = utils.Max(1, int(math.Ceil(float64(totalItems)/float64(itemsPerPage))))
|
||||
ok = true
|
||||
|
||||
page = 1
|
||||
|
|
|
@ -28,7 +28,7 @@ func ParsePageNumber(
|
|||
}
|
||||
}
|
||||
if page < 1 || numPages < page {
|
||||
return utils.IntClamp(1, page, numPages), false
|
||||
return utils.Clamp(1, page, numPages), false
|
||||
}
|
||||
|
||||
return page, true
|
||||
|
|
|
@ -126,12 +126,12 @@ func ProjectIndex(c *RequestContext) ResponseData {
|
|||
|
||||
AllProjects: true,
|
||||
|
||||
OfficialProjects: officialProjects[:utils.IntMin(len(officialProjects), projectsPerSection)],
|
||||
OfficialProjects: officialProjects[:utils.Min(len(officialProjects), projectsPerSection)],
|
||||
OfficialProjectsLink: hmnurl.BuildProjectIndex(1, "official"),
|
||||
PersonalProjects: personalProjects[:utils.IntMin(len(personalProjects), projectsPerSection)],
|
||||
PersonalProjects: personalProjects[:utils.Min(len(personalProjects), projectsPerSection)],
|
||||
PersonalProjectsLink: hmnurl.BuildProjectIndex(1, "personal"),
|
||||
// Current jam stuff set later
|
||||
PreviousJamProjects: previousJamProjects[:utils.IntMin(len(previousJamProjects), projectsPerSection)],
|
||||
PreviousJamProjects: previousJamProjects[:utils.Min(len(previousJamProjects), projectsPerSection)],
|
||||
PreviousJamProjectsLink: hmnurl.BuildProjectIndex(1, previousJam.UrlSlug),
|
||||
PreviousJamLink: hmnurl.BuildJamIndexAny(previousJam.UrlSlug),
|
||||
PreviousJamSlug: previousJam.UrlSlug,
|
||||
|
@ -140,7 +140,7 @@ func ProjectIndex(c *RequestContext) ResponseData {
|
|||
}
|
||||
|
||||
if currentJam != nil {
|
||||
tmpl.CurrentJamProjects = currentJamProjects[:utils.IntMin(len(currentJamProjects), projectsPerSection)]
|
||||
tmpl.CurrentJamProjects = currentJamProjects[:utils.Min(len(currentJamProjects), projectsPerSection)]
|
||||
tmpl.CurrentJamProjectsLink = hmnurl.BuildProjectIndex(1, currentJam.UrlSlug)
|
||||
tmpl.CurrentJamLink = hmnurl.BuildJamIndexAny(currentJam.UrlSlug)
|
||||
tmpl.CurrentJamSlug = currentJam.UrlSlug
|
||||
|
@ -195,12 +195,12 @@ func ProjectIndex(c *RequestContext) ResponseData {
|
|||
|
||||
FirstUrl: hmnurl.BuildProjectIndex(1, cat),
|
||||
LastUrl: hmnurl.BuildProjectIndex(numPages, cat),
|
||||
NextUrl: hmnurl.BuildProjectIndex(utils.IntClamp(1, page+1, numPages), cat),
|
||||
PreviousUrl: hmnurl.BuildProjectIndex(utils.IntClamp(1, page-1, numPages), cat),
|
||||
NextUrl: hmnurl.BuildProjectIndex(utils.Clamp(1, page+1, numPages), cat),
|
||||
PreviousUrl: hmnurl.BuildProjectIndex(utils.Clamp(1, page-1, numPages), cat),
|
||||
}
|
||||
|
||||
firstProjectIndex := (page - 1) * projectsPerPage
|
||||
endIndex := utils.IntMin(firstProjectIndex+projectsPerPage, len(projects))
|
||||
endIndex := utils.Min(firstProjectIndex+projectsPerPage, len(projects))
|
||||
pageProjects := projects[firstProjectIndex:endIndex]
|
||||
|
||||
baseData := getBaseData(c, "Projects", []templates.Breadcrumb{
|
||||
|
@ -474,7 +474,7 @@ func ProjectHomepage(c *RequestContext) ResponseData {
|
|||
return c.ErrorResponse(http.StatusInternalServerError, err)
|
||||
}
|
||||
|
||||
templateData.RecentActivity = templateData.RecentActivity[:utils.IntMin(len(templateData.RecentActivity)-1, maxRecentActivity)]
|
||||
templateData.RecentActivity = utils.ClampSlice(templateData.RecentActivity, maxRecentActivity)
|
||||
|
||||
followUrl := ""
|
||||
following := false
|
||||
|
|
|
@ -75,44 +75,50 @@ func FetchTimeline(ctx context.Context, conn db.ConnOrTx, currentUser *models.Us
|
|||
|
||||
perf.StartBlock("TIMELINE", "Fetch timeline data")
|
||||
if len(q.UserIDs) > 0 || len(q.ProjectIDs) > 0 {
|
||||
users, err := hmndata.FetchUsers(ctx, conn, currentUser, hmndata.UsersQuery{
|
||||
UserIDs: q.UserIDs,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, oops.New(err, "failed to fetch users")
|
||||
var err error
|
||||
|
||||
if len(q.UserIDs) > 0 {
|
||||
users, err = hmndata.FetchUsers(ctx, conn, currentUser, hmndata.UsersQuery{
|
||||
UserIDs: q.UserIDs,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, oops.New(err, "failed to fetch users")
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(asaf): Clear out invalid users in case we banned someone after they got followed
|
||||
q.UserIDs = q.UserIDs[0:0]
|
||||
validUserIDs := make([]int, 0, len(q.UserIDs))
|
||||
for _, u := range users {
|
||||
q.UserIDs = append(q.UserIDs, u.ID)
|
||||
validUserIDs = append(validUserIDs, u.ID)
|
||||
}
|
||||
|
||||
projects, err = hmndata.FetchProjects(ctx, conn, currentUser, hmndata.ProjectsQuery{
|
||||
ProjectIDs: q.ProjectIDs,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, oops.New(err, "failed to fetch projects")
|
||||
if len(q.ProjectIDs) > 0 {
|
||||
projects, err = hmndata.FetchProjects(ctx, conn, currentUser, hmndata.ProjectsQuery{
|
||||
ProjectIDs: q.ProjectIDs,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, oops.New(err, "failed to fetch projects")
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(asaf): The original projectIDs might container hidden/abandoned projects,
|
||||
// NOTE(asaf): The original projectIDs might contain hidden/abandoned projects,
|
||||
// so we recreate it after the projects get filtered by FetchProjects.
|
||||
q.ProjectIDs = q.ProjectIDs[0:0]
|
||||
validProjectIDs := make([]int, 0, len(q.ProjectIDs))
|
||||
for _, p := range projects {
|
||||
q.ProjectIDs = append(q.ProjectIDs, p.Project.ID)
|
||||
validProjectIDs = append(validProjectIDs, p.Project.ID)
|
||||
}
|
||||
|
||||
snippets, err = hmndata.FetchSnippets(ctx, conn, currentUser, hmndata.SnippetQuery{
|
||||
OwnerIDs: q.UserIDs,
|
||||
ProjectIDs: q.ProjectIDs,
|
||||
OwnerIDs: validUserIDs,
|
||||
ProjectIDs: validProjectIDs,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, oops.New(err, "failed to fetch user snippets")
|
||||
}
|
||||
|
||||
posts, err = hmndata.FetchPosts(ctx, conn, currentUser, hmndata.PostsQuery{
|
||||
UserIDs: q.UserIDs,
|
||||
ProjectIDs: q.ProjectIDs,
|
||||
UserIDs: validUserIDs,
|
||||
ProjectIDs: validProjectIDs,
|
||||
SortDescending: true,
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -120,8 +126,8 @@ func FetchTimeline(ctx context.Context, conn db.ConnOrTx, currentUser *models.Us
|
|||
}
|
||||
|
||||
streamers, err = hmndata.FetchTwitchStreamers(ctx, conn, hmndata.TwitchStreamersQuery{
|
||||
UserIDs: q.UserIDs,
|
||||
ProjectIDs: q.ProjectIDs,
|
||||
UserIDs: validUserIDs,
|
||||
ProjectIDs: validProjectIDs,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, oops.New(err, "failed to fetch streamers")
|
||||
|
|
Loading…
Reference in New Issue