[feature] Hashtag federation (in/out), hashtag client API endpoints (#2032)

* update go-fed

* do the things

* remove unused columns from tags

* update to latest lingo from main

* further tag shenanigans

* serve stub page at tag endpoint

* we did it lads

* tests, oh tests, ohhh tests, oh tests (doo doo doo doo)

* swagger docs

* document hashtag usage + federation

* instanceGet

* don't bother parsing tag href

* rename whereStartsWith -> whereStartsLike

* remove GetOrCreateTag

* dont cache status tag timelineability
This commit is contained in:
tobi
2023-07-31 15:47:35 +02:00
committed by GitHub
parent ed2477ebea
commit 2796a2e82f
69 changed files with 2536 additions and 482 deletions

View File

@@ -1760,26 +1760,20 @@ func NewTestStatuses() map[string]*gtsmodel.Status {
func NewTestTags() map[string]*gtsmodel.Tag {
return map[string]*gtsmodel.Tag{
"welcome": {
ID: "01F8MHA1A2NF9MJ3WCCQ3K8BSZ",
URL: "http://localhost:8080/tags/welcome",
Name: "welcome",
FirstSeenFromAccountID: "",
CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"),
UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"),
Useable: TrueBool(),
Listable: TrueBool(),
LastStatusAt: TimeMustParse("2022-05-14T13:21:09+02:00"),
ID: "01F8MHA1A2NF9MJ3WCCQ3K8BSZ",
Name: "welcome",
CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"),
UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"),
Useable: TrueBool(),
Listable: TrueBool(),
},
"Hashtag": {
ID: "01FCT9SGYA71487N8D0S1M638G",
URL: "http://localhost:8080/tags/Hashtag",
Name: "Hashtag",
FirstSeenFromAccountID: "",
CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"),
UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"),
Useable: TrueBool(),
Listable: TrueBool(),
LastStatusAt: TimeMustParse("2022-05-14T13:21:09+02:00"),
ID: "01FCT9SGYA71487N8D0S1M638G",
Name: "hashtag",
CreatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"),
UpdatedAt: TimeMustParse("2022-05-14T13:21:09+02:00"),
Useable: TrueBool(),
Listable: TrueBool(),
},
}
}
@@ -2092,6 +2086,7 @@ func NewTestActivities(accounts map[string]*gtsmodel.Account) map[string]Activit
nil,
true,
[]vocab.ActivityStreamsMention{},
[]vocab.TootHashtag{},
nil,
)
createDmForZork := WrapAPNoteInCreate(
@@ -2115,6 +2110,7 @@ func NewTestActivities(accounts map[string]*gtsmodel.Account) map[string]Activit
URLMustParse("http://localhost:8080/users/1happyturtle"),
"@1happyturtle@localhost:8080",
)},
[]vocab.TootHashtag{},
nil,
)
createReplyToTurtle := WrapAPNoteInCreate(
@@ -2136,6 +2132,7 @@ func NewTestActivities(accounts map[string]*gtsmodel.Account) map[string]Activit
nil,
false,
[]vocab.ActivityStreamsMention{},
[]vocab.TootHashtag{},
[]vocab.ActivityStreamsImage{
newAPImage(
URLMustParse("http://example.org/users/Some_User/statuses/afaba698-5740-4e32-a702-af61aa543bc1/attachment1.jpg"),
@@ -2483,6 +2480,7 @@ func NewTestFediStatuses() map[string]vocab.ActivityStreamsNote {
nil,
false,
[]vocab.ActivityStreamsMention{},
[]vocab.TootHashtag{},
[]vocab.ActivityStreamsImage{
newAPImage(
URLMustParse("http://example.org/users/Some_User/statuses/afaba698-5740-4e32-a702-af61aa543bc1/attachment1.jpg"),
@@ -2504,6 +2502,7 @@ func NewTestFediStatuses() map[string]vocab.ActivityStreamsNote {
[]*url.URL{},
false,
nil,
[]vocab.TootHashtag{},
nil,
),
"https://unknown-instance.com/users/brand_new_person/statuses/01FE5Y30E3W4P7TRE0R98KAYQV": NewAPNote(
@@ -2524,6 +2523,28 @@ func NewTestFediStatuses() map[string]vocab.ActivityStreamsNote {
"@the_mighty_zork@localhost:8080",
),
},
[]vocab.TootHashtag{},
nil,
),
"https://unknown-instance.com/users/brand_new_person/statuses/01H641QSRS3TCXSVC10X4GPKW7": NewAPNote(
URLMustParse("https://unknown-instance.com/users/brand_new_person/statuses/01H641QSRS3TCXSVC10X4GPKW7"),
URLMustParse("https://unknown-instance.com/users/@brand_new_person/01H641QSRS3TCXSVC10X4GPKW7"),
TimeMustParse("2023-04-12T12:13:12+02:00"),
"<p>Babe are you okay, you've hardly touched your <a href=\"https://unknown-instance.com/tags/piss\" class=\"mention hashtag\" rel=\"tag nofollow noreferrer noopener\" target=\"_blank\">#<span>piss</span></a></p>",
"",
URLMustParse("https://unknown-instance.com/users/brand_new_person"),
[]*url.URL{
URLMustParse(pub.PublicActivityPubIRI),
},
[]*url.URL{},
false,
[]vocab.ActivityStreamsMention{},
[]vocab.TootHashtag{
newAPHashtag(
URLMustParse("https://unknown-instance.com/tags/piss"),
"#piss",
),
},
nil,
),
"https://turnip.farm/users/turniplover6969/statuses/70c53e54-3146-42d5-a630-83c8b6c7c042": NewAPNote(
@@ -2539,6 +2560,7 @@ func NewTestFediStatuses() map[string]vocab.ActivityStreamsNote {
[]*url.URL{},
false,
nil,
[]vocab.TootHashtag{},
[]vocab.ActivityStreamsImage{
newAPImage(
URLMustParse("https://turnip.farm/attachments/f17843c7-015e-4251-9b5a-91389c49ee57.jpg"),
@@ -2566,6 +2588,7 @@ func NewTestFediStatuses() map[string]vocab.ActivityStreamsNote {
"@the_mighty_zork@localhost:8080",
),
},
[]vocab.TootHashtag{},
nil,
),
}
@@ -3349,6 +3372,20 @@ func newAPMention(uri *url.URL, namestring string) vocab.ActivityStreamsMention
return mention
}
func newAPHashtag(href *url.URL, name string) vocab.TootHashtag {
hashtag := streams.NewTootHashtag()
hrefProp := streams.NewActivityStreamsHrefProperty()
hrefProp.SetIRI(href)
hashtag.SetActivityStreamsHref(hrefProp)
nameProp := streams.NewActivityStreamsNameProperty()
nameProp.AppendXMLSchemaString(name)
hashtag.SetActivityStreamsName(nameProp)
return hashtag
}
func newAPImage(url *url.URL, mediaType string, imageDescription string, blurhash string) vocab.ActivityStreamsImage {
image := streams.NewActivityStreamsImage()
@@ -3413,6 +3450,7 @@ func NewAPNote(
noteCC []*url.URL,
noteSensitive bool,
noteMentions []vocab.ActivityStreamsMention,
noteTags []vocab.TootHashtag,
noteAttachments []vocab.ActivityStreamsImage,
) vocab.ActivityStreamsNote {
// create the note itself
@@ -3475,13 +3513,20 @@ func NewAPNote(
note.SetActivityStreamsCc(cc)
}
// mentions
// Tag entries
tag := streams.NewActivityStreamsTagProperty()
// mentions
for _, m := range noteMentions {
tag.AppendActivityStreamsMention(m)
}
note.SetActivityStreamsTag(tag)
// hashtags
for _, t := range noteTags {
tag.AppendTootHashtag(t)
}
// append any attachments as ActivityStreamsImage
if noteAttachments != nil {
attachmentProperty := streams.NewActivityStreamsAttachmentProperty()