mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-02-04 07:06:59 +01:00
Feat: display boosts on public profile
This commit is contained in:
parent
d9e59820ed
commit
af5a766f62
14 changed files with 112 additions and 34 deletions
|
@ -118,6 +118,10 @@ type WebStatus struct {
|
||||||
// Override API account with web account.
|
// Override API account with web account.
|
||||||
Account *WebAccount `json:"account"`
|
Account *WebAccount `json:"account"`
|
||||||
|
|
||||||
|
// Account that reblogged the status.
|
||||||
|
// needed to properly render reblogged statuses on profile pages.
|
||||||
|
ReblogAccount *WebAccount `json:"reblog_account"`
|
||||||
|
|
||||||
// Web version of media
|
// Web version of media
|
||||||
// attached to this status.
|
// attached to this status.
|
||||||
MediaAttachments []*WebAttachment `json:"media_attachments"`
|
MediaAttachments []*WebAttachment `json:"media_attachments"`
|
||||||
|
|
|
@ -1017,6 +1017,7 @@ func (a *accountDB) GetAccountWebStatuses(
|
||||||
) ([]*gtsmodel.Status, error) {
|
) ([]*gtsmodel.Status, error) {
|
||||||
// Check for an easy case: account exposes no statuses via the web.
|
// Check for an easy case: account exposes no statuses via the web.
|
||||||
webVisibility := account.Settings.WebVisibility
|
webVisibility := account.Settings.WebVisibility
|
||||||
|
hideBoosts := *account.Settings.HideBoosts
|
||||||
if webVisibility == gtsmodel.VisibilityNone {
|
if webVisibility == gtsmodel.VisibilityNone {
|
||||||
return nil, db.ErrNoEntries
|
return nil, db.ErrNoEntries
|
||||||
}
|
}
|
||||||
|
@ -1035,9 +1036,12 @@ func (a *accountDB) GetAccountWebStatuses(
|
||||||
// Select only IDs from table
|
// Select only IDs from table
|
||||||
Column("status.id").
|
Column("status.id").
|
||||||
Where("? = ?", bun.Ident("status.account_id"), account.ID).
|
Where("? = ?", bun.Ident("status.account_id"), account.ID).
|
||||||
// Don't show replies or boosts.
|
// Don't show replies.
|
||||||
Where("? IS NULL", bun.Ident("status.in_reply_to_uri")).
|
Where("? IS NULL", bun.Ident("status.in_reply_to_uri"))
|
||||||
Where("? IS NULL", bun.Ident("status.boost_of_id"))
|
|
||||||
|
if hideBoosts {
|
||||||
|
q = q.Where("? IS NULL", bun.Ident("status.boost_of_id"))
|
||||||
|
}
|
||||||
|
|
||||||
// Select statuses for this account according
|
// Select statuses for this account according
|
||||||
// to their web visibility preference.
|
// to their web visibility preference.
|
||||||
|
|
|
@ -123,8 +123,8 @@ func (p *Processor) GetRSSFeedForUsername(ctx context.Context, username string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add each status to the rss feed.
|
// Add each status to the rss feed.
|
||||||
for _, status := range statuses {
|
for _, s := range statuses {
|
||||||
item, err := p.converter.StatusToRSSItem(ctx, status)
|
item, err := p.converter.StatusToRSSItem(ctx, s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = gtserror.Newf("error converting status to feed item: %w", err)
|
err = gtserror.Newf("error converting status to feed item: %w", err)
|
||||||
return "", gtserror.NewErrorInternalError(err)
|
return "", gtserror.NewErrorInternalError(err)
|
||||||
|
|
|
@ -42,6 +42,16 @@ func (suite *GetRSSTestSuite) TestGetAccountRSSAdmin() {
|
||||||
<description>Posts from @admin@localhost:8080</description>
|
<description>Posts from @admin@localhost:8080</description>
|
||||||
<pubDate>Wed, 20 Oct 2021 10:41:37 +0000</pubDate>
|
<pubDate>Wed, 20 Oct 2021 10:41:37 +0000</pubDate>
|
||||||
<lastBuildDate>Wed, 20 Oct 2021 10:41:37 +0000</lastBuildDate>
|
<lastBuildDate>Wed, 20 Oct 2021 10:41:37 +0000</lastBuildDate>
|
||||||
|
<item>
|
||||||
|
<title>introduction post</title>
|
||||||
|
<link>http://localhost:8080/@the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY</link>
|
||||||
|
<description>@the_mighty_zork@localhost:8080 made a new post: "hello everyone!"</description>
|
||||||
|
<content:encoded><![CDATA[hello everyone!]]></content:encoded>
|
||||||
|
<author>@the_mighty_zork@localhost:8080</author>
|
||||||
|
<guid isPermaLink="true">http://localhost:8080/@the_mighty_zork/statuses/01F8MHAMCHF6Y650WCRSCP4WMY</guid>
|
||||||
|
<pubDate>Wed, 20 Oct 2021 10:40:37 +0000</pubDate>
|
||||||
|
<source>http://localhost:8080/@the_mighty_zork/feed.rss</source>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<title>open to see some puppies</title>
|
<title>open to see some puppies</title>
|
||||||
<link>http://localhost:8080/@admin/statuses/01F8MHAAY43M6RJ473VQFCVH37</link>
|
<link>http://localhost:8080/@admin/statuses/01F8MHAAY43M6RJ473VQFCVH37</link>
|
||||||
|
|
|
@ -184,6 +184,7 @@ func (p *Processor) WebStatusesGet(
|
||||||
log.Errorf(ctx, "error convering to web status: %v", err)
|
log.Errorf(ctx, "error convering to web status: %v", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
items = append(items, item)
|
items = append(items, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1046,7 +1046,15 @@ func (c *Converter) StatusToWebStatus(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
s *gtsmodel.Status,
|
s *gtsmodel.Status,
|
||||||
) (*apimodel.WebStatus, error) {
|
) (*apimodel.WebStatus, error) {
|
||||||
apiStatus, err := c.statusToFrontend(ctx, s,
|
|
||||||
|
isBoost := s.BoostOf != nil
|
||||||
|
status := s
|
||||||
|
|
||||||
|
if isBoost {
|
||||||
|
status = s.BoostOf
|
||||||
|
}
|
||||||
|
|
||||||
|
apiStatus, err := c.statusToFrontend(ctx, status,
|
||||||
nil, // No authed requester.
|
nil, // No authed requester.
|
||||||
statusfilter.FilterContextNone, // No filters.
|
statusfilter.FilterContextNone, // No filters.
|
||||||
nil, // No filters.
|
nil, // No filters.
|
||||||
|
@ -1057,7 +1065,7 @@ func (c *Converter) StatusToWebStatus(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert status author to web model.
|
// Convert status author to web model.
|
||||||
acct, err := c.AccountToWebAccount(ctx, s.Account)
|
acct, err := c.AccountToWebAccount(ctx, status.Account)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -1067,6 +1075,14 @@ func (c *Converter) StatusToWebStatus(
|
||||||
Account: acct,
|
Account: acct,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isBoost {
|
||||||
|
reblogAcct, err := c.AccountToWebAccount(ctx, s.Account)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
webStatus.ReblogAccount = reblogAcct
|
||||||
|
}
|
||||||
|
|
||||||
// Whack a newline before and after each "pre" to make it easier to outdent it.
|
// Whack a newline before and after each "pre" to make it easier to outdent it.
|
||||||
webStatus.Content = strings.ReplaceAll(webStatus.Content, "<pre>", "\n<pre>")
|
webStatus.Content = strings.ReplaceAll(webStatus.Content, "<pre>", "\n<pre>")
|
||||||
webStatus.Content = strings.ReplaceAll(webStatus.Content, "</pre>", "</pre>\n")
|
webStatus.Content = strings.ReplaceAll(webStatus.Content, "</pre>", "</pre>\n")
|
||||||
|
|
|
@ -1401,6 +1401,7 @@ func (suite *InternalToFrontendTestSuite) TestStatusToWebStatus() {
|
||||||
"emojis": [],
|
"emojis": [],
|
||||||
"fields": []
|
"fields": []
|
||||||
},
|
},
|
||||||
|
"reblog_account": null,
|
||||||
"media_attachments": [
|
"media_attachments": [
|
||||||
{
|
{
|
||||||
"id": "01HE7Y3C432WRSNS10EZM86SA5",
|
"id": "01HE7Y3C432WRSNS10EZM86SA5",
|
||||||
|
|
|
@ -39,6 +39,12 @@
|
||||||
func (c *Converter) StatusToRSSItem(ctx context.Context, s *gtsmodel.Status) (*feeds.Item, error) {
|
func (c *Converter) StatusToRSSItem(ctx context.Context, s *gtsmodel.Status) (*feeds.Item, error) {
|
||||||
// see https://cyber.harvard.edu/rss/rss.html
|
// see https://cyber.harvard.edu/rss/rss.html
|
||||||
|
|
||||||
|
// If status is a boost,
|
||||||
|
// display the boost instead.
|
||||||
|
if s.BoostOf != nil {
|
||||||
|
s = s.BoostOf
|
||||||
|
}
|
||||||
|
|
||||||
// Title -- The title of the item.
|
// Title -- The title of the item.
|
||||||
// example: Venice Film Festival Tries to Quit Sinking
|
// example: Venice Film Festival Tries to Quit Sinking
|
||||||
var title string
|
var title string
|
||||||
|
|
|
@ -41,6 +41,12 @@ main {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.boosted {
|
||||||
|
padding: 0 0.75rem 0.75rem;
|
||||||
|
color: var(--fg-reduced);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
.status-header > address {
|
.status-header > address {
|
||||||
/*
|
/*
|
||||||
Avoid stretching so wide that user
|
Avoid stretching so wide that user
|
||||||
|
@ -65,11 +71,21 @@ main {
|
||||||
height: 3.5rem;
|
height: 3.5rem;
|
||||||
width: 3.5rem;
|
width: 3.5rem;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
border: 0.15rem solid $avatar-border;
|
border: 0.15rem solid $avatar-border;
|
||||||
border-radius: $br;
|
border-radius: $br;
|
||||||
overflow: hidden; /* hides corners from img overflowing */
|
overflow: hidden; /* hides corners from img overflowing */
|
||||||
|
|
||||||
|
.boosted-avatar {
|
||||||
|
height: 50%;
|
||||||
|
width: 50%;
|
||||||
|
z-index: 10;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
inset-inline-end: 0;
|
||||||
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
@ -247,6 +247,16 @@
|
||||||
class="status expanded"
|
class="status expanded"
|
||||||
{{- includeAttr "status_attributes.tmpl" . | indentAttr 6 }}
|
{{- includeAttr "status_attributes.tmpl" . | indentAttr 6 }}
|
||||||
>
|
>
|
||||||
|
{{- if .ReblogAccount }}
|
||||||
|
<div class="boosted text-cutoff">
|
||||||
|
<i class="fa fa-retweet" aria-hidden="true"></i> 
|
||||||
|
{{- if $.account.DisplayName }}
|
||||||
|
{{- emojify $.account.Emojis (escape $.account.DisplayName) }} boosted
|
||||||
|
{{- else }}
|
||||||
|
{{- $.account.Username }} boosted
|
||||||
|
{{- end }}
|
||||||
|
</div>
|
||||||
|
{{- end }}
|
||||||
{{- include "status.tmpl" . | indent 6 }}
|
{{- include "status.tmpl" . | indent 6 }}
|
||||||
</article>
|
</article>
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
|
@ -48,6 +48,16 @@
|
||||||
alt="Avatar for {{ .Username -}}"
|
alt="Avatar for {{ .Username -}}"
|
||||||
title="Avatar for {{ .Username -}}"
|
title="Avatar for {{ .Username -}}"
|
||||||
>
|
>
|
||||||
|
{{ if $.ReblogAccount }}
|
||||||
|
<img
|
||||||
|
class="boosted-avatar"
|
||||||
|
src="{{ $.ReblogAccount.Avatar }}"
|
||||||
|
alt="Avatar for {{ $.ReblogAccount.Username -}}"
|
||||||
|
title="Avatar for {{ $.ReblogAccount.Username -}}"
|
||||||
|
>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
|
||||||
</picture>
|
</picture>
|
||||||
<div class="author-strap">
|
<div class="author-strap">
|
||||||
<span class="displayname text-cutoff">
|
<span class="displayname text-cutoff">
|
||||||
|
|
Loading…
Reference in a new issue