Add tweet detail "/like" and "/unlike" URLs
- refactor TweetDetail to determine a bit more systematically whether scraping is required
This commit is contained in:
parent
dc1bde2fe6
commit
d1edcbf363
@ -51,44 +51,71 @@ func (app *Application) TweetDetail(w http.ResponseWriter, r *http.Request) {
|
||||
data := NewTweetDetailData()
|
||||
data.MainTweetID = tweet_id
|
||||
|
||||
// Return whether the scrape succeeded (if false, we should 404)
|
||||
try_scrape_tweet := func() bool {
|
||||
if app.IsScrapingDisabled {
|
||||
return false
|
||||
}
|
||||
trove, err := scraper.GetTweetFullAPIV2(tweet_id, 50) // TODO: parameterizable
|
||||
if err != nil {
|
||||
app.ErrorLog.Print(err)
|
||||
return false
|
||||
}
|
||||
app.Profile.SaveTweetTrove(trove)
|
||||
return true
|
||||
}
|
||||
is_needing_scrape := (len(parts) > 2 && parts[2] == "scrape")
|
||||
is_available := false
|
||||
|
||||
// Check if tweet is already in DB
|
||||
tweet, err := app.Profile.GetTweetById(tweet_id)
|
||||
if err != nil {
|
||||
if errors.Is(err, persistence.ErrNotInDB) {
|
||||
if !try_scrape_tweet() {
|
||||
app.error_404(w)
|
||||
return
|
||||
}
|
||||
is_needing_scrape = true
|
||||
is_available = false
|
||||
} else {
|
||||
panic(err)
|
||||
}
|
||||
} else if !tweet.IsConversationScraped || (len(parts) > 2 && parts[2] == "scrape") {
|
||||
try_scrape_tweet() // If it fails, we can still render it (not 404)
|
||||
} else {
|
||||
is_available = true
|
||||
if !tweet.IsConversationScraped {
|
||||
is_needing_scrape = true
|
||||
}
|
||||
}
|
||||
if is_available && len(parts) > 2 && (parts[2] == "like" || parts[2] == "unlike") {
|
||||
is_needing_scrape = false
|
||||
}
|
||||
|
||||
if is_needing_scrape && !app.IsScrapingDisabled {
|
||||
trove, err := scraper.GetTweetFullAPIV2(tweet_id, 50) // TODO: parameterizable
|
||||
if err == nil {
|
||||
app.Profile.SaveTweetTrove(trove)
|
||||
is_available = true
|
||||
} else {
|
||||
app.ErrorLog.Print(err)
|
||||
// TODO: show error in UI
|
||||
}
|
||||
}
|
||||
|
||||
if !is_available {
|
||||
app.error_404(w)
|
||||
return
|
||||
}
|
||||
|
||||
if len(parts) > 2 && parts[2] == "like" {
|
||||
like, err := scraper.LikeTweet(tweet.ID)
|
||||
// if err != nil && !errors.Is(err, scraper.AlreadyLikedThisTweet) {}
|
||||
panic_if(err)
|
||||
fmt.Printf("Like: %#v\n", like)
|
||||
err = app.Profile.SaveLike(like)
|
||||
panic_if(err)
|
||||
tweet.IsLikedByCurrentUser = true
|
||||
|
||||
app.buffered_render_basic_htmx(w, "likes-count", tweet)
|
||||
return
|
||||
} else if len(parts) > 2 && parts[2] == "unlike" {
|
||||
err = scraper.UnlikeTweet(tweet_id)
|
||||
panic_if(err)
|
||||
err = app.Profile.DeleteLike(scraper.Like{UserID: app.ActiveUser.ID, TweetID: tweet.ID})
|
||||
panic_if(err)
|
||||
tweet.IsLikedByCurrentUser = false
|
||||
|
||||
app.buffered_render_basic_htmx(w, "likes-count", tweet)
|
||||
return
|
||||
}
|
||||
|
||||
trove, err := app.Profile.GetTweetDetail(data.MainTweetID, app.ActiveUser.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, persistence.ErrNotInDB) {
|
||||
app.error_404(w)
|
||||
return
|
||||
} else {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
panic_if(err) // ErrNotInDB should be impossible, since we already fetched the single tweet successfully
|
||||
|
||||
data.TweetDetailView = trove
|
||||
// fmt.Println(to_json(data))
|
||||
|
||||
app.buffered_render_tweet_page(w, "tpl/tweet_detail.tpl", data)
|
||||
}
|
||||
|
@ -574,6 +574,9 @@ ul.dropdown-items {
|
||||
.tweet video {
|
||||
max-height: 25em;
|
||||
}
|
||||
.like-icon {
|
||||
cursor: pointer;
|
||||
}
|
||||
.like-icon.liked, .like-icon:hover {
|
||||
filter: invert(20%) sepia(97%) saturate(4383%) hue-rotate(321deg) brightness(101%) contrast(95%);
|
||||
}
|
||||
|
10
internal/webserver/tpl/includes/likes_count.tpl
Normal file
10
internal/webserver/tpl/includes/likes_count.tpl
Normal file
@ -0,0 +1,10 @@
|
||||
{{define "likes-count"}}
|
||||
<div class="interaction-stat" hx-trigger="click consume">
|
||||
{{if .IsLikedByCurrentUser}}
|
||||
<img class="svg-icon like-icon liked" src="/static/icons/like_filled.svg" hx-get="/tweet/{{.ID}}/unlike" hx-target="closest .interaction-stat" hx-push-url="false" hx-swap="outerHTML focus-scroll:false" />
|
||||
{{else}}
|
||||
<img class="svg-icon like-icon" src="/static/icons/like.svg" hx-get="/tweet/{{.ID}}/like" hx-target="closest .interaction-stat" hx-push-url="false" hx-swap="outerHTML focus-scroll:false" />
|
||||
{{end}}
|
||||
<span>{{.NumLikes}}</span>
|
||||
</div>
|
||||
{{end}}
|
@ -117,14 +117,7 @@
|
||||
<img class="svg-icon" src="/static/icons/retweet.svg" />
|
||||
<span>{{$main_tweet.NumRetweets}}</span>
|
||||
</div>
|
||||
<div class="interaction-stat">
|
||||
{{if $main_tweet.IsLikedByCurrentUser}}
|
||||
<img class="svg-icon like-icon liked" src="/static/icons/like_filled.svg" />
|
||||
{{else}}
|
||||
<img class="svg-icon like-icon" src="/static/icons/like.svg" />
|
||||
{{end}}
|
||||
<span>{{$main_tweet.NumLikes}}</span>
|
||||
</div>
|
||||
{{template "likes-count" $main_tweet}}
|
||||
<div class="dummy"></div>
|
||||
<div class="dropdown" hx-trigger="click consume">
|
||||
<button class="dropdown-button" title="Options">
|
||||
|
Loading…
x
Reference in New Issue
Block a user