Enable search sort-orders
This commit is contained in:
parent
99ef17f820
commit
535f28c278
@ -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
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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 y’all 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)
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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}}
|
||||
|
@ -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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user