mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-11-25 13:16:40 +00:00
Feat: display boosts on public profile
This commit is contained in:
parent
d9e59820ed
commit
af5a766f62
|
@ -447,7 +447,7 @@ func (suite *StatusCreateTestSuite) TestPostNewStatusMessedUpIntPolicy() {
|
|||
suite.Equal(http.StatusBadRequest, recorder.Code)
|
||||
|
||||
// We should have a helpful error
|
||||
// message telling us how we screwed up.
|
||||
// message telling us how we screwed up.
|
||||
suite.Equal(`{
|
||||
"error": "Bad Request: error converting followers_only.can_reply.always: policyURI public is not feasible for visibility followers_only"
|
||||
}`, out)
|
||||
|
|
|
@ -118,6 +118,10 @@ type WebStatus struct {
|
|||
// Override API account with web 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
|
||||
// attached to this status.
|
||||
MediaAttachments []*WebAttachment `json:"media_attachments"`
|
||||
|
|
|
@ -1017,6 +1017,7 @@ func (a *accountDB) GetAccountWebStatuses(
|
|||
) ([]*gtsmodel.Status, error) {
|
||||
// Check for an easy case: account exposes no statuses via the web.
|
||||
webVisibility := account.Settings.WebVisibility
|
||||
hideBoosts := *account.Settings.HideBoosts
|
||||
if webVisibility == gtsmodel.VisibilityNone {
|
||||
return nil, db.ErrNoEntries
|
||||
}
|
||||
|
@ -1035,9 +1036,12 @@ func (a *accountDB) GetAccountWebStatuses(
|
|||
// Select only IDs from table
|
||||
Column("status.id").
|
||||
Where("? = ?", bun.Ident("status.account_id"), account.ID).
|
||||
// Don't show replies or boosts.
|
||||
Where("? IS NULL", bun.Ident("status.in_reply_to_uri")).
|
||||
Where("? IS NULL", bun.Ident("status.boost_of_id"))
|
||||
// Don't show replies.
|
||||
Where("? IS NULL", bun.Ident("status.in_reply_to_uri"))
|
||||
|
||||
if hideBoosts {
|
||||
q = q.Where("? IS NULL", bun.Ident("status.boost_of_id"))
|
||||
}
|
||||
|
||||
// Select statuses for this account according
|
||||
// to their web visibility preference.
|
||||
|
|
|
@ -33,7 +33,7 @@ type AccountSettings struct {
|
|||
Theme string `bun:",nullzero"` // Preset CSS theme filename selected by this Account (empty string if nothing set).
|
||||
CustomCSS string `bun:",nullzero"` // Custom CSS that should be displayed for this Account's profile and statuses.
|
||||
EnableRSS *bool `bun:",nullzero,notnull,default:false"` // enable RSS feed subscription for this account's public posts at [URL]/feed
|
||||
HideBoosts *bool `bun:",nullzero,notnull,default:false"` // Hide boosts from this accounts profile page.
|
||||
HideBoosts *bool `bun:",nullzero,notnull,default:false"` // Hide boosts from this accounts profile page.
|
||||
HideCollections *bool `bun:",nullzero,notnull,default:false"` // Hide this account's followers/following collections.
|
||||
WebVisibility Visibility `bun:",nullzero,notnull,default:public"` // Visibility level of statuses that visitors can view via the web profile.
|
||||
InteractionPolicyDirect *InteractionPolicy `bun:""` // Interaction policy to use for new direct visibility statuses by this account. If null, assume default policy.
|
||||
|
|
|
@ -123,8 +123,8 @@ func (p *Processor) GetRSSFeedForUsername(ctx context.Context, username string)
|
|||
}
|
||||
|
||||
// Add each status to the rss feed.
|
||||
for _, status := range statuses {
|
||||
item, err := p.converter.StatusToRSSItem(ctx, status)
|
||||
for _, s := range statuses {
|
||||
item, err := p.converter.StatusToRSSItem(ctx, s)
|
||||
if err != nil {
|
||||
err = gtserror.Newf("error converting status to feed item: %w", err)
|
||||
return "", gtserror.NewErrorInternalError(err)
|
||||
|
|
|
@ -42,6 +42,16 @@ func (suite *GetRSSTestSuite) TestGetAccountRSSAdmin() {
|
|||
<description>Posts from @admin@localhost:8080</description>
|
||||
<pubDate>Wed, 20 Oct 2021 10:41:37 +0000</pubDate>
|
||||
<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>
|
||||
<title>open to see some puppies</title>
|
||||
<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)
|
||||
continue
|
||||
}
|
||||
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
|
|
|
@ -310,7 +310,7 @@ func (c *Converter) accountToAPIAccountPublic(ctx context.Context, a *gtsmodel.A
|
|||
enableRSS bool
|
||||
theme string
|
||||
customCSS string
|
||||
hideBoosts bool
|
||||
hideBoosts bool
|
||||
hideCollections bool
|
||||
)
|
||||
|
||||
|
@ -1046,7 +1046,15 @@ func (c *Converter) StatusToWebStatus(
|
|||
ctx context.Context,
|
||||
s *gtsmodel.Status,
|
||||
) (*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.
|
||||
statusfilter.FilterContextNone, // No filters.
|
||||
nil, // No filters.
|
||||
|
@ -1057,7 +1065,7 @@ func (c *Converter) StatusToWebStatus(
|
|||
}
|
||||
|
||||
// Convert status author to web model.
|
||||
acct, err := c.AccountToWebAccount(ctx, s.Account)
|
||||
acct, err := c.AccountToWebAccount(ctx, status.Account)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -1067,6 +1075,14 @@ func (c *Converter) StatusToWebStatus(
|
|||
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.
|
||||
webStatus.Content = strings.ReplaceAll(webStatus.Content, "<pre>", "\n<pre>")
|
||||
webStatus.Content = strings.ReplaceAll(webStatus.Content, "</pre>", "</pre>\n")
|
||||
|
|
|
@ -1401,6 +1401,7 @@ func (suite *InternalToFrontendTestSuite) TestStatusToWebStatus() {
|
|||
"emojis": [],
|
||||
"fields": []
|
||||
},
|
||||
"reblog_account": null,
|
||||
"media_attachments": [
|
||||
{
|
||||
"id": "01HE7Y3C432WRSNS10EZM86SA5",
|
||||
|
|
|
@ -39,6 +39,12 @@
|
|||
func (c *Converter) StatusToRSSItem(ctx context.Context, s *gtsmodel.Status) (*feeds.Item, error) {
|
||||
// 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.
|
||||
// example: Venice Film Festival Tries to Quit Sinking
|
||||
var title string
|
||||
|
|
|
@ -657,7 +657,7 @@ func NewTestAccountSettings() map[string]*gtsmodel.AccountSettings {
|
|||
Sensitive: util.Ptr(false),
|
||||
Language: "en",
|
||||
EnableRSS: util.Ptr(false),
|
||||
HideBoosts: util.Ptr(false),
|
||||
HideBoosts: util.Ptr(false),
|
||||
HideCollections: util.Ptr(false),
|
||||
WebVisibility: gtsmodel.VisibilityPublic,
|
||||
},
|
||||
|
@ -669,7 +669,7 @@ func NewTestAccountSettings() map[string]*gtsmodel.AccountSettings {
|
|||
Sensitive: util.Ptr(false),
|
||||
Language: "en",
|
||||
EnableRSS: util.Ptr(true),
|
||||
HideBoosts: util.Ptr(false),
|
||||
HideBoosts: util.Ptr(false),
|
||||
HideCollections: util.Ptr(false),
|
||||
WebVisibility: gtsmodel.VisibilityPublic,
|
||||
},
|
||||
|
@ -681,7 +681,7 @@ func NewTestAccountSettings() map[string]*gtsmodel.AccountSettings {
|
|||
Sensitive: util.Ptr(false),
|
||||
Language: "en",
|
||||
EnableRSS: util.Ptr(true),
|
||||
HideBoosts: util.Ptr(false),
|
||||
HideBoosts: util.Ptr(false),
|
||||
HideCollections: util.Ptr(false),
|
||||
WebVisibility: gtsmodel.VisibilityUnlocked,
|
||||
},
|
||||
|
@ -693,7 +693,7 @@ func NewTestAccountSettings() map[string]*gtsmodel.AccountSettings {
|
|||
Sensitive: util.Ptr(true),
|
||||
Language: "fr",
|
||||
EnableRSS: util.Ptr(false),
|
||||
HideBoosts: util.Ptr(false),
|
||||
HideBoosts: util.Ptr(false),
|
||||
HideCollections: util.Ptr(true),
|
||||
WebVisibility: gtsmodel.VisibilityPublic,
|
||||
},
|
||||
|
|
|
@ -41,6 +41,12 @@ main {
|
|||
text-decoration: none;
|
||||
}
|
||||
|
||||
.boosted {
|
||||
padding: 0 0.75rem 0.75rem;
|
||||
color: var(--fg-reduced);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.status-header > address {
|
||||
/*
|
||||
Avoid stretching so wide that user
|
||||
|
@ -59,17 +65,27 @@ main {
|
|||
"avatar author-strap author-strap";
|
||||
gap: 0 0.5rem;
|
||||
font-style: normal;
|
||||
|
||||
|
||||
.avatar {
|
||||
grid-area: avatar;
|
||||
height: 3.5rem;
|
||||
width: 3.5rem;
|
||||
object-fit: cover;
|
||||
|
||||
position: relative;
|
||||
|
||||
border: 0.15rem solid $avatar-border;
|
||||
border-radius: $br;
|
||||
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 {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
@ -77,7 +93,7 @@ main {
|
|||
background: $bg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.author-strap {
|
||||
grid-area: author-strap;
|
||||
display: grid;
|
||||
|
@ -87,7 +103,7 @@ main {
|
|||
"display display"
|
||||
"user user";
|
||||
gap: 0 0.5rem;
|
||||
|
||||
|
||||
.displayname, .username {
|
||||
justify-self: start;
|
||||
align-self: start;
|
||||
|
@ -95,12 +111,12 @@ main {
|
|||
font-size: 1rem;
|
||||
line-height: 1.3rem;
|
||||
}
|
||||
|
||||
|
||||
.displayname {
|
||||
grid-area: display;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
.username {
|
||||
grid-area: user;
|
||||
color: $link-fg;
|
||||
|
@ -200,34 +216,34 @@ main {
|
|||
.poll {
|
||||
background-color: $gray2;
|
||||
z-index: 2;
|
||||
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: $br;
|
||||
padding: 0.5rem;
|
||||
margin: 0;
|
||||
gap: 1rem;
|
||||
|
||||
|
||||
.poll-options {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
|
||||
|
||||
.poll-option {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.1rem;
|
||||
|
||||
|
||||
label {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
|
||||
meter {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
.poll-vote-summary {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
@ -236,7 +252,7 @@ main {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.poll-info {
|
||||
background-color: $gray4;
|
||||
display: flex;
|
||||
|
@ -245,7 +261,7 @@ main {
|
|||
border-radius: $br-inner;
|
||||
padding: 0.25rem;
|
||||
gap: 0.25rem;
|
||||
|
||||
|
||||
span {
|
||||
justify-self: center;
|
||||
white-space: nowrap;
|
||||
|
@ -301,12 +317,12 @@ main {
|
|||
width: 100%;
|
||||
z-index: 3;
|
||||
overflow: hidden;
|
||||
|
||||
|
||||
display: grid;
|
||||
padding: 1rem;
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
grid-template-rows: 1fr 1fr;
|
||||
grid-template-areas:
|
||||
grid-template-areas:
|
||||
"eye sensitive ."
|
||||
". sensitive .";
|
||||
|
||||
|
@ -369,7 +385,7 @@ main {
|
|||
height: 100%;
|
||||
padding: 0.8rem;
|
||||
border: 0.2rem dashed $white2;
|
||||
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
@ -518,4 +534,4 @@ main {
|
|||
.plyr {
|
||||
max-height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -247,6 +247,16 @@
|
|||
class="status expanded"
|
||||
{{- 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 }}
|
||||
</article>
|
||||
{{- end }}
|
||||
|
|
|
@ -48,6 +48,16 @@
|
|||
alt="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>
|
||||
<div class="author-strap">
|
||||
<span class="displayname text-cutoff">
|
||||
|
@ -63,4 +73,4 @@
|
|||
<span class="sr-only">(open profile)</span>
|
||||
</a>
|
||||
</address>
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
|
Loading…
Reference in a new issue