server: implement FEP-e232 style quotes #318

Manually merged
Johann150 merged 5 commits from federation-quote into main 2023-01-17 20:51:55 +00:00
Owner

This implements (yet another) way of federating quotes (in&out) as laid out in FEP-e232.

Took some code from a previous PR to Misskey, rewrote some other parts.

This implements (yet another) way of federating quotes (in&out) as laid out in [FEP-e232](https://codeberg.org/fediverse/fep/src/branch/main/feps/fep-e232.md). Took some code from a previous PR to Misskey, rewrote some other parts.
Johann150 added the
feature
label 2023-01-05 21:42:52 +00:00
Johann150 added 2 commits 2023-01-05 21:42:53 +00:00
Ref: FEP-e232
server: parse quote tag syntax
Some checks failed
ci/woodpecker/push/lint-foundkey-js Pipeline was successful
ci/woodpecker/push/lint-backend Pipeline was successful
ci/woodpecker/push/build Pipeline was successful
ci/woodpecker/push/lint-client Pipeline was successful
ci/woodpecker/push/lint-sw Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/pr/lint-foundkey-js Pipeline was successful
ci/woodpecker/pr/lint-client Pipeline failed
ci/woodpecker/pr/lint-backend Pipeline failed
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/lint-sw Pipeline failed
ci/woodpecker/pr/test Pipeline failed
524352ae87
Ref: FEP-e232
Johann150 added 1 commit 2023-01-05 21:53:30 +00:00
fixup: return just the href
Some checks failed
ci/woodpecker/push/build Pipeline was successful
ci/woodpecker/push/lint-client Pipeline was successful
ci/woodpecker/push/lint-backend Pipeline was successful
ci/woodpecker/push/lint-foundkey-js Pipeline was successful
ci/woodpecker/push/lint-sw Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/pr/lint-client Pipeline failed
ci/woodpecker/pr/lint-backend Pipeline failed
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/lint-sw Pipeline failed
ci/woodpecker/pr/lint-foundkey-js Pipeline was successful
ci/woodpecker/pr/test Pipeline failed
288a194392
a reviewed 2023-01-06 01:34:18 +00:00
a left a comment
First-time contributor

extractQuoteUrl()

// stop if there are no tags
if (tags == null) return null;

// check for quote relations
function hasRelQuote(link: ILink): boolean {
  link.rel != null
  &&
  toArray(link.rel).includes(
    'https://misskey-hub.net/ns#_misskey_quote'
    // may be expanded in the future?
    // may also want to sort the output of this function
    //     so that _misskey_quote is prioritized
    //     over other potential future "quote" rel-types
  );
}

// filter for rel=quote
let quotes = toArray(tags).filter(hasRelQuote);
if quotes.length > 0 return quotes[0].href; // take the first one?

// no rel-quote links found, so fallback to object links
let objectlinks = toArray(tags).filter(link => [
    'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
    'application/activity+json'
  ].includes(link.mediaType?.toLowerCase());

// optional: pass in the `content` and check the object link is at the end of content
objectlinks.filter(link => content.endsWith(link.href))

// return the first object link i guess (if you consider it a "quote")
if objectlinks.length > 0 return objectlinks[0].href
extractQuoteUrl() ```js // stop if there are no tags if (tags == null) return null; // check for quote relations function hasRelQuote(link: ILink): boolean { link.rel != null && toArray(link.rel).includes( 'https://misskey-hub.net/ns#_misskey_quote' // may be expanded in the future? // may also want to sort the output of this function // so that _misskey_quote is prioritized // over other potential future "quote" rel-types ); } // filter for rel=quote let quotes = toArray(tags).filter(hasRelQuote); if quotes.length > 0 return quotes[0].href; // take the first one? // no rel-quote links found, so fallback to object links let objectlinks = toArray(tags).filter(link => [ 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"', 'application/activity+json' ].includes(link.mediaType?.toLowerCase()); // optional: pass in the `content` and check the object link is at the end of content objectlinks.filter(link => content.endsWith(link.href)) // return the first object link i guess (if you consider it a "quote") if objectlinks.length > 0 return objectlinks[0].href ```
@ -19,0 +28,4 @@
[
'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
'application/activity+json'
].includes(link.mediaType?.toLowerCase())
First-time contributor

i'd instead do toArray(tags).filter(hasRel) because the link relation is what is doing all the semantic heavy-lifting

i'd instead do `toArray(tags).filter(hasRel)` because the link relation is what is doing all the semantic heavy-lifting
Author
Owner

This part is to implement the FEP because it says that this media type is required.

This part is to implement the FEP because it says that this media type is required.
Johann150 marked this conversation as resolved
@ -19,0 +38,4 @@
toArray(link.rel)
.includes('https://misskey-hub.net/ns#_misskey_quote')
}
quotes.sort((a, b) => {
First-time contributor

as above: replace this sort with a second filter that only runs if no tags have a rel=quote

as above: replace this sort with a second filter that only runs if no tags have a rel=quote
Author
Owner

Since the FEP says the media type is required and we want to require the rel as well, I've changed it to filter by both in one go. I'll also accept any URI that was accepted as a JSON-LD property before, in hopes of not having to adjust this rel array.

Since the FEP says the media type is required and we want to require the `rel` as well, I've changed it to filter by both in one go. I'll also accept any URI that was accepted as a JSON-LD property before, in hopes of not having to adjust this rel array.
Johann150 marked this conversation as resolved
@ -19,0 +47,4 @@
if (quotes.length === 0) return null;
// If there is more than one quote, we just pick the first/a random one.
First-time contributor

is this a valid assumption? should any Link with a correct mediaType be considered a quote? should you only consider the first object link, or should you maybe consider object links that are at the end of content?

is this a valid assumption? should any Link with a correct mediaType be considered a quote? should you only consider the first object link, or should you maybe consider object links that are at the end of `content`?
Johann150 marked this conversation as resolved
@ -280,2 +280,4 @@
}
export interface ILink extends IObject {
type: 'Link';
First-time contributor

type may not be always Link. it may be an extension or subclass of Link. a Link is just a node that has href (and optionally rel, mediaType, name, hreflang, height, width, preview`)

also i'm not sure if IObject as an interface follows the activitypub Object definition, but if it does, then note that Object and Link are actually disjoint -- an Object is not a Link, and a Link is not an Object. for example, a Link does not require an id.

essentially i'd use the following interface definition instead:

export interface ILink {
  href: string;
  rel?: string | string[];
  mediaType?: string;
  name?: string; // you need to account for nameMap
  hreflang?: string;
  height?: // non-negative integer
  width?: // non-negative integer
  preview?: // Object or Link
}

although it's okay to leave out the properties you don't need i suppose

`type` may not be always `Link`. it may be an extension or subclass of `Link`. a Link is just a node that has `href` (and optionally `rel`, `mediaType`, `name`, `hreflang`, `height`, width`, `preview`) also i'm not sure if `IObject` as an interface follows the activitypub Object definition, but if it does, then note that `Object` and `Link` are actually disjoint -- an Object is not a Link, and a Link is not an Object. for example, a Link does not require an `id`. essentially i'd use the following interface definition instead: ```js export interface ILink { href: string; rel?: string | string[]; mediaType?: string; name?: string; // you need to account for nameMap hreflang?: string; height?: // non-negative integer width?: // non-negative integer preview?: // Object or Link } ``` although it's okay to leave out the properties you don't need i suppose
Johann150 marked this conversation as resolved
a reviewed 2023-01-06 01:37:21 +00:00
@ -293,3 +300,11 @@ export const isLike = (object: IObject): object is ILike => getApType(object) ==
export const isAnnounce = (object: IObject): object is IAnnounce => getApType(object) === 'Announce';
export const isBlock = (object: IObject): object is IBlock => getApType(object) === 'Block';
export const isFlag = (object: IObject): object is IFlag => getApType(object) === 'Flag';
export const isLink = (object: IObject): object is ILink => getApType(object) === 'Link'
First-time contributor

remove getApType(object) === 'Link'

remove `getApType(object) === 'Link'`
Johann150 marked this conversation as resolved
Johann150 added 1 commit 2023-01-06 07:14:06 +00:00
fixup: require rel and accept more of them
Some checks failed
ci/woodpecker/push/build Pipeline was successful
ci/woodpecker/push/lint-foundkey-js Pipeline was successful
ci/woodpecker/push/lint-backend Pipeline was successful
ci/woodpecker/push/lint-client Pipeline was successful
ci/woodpecker/push/lint-sw Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/pr/lint-foundkey-js Pipeline was successful
ci/woodpecker/pr/lint-client Pipeline failed
ci/woodpecker/pr/lint-backend Pipeline failed
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/lint-sw Pipeline failed
ci/woodpecker/pr/test Pipeline failed
3d3ecab271
Accept all URIs that are accepted as quote properties.
Johann150 added 1 commit 2023-01-07 20:37:58 +00:00
fixup: ILink != IObject; IApMention, IApHashtag = ILink
Some checks failed
ci/woodpecker/push/lint-client Pipeline was successful
ci/woodpecker/push/lint-foundkey-js Pipeline was successful
ci/woodpecker/push/lint-backend Pipeline was successful
ci/woodpecker/push/build Pipeline was successful
ci/woodpecker/push/lint-sw Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/pr/lint-foundkey-js Pipeline was successful
ci/woodpecker/pr/lint-client Pipeline failed
ci/woodpecker/pr/lint-backend Pipeline failed
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/lint-sw Pipeline failed
ci/woodpecker/pr/test Pipeline failed
594764ade7
Johann150 manually merged commit e3fd371f4a into main 2023-01-17 20:51:55 +00:00
Johann150 deleted branch federation-quote 2023-01-17 20:52:07 +00:00
Sign in to join this conversation.
No reviewers
No labels
feature
fix
upkeep
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: FoundKeyGang/FoundKey#318
No description provided.