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"
"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) {
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)")
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)
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 {
// It's a Show More request

View File

@ -7,6 +7,7 @@ import (
"io"
"io/fs"
"net/http"
"net/url"
"path"
"path/filepath"
"regexp"
@ -15,6 +16,7 @@ import (
"github.com/Masterminds/sprig/v3"
"gitlab.com/offline-twitter/twitter_offline_engine/pkg/persistence"
"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{
Funcs: func_map(template.FuncMap{
"tweet": data.Tweet,
"user": data.User,
"retweet": data.Retweet,
"space": data.Space,
"active_user": app.get_active_user,
"focused_tweet_id": data.FocusedTweetID,
"get_entities": get_entities,
"get_tombstone_text": get_tombstone_text,
"tweet": data.Tweet,
"user": data.User,
"retweet": data.Retweet,
"space": data.Space,
"active_user": app.get_active_user,
"focused_tweet_id": data.FocusedTweetID,
"get_entities": get_entities,
"get_tombstone_text": get_tombstone_text,
"cursor_to_query_params": cursor_to_query_params,
}),
Filenames: append(partials, get_filepath(tpl_file)),
TplName: "base",
@ -121,14 +124,15 @@ func (app *Application) buffered_render_tweet_htmx(w http.ResponseWriter, tpl_na
r := renderer{
Funcs: func_map(template.FuncMap{
"tweet": data.Tweet,
"user": data.User,
"retweet": data.Retweet,
"space": data.Space,
"active_user": app.get_active_user,
"focused_tweet_id": data.FocusedTweetID,
"get_entities": get_entities,
"get_tombstone_text": get_tombstone_text,
"tweet": data.Tweet,
"user": data.User,
"retweet": data.Retweet,
"space": data.Space,
"active_user": app.get_active_user,
"focused_tweet_id": data.FocusedTweetID,
"get_entities": get_entities,
"get_tombstone_text": get_tombstone_text,
"cursor_to_query_params": cursor_to_query_params,
}),
Filenames: partials,
TplName: tpl_name,
@ -233,3 +237,10 @@ func (r renderer) BufferedRender(w io.Writer) {
_, err = buf.WriteTo(w)
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)
}
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) {
assert := assert.New(t)

View File

@ -1,6 +1,18 @@
{{define "title"}}Search{{end}}
{{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">
{{template "timeline" .}}
</div>

View File

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

View File

@ -19,6 +19,21 @@ const (
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 {
switch o {
case SORT_ORDER_NEWEST: