Enable search sort-orders

This commit is contained in:
Alessio 2023-10-14 15:06:50 -03:00
parent 99ef17f820
commit 535f28c278
6 changed files with 132 additions and 18 deletions

View File

@ -9,8 +9,41 @@ import (
"strings" "strings"
"gitlab.com/offline-twitter/twitter_offline_engine/pkg/persistence" "gitlab.com/offline-twitter/twitter_offline_engine/pkg/persistence"
"gitlab.com/offline-twitter/twitter_offline_engine/pkg/scraper"
) )
type SearchPageData struct {
persistence.Feed
SearchText string
SortOrder persistence.SortOrder
SortOrderOptions []string
// TODO: fill out the search text in the search bar as well (needs modifying the base template)
}
func NewSearchPageData() SearchPageData {
ret := SearchPageData{SortOrderOptions: []string{}}
for i := 0; i < 4; i++ { // Don't include "Liked At" option which is #4
ret.SortOrderOptions = append(ret.SortOrderOptions, persistence.SortOrder(i).String())
}
return ret
}
func (t SearchPageData) Tweet(id scraper.TweetID) scraper.Tweet {
return t.Tweets[id]
}
func (t SearchPageData) User(id scraper.UserID) scraper.User {
return t.Users[id]
}
func (t SearchPageData) Retweet(id scraper.TweetID) scraper.Retweet {
return t.Retweets[id]
}
func (t SearchPageData) Space(id scraper.SpaceID) scraper.Space {
return t.Spaces[id]
}
func (t SearchPageData) FocusedTweetID() scraper.TweetID {
return scraper.TweetID(0)
}
func (app *Application) Search(w http.ResponseWriter, r *http.Request) { func (app *Application) Search(w http.ResponseWriter, r *http.Request) {
app.traceLog.Printf("'Search' handler (path: %q)", r.URL.Path) app.traceLog.Printf("'Search' handler (path: %q)", r.URL.Path)
@ -67,6 +100,11 @@ func (app *Application) Search(w http.ResponseWriter, r *http.Request) {
app.error_400_with_message(w, "invalid cursor (must be a number)") app.error_400_with_message(w, "invalid cursor (must be a number)")
return return
} }
var is_ok bool
c.SortOrder, is_ok = persistence.SortOrderFromString(r.URL.Query().Get("sort-order"))
if !is_ok && r.URL.Query().Get("sort-order") != "" {
app.error_400_with_message(w, "Invalid sort order")
}
feed, err := app.Profile.NextPage(c, app.ActiveUser.ID) feed, err := app.Profile.NextPage(c, app.ActiveUser.ID)
if err != nil { if err != nil {
@ -77,7 +115,10 @@ func (app *Application) Search(w http.ResponseWriter, r *http.Request) {
} }
} }
data := UserProfileData{Feed: feed} // TODO: wrong struct data := NewSearchPageData()
data.Feed = feed
data.SearchText = search_text
data.SortOrder = c.SortOrder
if r.Header.Get("HX-Request") == "true" && c.CursorPosition == persistence.CURSOR_MIDDLE { if r.Header.Get("HX-Request") == "true" && c.CursorPosition == persistence.CURSOR_MIDDLE {
// It's a Show More request // It's a Show More request

View File

@ -7,6 +7,7 @@ import (
"io" "io"
"io/fs" "io/fs"
"net/http" "net/http"
"net/url"
"path" "path"
"path/filepath" "path/filepath"
"regexp" "regexp"
@ -15,6 +16,7 @@ import (
"github.com/Masterminds/sprig/v3" "github.com/Masterminds/sprig/v3"
"gitlab.com/offline-twitter/twitter_offline_engine/pkg/persistence"
"gitlab.com/offline-twitter/twitter_offline_engine/pkg/scraper" "gitlab.com/offline-twitter/twitter_offline_engine/pkg/scraper"
) )
@ -86,14 +88,15 @@ func (app *Application) buffered_render_tweet_page(w http.ResponseWriter, tpl_fi
r := renderer{ r := renderer{
Funcs: func_map(template.FuncMap{ Funcs: func_map(template.FuncMap{
"tweet": data.Tweet, "tweet": data.Tweet,
"user": data.User, "user": data.User,
"retweet": data.Retweet, "retweet": data.Retweet,
"space": data.Space, "space": data.Space,
"active_user": app.get_active_user, "active_user": app.get_active_user,
"focused_tweet_id": data.FocusedTweetID, "focused_tweet_id": data.FocusedTweetID,
"get_entities": get_entities, "get_entities": get_entities,
"get_tombstone_text": get_tombstone_text, "get_tombstone_text": get_tombstone_text,
"cursor_to_query_params": cursor_to_query_params,
}), }),
Filenames: append(partials, get_filepath(tpl_file)), Filenames: append(partials, get_filepath(tpl_file)),
TplName: "base", TplName: "base",
@ -121,14 +124,15 @@ func (app *Application) buffered_render_tweet_htmx(w http.ResponseWriter, tpl_na
r := renderer{ r := renderer{
Funcs: func_map(template.FuncMap{ Funcs: func_map(template.FuncMap{
"tweet": data.Tweet, "tweet": data.Tweet,
"user": data.User, "user": data.User,
"retweet": data.Retweet, "retweet": data.Retweet,
"space": data.Space, "space": data.Space,
"active_user": app.get_active_user, "active_user": app.get_active_user,
"focused_tweet_id": data.FocusedTweetID, "focused_tweet_id": data.FocusedTweetID,
"get_entities": get_entities, "get_entities": get_entities,
"get_tombstone_text": get_tombstone_text, "get_tombstone_text": get_tombstone_text,
"cursor_to_query_params": cursor_to_query_params,
}), }),
Filenames: partials, Filenames: partials,
TplName: tpl_name, TplName: tpl_name,
@ -233,3 +237,10 @@ func (r renderer) BufferedRender(w io.Writer) {
_, err = buf.WriteTo(w) _, err = buf.WriteTo(w)
panic_if(err) panic_if(err)
} }
func cursor_to_query_params(c persistence.Cursor) string {
result := url.Values{}
result.Set("cursor", fmt.Sprint(c.CursorValue))
result.Set("sort-order", c.SortOrder.String())
return result.Encode()
}

View File

@ -270,6 +270,41 @@ func TestSearchWithCursor(t *testing.T) {
assert.Len(cascadia.QueryAll(root, selector(".timeline > .tweet")), 2) assert.Len(cascadia.QueryAll(root, selector(".timeline > .tweet")), 2)
} }
func TestSearchWithSortOrder(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
resp := do_request(httptest.NewRequest("GET", "/search/think?sort-order=most%20likes", nil))
require.Equal(resp.StatusCode, 200)
root, err := html.Parse(resp.Body)
require.NoError(err)
assert.Contains(cascadia.Query(root, selector("select[name='sort-order'] option[selected]")).FirstChild.Data, "most likes")
tweets := cascadia.QueryAll(root, selector(".timeline > .tweet"))
txts := []string{
"Morally nuanced and complicated discussion",
"a lot of yall embarrass yourselves on this",
"this is why the \"think tank mindset\" is a dead end",
"At this point what can we expect I guess",
"Idk if this is relevant to your department",
}
for i, txt := range txts {
assert.Contains(cascadia.Query(tweets[i], selector("p.text")).FirstChild.Data, txt)
}
resp = do_request(httptest.NewRequest("GET", "/search/think?sort-order=most%20likes&cursor=413", nil))
require.Equal(resp.StatusCode, 200)
root, err = html.Parse(resp.Body)
require.NoError(err)
tweets = cascadia.QueryAll(root, selector(".timeline > .tweet"))
for i, txt := range txts[2:] {
assert.Contains(cascadia.Query(tweets[i], selector("p.text")).FirstChild.Data, txt)
}
}
// Search bar pasted link redirects
// --------------------------------
func TestSearchRedirectOnUserHandle(t *testing.T) { func TestSearchRedirectOnUserHandle(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)

View File

@ -1,6 +1,18 @@
{{define "title"}}Search{{end}} {{define "title"}}Search{{end}}
{{define "main"}} {{define "main"}}
<div class="search-header">
<h2>Search results: {{.SearchText}}</h2>
<select name="sort-order" style="text-transform: capitalize;" hx-get="#" hx-target="body" hx-push-url="true">
{{range .SortOrderOptions}}
<option
value="{{.}}"
{{if (eq ($.SortOrder.String) .)}} selected {{end}}
style="text-transform: capitalize;"
>{{.}}</option>
{{end}}
</select>
</div>
<div class="timeline"> <div class="timeline">
{{template "timeline" .}} {{template "timeline" .}}
</div> </div>

View File

@ -6,7 +6,7 @@
<p>End of feed</p> <p>End of feed</p>
{{else}} {{else}}
<button class="show-more" <button class="show-more"
hx-get="?cursor={{.CursorBottom.CursorValue}}" hx-get="?{{(cursor_to_query_params .CursorBottom)}}"
hx-swap="outerHTML" hx-swap="outerHTML"
>Show more</button> >Show more</button>
{{end}} {{end}}

View File

@ -19,6 +19,21 @@ const (
SORT_ORDER_LIKED_AT SORT_ORDER_LIKED_AT
) )
func (o SortOrder) String() string {
return []string{"newest", "oldest", "most likes", "most retweets", "liked at"}[o]
}
func SortOrderFromString(s string) (SortOrder, bool) {
result, is_ok := map[string]SortOrder{
"newest": SORT_ORDER_NEWEST,
"oldest": SORT_ORDER_OLDEST,
"most likes": SORT_ORDER_MOST_LIKES,
"most retweets": SORT_ORDER_MOST_RETWEETS,
"liked at": SORT_ORDER_LIKED_AT,
}[s]
return result, is_ok // Have to store as temporary variable b/c otherwise it interprets it as single-value and compile fails
}
func (o SortOrder) OrderByClause() string { func (o SortOrder) OrderByClause() string {
switch o { switch o {
case SORT_ORDER_NEWEST: case SORT_ORDER_NEWEST: