Selaa lähdekoodia

Merge branch 'develop' into dtluna/pleroma-refactor/1

tags/v0.9.9
Roger Braun 7 vuotta sitten
vanhempi
commit
c48c381e90
63 muutettua tiedostoa jossa 3292 lisäystä ja 227 poistoa
  1. +6
    -2
      TODO.txt
  2. +2
    -1
      config/config.exs
  3. +2
    -1
      config/test.exs
  4. +6
    -0
      lib/pleroma/activity.ex
  5. +2
    -2
      lib/pleroma/application.ex
  6. +20
    -0
      lib/pleroma/object.ex
  7. +26
    -1
      lib/pleroma/user.ex
  8. +45
    -7
      lib/pleroma/web/activity_pub/activity_pub.ex
  9. +38
    -0
      lib/pleroma/web/federator/federator.ex
  10. +112
    -5
      lib/pleroma/web/ostatus/activity_representer.ex
  11. +5
    -2
      lib/pleroma/web/ostatus/feed_representer.ex
  12. +201
    -2
      lib/pleroma/web/ostatus/ostatus.ex
  13. +31
    -3
      lib/pleroma/web/ostatus/ostatus_controller.ex
  14. +8
    -2
      lib/pleroma/web/router.ex
  15. +99
    -18
      lib/pleroma/web/salmon/salmon.ex
  16. +8
    -1
      lib/pleroma/web/twitter_api/representers/activity_representer.ex
  17. +3
    -2
      lib/pleroma/web/twitter_api/representers/user_representer.ex
  18. +124
    -109
      lib/pleroma/web/twitter_api/twitter_api.ex
  19. +8
    -0
      lib/pleroma/web/twitter_api/twitter_api_controller.ex
  20. +1
    -22
      lib/pleroma/web/web.ex
  21. +82
    -10
      lib/pleroma/web/web_finger/web_finger.ex
  22. +104
    -6
      lib/pleroma/web/websub/websub.ex
  23. +16
    -0
      lib/pleroma/web/websub/websub_client_subscription.ex
  24. +33
    -1
      lib/pleroma/web/websub/websub_controller.ex
  25. +19
    -0
      lib/pleroma/web/xml/xml.ex
  26. +10
    -0
      priv/repo/migrations/20170423154511_add_fields_to_users.exs
  27. +15
    -0
      priv/repo/migrations/20170426154155_create_websub_client_subscription.exs
  28. +10
    -0
      priv/repo/migrations/20170427054757_add_user_and_hub.exs
  29. +8
    -0
      priv/repo/migrations/20170501124823_add_id_contraints_to_activities_and_objects.exs
  30. +10
    -0
      priv/repo/migrations/20170501133231_add_id_contraints_to_activities_and_objects_part_two.exs
  31. +11
    -0
      priv/repo/migrations/20170502083023_add_local_field_to_activities.exs
  32. +7
    -0
      test/activity_test.exs
  33. +508
    -0
      test/fixtures/23211.atom
  34. +40
    -0
      test/fixtures/incoming_note_activity.xml
  35. +42
    -0
      test/fixtures/incoming_note_activity_answer.xml
  36. +29
    -0
      test/fixtures/incoming_reply_mastodon.xml
  37. +59
    -0
      test/fixtures/incoming_websub_gnusocial_attachments.xml
  38. +479
    -0
      test/fixtures/lambadalambda.atom
  39. +57
    -0
      test/fixtures/ostatus_incoming_post.xml
  40. +60
    -0
      test/fixtures/ostatus_incoming_reply.xml
  41. +27
    -0
      test/fixtures/private_key.pem
  42. +2
    -0
      test/fixtures/salmon2.xml
  43. +99
    -0
      test/fixtures/share-gs.xml
  44. +54
    -0
      test/fixtures/share.xml
  45. +10
    -0
      test/fixtures/user_full.xml
  46. +5
    -0
      test/fixtures/user_name_only.xml
  47. +20
    -0
      test/fixtures/webfinger.xml
  48. +2
    -2
      test/support/builders/activity_builder.ex
  49. +14
    -2
      test/support/factory.ex
  50. +37
    -1
      test/user_test.exs
  51. +9
    -0
      test/web/activity_pub/activity_pub_test.exs
  52. +124
    -1
      test/web/ostatus/activity_representer_test.exs
  53. +3
    -2
      test/web/ostatus/feed_representer_test.exs
  54. +11
    -0
      test/web/ostatus/ostatus_controller_test.exs
  55. +194
    -0
      test/web/ostatus/ostatus_test.exs
  56. +73
    -0
      test/web/salmon/salmon_test.exs
  57. +7
    -4
      test/web/twitter_api/representers/activity_representer_test.exs
  58. +4
    -2
      test/web/twitter_api/representers/user_representer_test.exs
  59. +4
    -3
      test/web/twitter_api/twitter_api_controller_test.exs
  60. +46
    -10
      test/web/twitter_api/twitter_api_test.exs
  61. +51
    -1
      test/web/web_finger/web_finger_test.exs
  62. +61
    -0
      test/web/websub/websub_controller_test.exs
  63. +89
    -2
      test/web/websub/websub_test.exs

+ 6
- 2
TODO.txt Näytä tiedosto

@@ -1,5 +1,9 @@
- Add cache for user fetching / representing. (mostly in TwitterAPI.activity_to_status)

Unliking:

- Add a proper undo activity, find out how to ignore those in twitter api.

WEBSUB:

- Add unsubscription
- Add periodical renewal


+ 2
- 1
config/config.exs Näytä tiedosto

@@ -30,7 +30,8 @@ config :mime, :types, %{
"application/xrd+xml" => ["xrd+xml"]
}

config :pleroma, :websub_verifier, Pleroma.Web.Websub
config :pleroma, :websub, Pleroma.Web.Websub
config :pleroma, :ostatus, Pleroma.Web.OStatus

# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.


+ 2
- 1
config/test.exs Näytä tiedosto

@@ -25,4 +25,5 @@ config :pleroma, Pleroma.Repo,
# Reduce hash rounds for testing
config :comeonin, :pbkdf2_rounds, 1

config :pleroma, :websub_verifier, Pleroma.Web.WebsubMock
config :pleroma, :websub, Pleroma.Web.WebsubMock
config :pleroma, :ostatus, Pleroma.Web.OStatusMock

+ 6
- 0
lib/pleroma/activity.ex Näytä tiedosto

@@ -5,6 +5,7 @@ defmodule Pleroma.Activity do

schema "activities" do
field :data, :map
field :local, :boolean, default: true

timestamps()
end
@@ -18,4 +19,9 @@ defmodule Pleroma.Activity do
Repo.all(from activity in Activity,
where: fragment("? @> ?", activity.data, ^%{object: %{id: ap_id}}))
end

def get_create_activity_by_object_ap_id(ap_id) do
Repo.one(from activity in Activity,
where: fragment("? @> ?", activity.data, ^%{type: "Create", object: %{id: ap_id}}))
end
end

+ 2
- 2
lib/pleroma/application.ex Näytä tiedosto

@@ -15,9 +15,9 @@ defmodule Pleroma.Application do
# Start your own worker by calling: Pleroma.Worker.start_link(arg1, arg2, arg3)
# worker(Pleroma.Worker, [arg1, arg2, arg3]),
worker(Cachex, [:user_cache, [
default_ttl: 5000,
default_ttl: 25000,
ttl_interval: 1000,
limit: 500
limit: 2500
]])
]



+ 20
- 0
lib/pleroma/object.ex Näytä tiedosto

@@ -13,4 +13,24 @@ defmodule Pleroma.Object do
Repo.one(from object in Object,
where: fragment("? @> ?", object.data, ^%{id: ap_id}))
end

def get_cached_by_ap_id(ap_id) do
if Mix.env == :test do
get_by_ap_id(ap_id)
else
key = "object:#{ap_id}"
Cachex.get!(:user_cache, key, fallback: fn(_) ->
object = get_by_ap_id(ap_id)
if object do
{:commit, object}
else
{:ignore, object}
end
end)
end
end

def context_mapping(context) do
%Object{data: %{"id" => context}}
end
end

+ 26
- 1
lib/pleroma/user.ex Näytä tiedosto

@@ -1,8 +1,10 @@
defmodule Pleroma.User do
use Ecto.Schema

import Ecto.{Changeset, Query}
alias Pleroma.{Repo, User, Object, Web}
alias Comeonin.Pbkdf2
alias Pleroma.Web.OStatus

schema "users" do
field :bio, :string
@@ -15,6 +17,8 @@ defmodule Pleroma.User do
field :following, {:array, :string}, default: []
field :ap_id, :string
field :avatar, :map
field :local, :boolean, default: true
field :info, :map, default: %{}

timestamps()
end
@@ -118,6 +122,27 @@ defmodule Pleroma.User do

def get_cached_by_nickname(nickname) do
key = "nickname:#{nickname}"
Cachex.get!(:user_cache, key, fallback: fn(_) -> Repo.get_by(User, nickname: nickname) end)
Cachex.get!(:user_cache, key, fallback: fn(_) -> get_or_fetch_by_nickname(nickname) end)
end

def get_by_nickname(nickname) do
Repo.get_by(User, nickname: nickname)
end

def get_cached_user_info(user) do
key = "user_info:#{user.id}"
Cachex.get!(:user_cache, key, fallback: fn(_) -> user_info(user) end)
end

def get_or_fetch_by_nickname(nickname) do
with %User{} = user <- get_by_nickname(nickname) do
user
else _e ->
with [nick, domain] <- String.split(nickname, "@"),
{:ok, user} <- OStatus.make_user(nickname) do
user
else _e -> nil
end
end
end
end

+ 45
- 7
lib/pleroma/web/activity_pub/activity_pub.ex Näytä tiedosto

@@ -3,7 +3,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
alias Ecto.{Changeset, UUID}
import Ecto.Query

def insert(map) when is_map(map) do
def insert(map, local \\ true) when is_map(map) do
map = map
|> Map.put_new_lazy("id", &generate_activity_id/0)
|> Map.put_new_lazy("published", &make_date/0)
@@ -16,7 +16,29 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
map
end

Repo.insert(%Activity{data: map})
Repo.insert(%Activity{data: map, local: local})
end

def create(to, actor, context, object, additional \\ %{}, published \\ nil, local \\ true) do
published = published || make_date()

activity = %{
"type" => "Create",
"to" => to |> Enum.uniq,
"actor" => actor.ap_id,
"object" => object,
"published" => published,
"context" => context
}
|> Map.merge(additional)

with {:ok, activity} <- insert(activity, local) do
if actor.local do
Pleroma.Web.Federator.enqueue(:publish, activity)
end

{:ok, activity}
end
end

def like(%User{ap_id: ap_id} = user, %Object{data: %{"id" => id}} = object) do
@@ -33,7 +55,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
"type" => "Like",
"actor" => ap_id,
"object" => id,
"to" => [User.ap_followers(user), object.data["actor"]]
"to" => [User.ap_followers(user), object.data["actor"]],
"context" => object.data["context"]
}

{:ok, activity} = insert(data)
@@ -49,6 +72,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do

update_object_in_activities(object)

if user.local do
Pleroma.Web.Federator.enqueue(:publish, activity)
end

{:ok, activity, object}
end
end
@@ -99,7 +126,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end

def generate_object_id do
generate_id("objects")
Pleroma.Web.Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :object, Ecto.UUID.generate)
end

def generate_id(type) do
@@ -127,6 +154,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
query = from activity in query,
where: activity.id > ^since_id

query = if opts["local_only"] do
from activity in query, where: activity.local == true
else
query
end

query = if opts["max_id"] do
from activity in query, where: activity.id < ^opts["max_id"]
else
@@ -143,15 +176,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
Enum.reverse(Repo.all(query))
end

def announce(%User{ap_id: ap_id} = user, %Object{data: %{"id" => id}} = object) do
def announce(%User{ap_id: ap_id} = user, %Object{data: %{"id" => id}} = object, local \\ true) do
data = %{
"type" => "Announce",
"actor" => ap_id,
"object" => id,
"to" => [User.ap_followers(user), object.data["actor"]]
"to" => [User.ap_followers(user), object.data["actor"]],
"context" => object.data["context"]
}

{:ok, activity} = insert(data)
{:ok, activity} = insert(data, local)

announcements = [ap_id | (object.data["announcements"] || [])] |> Enum.uniq

@@ -164,6 +198,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do

update_object_in_activities(object)

if user.local do
Pleroma.Web.Federator.enqueue(:publish, activity)
end

{:ok, activity, object}
end



+ 38
- 0
lib/pleroma/web/federator/federator.ex Näytä tiedosto

@@ -0,0 +1,38 @@
defmodule Pleroma.Web.Federator do
alias Pleroma.User
alias Pleroma.Web.WebFinger
require Logger

@websub Application.get_env(:pleroma, :websub)

def handle(:publish, activity) do
Logger.debug("Running publish for #{activity.data["id"]}")
with actor when not is_nil(actor) <- User.get_cached_by_ap_id(activity.data["actor"]) do
Logger.debug("Sending #{activity.data["id"]} out via websub")
Pleroma.Web.Websub.publish(Pleroma.Web.OStatus.feed_path(actor), actor, activity)

{:ok, actor} = WebFinger.ensure_keys_present(actor)
Logger.debug("Sending #{activity.data["id"]} out via salmon")
Pleroma.Web.Salmon.publish(actor, activity)
end
end

def handle(:verify_websub, websub) do
Logger.debug("Running websub verification for #{websub.id} (#{websub.topic}, #{websub.callback})")
@websub.verify(websub)
end

def handle(type, payload) do
Logger.debug("Unknown task: #{type}")
{:error, "Don't know what do do with this"}
end

def enqueue(type, payload) do
# for now, just run immediately in a new process.
if Mix.env == :test do
handle(type, payload)
else
spawn(fn -> handle(type, payload) end)
end
end
end

+ 112
- 5
lib/pleroma/web/ostatus/activity_representer.ex Näytä tiedosto

@@ -1,5 +1,31 @@
defmodule Pleroma.Web.OStatus.ActivityRepresenter do
def to_simple_form(%{data: %{"object" => %{"type" => "Note"}}} = activity, user) do
alias Pleroma.{Activity, User}
alias Pleroma.Web.OStatus.UserRepresenter
require Logger

defp get_in_reply_to(%{"object" => %{ "inReplyTo" => in_reply_to}}) do
[{:"thr:in-reply-to", [ref: to_charlist(in_reply_to)], []}]
end

defp get_in_reply_to(_), do: []

defp get_mentions(to) do
Enum.map(to, fn (id) ->
cond do
# Special handling for the AP/Ostatus public collections
"https://www.w3.org/ns/activitystreams#Public" == id ->
{:link, [rel: "mentioned", "ostatus:object-type": "http://activitystrea.ms/schema/1.0/collection", href: "http://activityschema.org/collection/public"], []}
# Ostatus doesn't handle follower collections, ignore these.
Regex.match?(~r/^#{Pleroma.Web.base_url}.+followers$/, id) ->
[]
true ->
{:link, [rel: "mentioned", "ostatus:object-type": "http://activitystrea.ms/schema/1.0/person", href: id], []}
end
end)
end

def to_simple_form(activity, user, with_author \\ false)
def to_simple_form(%{data: %{"object" => %{"type" => "Note"}}} = activity, user, with_author) do
h = fn(str) -> [to_charlist(str)] end

updated_at = activity.updated_at
@@ -12,16 +38,97 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenter do
{:link, [rel: 'enclosure', href: to_charlist(url["href"]), type: to_charlist(url["mediaType"])], []}
end)

in_reply_to = get_in_reply_to(activity.data)
author = if with_author, do: [{:author, UserRepresenter.to_simple_form(user)}], else: []
mentions = activity.data["to"] |> get_mentions

[
{:"activity:object-type", ['http://activitystrea.ms/schema/1.0/note']},
{:"activity:verb", ['http://activitystrea.ms/schema/1.0/post']},
{:id, h.(activity.data["object"]["id"])},
{:id, h.(activity.data["object"]["id"])}, # For notes, federate the object id.
{:title, ['New note by #{user.nickname}']},
{:content, [type: 'html'], h.(activity.data["object"]["content"])},
{:published, h.(inserted_at)},
{:updated, h.(updated_at)}
] ++ attachments
{:updated, h.(updated_at)},
{:"ostatus:conversation", [], h.(activity.data["context"])},
{:link, [href: h.(activity.data["context"]), rel: 'ostatus:conversation'], []},
{:link, [type: ['application/atom+xml'], href: h.(activity.data["object"]["id"]), rel: 'self'], []}
] ++ attachments ++ in_reply_to ++ author ++ mentions
end

def to_simple_form(%{data: %{"type" => "Like"}} = activity, user, with_author) do
h = fn(str) -> [to_charlist(str)] end

updated_at = activity.updated_at
|> NaiveDateTime.to_iso8601
inserted_at = activity.inserted_at
|> NaiveDateTime.to_iso8601

in_reply_to = get_in_reply_to(activity.data)
author = if with_author, do: [{:author, UserRepresenter.to_simple_form(user)}], else: []
mentions = activity.data["to"] |> get_mentions

[
{:"activity:verb", ['http://activitystrea.ms/schema/1.0/favorite']},
{:id, h.(activity.data["id"])},
{:title, ['New favorite by #{user.nickname}']},
{:content, [type: 'html'], ['#{user.nickname} favorited something']},
{:published, h.(inserted_at)},
{:updated, h.(updated_at)},
{:"activity:object", [
{:"activity:object-type", ['http://activitystrea.ms/schema/1.0/note']},
{:id, h.(activity.data["object"])}, # For notes, federate the object id.
]},
{:"ostatus:conversation", [], h.(activity.data["context"])},
{:link, [href: h.(activity.data["context"]), rel: 'ostatus:conversation'], []},
{:link, [rel: 'self', type: ['application/atom+xml'], href: h.(activity.data["id"])], []},
{:"thr:in-reply-to", [ref: to_charlist(activity.data["object"])], []}
] ++ author ++ mentions
end

def to_simple_form(%{data: %{"type" => "Announce"}} = activity, user, with_author) do
h = fn(str) -> [to_charlist(str)] end

updated_at = activity.updated_at
|> NaiveDateTime.to_iso8601
inserted_at = activity.inserted_at
|> NaiveDateTime.to_iso8601

in_reply_to = get_in_reply_to(activity.data)
author = if with_author, do: [{:author, UserRepresenter.to_simple_form(user)}], else: []

retweeted_activity = Activity.get_create_activity_by_object_ap_id(activity.data["object"])
retweeted_user = User.get_cached_by_ap_id(retweeted_activity.data["actor"])

retweeted_xml = to_simple_form(retweeted_activity, retweeted_user, true)

mentions = activity.data["to"] |> get_mentions
[
{:"activity:object-type", ['http://activitystrea.ms/schema/1.0/activity']},
{:"activity:verb", ['http://activitystrea.ms/schema/1.0/share']},
{:id, h.(activity.data["id"])},
{:title, ['#{user.nickname} repeated a notice']},
{:content, [type: 'html'], ['RT #{retweeted_activity.data["object"]["content"]}']},
{:published, h.(inserted_at)},
{:updated, h.(updated_at)},
{:"ostatus:conversation", [], h.(activity.data["context"])},
{:link, [href: h.(activity.data["context"]), rel: 'ostatus:conversation'], []},
{:link, [rel: 'self', type: ['application/atom+xml'], href: h.(activity.data["id"])], []},
{:"activity:object", retweeted_xml}
] ++ mentions ++ author
end

def wrap_with_entry(simple_form) do
[{
:entry, [
xmlns: 'http://www.w3.org/2005/Atom',
"xmlns:thr": 'http://purl.org/syndication/thread/1.0',
"xmlns:activity": 'http://activitystrea.ms/spec/1.0/',
"xmlns:poco": 'http://portablecontacts.net/spec/1.0',
"xmlns:ostatus": 'http://ostatus.org/schema/1.0'
], simple_form
}]
end

def to_simple_form(_, _), do: nil
def to_simple_form(_, _, _), do: nil
end

+ 5
- 2
lib/pleroma/web/ostatus/feed_representer.ex Näytä tiedosto

@@ -17,14 +17,17 @@ defmodule Pleroma.Web.OStatus.FeedRepresenter do
[{
:feed, [
xmlns: 'http://www.w3.org/2005/Atom',
"xmlns:thr": 'http://purl.org/syndication/thread/1.0',
"xmlns:activity": 'http://activitystrea.ms/spec/1.0/',
"xmlns:poco": 'http://portablecontacts.net/spec/1.0'
"xmlns:poco": 'http://portablecontacts.net/spec/1.0',
"xmlns:ostatus": 'http://ostatus.org/schema/1.0'
], [
{:id, h.(OStatus.feed_path(user))},
{:title, ['#{user.nickname}\'s timeline']},
{:updated, h.(most_recent_update)},
{:link, [rel: 'hub', href: h.(OStatus.pubsub_path(user))], []},
{:link, [rel: 'self', href: h.(OStatus.feed_path(user))], []},
{:link, [rel: 'salmon', href: h.(OStatus.salmon_path(user))], []},
{:link, [rel: 'self', href: h.(OStatus.feed_path(user)), type: 'application/atom+xml'], []},
{:author, UserRepresenter.to_simple_form(user)},
] ++ entries
}]


+ 201
- 2
lib/pleroma/web/ostatus/ostatus.ex Näytä tiedosto

@@ -1,5 +1,11 @@
defmodule Pleroma.Web.OStatus do
alias Pleroma.Web
import Ecto.Query
import Pleroma.Web.XML
require Logger

alias Pleroma.{Repo, User, Web, Object}
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.{WebFinger, Websub}

def feed_path(user) do
"#{user.ap_id}/feed.atom"
@@ -9,6 +15,199 @@ defmodule Pleroma.Web.OStatus do
"#{Web.base_url}/push/hub/#{user.nickname}"
end

def user_path(user) do
def salmon_path(user) do
"#{user.ap_id}/salmon"
end

def handle_incoming(xml_string) do
doc = parse_document(xml_string)
entries = :xmerl_xpath.string('//entry', doc)

activities = Enum.map(entries, fn (entry) ->
{:xmlObj, :string, object_type } = :xmerl_xpath.string('string(/entry/activity:object-type[1])', entry)
{:xmlObj, :string, verb } = :xmerl_xpath.string('string(/entry/activity:verb[1])', entry)

case verb do
'http://activitystrea.ms/schema/1.0/share' ->
with {:ok, activity, retweeted_activity} <- handle_share(entry, doc), do: [activity, retweeted_activity]
_ ->
case object_type do
'http://activitystrea.ms/schema/1.0/note' ->
with {:ok, activity} <- handle_note(entry, doc), do: activity
'http://activitystrea.ms/schema/1.0/comment' ->
with {:ok, activity} <- handle_note(entry, doc), do: activity
_ ->
Logger.error("Couldn't parse incoming document")
nil
end
end
end)
{:ok, activities}
end

def make_share(entry, doc, retweeted_activity) do
with {:ok, actor} <- find_make_or_update_user(doc),
%Object{} = object <- Object.get_cached_by_ap_id(retweeted_activity.data["object"]["id"]),
{:ok, activity, object} = ActivityPub.announce(actor, object, false) do
{:ok, activity}
end
end

def handle_share(entry, doc) do
with [object] <- :xmerl_xpath.string('/entry/activity:object', entry),
{:ok, retweeted_activity} <- handle_note(object, object),
{:ok, activity} <- make_share(entry, doc, retweeted_activity) do
{:ok, activity, retweeted_activity}
else
e -> {:error, e}
end
end

def get_attachments(entry) do
:xmerl_xpath.string('/entry/link[@rel="enclosure"]', entry)
|> Enum.map(fn (enclosure) ->
with href when not is_nil(href) <- string_from_xpath("/link/@href", enclosure),
type when not is_nil(type) <- string_from_xpath("/link/@type", enclosure) do
%{
"type" => "Attachment",
"url" => [%{
"type" => "Link",
"mediaType" => type,
"href" => href
}]
}
end
end)
|> Enum.filter(&(&1))
end

def handle_note(entry, doc \\ nil) do
content_html = string_from_xpath("//content[1]", entry)

[author] = :xmerl_xpath.string('//author[1]', doc)
{:ok, actor} = find_make_or_update_user(author)
inReplyTo = string_from_xpath("//thr:in-reply-to[1]/@ref", entry)

context = (string_from_xpath("//ostatus:conversation[1]", entry) || "") |> String.trim

attachments = get_attachments(entry)

context = with %{data: %{"context" => context}} <- Object.get_cached_by_ap_id(inReplyTo) do
context
else _e ->
if String.length(context) > 0 do
context
else
ActivityPub.generate_context_id
end
end

to = [
"https://www.w3.org/ns/activitystreams#Public"
]

mentions = :xmerl_xpath.string('//link[@rel="mentioned" and @ostatus:object-type="http://activitystrea.ms/schema/1.0/person"]', entry)
|> Enum.map(fn(person) -> string_from_xpath("@href", person) end)

to = to ++ mentions

date = string_from_xpath("//published", entry)
id = string_from_xpath("//id", entry)

object = %{
"id" => id,
"type" => "Note",
"to" => to,
"content" => content_html,
"published" => date,
"context" => context,
"actor" => actor.ap_id,
"attachment" => attachments
}

object = if inReplyTo do
Map.put(object, "inReplyTo", inReplyTo)
else
object
end

# TODO: Bail out sooner and use transaction.
if Object.get_by_ap_id(id) do
{:error, "duplicate activity"}
else
ActivityPub.create(to, actor, context, object, %{}, date, false)
end
end

def find_make_or_update_user(doc) do
uri = string_from_xpath("//author/uri[1]", doc)
with {:ok, user} <- find_or_make_user(uri) do
avatar = make_avatar_object(doc)
if user.avatar != avatar do
change = Ecto.Changeset.change(user, %{avatar: avatar})
Repo.update(change)
else
{:ok, user}
end
end
end

def find_or_make_user(uri) do
query = from user in User,
where: user.local == false and fragment("? @> ?", user.info, ^%{uri: uri})

user = Repo.one(query)

if is_nil(user) do
make_user(uri)
else
{:ok, user}
end
end

def make_user(uri) do
with {:ok, info} <- gather_user_info(uri) do
data = %{
local: false,
name: info["name"],
nickname: info["nickname"] <> "@" <> info["host"],
ap_id: info["uri"],
info: info,
avatar: info["avatar"]
}
# TODO: Make remote user changeset
# SHould enforce fqn nickname
Repo.insert(Ecto.Changeset.change(%User{}, data))
end
end

# TODO: Just takes the first one for now.
def make_avatar_object(author_doc) do
href = string_from_xpath("//author[1]/link[@rel=\"avatar\"]/@href", author_doc)
type = string_from_xpath("//author[1]/link[@rel=\"avatar\"]/@type", author_doc)

if href do
%{
"type" => "Image",
"url" =>
[%{
"type" => "Link",
"mediaType" => type,
"href" => href
}]
}
else
nil
end
end

def gather_user_info(username) do
with {:ok, webfinger_data} <- WebFinger.finger(username),
{:ok, feed_data} <- Websub.gather_feed_data(webfinger_data["topic"]) do
{:ok, Map.merge(webfinger_data, feed_data) |> Map.put("fqn", username)}
else e ->
Logger.debug("Couldn't gather info for #{username}")
{:error, e}
end
end
end

+ 31
- 3
lib/pleroma/web/ostatus/ostatus_controller.ex Näytä tiedosto

@@ -2,10 +2,16 @@ defmodule Pleroma.Web.OStatus.OStatusController do
use Pleroma.Web, :controller

alias Pleroma.{User, Activity}
alias Pleroma.Web.OStatus.FeedRepresenter
alias Pleroma.Web.OStatus.{FeedRepresenter, ActivityRepresenter}
alias Pleroma.Repo
alias Pleroma.Web.OStatus
import Ecto.Query

def feed_redirect(conn, %{"nickname" => nickname}) do
user = User.get_cached_by_nickname(nickname)
redirect conn, external: OStatus.feed_path(user)
end

def feed(conn, %{"nickname" => nickname}) do
user = User.get_cached_by_nickname(nickname)
query = from activity in Activity,
@@ -26,7 +32,29 @@ defmodule Pleroma.Web.OStatus.OStatusController do
|> send_resp(200, response)
end

def temp(_conn, params) do
IO.inspect(params)
def salmon_incoming(conn, params) do
{:ok, body, _conn} = read_body(conn)
{:ok, magic_key} = Pleroma.Web.Salmon.fetch_magic_key(body)
{:ok, doc} = Pleroma.Web.Salmon.decode_and_validate(magic_key, body)

Pleroma.Web.OStatus.handle_incoming(doc)

conn
|> send_resp(200, "")
end

def object(conn, %{"uuid" => uuid}) do
id = o_status_url(conn, :object, uuid)
activity = Activity.get_create_activity_by_object_ap_id(id)
user = User.get_cached_by_ap_id(activity.data["actor"])

response = ActivityRepresenter.to_simple_form(activity, user, true)
|> ActivityRepresenter.wrap_with_entry
|> :xmerl.export_simple(:xmerl_xml)
|> to_string

conn
|> put_resp_content_type("application/atom+xml")
|> send_resp(200, response)
end
end

+ 8
- 2
lib/pleroma/web/router.ex Näytä tiedosto

@@ -30,7 +30,7 @@ defmodule Pleroma.Web.Router do
get "/statusnet/config", TwitterAPI.Controller, :config

get "/statuses/public_timeline", TwitterAPI.Controller, :public_timeline
get "/statuses/public_and_external_timeline", TwitterAPI.Controller, :public_timeline
get "/statuses/public_and_external_timeline", TwitterAPI.Controller, :public_and_external_timeline
get "/statuses/user_timeline", TwitterAPI.Controller, :user_timeline

get "/statuses/show/:id", TwitterAPI.Controller, :fetch_status
@@ -73,8 +73,14 @@ defmodule Pleroma.Web.Router do
scope "/", Pleroma.Web do
pipe_through :ostatus

get "/objects/:uuid", OStatus.OStatusController, :object

get "/users/:nickname/feed", OStatus.OStatusController, :feed
get "/users/:nickname", OStatus.OStatusController, :feed_redirect
post "/users/:nickname/salmon", OStatus.OStatusController, :salmon_incoming
post "/push/hub/:nickname", Websub.WebsubController, :websub_subscription_request
get "/push/subscriptions/:id", Websub.WebsubController, :websub_subscription_confirmation
post "/push/subscriptions/:id", Websub.WebsubController, :websub_incoming
end

scope "/.well-known", Pleroma.Web do
@@ -92,5 +98,5 @@ end

defmodule Fallback.RedirectController do
use Pleroma.Web, :controller
def redirector(conn, _params), do: send_file(conn, 200, "priv/static/index.html")
def redirector(conn, _params), do: (if Mix.env != :test, do: send_file(conn, 200, "priv/static/index.html"))
end

+ 99
- 18
lib/pleroma/web/salmon/salmon.ex Näytä tiedosto

@@ -1,8 +1,12 @@
defmodule Pleroma.Web.Salmon do
use Bitwise
alias Pleroma.Web.XML
alias Pleroma.Web.OStatus.ActivityRepresenter
alias Pleroma.User
require Logger

def decode(salmon) do
{doc, _rest} = :xmerl_scan.string(to_charlist(salmon))
doc = XML.parse_document(salmon)

{:xmlObj, :string, data} = :xmerl_xpath.string('string(//me:data[1])', doc)
{:xmlObj, :string, sig} = :xmerl_xpath.string('string(//me:sig[1])', doc)
@@ -20,22 +24,12 @@ defmodule Pleroma.Web.Salmon do
end

def fetch_magic_key(salmon) do
[data, _, _, _, _] = decode(salmon)
{doc, _rest} = :xmerl_scan.string(to_charlist(data))
{:xmlObj, :string, uri} = :xmerl_xpath.string('string(//author[1]/uri)', doc)

uri = to_string(uri)
base = URI.parse(uri).host

# TODO: Find out if this endpoint is mandated by the standard.
{:ok, response} = HTTPoison.get(base <> "/.well-known/webfinger", ["Accept": "application/xrd+xml"], [params: [resource: uri]])

{doc, _rest} = :xmerl_scan.string(to_charlist(response.body))

{:xmlObj, :string, magickey} = :xmerl_xpath.string('string(//Link[@rel="magic-public-key"]/@href)', doc)
"data:application/magic-public-key," <> magickey = to_string(magickey)

magickey
with [data, _, _, _, _] <- decode(salmon),
doc <- XML.parse_document(data),
uri when not is_nil(uri) <- XML.string_from_xpath("/entry/author[1]/uri", doc),
{:ok, %{info: %{"magic_key" => magic_key}}} <- Pleroma.Web.OStatus.find_or_make_user(uri) do
{:ok, magic_key}
end
end

def decode_and_validate(magickey, salmon) do
@@ -56,7 +50,7 @@ defmodule Pleroma.Web.Salmon do
end
end

defp decode_key("RSA." <> magickey) do
def decode_key("RSA." <> magickey) do
make_integer = fn(bin) ->
list = :erlang.binary_to_list(bin)
Enum.reduce(list, 0, fn (el, acc) -> (acc <<< 8) ||| el end)
@@ -69,4 +63,91 @@ defmodule Pleroma.Web.Salmon do

{:RSAPublicKey, modulus, exponent}
end

def encode_key({:RSAPublicKey, modulus, exponent}) do
modulus_enc = :binary.encode_unsigned(modulus) |> Base.url_encode64
exponent_enc = :binary.encode_unsigned(exponent) |> Base.url_encode64

"RSA.#{modulus_enc}.#{exponent_enc}"
end

def generate_rsa_pem do
port = Port.open({:spawn, "openssl genrsa"}, [:binary])
{:ok, pem} = receive do
{^port, {:data, pem}} -> {:ok, pem}
end
Port.close(port)
if Regex.match?(~r/RSA PRIVATE KEY/, pem) do
{:ok, pem}
else
:error
end
end

def keys_from_pem(pem) do
[private_key_code] = :public_key.pem_decode(pem)
private_key = :public_key.pem_entry_decode(private_key_code)
{:RSAPrivateKey, _, modulus, exponent, _, _, _, _, _, _, _} = private_key
public_key = {:RSAPublicKey, modulus, exponent}
{:ok, private_key, public_key}
end

def encode(private_key, doc) do
type = "application/atom+xml"
encoding = "base64url"
alg = "RSA-SHA256"

signed_text = [doc, type, encoding, alg]
|> Enum.map(&Base.url_encode64/1)
|> Enum.join(".")

signature = :public_key.sign(signed_text, :sha256, private_key) |> to_string |> Base.url_encode64
doc_base64= doc |> Base.url_encode64

# Don't need proper xml building, these strings are safe to leave unescaped
salmon = """
<?xml version="1.0" encoding="UTF-8"?>
<me:env xmlns:me="http://salmon-protocol.org/ns/magic-env">
<me:data type="application/atom+xml">#{doc_base64}</me:data>
<me:encoding>#{encoding}</me:encoding>
<me:alg>#{alg}</me:alg>
<me:sig>#{signature}</me:sig>
</me:env>
"""

{:ok, salmon}
end

def remote_users(%{data: %{"to" => to}}) do
to
|> Enum.map(fn(id) -> User.get_cached_by_ap_id(id) end)
|> Enum.filter(fn(user) -> user && !user.local end)
end

defp send_to_user(%{info: %{"salmon" => salmon}}, feed, poster) do
poster.(salmon, feed, [{"Content-Type", "application/magic-envelope+xml"}])
end

defp send_to_user(_,_,_), do: nil

def publish(user, activity, poster \\ &HTTPoison.post/3)
def publish(%{info: %{"keys" => keys}} = user, activity, poster) do
feed = ActivityRepresenter.to_simple_form(activity, user, true)
|> ActivityRepresenter.wrap_with_entry
|> :xmerl.export_simple(:xmerl_xml)
|> to_string

if feed do
{:ok, private, _} = keys_from_pem(keys)
{:ok, feed} = encode(private, feed)

remote_users(activity)
|> Enum.each(fn(remote_user) ->
Logger.debug("sending salmon to #{remote_user.ap_id}")
send_to_user(remote_user, feed, poster)
end)
end
end

def publish(%{id: id}, _, _), do: Logger.debug("Keys missing for user #{id}")
end

+ 8
- 1
lib/pleroma/web/twitter_api/representers/activity_representer.ex Näytä tiedosto

@@ -3,6 +3,7 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
alias Pleroma.Web.TwitterAPI.Representers.{UserRepresenter, ObjectRepresenter}
alias Pleroma.{Activity, User}
alias Calendar.Strftime
alias Pleroma.Web.TwitterAPI.TwitterAPI

defp user_by_ap_id(user_list, ap_id) do
Enum.find(user_list, fn (%{ap_id: user_id}) -> ap_id == user_id end)
@@ -81,6 +82,12 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
|> Enum.filter(&(&1))
|> Enum.map(fn (user) -> UserRepresenter.to_map(user, opts) end)


conversation_id = with context when not is_nil(context) <- activity.data["context"] do
TwitterAPI.context_to_conversation_id(context)
else _e -> nil
end

%{
"id" => activity.id,
"user" => UserRepresenter.to_map(user, opts),
@@ -91,7 +98,7 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter do
"is_post_verb" => true,
"created_at" => created_at,
"in_reply_to_status_id" => object["inReplyToStatusId"],
"statusnet_conversation_id" => object["statusnetConversationId"],
"statusnet_conversation_id" => conversation_id,
"attachments" => (object["attachment"] || []) |> ObjectRepresenter.enum_to_list(opts),
"attentions" => attentions,
"fave_num" => like_count,


+ 3
- 2
lib/pleroma/web/twitter_api/representers/user_representer.ex Näytä tiedosto

@@ -11,7 +11,7 @@ defmodule Pleroma.Web.TwitterAPI.Representers.UserRepresenter do
false
end

user_info = User.user_info(user)
user_info = User.get_cached_user_info(user)

map = %{
"id" => user.id,
@@ -28,7 +28,8 @@ defmodule Pleroma.Web.TwitterAPI.Representers.UserRepresenter do
"profile_image_url_https" => image,
"profile_image_url_profile_size" => image,
"profile_image_url_original" => image,
"rights" => %{}
"rights" => %{},
"statusnet_profile_url" => user.ap_id
}

map


+ 124
- 109
lib/pleroma/web/twitter_api/twitter_api.ex Näytä tiedosto

@@ -1,38 +1,81 @@
defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
alias Ecto.Changeset
alias Pleroma.{User, Activity, Repo, Object}
alias Pleroma.Web.{ActivityPub.ActivityPub, Websub, OStatus}
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.TwitterAPI.Representers.{ActivityRepresenter, UserRepresenter}

import Ecto.Query

def create_status(%User{} = user, %{} = data) do
attachments = Enum.map(data["media_ids"] || [], fn (media_id) ->
def to_for_user_and_mentions(user, mentions) do
default_to = [
User.ap_followers(user),
"https://www.w3.org/ns/activitystreams#Public"
]

default_to ++ Enum.map(mentions, fn ({_, %{ap_id: ap_id}}) -> ap_id end)
end

def format_input(text, mentions) do
HtmlSanitizeEx.strip_tags(text)
|> String.replace("\n", "<br>")
|> add_user_links(mentions)
end

def attachments_from_ids(ids) do
Enum.map(ids || [], fn (media_id) ->
Repo.get(Object, media_id).data
end)
end

context = ActivityPub.generate_context_id
def get_replied_to_activity(id) when not is_nil(id) do
Repo.get(Activity, id)
end

content = data["status"] |> HtmlSanitizeEx.strip_tags |> String.replace("\n", "<br>")
def get_replied_to_activity(_), do: nil

mentions = parse_mentions(content)
def add_attachments(text, attachments) do
attachment_text = Enum.map(attachments, fn
(%{"url" => [%{"href" => href} | _]}) ->
"<a href='#{href}'>#{href}</a>"
_ -> ""
end)
Enum.join([text | attachment_text], "<br>")
end

default_to = [
User.ap_followers(user),
"https://www.w3.org/ns/activitystreams#Public"
]
def create_status(user = %User{}, data = %{"status" => status}) do
attachments = attachments_from_ids(data["media_ids"])
context = ActivityPub.generate_context_id
mentions = parse_mentions(status)
content_html = status
|> format_input(mentions)
|> add_attachments(attachments)

to = default_to ++ Enum.map(mentions, fn ({_, %{ap_id: ap_id}}) -> ap_id end)
to = to_for_user_and_mentions(user, mentions)
date = make_date()

content_html = add_user_links(content, mentions)
inReplyTo = get_replied_to_activity(data["in_reply_to_status_id"])

date = make_date()
# Wire up reply info.
[to, context, object, additional] =
if inReplyTo do
context = inReplyTo.data["context"]
to = to ++ [inReplyTo.data["actor"]]

activity = %{
"type" => "Create",
"to" => to,
"actor" => user.ap_id,
"object" => %{
object = %{
"type" => "Note",
"to" => to,
"content" => content_html,
"published" => date,
"context" => context,
"attachment" => attachments,
"actor" => user.ap_id,
"inReplyTo" => inReplyTo.data["object"]["id"],
"inReplyToStatusId" => inReplyTo.id,
}
additional = %{}

[to, context, object, additional]
else
object = %{
"type" => "Note",
"to" => to,
"content" => content_html,
@@ -40,65 +83,41 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
"context" => context,
"attachment" => attachments,
"actor" => user.ap_id
},
"published" => date,
"context" => context
}

# Wire up reply info.
activity = with inReplyToId when not is_nil(inReplyToId) <- data["in_reply_to_status_id"],
inReplyTo <- Repo.get(Activity, inReplyToId),
context <- inReplyTo.data["context"]
do

to = activity["to"] ++ [inReplyTo.data["actor"]]

activity
|> put_in(["to"], to)
|> put_in(["context"], context)
|> put_in(["object", "context"], context)
|> put_in(["object", "inReplyTo"], inReplyTo.data["object"]["id"])
|> put_in(["object", "inReplyToStatusId"], inReplyToId)
|> put_in(["statusnetConversationId"], inReplyTo.data["statusnetConversationId"])
|> put_in(["object", "statusnetConversationId"], inReplyTo.data["statusnetConversationId"])
else _e ->
activity
end

with {:ok, activity} <- ActivityPub.insert(activity) do
{:ok, activity} = add_conversation_id(activity)
Websub.publish(OStatus.feed_path(user), user, activity)
{:ok, activity}
}
[to, context, object, %{}]
end

ActivityPub.create(to, user, context, object, additional, data)
end

def fetch_friend_statuses(user, opts \\ %{}) do
activities = ActivityPub.fetch_activities([user.ap_id | user.following], opts)
activities_to_statuses(activities, %{for: user})
ActivityPub.fetch_activities([user.ap_id | user.following], opts)
|> activities_to_statuses(%{for: user})
end

def fetch_public_statuses(user, opts \\ %{}) do
activities = ActivityPub.fetch_public_activities(opts)
activities_to_statuses(activities, %{for: user})
opts = Map.put(opts, "local_only", true)
ActivityPub.fetch_public_activities(opts)
|> activities_to_statuses(%{for: user})
end

def fetch_public_and_external_statuses(user, opts \\ %{}) do
ActivityPub.fetch_public_activities(opts)
|> activities_to_statuses(%{for: user})
end

def fetch_user_statuses(user, opts \\ %{}) do
activities = ActivityPub.fetch_activities([], opts)
activities_to_statuses(activities, %{for: user})
ActivityPub.fetch_activities([], opts)
|> activities_to_statuses(%{for: user})
end

def fetch_mentions(user, opts \\ %{}) do
activities = ActivityPub.fetch_activities([user.ap_id], opts)
activities_to_statuses(activities, %{for: user})
ActivityPub.fetch_activities([user.ap_id], opts)
|> activities_to_statuses(%{for: user})
end

def fetch_conversation(user, id) do
query = from activity in Activity,
where: fragment("? @> ?", activity.data, ^%{statusnetConversationId: id}),
limit: 1

with %Activity{} = activity <- Repo.one(query),
context <- activity.data["context"],
with context when is_binary(context) <- conversation_id_to_context(id),
activities <- ActivityPub.fetch_activities_for_context(context),
statuses <- activities |> activities_to_statuses(%{for: user})
do
@@ -116,26 +135,26 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
end

def follow(%User{} = follower, params) do
with {:ok, %User{} = followed} <- get_user(params),
{:ok, follower} <- User.follow(follower, followed),
{:ok, activity} <- ActivityPub.insert(%{
"type" => "Follow",
"actor" => follower.ap_id,
"object" => followed.ap_id,
"published" => make_date()
})
with { :ok, %User{} = followed } <- get_user(params),
{ :ok, follower } <- User.follow(follower, followed),
{ :ok, activity } <- ActivityPub.insert(%{
"type" => "Follow",
"actor" => follower.ap_id,
"object" => followed.ap_id,
"published" => make_date()
})
do
{:ok, follower, followed, activity}
{ :ok, follower, followed, activity }
else
err -> err
end
end

def unfollow(%User{} = follower, params) do
with {:ok, %User{} = unfollowed} <- get_user(params),
{:ok, follower} <- User.unfollow(follower, unfollowed)
with { :ok, %User{} = unfollowed } <- get_user(params),
{ :ok, follower } <- User.unfollow(follower, unfollowed)
do
{:ok, follower, unfollowed}
{ :ok, follower, unfollowed}
else
err -> err
end
@@ -207,7 +226,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
media_id_string: "#{object.id}}",
media_url: href,
size: 0
} |> Poison.encode!
} |> Poison.encode!
end
end

@@ -215,36 +234,15 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
# Modified from https://www.w3.org/TR/html5/forms.html#valid-e-mail-address
regex = ~r/@[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@?[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*/

regex
|> Regex.scan(text)
Regex.scan(regex, text)
|> List.flatten
|> Enum.uniq
|> Enum.map(fn ("@" <> match = full_match) ->
{full_match, User.get_cached_by_nickname(match)} end)
|> Enum.map(fn ("@" <> match = full_match) -> {full_match, User.get_cached_by_nickname(match)} end)
|> Enum.filter(fn ({_match, user}) -> user end)
end

def add_user_links(text, mentions) do
Enum.reduce(mentions, text, fn ({match, %User{ap_id: ap_id}}, text) ->
String.replace(text, match, "<a href='#{ap_id}'>#{match}</a>") end)
end

defp add_conversation_id(activity) do
if is_integer(activity.data["statusnetConversationId"]) do
{:ok, activity}
else
data = activity.data
|> put_in(["object", "statusnetConversationId"], activity.id)
|> put_in(["statusnetConversationId"], activity.id)

object = Object.get_by_ap_id(activity.data["object"]["id"])

changeset = Changeset.change(object, data: data["object"])
Repo.update(changeset)

changeset = Changeset.change(activity, data: data)
Repo.update(changeset)
end
Enum.reduce(mentions, text, fn ({match, %User{ap_id: ap_id}}, text) -> String.replace(text, match, "<a href='#{ap_id}'>#{match}</a>") end)
end

def register_user(params) do
@@ -255,7 +253,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
email: params["email"],
password: params["password"],
password_confirmation: params["confirm"]
}
}

changeset = User.register_changeset(%User{}, params)

@@ -263,21 +261,22 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
{:ok, UserRepresenter.to_map(user)}
else
{:error, changeset} ->
errors = Poison.encode!(Changeset.traverse_errors(changeset, fn {msg, _opts} -> msg end))
{:error, %{error: errors}}
errors = Ecto.Changeset.traverse_errors(changeset, fn {msg, _opts} -> msg end)
|> Poison.encode!
{:error, %{error: errors}}
end
end

def get_user(user \\ nil, params) do
case params do
%{"user_id" => user_id} ->
%{ "user_id" => user_id } ->
case target = Repo.get(User, user_id) do
nil ->
{:error, "No user with such user_id"}
_ ->
{:ok, target}
end
%{"screen_name" => nickname} ->
%{ "screen_name" => nickname } ->
case target = Repo.get_by(User, nickname: nickname) do
nil ->
{:error, "No user with such screen_name"}
@@ -305,8 +304,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
user = User.get_cached_by_ap_id(actor)
[liked_activity] = Activity.all_by_object_ap_id(activity.data["object"])

ActivityRepresenter.to_map(activity,
Map.merge(opts, %{user: user, liked_activity: liked_activity}))
ActivityRepresenter.to_map(activity, Map.merge(opts, %{user: user, liked_activity: liked_activity}))
end

# For announces, fetch the announced activity and the user.
@@ -316,8 +314,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
[announced_activity] = Activity.all_by_object_ap_id(activity.data["object"])
announced_actor = User.get_cached_by_ap_id(announced_activity.data["actor"])

ActivityRepresenter.to_map(activity,
Map.merge(opts, %{users: [user, announced_actor], announced_activity: announced_activity}))
ActivityRepresenter.to_map(activity, Map.merge(opts, %{users: [user, announced_actor], announced_activity: announced_activity}))
end

defp activity_to_status(activity, opts) do
@@ -327,7 +324,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
mentioned_users = Enum.map(activity.data["to"] || [], fn (ap_id) ->
User.get_cached_by_ap_id(ap_id)
end)
mentioned_users = mentioned_users |> Enum.filter(&(&1))
|> Enum.filter(&(&1))

ActivityRepresenter.to_map(activity, Map.merge(opts, %{user: user, mentioned: mentioned_users}))
end
@@ -335,4 +332,22 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
defp make_date do
DateTime.utc_now() |> DateTime.to_iso8601
end

def context_to_conversation_id(context) do
with %Object{id: id} <- Object.get_cached_by_ap_id(context) do
id
else _e ->
changeset = Object.context_mapping(context)
{:ok, %{id: id}} = Repo.insert(changeset)
id
end
end

def conversation_id_to_context(id) do
with %Object{data: %{"id" => context}} <- Repo.get(Object, id) do
context
else _e ->
{:error, "No such conversation"}
end
end
end

+ 8
- 0
lib/pleroma/web/twitter_api/twitter_api_controller.ex Näytä tiedosto

@@ -42,6 +42,14 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
end
end

def public_and_external_timeline(%{assigns: %{user: user}} = conn, params) do
statuses = TwitterAPI.fetch_public_and_external_statuses(user, params)
{:ok, json} = Poison.encode(statuses)

conn
|> json_reply(200, json)
end

def public_timeline(%{assigns: %{user: user}} = conn, params) do
statuses = TwitterAPI.fetch_public_statuses(user, params)
{:ok, json} = Poison.encode(statuses)


+ 1
- 22
lib/pleroma/web/web.ex Näytä tiedosto

@@ -58,28 +58,7 @@ defmodule Pleroma.Web do
apply(__MODULE__, which, [])
end

def host do
settings = Application.get_env(:pleroma, Pleroma.Web.Endpoint)
settings
|> Keyword.fetch!(:url)
|> Keyword.fetch!(:host)
end

def base_url do
settings = Application.get_env(:pleroma, Pleroma.Web.Endpoint)

host = host()

protocol = settings |> Keyword.fetch!(:protocol)

port_fragment = with {:ok, protocol_info} <- settings
|> Keyword.fetch(String.to_atom(protocol)),
{:ok, port} <- protocol_info |> Keyword.fetch(:port)
do
":#{port}"
else _e ->
""
end
"#{protocol}://#{host}#{port_fragment}"
Pleroma.Web.Endpoint.url
end
end

+ 82
- 10
lib/pleroma/web/web_finger/web_finger.ex Näytä tiedosto

@@ -1,6 +1,9 @@
defmodule Pleroma.Web.WebFinger do
alias Pleroma.{User, XmlBuilder}
alias Pleroma.{Web, Web.OStatus}

alias Pleroma.{Repo, User, XmlBuilder}
alias Pleroma.Web
alias Pleroma.Web.{XML, Salmon, OStatus}
require Logger

def host_meta do
base_url = Web.base_url
@@ -14,25 +17,94 @@ defmodule Pleroma.Web.WebFinger do
end

def webfinger(resource) do
host = Web.host
regex = ~r/acct:(?<username>\w+)@#{host}/
case Regex.named_captures(regex, resource) do
%{"username" => username} ->
user = User.get_cached_by_nickname(username)
host = Pleroma.Web.Endpoint.host
regex = ~r/(acct:)?(?<username>\w+)@#{host}/
with %{"username" => username} <- Regex.named_captures(regex, resource) do
user = User.get_by_nickname(username)
{:ok, represent_user(user)}
else _e ->
with user when not is_nil(user) <- User.get_cached_by_ap_id(resource) do
{:ok, represent_user(user)}
_ -> nil
else _e ->
{:error, "Couldn't find user"}
end
end
end

def represent_user(user) do
{:ok, user} = ensure_keys_present(user)
{:ok, _private, public} = Salmon.keys_from_pem(user.info["keys"])
magic_key = Salmon.encode_key(public)
{
:XRD, %{xmlns: "http://docs.oasis-open.org/ns/xri/xrd-1.0"},
[
{:Subject, "acct:#{user.nickname}@#{Web.host}"},
{:Subject, "acct:#{user.nickname}@#{Pleroma.Web.Endpoint.host}"},
{:Alias, user.ap_id},
{:Link, %{rel: "http://schemas.google.com/g/2010#updates-from", type: "application/atom+xml", href: OStatus.feed_path(user)}}
{:Link, %{rel: "http://schemas.google.com/g/2010#updates-from", type: "application/atom+xml", href: OStatus.feed_path(user)}},
{:Link, %{rel: "http://webfinger.net/rel/profile-page", type: "text/html", href: user.ap_id}},
{:Link, %{rel: "salmon", href: OStatus.salmon_path(user)}},
{:Link, %{rel: "magic-public-key", href: "data:application/magic-public-key,#{magic_key}"}}
]
}
|> XmlBuilder.to_doc
end

# This seems a better fit in Salmon
def ensure_keys_present(user) do
info = user.info || %{}
if info["keys"] do
{:ok, user}
else
{:ok, pem} = Salmon.generate_rsa_pem
info = Map.put(info, "keys", pem)
Repo.update(Ecto.Changeset.change(user, info: info))
end
end

# FIXME: Make this call the host-meta to find the actual address.
defp webfinger_address(domain) do
"//#{domain}/.well-known/webfinger"
end

defp webfinger_from_xml(doc) do
magic_key = XML.string_from_xpath(~s{//Link[@rel="magic-public-key"]/@href}, doc)
"data:application/magic-public-key," <> magic_key = magic_key
topic = XML.string_from_xpath(~s{//Link[@rel="http://schemas.google.com/g/2010#updates-from"]/@href}, doc)
subject = XML.string_from_xpath("//Subject", doc)
salmon = XML.string_from_xpath(~s{//Link[@rel="salmon"]/@href}, doc)
data = %{
"magic_key" => magic_key,
"topic" => topic,
"subject" => subject,
"salmon" => salmon
}
{:ok, data}
end

def finger(account, getter \\ &HTTPoison.get/3) do
domain = with [_name, domain] <- String.split(account, "@") do
domain
else _e ->
URI.parse(account).host
end
address = webfinger_address(domain)

# try https first
response = with {:ok, result} <- getter.("https:" <> address, ["Accept": "application/xrd+xml"], [params: [resource: account]]) do
{:ok, result}
else _ ->
getter.("http:" <> address, ["Accept": "application/xrd+xml"], [params: [resource: account], follow_redirect: true])
end

with {:ok, %{status_code: status_code, body: body}} when status_code in 200..299 <- response,
doc <- XML.parse_document(body),
{:ok, data} <- webfinger_from_xml(doc) do
{:ok, data}
else
e ->
Logger.debug("Couldn't finger #{account}.")
Logger.debug(inspect(e))
{:error, e}
end
end
end

+ 104
- 6
lib/pleroma/web/websub/websub.ex Näytä tiedosto

@@ -1,9 +1,11 @@
defmodule Pleroma.Web.Websub do
alias Ecto.Changeset
alias Pleroma.Repo
alias Pleroma.Web.Websub.WebsubServerSubscription
alias Pleroma.Web.Websub.{WebsubServerSubscription, WebsubClientSubscription}
alias Pleroma.Web.OStatus.FeedRepresenter
alias Pleroma.Web.OStatus
alias Pleroma.Web.{XML, Endpoint, OStatus}
alias Pleroma.Web.Router.Helpers
require Logger

import Ecto.Query

@@ -44,8 +46,10 @@ defmodule Pleroma.Web.Websub do
response = user
|> FeedRepresenter.to_simple_form([activity], [user])
|> :xmerl.export_simple(:xmerl_xml)
|> to_string

signature = Base.encode16(:crypto.hmac(:sha, sub.secret, response))
signature = sign(sub.secret || "", response)
Logger.debug("Pushing to #{sub.callback}")

HTTPoison.post(sub.callback, response, [
{"Content-Type", "application/atom+xml"},
@@ -54,6 +58,10 @@ defmodule Pleroma.Web.Websub do
end)
end

def sign(secret, doc) do
:crypto.hmac(:sha, secret, to_string(doc)) |> Base.encode16 |> String.downcase
end

def incoming_subscription_request(user, %{"hub.mode" => "subscribe"} = params) do
with {:ok, topic} <- valid_topic(params, user),
{:ok, lease_time} <- lease_time(params),
@@ -75,11 +83,13 @@ defmodule Pleroma.Web.Websub do
NaiveDateTime.add(websub.updated_at, lease_time)})
websub = Repo.update!(change)

# Just spawn that for now, maybe pool later.
spawn(fn -> @websub_verifier.verify(websub) end)
Pleroma.Web.Federator.enqueue(:verify_websub, websub)

{:ok, websub}
else {:error, reason} ->
Logger.debug("Couldn't create subscription.")
Logger.debug(inspect(reason))

{:error, reason}
end
end
@@ -89,6 +99,11 @@ defmodule Pleroma.Web.Websub do
%WebsubServerSubscription{}
end

# Temp hack for mastodon.
defp lease_time(%{"hub.lease_seconds" => ""}) do
{:ok, 60 * 60 * 24 * 3} # three days
end

defp lease_time(%{"hub.lease_seconds" => lease_seconds}) do
{:ok, String.to_integer(lease_seconds)}
end
@@ -99,9 +114,92 @@ defmodule Pleroma.Web.Websub do

defp valid_topic(%{"hub.topic" => topic}, user) do
if topic == OStatus.feed_path(user) do
{:ok, topic}
{:ok, OStatus.feed_path(user)}
else
{:error, "Wrong topic requested, expected #{OStatus.feed_path(user)}, got #{topic}"}
end
end

def subscribe(subscriber, subscribed, requester \\ &request_subscription/1) do
topic = subscribed.info["topic"]
# FIXME: Race condition, use transactions
{:ok, subscription} = with subscription when not is_nil(subscription) <- Repo.get_by(WebsubClientSubscription, topic: topic) do
subscribers = [subscriber.ap_id, subscription.subscribers] |> Enum.uniq
change = Ecto.Changeset.change(subscription, %{subscribers: subscribers})
Repo.update(change)
else _e ->
subscription = %WebsubClientSubscription{
topic: topic,
hub: subscribed.info["hub"],
subscribers: [subscriber.ap_id],
state: "requested",
secret: :crypto.strong_rand_bytes(8) |> Base.url_encode64,
user: subscribed
}
Repo.insert(subscription)
end
requester.(subscription)
end

def gather_feed_data(topic, getter \\ &HTTPoison.get/1) do
with {:ok, response} <- getter.(topic),
status_code when status_code in 200..299 <- response.status_code,
body <- response.body,
doc <- XML.parse_document(body),
uri when not is_nil(uri) <- XML.string_from_xpath("/feed/author[1]/uri", doc),
hub when not is_nil(hub) <- XML.string_from_xpath(~S{/feed/link[@rel="hub"]/@href}, doc) do

name = XML.string_from_xpath("/feed/author[1]/name", doc)
preferredUsername = XML.string_from_xpath("/feed/author[1]/poco:preferredUsername", doc)
displayName = XML.string_from_xpath("/feed/author[1]/poco:displayName", doc)
avatar = OStatus.make_avatar_object(doc)

{:ok, %{
"uri" => uri,
"hub" => hub,
"nickname" => preferredUsername || name,
"name" => displayName || name,
"host" => URI.parse(uri).host,
"avatar" => avatar
}}
else e ->
{:error, e}
end
end

def request_subscription(websub, poster \\ &HTTPoison.post/3, timeout \\ 10_000) do
data = [
"hub.mode": "subscribe",
"hub.topic": websub.topic,
"hub.secret": websub.secret,
"hub.callback": Helpers.websub_url(Endpoint, :websub_subscription_confirmation, websub.id)
]

# This checks once a second if we are confirmed yet
websub_checker = fn ->
helper = fn (helper) ->
:timer.sleep(1000)
websub = Repo.get_by(WebsubClientSubscription, id: websub.id, state: "accepted")
if websub, do: websub, else: helper.(helper)
end
helper.(helper)
end

task = Task.async(websub_checker)

with {:ok, %{status_code: 202}} <- poster.(websub.hub, {:form, data}, ["Content-type": "application/x-www-form-urlencoded"]),
{:ok, websub} <- Task.yield(task, timeout) do
{:ok, websub}
else e ->
Task.shutdown(task)

change = Ecto.Changeset.change(websub, %{state: "rejected"})
{:ok, websub} = Repo.update(change)

Logger.debug("Couldn't confirm subscription: #{inspect(websub)}")
Logger.debug("error: #{inspect(e)}")

{:error, websub}
end
end
end

+ 16
- 0
lib/pleroma/web/websub/websub_client_subscription.ex Näytä tiedosto

@@ -0,0 +1,16 @@
defmodule Pleroma.Web.Websub.WebsubClientSubscription do
use Ecto.Schema
alias Pleroma.User

schema "websub_client_subscriptions" do
field :topic, :string
field :secret, :string
field :valid_until, :naive_datetime
field :state, :string
field :subscribers, {:array, :string}, default: []
field :hub, :string
belongs_to :user, User

timestamps()
end
end

+ 33
- 1
lib/pleroma/web/websub/websub_controller.ex Näytä tiedosto

@@ -1,7 +1,11 @@
defmodule Pleroma.Web.Websub.WebsubController do
use Pleroma.Web, :controller
alias Pleroma.User
alias Pleroma.{Repo, User}
alias Pleroma.Web.Websub
alias Pleroma.Web.Websub.WebsubClientSubscription
require Logger

@ostatus Application.get_env(:pleroma, :ostatus)

def websub_subscription_request(conn, %{"nickname" => nickname} = params) do
user = User.get_cached_by_nickname(nickname)
@@ -15,4 +19,32 @@ defmodule Pleroma.Web.Websub.WebsubController do
|> send_resp(500, reason)
end
end

def websub_subscription_confirmation(conn, %{"id" => id, "hub.mode" => "subscribe", "hub.challenge" => challenge, "hub.topic" => topic}) do
with %WebsubClientSubscription{} = websub <- Repo.get_by(WebsubClientSubscription, id: id, topic: topic) do
change = Ecto.Changeset.change(websub, %{state: "accepted"})
{:ok, _websub} = Repo.update(change)
conn
|> send_resp(200, challenge)
else _e ->
conn
|> send_resp(500, "Error")
end
end

def websub_incoming(conn, %{"id" => id}) do
with "sha1=" <> signature <- hd(get_req_header(conn, "x-hub-signature")),
signature <- String.downcase(signature),
%WebsubClientSubscription{} = websub <- Repo.get(WebsubClientSubscription, id),
{:ok, body, _conn} = read_body(conn),
^signature <- Websub.sign(websub.secret, body) do
@ostatus.handle_incoming(body)
conn
|> send_resp(200, "OK")
else _e ->
Logger.debug("Can't handle incoming subscription post")
conn
|> send_resp(500, "Error")
end
end
end

+ 19
- 0
lib/pleroma/web/xml/xml.ex Näytä tiedosto

@@ -0,0 +1,19 @@
defmodule Pleroma.Web.XML do
def string_from_xpath(xpath, doc) do
{:xmlObj, :string, res} = :xmerl_xpath.string('string(#{xpath})', doc)

res = res
|> to_string
|> String.trim

if res == "", do: nil, else: res
end

def parse_document(text) do
{doc, _rest} = text
|> :binary.bin_to_list
|> :xmerl_scan.string

doc
end
end

+ 10
- 0
priv/repo/migrations/20170423154511_add_fields_to_users.exs Näytä tiedosto

@@ -0,0 +1,10 @@
defmodule Pleroma.Repo.Migrations.AddFieldsToUsers do
use Ecto.Migration

def change do
alter table(:users) do
add :local, :boolean, default: true
add :info, :map
end
end
end

+ 15
- 0
priv/repo/migrations/20170426154155_create_websub_client_subscription.exs Näytä tiedosto

@@ -0,0 +1,15 @@
defmodule Pleroma.Repo.Migrations.CreateWebsubClientSubscription do
use Ecto.Migration

def change do
create table(:websub_client_subscriptions) do
add :topic, :string
add :secret, :string
add :valid_until, :naive_datetime
add :state, :string
add :subscribers, :map

timestamps()
end
end
end

+ 10
- 0
priv/repo/migrations/20170427054757_add_user_and_hub.exs Näytä tiedosto

@@ -0,0 +1,10 @@
defmodule Pleroma.Repo.Migrations.AddUserAndHub do
use Ecto.Migration

def change do
alter table(:websub_client_subscriptions) do
add :hub, :string
add :user_id, references(:users)
end
end
end

+ 8
- 0
priv/repo/migrations/20170501124823_add_id_contraints_to_activities_and_objects.exs Näytä tiedosto

@@ -0,0 +1,8 @@
defmodule Pleroma.Repo.Migrations.AddIdContraintsToActivitiesAndObjects do
use Ecto.Migration

def change do
create index(:objects, ["(data->>\"id\")"], name: :objects_unique_apid_index)
create index(:activities, ["(data->>\"id\")"], name: :activities_unique_apid_index)
end
end

+ 10
- 0
priv/repo/migrations/20170501133231_add_id_contraints_to_activities_and_objects_part_two.exs Näytä tiedosto

@@ -0,0 +1,10 @@
defmodule Pleroma.Repo.Migrations.AddIdContraintsToActivitiesAndObjectsPartTwo do
use Ecto.Migration

def change do
drop index(:objects, ["(data->>\"id\")"], name: :objects_unique_apid_index)
drop index(:activities, ["(data->>\"id\")"], name: :activities_unique_apid_index)
create unique_index(:objects, ["(data->>'id')"], name: :objects_unique_apid_index)
create unique_index(:activities, ["(data->>'id')"], name: :activities_unique_apid_index)
end
end

+ 11
- 0
priv/repo/migrations/20170502083023_add_local_field_to_activities.exs Näytä tiedosto

@@ -0,0 +1,11 @@
defmodule Pleroma.Repo.Migrations.AddLocalFieldToActivities do
use Ecto.Migration

def change do
alter table(:activities) do
add :local, :boolean, default: true
end

create index(:activities, [:local])
end
end

+ 7
- 0
test/activity_test.exs Näytä tiedosto

@@ -15,4 +15,11 @@ defmodule Pleroma.ActivityTest do

assert activity == found_activity
end

test "returns the activity that created an object" do
activity = insert(:note_activity)
found_activity = Pleroma.Activity.get_create_activity_by_object_ap_id(activity.data["object"]["id"])

assert activity == found_activity
end
end

+ 508
- 0
test/fixtures/23211.atom Näytä tiedosto

@@ -0,0 +1,508 @@
<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/">
<generator uri="https://gnu.io/social" version="1.0.2-dev">GNU social</generator>
<id>https://social.heldscal.la/api/statuses/user_timeline/23211.atom</id>
<title>lambadalambda timeline</title>
<subtitle>Updates from lambadalambda on social.heldscal.la!</subtitle>
<logo>https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg</logo>
<updated>2017-05-02T14:59:30+00:00</updated>
<author>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<uri>https://social.heldscal.la/user/23211</uri>
<name>lambadalambda</name>
<summary>Call me Deacon Blues.</summary>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/lambadalambda"/>
<link rel="avatar" type="image/jpeg" media:width="236" media:height="236" href="https://social.heldscal.la/avatar/23211-original-20170416114255.jpeg"/>
<link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg"/>
<link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/23211-48-20170416114255.jpeg"/>
<link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/23211-24-20170416114257.jpeg"/>
<poco:preferredUsername>lambadalambda</poco:preferredUsername>
<poco:displayName>Constance Variable</poco:displayName>
<poco:note>Call me Deacon Blues.</poco:note>
<poco:address>
<poco:formatted>Berlin</poco:formatted>
</poco:address>
<poco:urls>
<poco:type>homepage</poco:type>
<poco:value>https://heldscal.la</poco:value>
<poco:primary>true</poco:primary>
</poco:urls>
<followers url="https://social.heldscal.la/lambadalambda/subscribers"></followers>
<statusnet:profile_info local_id="23211"></statusnet:profile_info>
</author>
<link href="https://social.heldscal.la/lambadalambda" rel="alternate" type="text/html"/>
<link href="https://social.heldscal.la/main/sup" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/>
<link href="https://social.heldscal.la/api/statuses/user_timeline/23211.atom?max_id=2012090" rel="next" type="application/atom+xml"/>
<link href="https://social.heldscal.la/main/push/hub" rel="hub"/>
<link href="https://social.heldscal.la/main/salmon/user/23211" rel="salmon"/>
<link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-replies"/>
<link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-mention"/>
<link href="https://social.heldscal.la/api/statuses/user_timeline/23211.atom" rel="self" type="application/atom+xml"/>
<entry>
<id>tag:social.heldscal.la,2017-05-02:fave:23211:comment:2015260:2017-05-02T14:45:47+00:00</id>
<title>Favorite</title>
<content type="html">lambadalambda favorited something by godemperorofdune: &lt;p&gt;&lt;span class=&quot;h-card&quot;&gt;&lt;a href=&quot;https://social.heldscal.la/lambadalambda&quot; class=&quot;u-url mention&quot;&gt;@&lt;span&gt;lambadalambda&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; It's because your instance decided to be trap! lol.&lt;/p&gt;</content>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2015305"/>
<activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
<published>2017-05-02T14:45:47+00:00</published>
<updated>2017-05-02T14:45:47+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:pawoo.net,2017-05-02:objectId=7397439:objectType=Status</id>
<title>New comment by godemperorofdune</title>
<content type="html">&lt;p&gt;&lt;span class=&quot;h-card&quot;&gt;&lt;a href=&quot;https://social.heldscal.la/lambadalambda&quot; class=&quot;u-url mention&quot;&gt;@&lt;span&gt;lambadalambda&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; It's because your instance decided to be trap! lol.&lt;/p&gt;</content>
<link rel="alternate" type="text/html" href="https://pawoo.net/users/God_Emperor_of_Dune/updates/2090090"/>
<status_net notice_id="2015260"></status_net>
</activity:object>
<thr:in-reply-to ref="tag:pawoo.net,2017-05-02:objectId=7397439:objectType=Status" href="https://pawoo.net/users/God_Emperor_of_Dune/updates/2090090"></thr:in-reply-to>
<link rel="related" href="https://pawoo.net/users/God_Emperor_of_Dune/updates/2090090"/>
<link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1035308"/>
<ostatus:conversation href="https://social.heldscal.la/conversation/1035308" local_id="1035308" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=136e244b26cdf1e9">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=136e244b26cdf1e9</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2015305.atom"/>
<link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2015305.atom"/>
<statusnet:notice_info local_id="2015305" source="unknown"></statusnet:notice_info>
</entry>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<id>tag:social.heldscal.la,2017-05-02:noticeId=2015221:objectType=note</id>
<title>New note by lambadalambda</title>
<content type="html">Some script thinks I'm a mastodon server.&lt;br /&gt; &lt;br /&gt; [info] GET /api/v1/timelines/public&lt;br /&gt; [debug] Processing with Fallback.RedirectController.redirector/2&lt;br /&gt; Parameters: %{&amp;quot;limit&amp;quot; =&amp;gt; &amp;quot;40&amp;quot;, &amp;quot;path&amp;quot; =&amp;gt; [&amp;quot;api&amp;quot;, &amp;quot;v1&amp;quot;, &amp;quot;timelines&amp;quot;, &amp;quot;public&amp;quot;]}&lt;br /&gt; Pipelines: []</content>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2015221"/>
<status_net notice_id="2015221"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2017-05-02T14:40:50+00:00</published>
<updated>2017-05-02T14:40:50+00:00</updated>
<link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1035308"/>
<ostatus:conversation href="https://social.heldscal.la/conversation/1035308" local_id="1035308" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=136e244b26cdf1e9">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=136e244b26cdf1e9</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2015221.atom"/>
<link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2015221.atom"/>
<statusnet:notice_info local_id="2015221" source="Pleroma FE"></statusnet:notice_info>
</entry>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:social.heldscal.la,2017-05-02:noticeId=2014759:objectType=comment</id>
<title>New comment by lambadalambda</title>
<content type="html">@&lt;a href=&quot;https://mstdn.io/users/mattskala&quot; class=&quot;h-card u-url p-nickname mention&quot; title=&quot;Matthew Skala&quot;&gt;mattskala&lt;/a&gt; You and @&lt;a href=&quot;https://mastodon.social/users/kevinmarks&quot; class=&quot;h-card u-url p-nickname mention&quot; title=&quot;Kevin Marks&quot;&gt;kevinmarks&lt;/a&gt; are not wrong, but my comment was a suggestion to users and admins: Don't use big instances, don't run big instances. Also, it's a secondary advice to devs: Don't add features that encourage big instances.</content>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2014759"/>
<status_net notice_id="2014759"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2017-05-02T14:11:54+00:00</published>
<updated>2017-05-02T14:11:54+00:00</updated>
<thr:in-reply-to ref="tag:mstdn.io,2017-05-02:objectId=1316931:objectType=Status" href="https://mstdn.io/users/mattskala/updates/35698"></thr:in-reply-to>
<link rel="related" href="https://mstdn.io/users/mattskala/updates/35698"/>
<link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1031866"/>
<ostatus:conversation href="https://social.heldscal.la/conversation/1031866" local_id="1031866" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=58e32e013ab6487d">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=58e32e013ab6487d</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/kevinmarks"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mstdn.io/users/mattskala"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2014759.atom"/>
<link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2014759.atom"/>
<statusnet:notice_info local_id="2014759" source="Pleroma FE"></statusnet:notice_info>
</entry>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:social.heldscal.la,2017-05-02:noticeId=2014684:objectType=comment</id>
<title>New comment by lambadalambda</title>
<content type="html">@&lt;a href=&quot;https://mastodon.social/users/Ronkjeffries&quot; class=&quot;h-card u-url p-nickname mention&quot; title=&quot;Ron K Jeffries social&quot;&gt;ronkjeffries&lt;/a&gt; @&lt;a href=&quot;https://xoxo.zone/users/KevinMarks&quot; class=&quot;h-card u-url p-nickname mention&quot; title=&quot;Kevin Marks &quot;&gt;kevinmarks&lt;/a&gt; Usually people who run their own private instance just look at the timelines of other servers, follow a seed population and then go from there. This is of course hard on Mastodon, because it doesn't have a publicly visible timeline.</content>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2014684"/>
<status_net notice_id="2014684"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2017-05-02T14:07:00+00:00</published>
<updated>2017-05-02T14:07:00+00:00</updated>
<thr:in-reply-to ref="tag:mastodon.social,2017-05-02:objectId=4883853:objectType=Status" href="https://mastodon.social/users/Ronkjeffries/updates/2221244"></thr:in-reply-to>
<link rel="related" href="https://mastodon.social/users/Ronkjeffries/updates/2221244"/>
<link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1031866"/>
<ostatus:conversation href="https://social.heldscal.la/conversation/1031866" local_id="1031866" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=58e32e013ab6487d">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=58e32e013ab6487d</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://xoxo.zone/users/KevinMarks"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/Ronkjeffries"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2014684.atom"/>
<link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2014684.atom"/>
<statusnet:notice_info local_id="2014684" source="Pleroma FE"></statusnet:notice_info>
</entry>
<entry>
<id>tag:social.heldscal.la,2017-05-02:fave:23211:comment:2014584:2017-05-02T14:05:32+00:00</id>
<title>Favorite</title>
<content type="html">lambadalambda favorited something by mattskala: &lt;p&gt;&lt;span class=&quot;h-card&quot;&gt;&lt;a href=&quot;https://social.heldscal.la/lambadalambda&quot; class=&quot;u-url mention&quot;&gt;@&lt;span&gt;lambadalambda&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; It's reasonable to expect that instance sizes will obey a power-law distribution because that's what such things in nature nearly always do. If so, there'll necessarily be a few instances much larger than the others; even if most are small, the network both socially and technically has to be able to deal with the existence of the few large ones.&lt;/p&gt;</content>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2014659"/>
<activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
<published>2017-05-02T14:05:32+00:00</published>
<updated>2017-05-02T14:05:32+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:mstdn.io,2017-05-02:objectId=1316931:objectType=Status</id>
<title>New comment by mattskala</title>
<content type="html">&lt;p&gt;&lt;span class=&quot;h-card&quot;&gt;&lt;a href=&quot;https://social.heldscal.la/lambadalambda&quot; class=&quot;u-url mention&quot;&gt;@&lt;span&gt;lambadalambda&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; It's reasonable to expect that instance sizes will obey a power-law distribution because that's what such things in nature nearly always do. If so, there'll necessarily be a few instances much larger than the others; even if most are small, the network both socially and technically has to be able to deal with the existence of the few large ones.&lt;/p&gt;</content>
<link rel="alternate" type="text/html" href="https://mstdn.io/users/mattskala/updates/35698"/>
<status_net notice_id="2014584"></status_net>
</activity:object>
<thr:in-reply-to ref="tag:mstdn.io,2017-05-02:objectId=1316931:objectType=Status" href="https://mstdn.io/users/mattskala/updates/35698"></thr:in-reply-to>
<link rel="related" href="https://mstdn.io/users/mattskala/updates/35698"/>
<link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1031866"/>
<ostatus:conversation href="https://social.heldscal.la/conversation/1031866" local_id="1031866" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=58e32e013ab6487d">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=58e32e013ab6487d</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2014659.atom"/>
<link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2014659.atom"/>
<statusnet:notice_info local_id="2014659" source="unknown"></statusnet:notice_info>
</entry>
<entry>
<id>tag:social.heldscal.la,2017-05-02:fave:23211:comment:2013568:2017-05-02T14:05:29+00:00</id>
<title>Favorite</title>
<content type="html">lambadalambda favorited something by kevinmarks: &lt;p&gt;&lt;span class=&quot;h-card&quot;&gt;&lt;a href=&quot;https://social.heldscal.la/lambadalambda&quot; class=&quot;u-url mention&quot;&gt;@&lt;span&gt;lambadalambda&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; except instance populations will be power law distributed, and the problems for the tummlers are worse at scale&lt;/p&gt;</content>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2014657"/>
<activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
<published>2017-05-02T14:05:29+00:00</published>
<updated>2017-05-02T14:05:29+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:xoxo.zone,2017-05-02:objectId=89478:objectType=Status</id>
<title>New comment by kevinmarks</title>
<content type="html">&lt;p&gt;&lt;span class=&quot;h-card&quot;&gt;&lt;a href=&quot;https://social.heldscal.la/lambadalambda&quot; class=&quot;u-url mention&quot;&gt;@&lt;span&gt;lambadalambda&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; except instance populations will be power law distributed, and the problems for the tummlers are worse at scale&lt;/p&gt;</content>
<link rel="alternate" type="text/html" href="https://xoxo.zone/users/KevinMarks/updates/1749"/>
<status_net notice_id="2013568"></status_net>
</activity:object>
<thr:in-reply-to ref="tag:xoxo.zone,2017-05-02:objectId=89478:objectType=Status" href="https://xoxo.zone/users/KevinMarks/updates/1749"></thr:in-reply-to>
<link rel="related" href="https://xoxo.zone/users/KevinMarks/updates/1749"/>
<link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1031866"/>
<ostatus:conversation href="https://social.heldscal.la/conversation/1031866" local_id="1031866" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=58e32e013ab6487d">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=58e32e013ab6487d</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2014657.atom"/>
<link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2014657.atom"/>
<statusnet:notice_info local_id="2014657" source="unknown"></statusnet:notice_info>
</entry>
<entry>
<id>tag:social.heldscal.la,2017-05-02:fave:23211:comment:2014060:2017-05-02T13:34:32+00:00</id>
<title>Favorite</title>
<content type="html">lambadalambda favorited something by gcarregues: &lt;p&gt;&lt;span class=&quot;h-card&quot;&gt;&lt;a href=&quot;https://social.heldscal.la/lambadalambda&quot; class=&quot;u-url mention&quot;&gt;@&lt;span&gt;lambadalambda&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; Oh purée ! Ma vie en images !&lt;/p&gt;</content>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2014147"/>
<activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
<published>2017-05-02T13:34:32+00:00</published>
<updated>2017-05-02T13:34:32+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:mastodon.etalab.gouv.fr,2017-05-02:objectId=55287:objectType=Status</id>
<title>New comment by gcarregues</title>
<content type="html">&lt;p&gt;&lt;span class=&quot;h-card&quot;&gt;&lt;a href=&quot;https://social.heldscal.la/lambadalambda&quot; class=&quot;u-url mention&quot;&gt;@&lt;span&gt;lambadalambda&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; Oh purée ! Ma vie en images !&lt;/p&gt;</content>
<link rel="alternate" type="text/html" href="https://mastodon.etalab.gouv.fr/users/gcarregues/updates/4370"/>
<status_net notice_id="2014060"></status_net>
</activity:object>
<thr:in-reply-to ref="tag:mastodon.etalab.gouv.fr,2017-05-02:objectId=55287:objectType=Status" href="https://mastodon.etalab.gouv.fr/users/gcarregues/updates/4370"></thr:in-reply-to>
<link rel="related" href="https://mastodon.etalab.gouv.fr/users/gcarregues/updates/4370"/>
<link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1034065"/>
<ostatus:conversation href="https://social.heldscal.la/conversation/1034065" local_id="1034065" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=2c27c27df8ec4dcc">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=2c27c27df8ec4dcc</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2014147.atom"/>
<link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2014147.atom"/>
<statusnet:notice_info local_id="2014147" source="unknown"></statusnet:notice_info>
</entry>
<entry>
<id>tag:social.heldscal.la,2017-05-02:fave:23211:note:2013573:2017-05-02T13:03:33+00:00</id>
<title>Favorite</title>
<content type="html">lambadalambda favorited something by phildobangnz: also @&lt;a href=&quot;https://sealion.club/user/579&quot; class=&quot;h-card mention&quot; title=&quot;Sim Bot&quot;&gt;sim&lt;/a&gt; reminder you are awesome; don't even trip- u kewler than Tutankhamen's cucumber, fam. Okay, good night.</content>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2013702"/>
<activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
<published>2017-05-02T13:03:33+00:00</published>
<updated>2017-05-02T13:03:33+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<id>tag:sealion.club,2017-05-02:noticeId=3060818:objectType=note</id>
<title>New note by phildobangnz</title>
<content type="html">also @&lt;a href=&quot;https://sealion.club/user/579&quot; class=&quot;h-card mention&quot; title=&quot;Sim Bot&quot;&gt;sim&lt;/a&gt; reminder you are awesome; don't even trip- u kewler than Tutankhamen's cucumber, fam. Okay, good night.</content>
<link rel="alternate" type="text/html" href="https://sealion.club/notice/3060818"/>
<status_net notice_id="2013573"></status_net>
</activity:object>
<thr:in-reply-to ref="tag:sealion.club,2017-05-02:noticeId=3060818:objectType=note" href="https://sealion.club/notice/3060818"></thr:in-reply-to>
<link rel="related" href="https://sealion.club/notice/3060818"/>
<link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1034282"/>
<ostatus:conversation href="https://social.heldscal.la/conversation/1034282" local_id="1034282" ref="https://sealion.club/conversation/1633267">https://sealion.club/conversation/1633267</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013702.atom"/>
<link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013702.atom"/>
<statusnet:notice_info local_id="2013702" source="unknown"></statusnet:notice_info>
</entry>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:social.heldscal.la,2017-05-02:noticeId=2013586:objectType=comment</id>
<title>New comment by lambadalambda</title>
<content type="html">@&lt;a href=&quot;https://xoxo.zone/users/KevinMarks&quot; class=&quot;h-card u-url p-nickname mention&quot; title=&quot;Kevin Marks &quot;&gt;kevinmarks&lt;/a&gt; People can stay in their giant unmoderatable instances with meaningless public and federated timelines and experience constant federation drama if they want. I'll stay here with my 5 friends.</content>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2013586"/>
<status_net notice_id="2013586"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2017-05-02T12:54:59+00:00</published>
<updated>2017-05-02T12:54:59+00:00</updated>
<thr:in-reply-to ref="tag:xoxo.zone,2017-05-02:objectId=89478:objectType=Status" href="https://xoxo.zone/users/KevinMarks/updates/1749"></thr:in-reply-to>
<link rel="related" href="https://xoxo.zone/users/KevinMarks/updates/1749"/>
<link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1031866"/>
<ostatus:conversation href="https://social.heldscal.la/conversation/1031866" local_id="1031866" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=58e32e013ab6487d">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=58e32e013ab6487d</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://xoxo.zone/users/KevinMarks"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013586.atom"/>
<link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013586.atom"/>
<statusnet:notice_info local_id="2013586" source="Pleroma FE"></statusnet:notice_info>
</entry>
<entry>
<id>tag:social.heldscal.la,2017-05-02:fave:23211:note:2013486:2017-05-02T12:46:48+00:00</id>
<title>Favorite</title>
<content type="html">lambadalambda favorited something by fortune: There once was a dentist named Stone&lt;br /&gt; Who saw all his patients alone.&lt;br /&gt; In a fit of depravity&lt;br /&gt; He filled the wrong cavity,&lt;br /&gt; And my, how his practice has grown!</content>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2013511"/>
<activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
<published>2017-05-02T12:46:48+00:00</published>
<updated>2017-05-02T12:46:48+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<id>tag:gs.kawa-kun.com,2017-05-02:noticeId=1655658:objectType=note</id>
<title>New note by fortune</title>
<content type="html">There once was a dentist named Stone&lt;br /&gt; Who saw all his patients alone.&lt;br /&gt; In a fit of depravity&lt;br /&gt; He filled the wrong cavity,&lt;br /&gt; And my, how his practice has grown!</content>
<link rel="alternate" type="text/html" href="https://gs.kawa-kun.com/notice/1655658"/>
<status_net notice_id="2013486"></status_net>
</activity:object>
<thr:in-reply-to ref="tag:gs.kawa-kun.com,2017-05-02:noticeId=1655658:objectType=note" href="https://gs.kawa-kun.com/notice/1655658"></thr:in-reply-to>
<link rel="related" href="https://gs.kawa-kun.com/notice/1655658"/>
<link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1034222"/>
<ostatus:conversation href="https://social.heldscal.la/conversation/1034222" local_id="1034222" ref="https://gs.kawa-kun.com/conversation/714072">https://gs.kawa-kun.com/conversation/714072</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013511.atom"/>
<link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013511.atom"/>
<statusnet:notice_info local_id="2013511" source="unknown"></statusnet:notice_info>
</entry>
<entry>
<id>tag:social.heldscal.la,2017-05-02:fave:23211:note:2013365:2017-05-02T12:37:55+00:00</id>
<title>Favorite</title>
<content type="html">lambadalambda favorited something by xj9: &lt;p&gt;&amp;gt; rollerblading to work&lt;/p&gt;</content>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2013394"/>
<activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
<published>2017-05-02T12:37:55+00:00</published>
<updated>2017-05-02T12:37:55+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<id>tag:sunshinegardens.org,2017-05-02:objectId=61020:objectType=Status</id>
<title>New note by xj9</title>
<content type="html">&lt;p&gt;&amp;gt; rollerblading to work&lt;/p&gt;</content>
<link rel="alternate" type="text/html" href="https://sunshinegardens.org/users/xj9/updates/748"/>
<status_net notice_id="2013365"></status_net>
</activity:object>
<thr:in-reply-to ref="tag:sunshinegardens.org,2017-05-02:objectId=61020:objectType=Status" href="https://sunshinegardens.org/users/xj9/updates/748"></thr:in-reply-to>
<link rel="related" href="https://sunshinegardens.org/users/xj9/updates/748"/>
<link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1034152"/>
<ostatus:conversation href="https://social.heldscal.la/conversation/1034152" local_id="1034152" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=5a0e98612f634218">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=5a0e98612f634218</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013394.atom"/>
<link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013394.atom"/>
<statusnet:notice_info local_id="2013394" source="unknown"></statusnet:notice_info>
</entry>
<entry>
<id>tag:social.heldscal.la,2017-05-02:fave:23211:comment:2013259:2017-05-02T12:29:03+00:00</id>
<title>Favorite</title>
<content type="html">lambadalambda favorited something by cereal: @&lt;a href=&quot;https://gs.smuglo.li/user/28250&quot; class=&quot;h-card mention&quot; title=&quot;Bricky&quot;&gt;thatbrickster&lt;/a&gt; @&lt;a href=&quot;https://social.heldscal.la/user/23211&quot; class=&quot;h-card mention&quot; title=&quot;Constance Variable&quot;&gt;lambadalambda&lt;/a&gt; But why?</content>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2013267"/>
<activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
<published>2017-05-02T12:29:03+00:00</published>
<updated>2017-05-02T12:29:03+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:sealion.club,2017-05-02:noticeId=3059985:objectType=comment</id>
<title>New comment by cereal</title>
<content type="html">@&lt;a href=&quot;https://gs.smuglo.li/user/28250&quot; class=&quot;h-card mention&quot; title=&quot;Bricky&quot;&gt;thatbrickster&lt;/a&gt; @&lt;a href=&quot;https://social.heldscal.la/user/23211&quot; class=&quot;h-card mention&quot; title=&quot;Constance Variable&quot;&gt;lambadalambda&lt;/a&gt; But why?</content>
<link rel="alternate" type="text/html" href="https://sealion.club/notice/3059985"/>
<status_net notice_id="2013259"></status_net>
</activity:object>
<thr:in-reply-to ref="tag:sealion.club,2017-05-02:noticeId=3059985:objectType=comment" href="https://sealion.club/notice/3059985"></thr:in-reply-to>
<link rel="related" href="https://sealion.club/notice/3059985"/>
<link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1034065"/>
<ostatus:conversation href="https://social.heldscal.la/conversation/1034065" local_id="1034065" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=2c27c27df8ec4dcc">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=2c27c27df8ec4dcc</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013267.atom"/>
<link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013267.atom"/>
<statusnet:notice_info local_id="2013267" source="unknown"></statusnet:notice_info>
</entry>
<entry>
<id>tag:social.heldscal.la,2017-05-02:fave:23211:comment:2013227:2017-05-02T12:24:27+00:00</id>
<title>Favorite</title>
<content type="html">lambadalambda favorited something by thatbrickster: @&lt;a href=&quot;https://social.heldscal.la/user/23211&quot; class=&quot;h-card u-url p-nickname mention&quot; title=&quot;Constance Variable&quot;&gt;lambadalambda&lt;/a&gt; install gentoo</content>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2013230"/>
<activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
<published>2017-05-02T12:24:27+00:00</published>
<updated>2017-05-02T12:24:27+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:gs.smuglo.li,2017-05-02:noticeId=2144296:objectType=comment</id>
<title>New comment by thatbrickster</title>
<content type="html">@&lt;a href=&quot;https://social.heldscal.la/user/23211&quot; class=&quot;h-card u-url p-nickname mention&quot; title=&quot;Constance Variable&quot;&gt;lambadalambda&lt;/a&gt; install gentoo</content>
<link rel="alternate" type="text/html" href="https://gs.smuglo.li/notice/2144296"/>
<status_net notice_id="2013227"></status_net>
</activity:object>
<thr:in-reply-to ref="tag:gs.smuglo.li,2017-05-02:noticeId=2144296:objectType=comment" href="https://gs.smuglo.li/notice/2144296"></thr:in-reply-to>
<link rel="related" href="https://gs.smuglo.li/notice/2144296"/>
<link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1034065"/>
<ostatus:conversation href="https://social.heldscal.la/conversation/1034065" local_id="1034065" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=2c27c27df8ec4dcc">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=2c27c27df8ec4dcc</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013230.atom"/>
<link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013230.atom"/>
<statusnet:notice_info local_id="2013230" source="unknown"></statusnet:notice_info>
</entry>
<entry>
<id>tag:social.heldscal.la,2017-05-02:fave:23211:comment:2013213:2017-05-02T12:22:53+00:00</id>
<title>Favorite</title>
<content type="html">lambadalambda favorited something by dwmatiz: @&lt;a href=&quot;https://social.heldscal.la/user/23211&quot; class=&quot;h-card mention&quot;&gt;lambadalambda&lt;/a&gt; *unzips dick*</content>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2013218"/>
<activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
<published>2017-05-02T12:22:53+00:00</published>
<updated>2017-05-02T12:22:53+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:sealion.club,2017-05-02:noticeId=3059800:objectType=comment</id>
<title>New comment by dwmatiz</title>
<content type="html">@&lt;a href=&quot;https://social.heldscal.la/user/23211&quot; class=&quot;h-card mention&quot;&gt;lambadalambda&lt;/a&gt; *unzips dick*</content>
<link rel="alternate" type="text/html" href="https://sealion.club/notice/3059800"/>
<status_net notice_id="2013213"></status_net>
</activity:object>
<thr:in-reply-to ref="tag:sealion.club,2017-05-02:noticeId=3059800:objectType=comment" href="https://sealion.club/notice/3059800"></thr:in-reply-to>
<link rel="related" href="https://sealion.club/notice/3059800"/>
<link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1034065"/>
<ostatus:conversation href="https://social.heldscal.la/conversation/1034065" local_id="1034065" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=2c27c27df8ec4dcc">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=2c27c27df8ec4dcc</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013218.atom"/>
<link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013218.atom"/>
<statusnet:notice_info local_id="2013218" source="unknown"></statusnet:notice_info>
</entry>
<entry>
<id>tag:social.heldscal.la,2017-05-02:fave:23211:comment:2013199:2017-05-02T12:22:03+00:00</id>
<title>Favorite</title>
<content type="html">lambadalambda favorited something by shpuld: @&lt;a href=&quot;https://social.heldscal.la/user/23211&quot; class=&quot;h-card mention&quot; title=&quot;Constance Variable&quot;&gt;lambadalambda&lt;/a&gt; get #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://shitposter.club/tag/cofe&quot; rel=&quot;tag&quot;&gt;cofe&lt;/a&gt;&lt;/span&gt;</content>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2013206"/>
<activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
<published>2017-05-02T12:22:03+00:00</published>
<updated>2017-05-02T12:22:03+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:shitposter.club,2017-05-02:noticeId=2783524:objectType=comment</id>
<title>New comment by shpuld</title>
<content type="html">@&lt;a href=&quot;https://social.heldscal.la/user/23211&quot; class=&quot;h-card mention&quot; title=&quot;Constance Variable&quot;&gt;lambadalambda&lt;/a&gt; get #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://shitposter.club/tag/cofe&quot; rel=&quot;tag&quot;&gt;cofe&lt;/a&gt;&lt;/span&gt;</content>
<link rel="alternate" type="text/html" href="https://shitposter.club/notice/2783524"/>
<status_net notice_id="2013199"></status_net>
</activity:object>
<thr:in-reply-to ref="tag:shitposter.club,2017-05-02:noticeId=2783524:objectType=comment" href="https://shitposter.club/notice/2783524"></thr:in-reply-to>
<link rel="related" href="https://shitposter.club/notice/2783524"/>
<link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1034065"/>
<ostatus:conversation href="https://social.heldscal.la/conversation/1034065" local_id="1034065" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=2c27c27df8ec4dcc">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=2c27c27df8ec4dcc</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013206.atom"/>
<link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013206.atom"/>
<statusnet:notice_info local_id="2013206" source="unknown"></statusnet:notice_info>
</entry>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<id>tag:social.heldscal.la,2017-05-02:noticeId=2013185:objectType=note</id>
<title>New note by lambadalambda</title>
<content type="html">What now? &lt;a href=&quot;https://social.heldscal.la/file/e4822d95de677757ff50d49672a4046c83218b76c04a0ad5e5f1f0a9a9eb1a74.gif&quot; title=&quot;https://social.heldscal.la/file/e4822d95de677757ff50d49672a4046c83218b76c04a0ad5e5f1f0a9a9eb1a74.gif&quot; rel=&quot;nofollow external noreferrer&quot; class=&quot;attachment&quot; id=&quot;attachment-422572&quot;&gt;https://social.heldscal.la/attachment/422572&lt;/a&gt;</content>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2013185"/>
<status_net notice_id="2013185"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2017-05-02T12:21:04+00:00</published>
<updated>2017-05-02T12:21:04+00:00</updated>
<link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1034065"/>
<ostatus:conversation href="https://social.heldscal.la/conversation/1034065" local_id="1034065" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=2c27c27df8ec4dcc">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=2c27c27df8ec4dcc</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="enclosure" href="https://social.heldscal.la/file/e4822d95de677757ff50d49672a4046c83218b76c04a0ad5e5f1f0a9a9eb1a74.gif" type="image/gif" length="132349"/>
<link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013185.atom"/>
<link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2013185.atom"/>
<statusnet:notice_info local_id="2013185" source="Pleroma FE"></statusnet:notice_info>
</entry>
<entry>
<id>tag:social.heldscal.la,2017-05-02:fave:23211:note:2012929:2017-05-02T12:01:25+00:00</id>
<title>Favorite</title>
<content type="html">lambadalambda favorited something by drkmttr: &lt;p&gt;&lt;span class=&quot;h-card&quot;&gt;&lt;a href=&quot;https://social.heldscal.la/lambadalambda&quot; class=&quot;u-url mention&quot;&gt;@&lt;span&gt;lambadalambda&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; I checked out No Agenda because I saw you mention it several time. Sadly, I wasn't impressed. I'm all about varying perspectives but Adam and John basically just sound like resentful curmudgeons. It seems like their shtick is basically playing devil's advocate to everything to arouse some discontent. Just my two cents. 😉&lt;/p&gt;</content>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2012940"/>
<activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
<published>2017-05-02T12:01:25+00:00</published>
<updated>2017-05-02T12:01:25+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<id>tag:mstdn.io,2017-05-02:objectId=1310093:objectType=Status</id>
<title>New note by drkmttr</title>
<content type="html">&lt;p&gt;&lt;span class=&quot;h-card&quot;&gt;&lt;a href=&quot;https://social.heldscal.la/lambadalambda&quot; class=&quot;u-url mention&quot;&gt;@&lt;span&gt;lambadalambda&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; I checked out No Agenda because I saw you mention it several time. Sadly, I wasn't impressed. I'm all about varying perspectives but Adam and John basically just sound like resentful curmudgeons. It seems like their shtick is basically playing devil's advocate to everything to arouse some discontent. Just my two cents. 😉&lt;/p&gt;</content>
<link rel="alternate" type="text/html" href="https://mstdn.io/users/drkmttr/updates/35653"/>
<status_net notice_id="2012929"></status_net>
</activity:object>
<thr:in-reply-to ref="tag:mstdn.io,2017-05-02:objectId=1310093:objectType=Status" href="https://mstdn.io/users/drkmttr/updates/35653"></thr:in-reply-to>
<link rel="related" href="https://mstdn.io/users/drkmttr/updates/35653"/>
<link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1033892"/>
<ostatus:conversation href="https://social.heldscal.la/conversation/1033892" local_id="1033892" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=2f329b4eb20e83e2">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=2f329b4eb20e83e2</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2012940.atom"/>
<link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2012940.atom"/>
<statusnet:notice_info local_id="2012940" source="unknown"></statusnet:notice_info>
</entry>
<entry>
<id>tag:social.heldscal.la,2017-05-02:fave:23211:comment:2012336:2017-05-02T11:06:42+00:00</id>
<title>Favorite</title>
<content type="html">lambadalambda favorited something by clacke: @&lt;a href=&quot;https://mastodon.org.uk/users/dick_turpin&quot; class=&quot;h-card u-url p-nickname mention&quot; title=&quot;dick_turpin&quot;&gt;dickturpin&lt;/a&gt; @&lt;a href=&quot;http://quitter.se/user/113503&quot; class=&quot;h-card u-url p-nickname mention&quot; title=&quot;Luke&quot;&gt;luke&lt;/a&gt; Oh no, I miss being irritated by you, it helps me understand myself and others. Also it builds character. :-)&lt;br /&gt; &lt;br /&gt; So if this is not federation because you can't follow all of online mankind, what should we call it? Proto-federated? Pre-federated?&lt;br /&gt; &lt;br /&gt; The term has been used decades ago for just one Microsoft Active Directory domain cross-certifying the root of another, by mutual agreement. I don't see how it's any less relevant to opportunistic federation between open servers on an open internet.&lt;br /&gt; &lt;br /&gt; I'm not saying we should be satisfied, I'm just saying that &quot;federate&quot; is a useful word and to build a big system we need to start with a small one. And focus on the things we *can* change, like helping the OStatus network grow and making the tools more useful.&lt;br /&gt; &lt;br /&gt; Saying that the network's ideals have failed because other networks aren't joining is doing neither of that.</content>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2012341"/>
<activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
<published>2017-05-02T11:06:42+00:00</published>
<updated>2017-05-02T11:06:42+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:social.heldscal.la,2017-05-02:noticeId=2012336:objectType=comment</id>
<title>New comment by clacke</title>
<content type="html">@&lt;a href=&quot;https://mastodon.org.uk/users/dick_turpin&quot; class=&quot;h-card u-url p-nickname mention&quot; title=&quot;dick_turpin&quot;&gt;dickturpin&lt;/a&gt; @&lt;a href=&quot;http://quitter.se/user/113503&quot; class=&quot;h-card u-url p-nickname mention&quot; title=&quot;Luke&quot;&gt;luke&lt;/a&gt; Oh no, I miss being irritated by you, it helps me understand myself and others. Also it builds character. :-)&lt;br /&gt; &lt;br /&gt; So if this is not federation because you can't follow all of online mankind, what should we call it? Proto-federated? Pre-federated?&lt;br /&gt; &lt;br /&gt; The term has been used decades ago for just one Microsoft Active Directory domain cross-certifying the root of another, by mutual agreement. I don't see how it's any less relevant to opportunistic federation between open servers on an open internet.&lt;br /&gt; &lt;br /&gt; I'm not saying we should be satisfied, I'm just saying that &amp;quot;federate&amp;quot; is a useful word and to build a big system we need to start with a small one. And focus on the things we *can* change, like helping the OStatus network grow and making the tools more useful.&lt;br /&gt; &lt;br /&gt; Saying that the network's ideals have failed because other networks aren't joining is doing neither of that.</content>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2012336"/>
<status_net notice_id="2012336"></status_net>
</activity:object>
<thr:in-reply-to ref="tag:social.heldscal.la,2017-05-02:noticeId=2012336:objectType=comment" href="https://social.heldscal.la/notice/2012336"></thr:in-reply-to>
<link rel="related" href="https://social.heldscal.la/notice/2012336"/>
<link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1016421"/>
<ostatus:conversation href="https://social.heldscal.la/conversation/1016421" local_id="1016421" ref="https://s.wefamlee.be/conversation/16478">https://s.wefamlee.be/conversation/16478</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2012341.atom"/>
<link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2012341.atom"/>
<statusnet:notice_info local_id="2012341" source="unknown"></statusnet:notice_info>
</entry>
<entry>
<id>tag:social.heldscal.la,2017-05-02:fave:23211:comment:2011332:2017-05-02T10:37:40+00:00</id>
<title>Favorite</title>
<content type="html">lambadalambda favorited something by moonman: @&lt;a href=&quot;https://social.heldscal.la/user/23211&quot; class=&quot;h-card mention&quot; title=&quot;Constance Variable&quot;&gt;lambadalambda&lt;/a&gt; &lt;a href=&quot;https://www.youtube.com/watch?v=mKLizztikRk&quot; title=&quot;https://www.youtube.com/watch?v=mKLizztikRk&quot; class=&quot;attachment&quot; rel=&quot;nofollow&quot;&gt;https://www.youtube.com/watch?v=mKLizztikRk&lt;/a&gt;</content>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2012148"/>
<activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
<published>2017-05-02T10:37:40+00:00</published>
<updated>2017-05-02T10:37:40+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:shitposter.club,2017-05-02:noticeId=2781833:objectType=comment</id>
<title>New comment by moonman</title>
<content type="html">@&lt;a href=&quot;https://social.heldscal.la/user/23211&quot; class=&quot;h-card mention&quot; title=&quot;Constance Variable&quot;&gt;lambadalambda&lt;/a&gt; &lt;a href=&quot;https://www.youtube.com/watch?v=mKLizztikRk&quot; title=&quot;https://www.youtube.com/watch?v=mKLizztikRk&quot; class=&quot;attachment&quot; rel=&quot;nofollow&quot;&gt;https://www.youtube.com/watch?v=mKLizztikRk&lt;/a&gt;</content>
<link rel="alternate" type="text/html" href="https://shitposter.club/notice/2781833"/>
<status_net notice_id="2011332"></status_net>
</activity:object>
<thr:in-reply-to ref="tag:shitposter.club,2017-05-02:noticeId=2781833:objectType=comment" href="https://shitposter.club/notice/2781833"></thr:in-reply-to>
<link rel="related" href="https://shitposter.club/notice/2781833"/>
<link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1032783"/>
<ostatus:conversation href="https://social.heldscal.la/conversation/1032783" local_id="1032783" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=11d8b8c27d9513ec">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=11d8b8c27d9513ec</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2012148.atom"/>
<link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2012148.atom"/>
<statusnet:notice_info local_id="2012148" source="unknown"></statusnet:notice_info>
</entry>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:social.heldscal.la,2017-05-02:noticeId=2012145:objectType=comment</id>
<title>New comment by lambadalambda</title>
<content type="html">@&lt;a href=&quot;https://sealion.club/user/186&quot; class=&quot;h-card u-url p-nickname mention&quot; title=&quot;I'M CEREAL U GUISE&quot;&gt;cereal&lt;/a&gt; ? No, you don't even need the identity servers for federation.</content>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2012145"/>
<status_net notice_id="2012145"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2017-05-02T10:37:33+00:00</published>
<updated>2017-05-02T10:37:33+00:00</updated>
<thr:in-reply-to ref="tag:sealion.club,2017-05-02:noticeId=3056001:objectType=comment" href="https://sealion.club/notice/3056001"></thr:in-reply-to>
<link rel="related" href="https://sealion.club/notice/3056001"/>
<link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1033277"/>
<ostatus:conversation href="https://social.heldscal.la/conversation/1033277" local_id="1033277" ref="https://sealion.club/conversation/1629037">https://sealion.club/conversation/1629037</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://sealion.club/user/186"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2012145.atom"/>
<link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2012145.atom"/>
<statusnet:notice_info local_id="2012145" source="Pleroma FE"></statusnet:notice_info>
</entry>
</feed>

+ 40
- 0
test/fixtures/incoming_note_activity.xml Näytä tiedosto

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8" ?><entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:georss="http://www.georss.org/georss" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:statusnet="http://status.net/schema/api/1/">
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<id>tag:gs.example.org:4040,2017-04-23:noticeId=29:objectType=note</id>
<title>New note by lambda</title>
<content type="html">@&lt;a href=&quot;http://pleroma.example.org:4000/users/lain3&quot; class=&quot;h-card mention&quot;&gt;lain3&lt;/a&gt;</content>
<link rel="alternate" type="text/html" href="http://gs.example.org:4040/index.php/notice/29"/>
<status_net notice_id="29"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2017-04-23T14:51:03+00:00</published>
<updated>2017-04-23T14:51:03+00:00</updated>
<author>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<uri>http://gs.example.org:4040/index.php/user/1</uri>
<name>lambda</name>
<link rel="alternate" type="text/html" href="http://gs.example.org:4040/index.php/lambda"/>
<link rel="avatar" type="image/png" media:width="96" media:height="96" href="http://gs.example.org:4040/theme/neo-gnu/default-avatar-profile.png"/>
<link rel="avatar" type="image/png" media:width="48" media:height="48" href="http://gs.example.org:4040/theme/neo-gnu/default-avatar-stream.png"/>
<link rel="avatar" type="image/png" media:width="24" media:height="24" href="http://gs.example.org:4040/theme/neo-gnu/default-avatar-mini.png"/>
<poco:preferredUsername>lambda</poco:preferredUsername>
<poco:displayName>lambda</poco:displayName>
<followers url="http://gs.example.org:4040/index.php/lambda/subscribers"></followers>
<statusnet:profile_info local_id="1"></statusnet:profile_info>
</author>
<link rel="ostatus:conversation" href="tag:gs.example.org:4040,2017-04-23:objectType=thread:nonce=f09e22f58abd5c7b"/>
<ostatus:conversation>tag:gs.example.org:4040,2017-04-23:objectType=thread:nonce=f09e22f58abd5c7b</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="http://pleroma.example.org:4000/users/lain3"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<source>
<id>http://gs.example.org:4040/index.php/api/statuses/user_timeline/1.atom</id>
<title>lambda</title>
<link rel="alternate" type="text/html" href="http://gs.example.org:4040/index.php/lambda"/>
<link rel="self" type="application/atom+xml" href="http://gs.example.org:4040/index.php/api/statuses/user_timeline/1.atom"/>
<link rel="license" href="https://creativecommons.org/licenses/by/3.0/"/>
<icon>http://gs.example.org:4040/theme/neo-gnu/default-avatar-profile.png</icon>
<updated>2017-04-23T14:51:03+00:00</updated>
</source>
<link rel="self" type="application/atom+xml" href="http://gs.example.org:4040/index.php/api/statuses/show/29.atom"/>
<link rel="edit" type="application/atom+xml" href="http://gs.example.org:4040/index.php/api/statuses/show/29.atom"/>
<statusnet:notice_info local_id="29" source="web"></statusnet:notice_info>
</entry>

+ 42
- 0
test/fixtures/incoming_note_activity_answer.xml Näytä tiedosto

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8" ?><entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:georss="http://www.georss.org/georss" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:statusnet="http://status.net/schema/api/1/">
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<id>tag:gs.example.org:4040,2017-04-25:noticeId=55:objectType=note</id>
<title>New note by lambda</title>
<content type="html">hey.</content>
<link rel="alternate" type="text/html" href="http://gs.example.org:4040/index.php/notice/55"/>
<status_net notice_id="55"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2017-04-25T18:16:13+00:00</published>
<updated>2017-04-25T18:16:13+00:00</updated>
<author>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<uri>http://gs.example.org:4040/index.php/user/1</uri>
<name>lambda</name>
<link rel="alternate" type="text/html" href="http://gs.example.org:4040/index.php/lambda"/>
<link rel="avatar" type="image/png" media:width="96" media:height="96" href="http://gs.example.org:4040/theme/neo-gnu/default-avatar-profile.png"/>
<link rel="avatar" type="image/png" media:width="48" media:height="48" href="http://gs.example.org:4040/theme/neo-gnu/default-avatar-stream.png"/>
<link rel="avatar" type="image/png" media:width="24" media:height="24" href="http://gs.example.org:4040/theme/neo-gnu/default-avatar-mini.png"/>
<poco:preferredUsername>lambda</poco:preferredUsername>
<poco:displayName>lambda</poco:displayName>
<followers url="http://gs.example.org:4040/index.php/lambda/subscribers"></followers>
<statusnet:profile_info local_id="1"></statusnet:profile_info>
</author>
<thr:in-reply-to ref="http://pleroma.example.org:4000/objects/55bce8fc-b423-46b1-af71-3759ab4670bc" href="http://pleroma.example.org:4000/objects/55bce8fc-b423-46b1-af71-3759ab4670bc"></thr:in-reply-to>
<link rel="related" href="http://pleroma.example.org:4000/objects/55bce8fc-b423-46b1-af71-3759ab4670bc"/>
<link rel="ostatus:conversation" href="http://pleroma.example.org:4000/contexts/8f6f45d4-8e4d-4e1a-a2de-09f27367d2d0"/>
<ostatus:conversation>http://pleroma.example.org:4000/contexts/8f6f45d4-8e4d-4e1a-a2de-09f27367d2d0</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="http://pleroma.example.org:4000/users/lain5"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<source>
<id>http://gs.example.org:4040/index.php/api/statuses/user_timeline/1.atom</id>
<title>lambda</title>
<link rel="alternate" type="text/html" href="http://gs.example.org:4040/index.php/lambda"/>
<link rel="self" type="application/atom+xml" href="http://gs.example.org:4040/index.php/api/statuses/user_timeline/1.atom"/>
<link rel="license" href="https://creativecommons.org/licenses/by/3.0/"/>
<icon>http://gs.example.org:4040/theme/neo-gnu/default-avatar-profile.png</icon>
<updated>2017-04-25T18:16:13+00:00</updated>
</source>
<link rel="self" type="application/atom+xml" href="http://gs.example.org:4040/index.php/api/statuses/show/55.atom"/>
<link rel="edit" type="application/atom+xml" href="http://gs.example.org:4040/index.php/api/statuses/show/55.atom"/>
<statusnet:notice_info local_id="55" source="web"></statusnet:notice_info>
</entry>

+ 29
- 0
test/fixtures/incoming_reply_mastodon.xml Näytä tiedosto

@@ -0,0 +1,29 @@
<?xml version="1.0"?>
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0">
<id>tag:mastodon.social,2017-05-02:objectId=4901603:objectType=Status</id>
<published>2017-05-02T18:33:06Z</published>
<updated>2017-05-02T18:33:06Z</updated>
<title>New status by lambadalambda</title>
<author>
<id>https://mastodon.social/users/lambadalambda</id>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<uri>https://mastodon.social/users/lambadalambda</uri>
<name>lambadalambda</name>
<email>lambadalambda@mastodon.social</email>
<link rel="alternate" type="text/html" href="https://mastodon.social/@lambadalambda"/>
<link rel="avatar" type="image/gif" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/000/264/original/1429214160519.gif"/>
<link rel="header" type="" media:width="700" media:height="335" href="/headers/original/missing.png"/>
<poco:preferredUsername>lambadalambda</poco:preferredUsername>
<poco:displayName>Critical Value</poco:displayName>
<mastodon:scope>public</mastodon:scope>
</author>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<content type="html" xml:lang="el">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://pleroma.soykaf.com/users/lain" class="u-url mention"&gt;@&lt;span&gt;lain&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; hey&lt;/p&gt;</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/lain"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/2224923"/>
<link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2224923.atom"/>
<thr:in-reply-to ref="https://pleroma.soykaf.com/objects/c237d966-ac75-4fe3-a87a-d89d71a3a7a4" href=""/>
</entry>

+ 59
- 0
test/fixtures/incoming_websub_gnusocial_attachments.xml Näytä tiedosto

@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/">
<generator uri="https://gnu.io/social" version="1.0.2-dev">GNU social</generator>
<id>https://social.heldscal.la/api/statuses/user_timeline/23211.atom</id>
<title>lambadalambda timeline</title>
<subtitle>Updates from lambadalambda on social.heldscal.la!</subtitle>
<logo>https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg</logo>
<updated>2017-05-02T20:29:35+00:00</updated>
<author>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<uri>https://social.heldscal.la/user/23211</uri>
<name>lambadalambda</name>
<summary>Call me Deacon Blues.</summary>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/lambadalambda"/>
<link rel="avatar" type="image/jpeg" media:width="236" media:height="236" href="https://social.heldscal.la/avatar/23211-original-20170416114255.jpeg"/>
<link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg"/>
<link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/23211-48-20170416114255.jpeg"/>
<link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/23211-24-20170416114257.jpeg"/>
<poco:preferredUsername>lambadalambda</poco:preferredUsername>
<poco:displayName>Constance Variable</poco:displayName>
<poco:note>Call me Deacon Blues.</poco:note>
<poco:address>
<poco:formatted>Berlin</poco:formatted>
</poco:address>
<poco:urls>
<poco:type>homepage</poco:type>
<poco:value>https://heldscal.la</poco:value>
<poco:primary>true</poco:primary>
</poco:urls>
<followers url="https://social.heldscal.la/lambadalambda/subscribers"></followers>
<statusnet:profile_info local_id="23211"></statusnet:profile_info>
</author>
<link href="https://social.heldscal.la/lambadalambda" rel="alternate" type="text/html"/>
<link href="https://social.heldscal.la/main/sup" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/>
<link href="https://social.heldscal.la/main/push/hub" rel="hub"/>
<link href="https://social.heldscal.la/main/salmon/user/23211" rel="salmon"/>
<link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-replies"/>
<link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-mention"/>
<link href="https://social.heldscal.la/api/statuses/user_timeline/23211.atom" rel="self" type="application/atom+xml"/>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<id>tag:social.heldscal.la,2017-05-02:noticeId=2020923:objectType=note</id>
<title>New note by lambadalambda</title>
<content type="html">Okay gonna stream some cool games!! &lt;a href=&quot;https://social.heldscal.la/file/7ed5ee508e6376a6e3dd581e17e7ed0b7b638147c7e86784bf83abc2641ee3d4.gif&quot; title=&quot;https://social.heldscal.la/file/7ed5ee508e6376a6e3dd581e17e7ed0b7b638147c7e86784bf83abc2641ee3d4.gif&quot; rel=&quot;nofollow external noreferrer&quot; class=&quot;attachment&quot; id=&quot;attachment-423842&quot;&gt;https://social.heldscal.la/attachment/423842&lt;/a&gt; &lt;a href=&quot;https://social.heldscal.la/file/4c209099cadfc5afd3e27a334aa0db96b3a7510dde1603305d68a2707e59a11f.png&quot; title=&quot;https://social.heldscal.la/file/4c209099cadfc5afd3e27a334aa0db96b3a7510dde1603305d68a2707e59a11f.png&quot; rel=&quot;nofollow external noreferrer&quot; class=&quot;attachment&quot; id=&quot;attachment-423843&quot;&gt;https://social.heldscal.la/attachment/423843&lt;/a&gt;</content>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2020923"/>
<status_net notice_id="2020923"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2017-05-02T20:29:35+00:00</published>
<updated>2017-05-02T20:29:35+00:00</updated>
<link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1038558"/>
<ostatus:conversation href="https://social.heldscal.la/conversation/1038558" local_id="1038558" ref="tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=26c7afdcbcf4ebd4">tag:social.heldscal.la,2017-05-02:objectType=thread:nonce=26c7afdcbcf4ebd4</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="enclosure" href="https://social.heldscal.la/file/7ed5ee508e6376a6e3dd581e17e7ed0b7b638147c7e86784bf83abc2641ee3d4.gif" type="image/gif" length="17283"/>
<link rel="enclosure" href="https://social.heldscal.la/file/4c209099cadfc5afd3e27a334aa0db96b3a7510dde1603305d68a2707e59a11f.png" type="image/png" length="6965"/>
<link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2020923.atom"/>
<link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2020923.atom"/>
<statusnet:notice_info local_id="2020923" source="Pleroma FE"></statusnet:notice_info>
</entry>
</feed>

+ 479
- 0
test/fixtures/lambadalambda.atom Näytä tiedosto

@@ -0,0 +1,479 @@
<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0">
<id>https://mastodon.social/users/lambadalambda.atom</id>
<title>Critical Value</title>
<subtitle></subtitle>
<updated>2017-04-16T21:47:25Z</updated>
<logo>https://files.mastodon.social/accounts/avatars/000/000/264/original/1429214160519.gif?1492379244</logo>
<author>
<id>https://mastodon.social/users/lambadalambda</id>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<uri>https://mastodon.social/users/lambadalambda</uri>
<name>lambadalambda</name>
<email>lambadalambda@mastodon.social</email>
<summary></summary>
<link rel="alternate" type="text/html" href="https://mastodon.social/@lambadalambda"/>
<link rel="avatar" type="image/gif" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/000/264/original/1429214160519.gif?1492379244"/>
<link rel="header" type="" media:width="700" media:height="335" href="/headers/original/missing.png"/>
<poco:preferredUsername>lambadalambda</poco:preferredUsername>
<poco:displayName>Critical Value</poco:displayName>
<mastodon:scope>public</mastodon:scope>
</author>
<link rel="alternate" type="text/html" href="https://mastodon.social/@lambadalambda"/>
<link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda.atom"/>
<link rel="next" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda.atom?max_id=1488609"/>
<link rel="hub" href="https://mastodon.social/api/push"/>
<link rel="salmon" href="https://mastodon.social/api/salmon/264"/>
<entry>
<id>tag:mastodon.social,2017-04-07:objectId=1874242:objectType=Status</id>
<published>2017-04-07T11:02:56Z</published>
<updated>2017-04-07T11:02:56Z</updated>
<title>lambadalambda shared a status by 0xroy@social.wxcafe.net</title>
<activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb>
<activity:object>
<id>tag:social.wxcafe.net,2017-04-07:objectId=72554:objectType=Status</id>
<published>2017-04-07T11:01:59Z</published>
<updated>2017-04-07T11:02:00Z</updated>
<title>New status by 0xroy@social.wxcafe.net</title>
<author>
<id>https://social.wxcafe.net/users/0xroy</id>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<uri>https://social.wxcafe.net/users/0xroy</uri>
<name>0xroy</name>
<email>0xroy@social.wxcafe.net</email>
<summary>ta caution weeb | discussions privées : &lt;a href="https://💌.0xroy.me" rel="nofollow noopener" target="_blank"&gt;&lt;span class="invisible"&gt;https://&lt;/span&gt;&lt;span class=""&gt;💌.0xroy.me&lt;/span&gt;&lt;span class="invisible"&gt;&lt;/span&gt;&lt;/a&gt;</summary>
<link rel="alternate" type="text/html" href="https://social.wxcafe.net/@0xroy"/>
<link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/036/953/original/20068e41d0310172.jpg?1491240516"/>
<link rel="header" type="image/jpeg" media:width="700" media:height="335" href="https://files.mastodon.social/accounts/headers/000/036/953/original/2229d0e3f129fe8c.jpg?1491381114"/>
<poco:preferredUsername>0xroy</poco:preferredUsername>
<poco:displayName>「R O Y 🍵 B O S」</poco:displayName>
<poco:note>ta caution weeb | discussions privées : &lt;a href="https://%F0%9F%92%8C.0xroy.me" rel="nofollow noopener"&gt;&lt;span class="invisible"&gt;https://&lt;/span&gt;&lt;span class=""&gt;💌.0xroy.me&lt;/span&gt;&lt;span class="invisible"&gt;&lt;/span&gt;&lt;/a&gt;</poco:note>
<mastodon:scope>public</mastodon:scope>
</author>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<content type="html" xml:lang="en">&lt;p&gt;someone pls eli5 matrix (protocol) and riot&lt;/p&gt;</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href="https://social.wxcafe.net/users/0xroy/updates/4510"/>
</activity:object>
<content type="html" xml:lang="en">&lt;p&gt;someone pls eli5 matrix (protocol) and riot&lt;/p&gt;</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1689208"/>
<link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1689208.atom"/>
</entry>
<entry>
<id>tag:mastodon.social,2017-04-06:objectId=1768247:objectType=Status</id>
<published>2017-04-06T11:10:19Z</published>
<updated>2017-04-06T11:10:19Z</updated>
<title>lambadalambda shared a status by areyoutoo@mastodon.xyz</title>
<activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb>
<activity:object>
<id>tag:mastodon.xyz,2017-04-05:objectId=133327:objectType=Status</id>
<published>2017-04-05T17:36:41Z</published>
<updated>2017-04-05T18:12:14Z</updated>
<title>New status by areyoutoo@mastodon.xyz</title>
<author>
<id>https://mastodon.xyz/users/areyoutoo</id>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<uri>https://mastodon.xyz/users/areyoutoo</uri>
<name>areyoutoo</name>
<email>areyoutoo@mastodon.xyz</email>
<summary>devops | retired gamedev | always boost puppy pics</summary>
<link rel="alternate" type="text/html" href="https://mastodon.xyz/@areyoutoo"/>
<link rel="avatar" type="image/png" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/047/888/original/5ce2e132d4c18d65.png?1491343828"/>
<link rel="header" type="image/png" media:width="700" media:height="335" href="https://files.mastodon.social/accounts/headers/000/047/888/original/missing.png?1491336769"/>
<poco:preferredUsername>areyoutoo</poco:preferredUsername>
<poco:displayName>Raw Butter</poco:displayName>
<poco:note>devops | retired gamedev | always boost puppy pics</poco:note>
<mastodon:scope>public</mastodon:scope>
</author>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<content type="html" xml:lang="en">&lt;p&gt;Some UX thoughts for &lt;a href="https://mastodon.xyz/tags/mastodev" class="mention hashtag"&gt;#&lt;span&gt;mastodev&lt;/span&gt;&lt;/a&gt;:&lt;/p&gt;&lt;p&gt;- Would be nice if I could work on multiple draft toots? Clicking to reply to someone seems to erase any draft I had been working on.&lt;/p&gt;&lt;p&gt;- Kinda risky to click on the Federated Timeline if it loads new toots and scrolls 10ms before I click on something.&lt;/p&gt;&lt;p&gt;I probably don't know enough web frontend to help, but it might be fun to try.&lt;/p&gt;</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<category term="mastodev"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href="https://mastodon.xyz/users/areyoutoo/updates/36028"/>
</activity:object>
<content type="html" xml:lang="en">&lt;p&gt;Some UX thoughts for &lt;a href="https://mastodon.xyz/tags/mastodev" class="mention hashtag"&gt;#&lt;span&gt;mastodev&lt;/span&gt;&lt;/a&gt;:&lt;/p&gt;&lt;p&gt;- Would be nice if I could work on multiple draft toots? Clicking to reply to someone seems to erase any draft I had been working on.&lt;/p&gt;&lt;p&gt;- Kinda risky to click on the Federated Timeline if it loads new toots and scrolls 10ms before I click on something.&lt;/p&gt;&lt;p&gt;I probably don't know enough web frontend to help, but it might be fun to try.&lt;/p&gt;</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1658950"/>
<link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1658950.atom"/>
</entry>
<entry>
<id>tag:mastodon.social,2017-04-06:objectId=1764509:objectType=Status</id>
<published>2017-04-06T10:15:38Z</published>
<updated>2017-04-06T10:15:38Z</updated>
<title>New status by lambadalambda</title>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<summary xml:lang="en">This is a test for cw federation</summary>
<content type="html" xml:lang="en">&lt;p&gt;This is a test for cw federation body text.&lt;/p&gt;</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1657819"/>
<link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1657819.atom"/>
</entry>
<entry>
<id>tag:mastodon.social,2017-04-05:objectId=1645208:objectType=Status</id>
<published>2017-04-05T07:14:53Z</published>
<updated>2017-04-05T07:14:53Z</updated>
<title>lambadalambda shared a status by lambadalambda@social.heldscal.la</title>
<activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb>
<activity:object>
<id>tag:social.heldscal.la,2017-04-05:noticeId=1502088:objectType=note</id>
<published>2017-04-05T06:12:09Z</published>
<updated>2017-04-05T07:12:47Z</updated>
<title>New status by lambadalambda@social.heldscal.la</title>
<author>
<id>https://social.heldscal.la/user/23211</id>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<uri>https://social.heldscal.la/user/23211</uri>
<name>lambadalambda</name>
<email>lambadalambda@social.heldscal.la</email>
<summary>Call me Deacon Blues.</summary>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/lambadalambda"/>
<link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/000/236/original/23211-original-20170416114255.jpeg?1492345317"/>
<link rel="header" type="" media:width="700" media:height="335" href="/headers/original/missing.png"/>
<poco:preferredUsername>lambadalambda</poco:preferredUsername>
<poco:displayName>Constance Variable</poco:displayName>
<poco:note>Call me Deacon Blues.</poco:note>
<mastodon:scope>public</mastodon:scope>
</author>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<content type="html" xml:lang="en">Federation 101: &lt;a href="https://www.youtube.com/watch?v=t1lYU5CA40o" rel="nofollow external noreferrer" class="attachment thumbnail"&gt;https://www.youtube.com/watch?v=t1lYU5CA40o&lt;/a&gt;</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1502088"/>
</activity:object>
<content type="html" xml:lang="en">Federation 101: &lt;a href="https://www.youtube.com/watch?v=t1lYU5CA40o" rel="nofollow external noreferrer" class="attachment thumbnail"&gt;https://www.youtube.com/watch?v=t1lYU5CA40o&lt;/a&gt;</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1618003"/>
<link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1618003.atom"/>
</entry>
<entry>
<id>tag:mastodon.social,2017-04-05:objectId=1641750:objectType=Status</id>
<published>2017-04-05T05:44:48Z</published>
<updated>2017-04-05T05:44:48Z</updated>
<title>New status by lambadalambda</title>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<content type="html" xml:lang="en">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://social.heldscal.la/lambadalambda" class="u-url mention"&gt;@&lt;span&gt;lambadalambda&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; just a test.&lt;/p&gt;</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.heldscal.la/user/23211"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1616358"/>
<link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1616358.atom"/>
</entry>
<entry>
<id>tag:mastodon.social,2017-04-04:objectId=1540149:objectType=Status</id>
<published>2017-04-04T06:31:09Z</published>
<updated>2017-04-04T06:31:09Z</updated>
<title>New status by lambadalambda</title>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<content type="html" xml:lang="en">&lt;p&gt;Looks like you still can&amp;apos;t delete your account here (PRIVACY!), but I won&amp;apos;t be posting here anymore, my main account is &lt;span class="h-card"&gt;&lt;a href="https://social.heldscal.la/lambadalambda" class="u-url mention"&gt;@&lt;span&gt;lambadalambda&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.heldscal.la/user/23211"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1559641"/>
<link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1559641.atom"/>
</entry>
<entry>
<id>tag:mastodon.social,2017-04-04:objectId=1539608:objectType=Status</id>
<published>2017-04-04T06:18:16Z</published>
<updated>2017-04-04T06:18:16Z</updated>
<title>New status by lambadalambda</title>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<content type="html" xml:lang="en">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://mastodon.social/@ghostbar" class="u-url mention"&gt;@&lt;span&gt;ghostbar&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; Remember to rewrite it in Rust once you&amp;apos;re done.&lt;/p&gt;</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/ghostbar"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1559263"/>
<link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1559263.atom"/>
<thr:in-reply-to ref="tag:mastodon.social,2017-04-03:objectId=1514426:objectType=Status" href="https://mastodon.social/@ghostbar/1514426"/>
</entry>
<entry>
<id>tag:mastodon.social,2017-04-03:objectId=1504813:objectType=Status</id>
<published>2017-04-03T18:01:20Z</published>
<updated>2017-04-03T18:01:20Z</updated>
<title>New status by lambadalambda</title>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<content type="html" xml:lang="en">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://mastodon.xyz/@Azurolu" class="u-url mention"&gt;@&lt;span&gt;Azurolu&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; You mean gs.smuglo.li?&lt;/p&gt;</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.xyz/users/Azurolu"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1535844"/>
<link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1535844.atom"/>
<thr:in-reply-to ref="tag:mastodon.xyz,2017-04-03:objectId=21879:objectType=Status" href="https://mastodon.xyz/users/Azurolu/updates/3813"/>
</entry>
<entry>
<id>tag:mastodon.social,2017-04-03:objectId=1504805:objectType=Status</id>
<published>2017-04-03T18:01:05Z</published>
<updated>2017-04-03T18:01:05Z</updated>
<title>New status by lambadalambda</title>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<content type="html" xml:lang="en">&lt;p&gt;There&amp;apos;s nothing wrong with having several alt accounts all across the fediverse. Try out another mastodon instance (&lt;a href="https://icosahedron.website" rel="nofollow noopener" target="_blank"&gt;&lt;span class="invisible"&gt;https://&lt;/span&gt;&lt;span class=""&gt;icosahedron.website&lt;/span&gt;&lt;span class="invisible"&gt;&lt;/span&gt;&lt;/a&gt;) or a GNU Social instance (like &lt;a href="https://shitposter.club" rel="nofollow noopener" target="_blank"&gt;&lt;span class="invisible"&gt;https://&lt;/span&gt;&lt;span class=""&gt;shitposter.club&lt;/span&gt;&lt;span class="invisible"&gt;&lt;/span&gt;&lt;/a&gt; or &lt;a href="https://freezepeach.xyz" rel="nofollow noopener" target="_blank"&gt;&lt;span class="invisible"&gt;https://&lt;/span&gt;&lt;span class=""&gt;freezepeach.xyz&lt;/span&gt;&lt;span class="invisible"&gt;&lt;/span&gt;&lt;/a&gt;), or friendica. They are all on the same network, so you can still follow all your friends!&lt;/p&gt;</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1535837"/>
<link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1535837.atom"/>
</entry>
<entry>
<id>tag:mastodon.social,2017-04-03:objectId=1503965:objectType=Status</id>
<published>2017-04-03T17:31:30Z</published>
<updated>2017-04-03T17:31:30Z</updated>
<title>New status by lambadalambda</title>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<content type="html" xml:lang="en">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://mastodon.social/@20Hz" class="u-url mention"&gt;@&lt;span&gt;20Hz&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; you could also try out a GS instance, which are on the same network :)&lt;/p&gt;</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/20Hz"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1535176"/>
<link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1535176.atom"/>
<thr:in-reply-to ref="tag:mastodon.social,2017-04-03:objectId=1503524:objectType=Status" href="https://mastodon.social/@20Hz/1503524"/>
</entry>
<entry>
<id>tag:mastodon.social,2017-04-03:objectId=1503955:objectType=Status</id>
<published>2017-04-03T17:31:08Z</published>
<updated>2017-04-03T17:31:08Z</updated>
<title>lambadalambda shared a status by shpuld@shitposter.club</title>
<activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb>
<activity:object>
<id>tag:shitposter.club,2017-04-03:noticeId=2251717:objectType=note</id>
<published>2017-04-03T17:06:43Z</published>
<updated>2017-04-03T17:12:06Z</updated>
<title>New status by shpuld@shitposter.club</title>
<author>
<id>https://shitposter.club/user/5381</id>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<uri>https://shitposter.club/user/5381</uri>
<name>shpuld</name>
<email>shpuld@shitposter.club</email>
<summary></summary>
<link rel="alternate" type="text/html" href="https://shitposter.club/shpuld"/>
<link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/005/895/original/5381-original-20170401213417.jpeg?1491082522"/>
<link rel="header" type="" media:width="700" media:height="335" href="/headers/original/missing.png"/>
<poco:preferredUsername>shpuld</poco:preferredUsername>
<poco:displayName>shp</poco:displayName>
<mastodon:scope>public</mastodon:scope>
</author>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<content type="html" xml:lang="en">reposting the classic &lt;a href="https://shitposter.club/file/89c5fe483526caf3a46cfc5cdd4ae68061054350e767397731af658d54786e31.jpg" class="attachment" rel="nofollow external"&gt;https://shitposter.club/attachment/219846&lt;/a&gt;</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="enclosure" type="image/jpeg" length="30588" href="https://files.mastodon.social/media_attachments/files/000/156/256/original/89c5fe483526caf3a46cfc5cdd4ae68061054350e767397731af658d54786e31.jpg"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href="https://shitposter.club/notice/2251717"/>
</activity:object>
<content type="html" xml:lang="en">reposting the classic &lt;a href="https://shitposter.club/file/89c5fe483526caf3a46cfc5cdd4ae68061054350e767397731af658d54786e31.jpg" class="attachment" rel="nofollow external"&gt;https://shitposter.club/attachment/219846&lt;/a&gt;</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1535166"/>
<link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1535166.atom"/>
</entry>
<entry>
<id>tag:mastodon.social,2017-04-03:objectId=1503929:objectType=Status</id>
<published>2017-04-03T17:30:43Z</published>
<updated>2017-04-03T17:30:43Z</updated>
<title>New status by lambadalambda</title>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<content type="html" xml:lang="en">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://mastodon.social/@ghostbar" class="u-url mention"&gt;@&lt;span&gt;ghostbar&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; Normally you shouldn&amp;apos;t be running tens of thousands of users on one instance... That&amp;apos;s one of the reasons for federation.&lt;/p&gt;</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/ghostbar"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1535144"/>
<link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1535144.atom"/>
<thr:in-reply-to ref="tag:mastodon.social,2017-04-03:objectId=1503526:objectType=Status" href="https://mastodon.social/@ghostbar/1503526"/>
</entry>
<entry>
<id>tag:mastodon.social,2017-04-03:objectId=1477255:objectType=Status</id>
<published>2017-04-03T08:24:39Z</published>
<updated>2017-04-03T08:24:39Z</updated>
<title>New status by lambadalambda</title>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<content type="html" xml:lang="en">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://mastodon.social/@dot_tiff" class="u-url mention"&gt;@&lt;span&gt;dot_tiff&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; it&amp;apos;s the vaporwave mode.&lt;/p&gt;</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/dot_tiff"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1513305"/>
<link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1513305.atom"/>
<thr:in-reply-to ref="tag:mastodon.social,2017-04-03:objectId=1477220:objectType=Status" href="https://mastodon.social/@dot_tiff/1477220"/>
</entry>
<entry>
<id>tag:mastodon.social,2017-04-03:objectId=1476210:objectType=Status</id>
<published>2017-04-03T07:45:42Z</published>
<updated>2017-04-03T07:45:42Z</updated>
<title>lambadalambda shared a status by lambadalambda@social.heldscal.la</title>
<activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb>
<activity:object>
<id>tag:social.heldscal.la,2017-04-03:noticeId=1475727:objectType=note</id>
<published>2017-04-03T07:44:43Z</published>
<updated>2017-04-03T07:44:48Z</updated>
<title>New status by lambadalambda@social.heldscal.la</title>
<author>
<id>https://social.heldscal.la/user/23211</id>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<uri>https://social.heldscal.la/user/23211</uri>
<name>lambadalambda</name>
<email>lambadalambda@social.heldscal.la</email>
<summary>Call me Deacon Blues.</summary>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/lambadalambda"/>
<link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/000/236/original/23211-original-20170416114255.jpeg?1492345317"/>
<link rel="header" type="" media:width="700" media:height="335" href="/headers/original/missing.png"/>
<poco:preferredUsername>lambadalambda</poco:preferredUsername>
<poco:displayName>Constance Variable</poco:displayName>
<poco:note>Call me Deacon Blues.</poco:note>
<mastodon:scope>public</mastodon:scope>
</author>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<content type="html" xml:lang="en">Here's a song by the original anti-idol, Togawa Jun: &lt;a href="https://www.youtube.com/watch?v=kNI_NK2YY-s" rel="nofollow external noreferrer" class="attachment"&gt;https://www.youtube.com/watch?v=kNI_NK2YY-s&lt;/a&gt;</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1475727"/>
</activity:object>
<content type="html" xml:lang="en">Here's a song by the original anti-idol, Togawa Jun: &lt;a href="https://www.youtube.com/watch?v=kNI_NK2YY-s" rel="nofollow external noreferrer" class="attachment"&gt;https://www.youtube.com/watch?v=kNI_NK2YY-s&lt;/a&gt;</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1512485"/>
<link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1512485.atom"/>
</entry>
<entry>
<id>tag:mastodon.social,2017-04-03:objectId=1476047:objectType=Status</id>
<published>2017-04-03T07:39:14Z</published>
<updated>2017-04-03T07:39:14Z</updated>
<title>New status by lambadalambda</title>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<content type="html" xml:lang="en">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://mastodon.social/@amrrr" class="u-url mention"&gt;@&lt;span&gt;amrrr&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; tumblr/10, but pretty good!&lt;/p&gt;</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/amrrr"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1512350"/>
<link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1512350.atom"/>
<thr:in-reply-to ref="tag:mastodon.social,2017-04-03:objectId=1476030:objectType=Status" href="https://mastodon.social/@amrrr/1476030"/>
</entry>
<entry>
<id>tag:mastodon.social,2017-04-03:objectId=1475949:objectType=Status</id>
<published>2017-04-03T07:35:45Z</published>
<updated>2017-04-03T07:35:45Z</updated>
<title>New status by lambadalambda</title>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<content type="html" xml:lang="en">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://mastodon.social/@Shookaite" class="u-url mention"&gt;@&lt;span&gt;Shookaite&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; Oh, you mean like userstyles?&lt;/p&gt;</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/Shookaite"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1512271"/>
<link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1512271.atom"/>
<thr:in-reply-to ref="tag:mastodon.social,2017-04-03:objectId=1475879:objectType=Status" href="https://mastodon.social/@Shookaite/1475879"/>
</entry>
<entry>
<id>tag:mastodon.social,2017-04-03:objectId=1475581:objectType=Status</id>
<published>2017-04-03T07:20:03Z</published>
<updated>2017-04-03T07:20:03Z</updated>
<title>New status by lambadalambda</title>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<content type="html" xml:lang="en">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://mastodon.social/@Shookaite" class="u-url mention"&gt;@&lt;span&gt;Shookaite&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; Would be nice if someone helped port Pleroma to Mastodon, that has a theme switcher (click on the cog in the upper right): &lt;a href="https://pleroma.heldscal.la/main/all" rel="nofollow noopener" target="_blank"&gt;&lt;span class="invisible"&gt;https://&lt;/span&gt;&lt;span class=""&gt;pleroma.heldscal.la/main/all&lt;/span&gt;&lt;span class="invisible"&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/Shookaite"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1511987"/>
<link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1511987.atom"/>
<thr:in-reply-to ref="tag:mastodon.social,2017-04-03:objectId=1475550:objectType=Status" href="https://mastodon.social/@Shookaite/1475550"/>
</entry>
<entry>
<id>tag:mastodon.social,2017-04-02:objectId=1457325:objectType=Status</id>
<published>2017-04-02T21:57:43Z</published>
<updated>2017-04-02T21:57:43Z</updated>
<title>New status by lambadalambda</title>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<content type="html" xml:lang="en">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://mastodon.social/@rhosyn" class="u-url mention"&gt;@&lt;span&gt;rhosyn&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; &lt;span class="h-card"&gt;&lt;a href="https://mastodon.social/@Meaningness" class="u-url mention"&gt;@&lt;span&gt;Meaningness&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; you could take a look at those listed at social.guhnoo.org&lt;/p&gt;</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/rhosyn"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/Meaningness"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1496564"/>
<link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1496564.atom"/>
<thr:in-reply-to ref="tag:mastodon.social,2017-04-02:objectId=1449283:objectType=Status" href="https://mastodon.social/@rhosyn/1449283"/>
</entry>
<entry>
<id>tag:mastodon.social,2017-04-02:objectId=1447926:objectType=Status</id>
<published>2017-04-02T18:31:52Z</published>
<updated>2017-04-02T18:31:52Z</updated>
<title>New status by lambadalambda</title>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<content type="html" xml:lang="en">&lt;p&gt;My main account is &lt;span class="h-card"&gt;&lt;a href="https://social.heldscal.la/lambadalambda" class="u-url mention"&gt;@&lt;span&gt;lambadalambda&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; , btw.&lt;/p&gt;</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.heldscal.la/user/23211"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1488648"/>
<link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1488648.atom"/>
</entry>
<entry>
<id>tag:mastodon.social,2017-04-02:objectId=1447878:objectType=Status</id>
<published>2017-04-02T18:30:37Z</published>
<updated>2017-04-02T18:30:37Z</updated>
<title>lambadalambda shared a status by Firstaide@awoo.space</title>
<activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb>
<activity:object>
<id>tag:awoo.space,2017-04-02:objectId=135324:objectType=Status</id>
<published>2017-04-02T18:29:32Z</published>
<updated>2017-04-02T18:29:32Z</updated>
<title>New status by Firstaide@awoo.space</title>
<author>
<id>https://awoo.space/users/Firstaide</id>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<uri>https://awoo.space/users/Firstaide</uri>
<name>Firstaide</name>
<email>Firstaide@awoo.space</email>
<summary>A smol awoo account, for a smol autistic 💙
They/them please!
NB/white/ace</summary>
<link rel="alternate" type="text/html" href="https://awoo.space/@Firstaide"/>
<link rel="avatar" type="image/png" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/023/707/original/95e92639771fd225.png?1492022811"/>
<link rel="header" type="image/jpeg" media:width="700" media:height="335" href="https://files.mastodon.social/accounts/headers/000/023/707/original/e98df174c26747be.jpg?1491667928"/>
<poco:preferredUsername>Firstaide</poco:preferredUsername>
<poco:displayName>Miff🚑✨</poco:displayName>
<poco:note>A smol awoo account, for a smol autistic 💙
They/them please!
NB/white/ace</poco:note>
<mastodon:scope>public</mastodon:scope>
</author>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<content type="html" xml:lang="en">&lt;p&gt;&lt;a href="https://mastodon.social/users/lambadalambda" class="h-card u-url p-nickname mention"&gt;@&lt;span&gt;lambadalambda&lt;/span&gt;&lt;/a&gt; yeah, I think that's p much the big issue here? &lt;br&gt;When I first heard of Masto, I thought it was just like twitter at first, I had no idea federation was even a thing?, and I actually joined p early on? :-o &lt;/p&gt;&lt;p&gt;idk I think more stuff needs to be done about federation promotion, but honestly its gotta come from the get go when people get here to make an account I feel :-o&lt;/p&gt;</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/lambadalambda"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href="https://awoo.space/users/Firstaide/updates/10904"/>
<thr:in-reply-to ref="tag:mastodon.social,2017-04-02:objectId=1447682:objectType=Status" href="https://mastodon.social/@lambadalambda/1447682"/>
</activity:object>
<content type="html" xml:lang="en">&lt;p&gt;&lt;a href="https://mastodon.social/users/lambadalambda" class="h-card u-url p-nickname mention"&gt;@&lt;span&gt;lambadalambda&lt;/span&gt;&lt;/a&gt; yeah, I think that's p much the big issue here? &lt;br&gt;When I first heard of Masto, I thought it was just like twitter at first, I had no idea federation was even a thing?, and I actually joined p early on? :-o &lt;/p&gt;&lt;p&gt;idk I think more stuff needs to be done about federation promotion, but honestly its gotta come from the get go when people get here to make an account I feel :-o&lt;/p&gt;</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/1488609"/>
<link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/1488609.atom"/>
</entry>
</feed>

+ 57
- 0
test/fixtures/ostatus_incoming_post.xml Näytä tiedosto

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/">
<generator uri="https://gnu.io/social" version="1.0.2-dev">GNU social</generator>
<id>https://social.heldscal.la/api/statuses/user_timeline/23211.atom</id>
<title>lambadalambda timeline</title>
<subtitle>Updates from lambadalambda on social.heldscal.la!</subtitle>
<logo>https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg</logo>
<updated>2017-04-29T18:25:38+00:00</updated>
<author>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<uri>https://social.heldscal.la/user/23211</uri>
<name>lambadalambda</name>
<summary>Call me Deacon Blues.</summary>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/lambadalambda"/>
<link rel="avatar" type="image/jpeg" media:width="236" media:height="236" href="https://social.heldscal.la/avatar/23211-original-20170416114255.jpeg"/>
<link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg"/>
<link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/23211-48-20170416114255.jpeg"/>
<link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/23211-24-20170416114257.jpeg"/>
<poco:preferredUsername>lambadalambda</poco:preferredUsername>
<poco:displayName>Constance Variable</poco:displayName>
<poco:note>Call me Deacon Blues.</poco:note>
<poco:address>
<poco:formatted>Berlin</poco:formatted>
</poco:address>
<poco:urls>
<poco:type>homepage</poco:type>
<poco:value>https://heldscal.la</poco:value>
<poco:primary>true</poco:primary>
</poco:urls>
<followers url="https://social.heldscal.la/lambadalambda/subscribers"></followers>
<statusnet:profile_info local_id="23211"></statusnet:profile_info>
</author>
<link href="https://social.heldscal.la/lambadalambda" rel="alternate" type="text/html"/>
<link href="https://social.heldscal.la/main/sup" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/>
<link href="https://social.heldscal.la/main/push/hub" rel="hub"/>
<link href="https://social.heldscal.la/main/salmon/user/23211" rel="salmon"/>
<link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-replies"/>
<link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-mention"/>
<link href="https://social.heldscal.la/api/statuses/user_timeline/23211.atom" rel="self" type="application/atom+xml"/>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<id>tag:social.heldscal.la,2017-04-29:noticeId=1967725:objectType=note</id>
<title>New note by lambadalambda</title>
<content type="html">Will it blend?</content>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1967725"/>
<status_net notice_id="1967725"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2017-04-29T18:25:38+00:00</published>
<updated>2017-04-29T18:25:38+00:00</updated>
<link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1007861"/>
<ostatus:conversation href="https://social.heldscal.la/conversation/1007861" local_id="1007861" ref="tag:social.heldscal.la,2017-04-29:objectType=thread:nonce=3f3a9dd83acc4e35">tag:social.heldscal.la,2017-04-29:objectType=thread:nonce=3f3a9dd83acc4e35</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1967725.atom"/>
<link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1967725.atom"/>
<statusnet:notice_info local_id="1967725" source="Pleroma FE"></statusnet:notice_info>
</entry>
</feed>

+ 60
- 0
test/fixtures/ostatus_incoming_reply.xml Näytä tiedosto

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/">
<generator uri="https://gnu.io/social" version="1.0.2-dev">GNU social</generator>
<id>https://social.heldscal.la/api/statuses/user_timeline/23211.atom</id>
<title>lambadalambda timeline</title>
<subtitle>Updates from lambadalambda on social.heldscal.la!</subtitle>
<logo>https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg</logo>
<updated>2017-04-30T09:30:32+00:00</updated>
<author>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<uri>https://social.heldscal.la/user/23211</uri>
<name>lambadalambda</name>
<summary>Call me Deacon Blues.</summary>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/lambadalambda"/>
<link rel="avatar" type="image/jpeg" media:width="236" media:height="236" href="https://social.heldscal.la/avatar/23211-original-20170416114255.jpeg"/>
<link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg"/>
<link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/23211-48-20170416114255.jpeg"/>
<link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/23211-24-20170416114257.jpeg"/>
<poco:preferredUsername>lambadalambda</poco:preferredUsername>
<poco:displayName>Constance Variable</poco:displayName>
<poco:note>Call me Deacon Blues.</poco:note>
<poco:address>
<poco:formatted>Berlin</poco:formatted>
</poco:address>
<poco:urls>
<poco:type>homepage</poco:type>
<poco:value>https://heldscal.la</poco:value>
<poco:primary>true</poco:primary>
</poco:urls>
<followers url="https://social.heldscal.la/lambadalambda/subscribers"></followers>
<statusnet:profile_info local_id="23211"></statusnet:profile_info>
</author>
<link href="https://social.heldscal.la/lambadalambda" rel="alternate" type="text/html"/>
<link href="https://social.heldscal.la/main/sup" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/>
<link href="https://social.heldscal.la/main/push/hub" rel="hub"/>
<link href="https://social.heldscal.la/main/salmon/user/23211" rel="salmon"/>
<link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-replies"/>
<link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-mention"/>
<link href="https://social.heldscal.la/api/statuses/user_timeline/23211.atom" rel="self" type="application/atom+xml"/>
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
<id>tag:social.heldscal.la,2017-04-30:noticeId=1978790:objectType=comment</id>
<title>New comment by lambadalambda</title>
<content type="html">@&lt;a href=&quot;https://gs.archae.me/user/4687&quot; class=&quot;h-card u-url p-nickname mention&quot; title=&quot;shpbot&quot;&gt;shpbot&lt;/a&gt; why not indeed.</content>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1978790"/>
<status_net notice_id="1978790"></status_net>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2017-04-30T09:30:32+00:00</published>
<updated>2017-04-30T09:30:32+00:00</updated>
<thr:in-reply-to ref="tag:gs.archae.me,2017-04-30:noticeId=778260:objectType=note" href="https://gs.archae.me/notice/778260"></thr:in-reply-to>
<link rel="related" href="https://gs.archae.me/notice/778260"/>
<link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1013566"/>
<ostatus:conversation href="https://social.heldscal.la/conversation/1013566" local_id="1013566" ref="https://gs.archae.me/conversation/327120">https://gs.archae.me/conversation/327120</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.archae.me/user/4687"/>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1978790.atom"/>
<link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1978790.atom"/>
<statusnet:notice_info local_id="1978790" source="Pleroma FE"></statusnet:notice_info>
</entry>
</feed>

+ 27
- 0
test/fixtures/private_key.pem Näytä tiedosto

@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAqnWeDtrqWasCKNXiuSq1tSCLI5H7BSvIROy5YfuGsXHrIlCq
LdIm9QlIUUmIi9QyzgiGEDsPCCkA1UguCVgF/UrJ1+FvHcHsTELkkBu/yCl9mrgt
WzTckhb6KjOhqtxi/TKgRaJ2Rlwz2bvH5sbCP9qffthitdxfh14KC5V0gqDt1xCy
WgZo79vbYMcVkcQoh5uLtG64ksYFBMfgnLaSj7xg5i2qCDiIY7bqBujo5HllDqeo
w3LXmsztt1cT8heXEjW0SYJvAHJK00OsG1kp4cqhfKzxLCHNGQJVHQxLOXy97I7o
HOeuhbxPhjpGSBMgw7YFm3ODXviqf557eqFcaQIDAQABAoIBAC6f+VnK22sncXHF
/zvyyL0AZ86U8XpanW7s6VA5wn/qzwwV0Fa0Mt+3aEaDvIuywSrF/hWWcegjfwzX
r2/y2cCMomUgTopvLrk1WttoG68eWjLlydI2xVZYXpkIgmH/4juri1dAtuVL9wrJ
aEZhe2SH4jSJ74Ya/y5BtLGycaoA9FHyIzHPTx52Ix2jWKWtKimW8J+aERi2uHdN
7yTnLT2APhs5fnvNnn0tg85CI3Ny2GNiqmAail14yVfRz8Sf6qDIepH5Jfz9oll4
I+GYUOLs6eTgkHXBn8LGhtHTE/9UJmb42OyWrW8X+nc/Mjz5xh0u/g1Gdp36oUMz
OotfneECgYEA3cGfQxmxjEqSbXt9jbxiCukU7PmkDDQqBu97URC4N8qEcMF1wW7X
AddU7Kq/UJU+oqjD/7UQHoS2ZThPtto6SpVdXQzsnrnPWQcrv5b1DV/TpXfwGoZ3
svUIAcx4vGzhhmHDJCBsdY6n8xWBYtSqfLFXgN5UkdafLGy3EkCEtmUCgYEAxMgl
7eU2QkWkzgJxOj6xjG2yqM3jxOvvoiRnD0rIQaBS70P/1N94ZkMXzOwddddZ5OW+
55h/a8TmFKP/+NW4PHRYra/dazGI4IBlw6Yeq6uq/4jbuSqtBbaNn/Dz5kdHBTqM
PtbBvc9Fztd2zb3InyyLbb4c+WjMqi0AooN027UCgYB4Tax7GJtLwsEBiDcrB4Ig
7SYfEae/vyT1skIyTmHCUqnbCfk6QUl/hDRcWJ2FuBHM6MW8GZxvEgxpiU0lo+pv
v+xwqKxNx/wHDm7bd6fl45DMee7WVRDnEyuO3kC56E/JOYxGMxjkBcpzg703wqvj
Dcqs7PDwVYDw9uGykzHsSQKBgEQnNcvA+RvW1w9qlSChGgkS7S+9r0dCl8pGZVNM
iTMBfffUS0TE6QQx9IpKtKFdpoq6b3XywR7oIO/BJSRfkOGPQi9Vm5BGpatrjNNI
M5Mtb5n1InRtLWOvKDnez/pPcW+EKZKR+qPsp7bNtR3ovxUx7lBh6dMP0uKVl4Sx
lsWJAoGBAIeek9eG+S3m2jaJRHasfKo5mJ2JrrmnjQXUOGUP8/CgO8sW1VmG2WAk
Av7+BRI2mP2f+3SswG/AoRGmRXXw65ly63ws8ixrhK0MG3MgqDkWc69SbTaaMJ+u
BQFYMsB1vZdUV3CaRqySkjY68QWGcJ4Z5JKHuTXzKv/GeFmw0V9R
-----END RSA PRIVATE KEY-----

+ 2
- 0
test/fixtures/salmon2.xml
File diff suppressed because it is too large
Näytä tiedosto


+ 99
- 0
test/fixtures/share-gs.xml Näytä tiedosto

@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/">
<generator uri="https://gnu.io/social" version="1.0.2-dev">GNU social</generator>
<id>https://social.heldscal.la/api/statuses/user_timeline/23211.atom</id>
<title>lambadalambda timeline</title>
<subtitle>Updates from lambadalambda on social.heldscal.la!</subtitle>
<logo>https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg</logo>
<updated>2017-05-03T08:05:41+00:00</updated>
<author>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<uri>https://social.heldscal.la/user/23211</uri>
<name>lambadalambda</name>
<summary>Call me Deacon Blues.</summary>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/lambadalambda"/>
<link rel="avatar" type="image/jpeg" media:width="236" media:height="236" href="https://social.heldscal.la/avatar/23211-original-20170416114255.jpeg"/>
<link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/23211-96-20170416114255.jpeg"/>
<link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/23211-48-20170416114255.jpeg"/>
<link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/23211-24-20170416114257.jpeg"/>
<poco:preferredUsername>lambadalambda</poco:preferredUsername>
<poco:displayName>Constance Variable</poco:displayName>
<poco:note>Call me Deacon Blues.</poco:note>
<poco:address>
<poco:formatted>Berlin</poco:formatted>
</poco:address>
<poco:urls>
<poco:type>homepage</poco:type>
<poco:value>https://heldscal.la</poco:value>
<poco:primary>true</poco:primary>
</poco:urls>
<followers url="https://social.heldscal.la/lambadalambda/subscribers"></followers>
<statusnet:profile_info local_id="23211"></statusnet:profile_info>
</author>
<link href="https://social.heldscal.la/lambadalambda" rel="alternate" type="text/html"/>
<link href="https://social.heldscal.la/main/sup" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/>
<link href="https://social.heldscal.la/main/push/hub" rel="hub"/>
<link href="https://social.heldscal.la/main/salmon/user/23211" rel="salmon"/>
<link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-replies"/>
<link href="https://social.heldscal.la/main/salmon/user/23211" rel="http://salmon-protocol.org/ns/salmon-mention"/>
<link href="https://social.heldscal.la/api/statuses/user_timeline/23211.atom" rel="self" type="application/atom+xml"/>
<entry>
<id>tag:social.heldscal.la,2017-05-03:noticeId=2028428:objectType=note</id>
<title>lambadalambda repeated a notice by lain</title>
<content type="html">RT @&lt;a href=&quot;https://pleroma.soykaf.com/users/lain&quot; class=&quot;h-card u-url p-nickname mention&quot; title=&quot;Lain Iwakura&quot;&gt;lain&lt;/a&gt; Added returning the entries as xml... let's see if the mastodon hammering stops now.</content>
<link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2028428"/>
<activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb>
<published>2017-05-03T08:05:41+00:00</published>
<updated>2017-05-03T08:05:41+00:00</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
<id>https://pleroma.soykaf.com/objects/4c1bda26-902e-4525-9fcd-b9fd44925193</id>
<title></title>
<content type="html">Added returning the entries as xml... let's see if the mastodon hammering stops now.</content>
<link rel="alternate" type="text/html" href="https://pleroma.soykaf.com/objects/4c1bda26-902e-4525-9fcd-b9fd44925193"/>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<published>2017-05-03T08:04:44+00:00</published>
<updated>2017-05-03T08:04:44+00:00</updated>
<author>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<uri>https://pleroma.soykaf.com/users/lain</uri>
<name>lain</name>
<summary>Test account</summary>
<link rel="alternate" type="text/html" href="https://pleroma.soykaf.com/users/lain"/>
<link rel="avatar" type="image/jpeg" media:width="250" media:height="202" href="https://social.heldscal.la/avatar/43188-original-20170429171039.jpeg"/>
<link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/43188-96-20170429172422.jpeg"/>
<link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/43188-48-20170429172422.jpeg"/>
<link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/43188-24-20170429181411.jpeg"/>
<poco:preferredUsername>lain</poco:preferredUsername>
<poco:displayName>Lain Iwakura</poco:displayName>
<poco:note>Test account</poco:note>
<statusnet:profile_info local_id="43188"></statusnet:profile_info>
</author>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<id>https://pleroma.soykaf.com/objects/4c1bda26-902e-4525-9fcd-b9fd44925193</id>
<title>New note by lain</title>
<content type="html">Added returning the entries as xml... let's see if the mastodon hammering stops now.</content>
<link rel="alternate" type="text/html" href="https://pleroma.soykaf.com/objects/4c1bda26-902e-4525-9fcd-b9fd44925193"/>
<status_net notice_id="2028424"></status_net>
</activity:object>
<link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1042737"/>
<ostatus:conversation href="https://social.heldscal.la/conversation/1042737" local_id="1042737" ref="https://pleroma.soykaf.com/contexts/ede39a2b-7cf3-4fa4-8ccd-cb97431bcc22">https://pleroma.soykaf.com/contexts/ede39a2b-7cf3-4fa4-8ccd-cb97431bcc22</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<source>
<id>https://pleroma.soykaf.com/users/lain/feed.atom</id>
<title>Lain Iwakura</title>
<link rel="alternate" type="text/html" href="https://pleroma.soykaf.com/users/lain"/>
<link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/users/lain/feed.atom"/>
<icon>https://social.heldscal.la/avatar/43188-96-20170429172422.jpeg</icon>
<updated>2017-05-03T08:04:44+00:00</updated>
</source>
</activity:object>
<link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1042737"/>
<ostatus:conversation href="https://social.heldscal.la/conversation/1042737" local_id="1042737" ref="https://pleroma.soykaf.com/contexts/ede39a2b-7cf3-4fa4-8ccd-cb97431bcc22">https://pleroma.soykaf.com/contexts/ede39a2b-7cf3-4fa4-8ccd-cb97431bcc22</ostatus:conversation>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2028428.atom"/>
<link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2028428.atom"/>
<statusnet:notice_info local_id="2028428" source="api" repeat_of="2028424"></statusnet:notice_info>
</entry>
</feed>

+ 54
- 0
test/fixtures/share.xml Näytä tiedosto

@@ -0,0 +1,54 @@
<?xml version="1.0"?>
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0">
<id>tag:mastodon.social,2017-05-03:objectId=4934452:objectType=Status</id>
<published>2017-05-03T08:21:09Z</published>
<updated>2017-05-03T08:21:09Z</updated>
<title>lambadalambda shared a status by lain@pleroma.soykaf.com</title>
<author>
<id>https://mastodon.social/users/lambadalambda</id>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<uri>https://mastodon.social/users/lambadalambda</uri>
<name>lambadalambda</name>
<email>lambadalambda@mastodon.social</email>
<link rel="alternate" type="text/html" href="https://mastodon.social/@lambadalambda"/>
<link rel="avatar" type="image/gif" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/000/264/original/1429214160519.gif"/>
<link rel="header" type="" media:width="700" media:height="335" href="/headers/original/missing.png"/>
<poco:preferredUsername>lambadalambda</poco:preferredUsername>
<poco:displayName>Critical Value</poco:displayName>
<mastodon:scope>public</mastodon:scope>
</author>
<activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb>
<activity:object>
<id>https://pleroma.soykaf.com/objects/4c1bda26-902e-4525-9fcd-b9fd44925193</id>
<published>2017-05-03T08:04:44Z</published>
<updated>2017-05-03T08:05:52Z</updated>
<title>New status by lain@pleroma.soykaf.com</title>
<author>
<id>https://pleroma.soykaf.com/users/lain</id>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<uri>https://pleroma.soykaf.com/users/lain</uri>
<name>lain</name>
<email>lain@pleroma.soykaf.com</email>
<summary type="html">Test account</summary>
<link rel="alternate" type="text/html" href="https://pleroma.soykaf.com/users/lain"/>
<link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/125/902/original/6B3AFC74ACA841B24CFB94DB9044C84EDE6AFF31C71718B023D413DAED09A68E.jpeg"/>
<link rel="header" type="" media:width="700" media:height="335" href="/headers/original/missing.png"/>
<poco:preferredUsername>lain</poco:preferredUsername>
<poco:displayName>Lain Iwakura</poco:displayName>
<poco:note>Test account</poco:note>
<mastodon:scope>public</mastodon:scope>
</author>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<content type="html" xml:lang="en">Added returning the entries as xml... let's see if the mastodon hammering stops now.</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href=""/>
</activity:object>
<content type="html" xml:lang="en">Added returning the entries as xml... let's see if the mastodon hammering stops now.</content>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
<mastodon:scope>public</mastodon:scope>
<link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/2232660"/>
<link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2232660.atom"/>
</entry>

+ 10
- 0
test/fixtures/user_full.xml Näytä tiedosto

@@ -0,0 +1,10 @@
<author>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<uri>http://gs.example.org:4040/index.php/user/1</uri>
<name>lambda</name>
<link rel="avatar" type="image/png" media:width="96" media:height="96" href="http://gs.example.org:4040/theme/neo-gnu/default-avatar-profile.png"/>
<link rel="avatar" type="image/png" media:width="48" media:height="48" href="http://gs.example.org:4040/theme/neo-gnu/default-avatar-stream.png"/>
<link rel="avatar" type="image/png" media:width="24" media:height="24" href="http://gs.example.org:4040/theme/neo-gnu/default-avatar-mini.png"/>
<poco:preferredUsername>Constance Variable</poco:preferredUsername>
<poco:displayName>lambadalambda</poco:displayName>
</author>

+ 5
- 0
test/fixtures/user_name_only.xml Näytä tiedosto

@@ -0,0 +1,5 @@
<author>
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
<uri>http://gs.example.org:4040/index.php/user/1</uri>
<name>lambda</name>
</author>

+ 20
- 0
test/fixtures/webfinger.xml Näytä tiedosto

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
<Subject>acct:shp@social.heldscal.la</Subject>
<Alias>https://social.heldscal.la/user/29191</Alias>
<Alias>https://social.heldscal.la/shp</Alias>
<Alias>https://social.heldscal.la/index.php/user/29191</Alias>
<Alias>https://social.heldscal.la/index.php/shp</Alias>
<Link rel="http://webfinger.net/rel/profile-page" type="text/html" href="https://social.heldscal.la/shp"/>
<Link rel="http://gmpg.org/xfn/11" type="text/html" href="https://social.heldscal.la/shp"/>
<Link rel="describedby" type="application/rdf+xml" href="https://social.heldscal.la/shp/foaf"/>
<Link rel="http://apinamespace.org/atom" type="application/atomsvc+xml" href="https://social.heldscal.la/api/statusnet/app/service/shp.xml"/>
<Link rel="http://apinamespace.org/twitter" href="https://social.heldscal.la/api/"/>
<Link rel="http://specs.openid.net/auth/2.0/provider" href="https://social.heldscal.la/shp"/>
<Link rel="http://schemas.google.com/g/2010#updates-from" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/user_timeline/29191.atom"/>
<Link rel="magic-public-key" href="data:application/magic-public-key,RSA.wQ3i9UA0qmAxZ0WTIp4a-waZn_17Ez1pEEmqmqoooRsG1_BvpmOvLN0G2tEcWWxl2KOtdQMCiPptmQObeZeuj48mdsDZ4ArQinexY2hCCTcbV8Xpswpkb8K05RcKipdg07pnI7tAgQ0VWSZDImncL6YUGlG5YN8b5TjGOwk2VG8=.AQAB"/>
<Link rel="salmon" href="https://social.heldscal.la/main/salmon/user/29191"/>
<Link rel="http://salmon-protocol.org/ns/salmon-replies" href="https://social.heldscal.la/main/salmon/user/29191"/>
<Link rel="http://salmon-protocol.org/ns/salmon-mention" href="https://social.heldscal.la/main/salmon/user/29191"/>
<Link rel="http://ostatus.org/schema/1.0/subscribe" template="https://social.heldscal.la/main/ostatussub?profile={uri}"/>
</XRD>

+ 2
- 2
test/support/builders/activity_builder.ex Näytä tiedosto

@@ -5,7 +5,7 @@ defmodule Pleroma.Builders.ActivityBuilder do
def build(data \\ %{}, opts \\ %{}) do
user = opts[:user] || Pleroma.Factory.insert(:user)
activity = %{
"id" => 1,
"id" => Pleroma.Web.ActivityPub.ActivityPub.generate_object_id,
"actor" => user.ap_id,
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
"object" => %{
@@ -23,7 +23,7 @@ defmodule Pleroma.Builders.ActivityBuilder do

def insert_list(times, data \\ %{}, opts \\ %{}) do
Enum.map(1..times, fn (n) ->
{:ok, activity} = insert(Map.merge(data, %{"id" => n}))
{:ok, activity} = insert(data)
activity
end)
end


+ 14
- 2
test/support/factory.ex Näytä tiedosto

@@ -24,7 +24,8 @@ defmodule Pleroma.Factory do
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
"published_at" => DateTime.utc_now() |> DateTime.to_iso8601,
"likes" => [],
"like_count" => 0
"like_count" => 0,
"context" => "2hu"
}

%Pleroma.Object{
@@ -40,7 +41,8 @@ defmodule Pleroma.Factory do
"actor" => note.data["actor"],
"to" => note.data["to"],
"object" => note.data,
"published_at" => DateTime.utc_now() |> DateTime.to_iso8601
"published_at" => DateTime.utc_now() |> DateTime.to_iso8601,
"context" => note.data["context"]
}

%Pleroma.Activity{
@@ -74,4 +76,14 @@ defmodule Pleroma.Factory do
state: "requested"
}
end

def websub_client_subscription_factory do
%Pleroma.Web.Websub.WebsubClientSubscription{
topic: "http://example.org",
secret: "here's a secret",
valid_until: nil,
state: "requested",
subscribers: []
}
end
end

+ 37
- 1
test/user_test.exs Näytä tiedosto

@@ -13,7 +13,7 @@ defmodule Pleroma.UserTest do

user = UserBuilder.build

expected_ap_id = "https://#{host}/users/#{user.nickname}"
expected_ap_id = "#{Pleroma.Web.base_url}/users/#{user.nickname}"

assert expected_ap_id == User.ap_id(user)
end
@@ -86,4 +86,40 @@ defmodule Pleroma.UserTest do
assert changeset.changes[:following] == [User.ap_followers(%User{nickname: @full_user_data.nickname})]
end
end

describe "fetching a user from nickname or trying to build one" do
test "gets an existing user" do
user = insert(:user)
fetched_user = User.get_or_fetch_by_nickname(user.nickname)

assert user == fetched_user
end

# TODO: Make the test local.
test "fetches an external user via ostatus if no user exists" do
fetched_user = User.get_or_fetch_by_nickname("shp@social.heldscal.la")
assert fetched_user.nickname == "shp@social.heldscal.la"
end

test "returns nil if no user could be fetched" do
fetched_user = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
assert fetched_user == nil
end

test "returns nil for nonexistant local user" do
fetched_user = User.get_or_fetch_by_nickname("nonexistant")
assert fetched_user == nil
end
end

test "returns an ap_id for a user" do
user = insert(:user)
assert User.ap_id(user) == Pleroma.Web.Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :feed_redirect, user.nickname)
end

test "returns an ap_followers link for a user" do
user = insert(:user)
assert User.ap_followers(user) == Pleroma.Web.Router.Helpers.o_status_url(Pleroma.Web.Endpoint, :feed_redirect, user.nickname) <> "/followers"
end
end


+ 9
- 0
test/web/activity_pub/activity_pub_test.exs Näytä tiedosto

@@ -40,6 +40,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
end
end

describe "create activities" do
test "removes doubled 'to' recipients" do
{:ok, activity} = ActivityPub.create(["user1", "user1", "user2"], %User{ap_id: "1"}, "", %{})
assert activity.data["to"] == ["user1", "user2"]
end
end

describe "fetch activities for recipients" do
test "retrieve the activities for certain recipients" do
{:ok, activity_one} = ActivityBuilder.insert(%{"to" => ["someone"]})
@@ -125,6 +132,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert like_activity.data["type"] == "Like"
assert like_activity.data["object"] == object.data["id"]
assert like_activity.data["to"] == [User.ap_followers(user), note_activity.data["actor"]]
assert like_activity.data["context"] == object.data["context"]
assert object.data["like_count"] == 1
assert object.data["likes"] == [user.ap_id]

@@ -174,6 +182,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert announce_activity.data["to"] == [User.ap_followers(user), note_activity.data["actor"]]
assert announce_activity.data["object"] == object.data["id"]
assert announce_activity.data["actor"] == user.ap_id
assert announce_activity.data["context"] == object.data["context"]
end
end



+ 124
- 1
test/web/ostatus/activity_representer_test.exs Näytä tiedosto

@@ -2,7 +2,8 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenterTest do
use Pleroma.DataCase

alias Pleroma.Web.OStatus.ActivityRepresenter
alias Pleroma.{User, Activity}
alias Pleroma.{User, Activity, Object}
alias Pleroma.Web.ActivityPub.ActivityPub

import Pleroma.Factory

@@ -23,6 +24,10 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenterTest do
<content type="html">#{note_activity.data["object"]["content"]}</content>
<published>#{inserted_at}</published>
<updated>#{updated_at}</updated>
<ostatus:conversation>#{note_activity.data["context"]}</ostatus:conversation>
<link href="#{note_activity.data["context"]}" rel="ostatus:conversation" />
<link type="application/atom+xml" href="#{note_activity.data["object"]["id"]}" rel="self" />
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
"""

tuple = ActivityRepresenter.to_simple_form(note_activity, user)
@@ -32,6 +37,124 @@ defmodule Pleroma.Web.OStatus.ActivityRepresenterTest do
assert clean(res) == clean(expected)
end

test "a reply note" do
note = insert(:note_activity)
answer = insert(:note_activity)
object = answer.data["object"]
object = Map.put(object, "inReplyTo", note.data["object"]["id"])

data = %{answer.data | "object" => object}
answer = %{answer | data: data}

updated_at = answer.updated_at
|> NaiveDateTime.to_iso8601
inserted_at = answer.inserted_at
|> NaiveDateTime.to_iso8601

user = User.get_cached_by_ap_id(answer.data["actor"])

expected = """
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<id>#{answer.data["object"]["id"]}</id>
<title>New note by #{user.nickname}</title>
<content type="html">#{answer.data["object"]["content"]}</content>
<published>#{inserted_at}</published>
<updated>#{updated_at}</updated>
<ostatus:conversation>#{answer.data["context"]}</ostatus:conversation>
<link href="#{answer.data["context"]}" rel="ostatus:conversation" />
<link type="application/atom+xml" href="#{answer.data["object"]["id"]}" rel="self" />
<thr:in-reply-to ref="#{note.data["object"]["id"]}" />
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
"""

tuple = ActivityRepresenter.to_simple_form(answer, user)

res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> IO.iodata_to_binary

assert clean(res) == clean(expected)
end

test "an announce activity" do
note = insert(:note_activity)
user = insert(:user)
object = Object.get_cached_by_ap_id(note.data["object"]["id"])

{:ok, announce, object} = ActivityPub.announce(user, object)

announce = Repo.get(Activity, announce.id)

note_user = User.get_cached_by_ap_id(note.data["actor"])
note = Repo.get(Activity, note.id)
note_xml = ActivityRepresenter.to_simple_form(note, note_user, true)
|> :xmerl.export_simple_content(:xmerl_xml)
|> to_string

updated_at = announce.updated_at
|> NaiveDateTime.to_iso8601
inserted_at = announce.inserted_at
|> NaiveDateTime.to_iso8601

expected = """
<activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb>
<id>#{announce.data["id"]}</id>
<title>#{user.nickname} repeated a notice</title>
<content type="html">RT #{note.data["object"]["content"]}</content>
<published>#{inserted_at}</published>
<updated>#{updated_at}</updated>
<ostatus:conversation>#{announce.data["context"]}</ostatus:conversation>
<link href="#{announce.data["context"]}" rel="ostatus:conversation" />
<link rel="self" type="application/atom+xml" href="#{announce.data["id"]}"/>
<activity:object>
#{note_xml}
</activity:object>
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="#{note.data["actor"]}"/>
"""

announce_xml = ActivityRepresenter.to_simple_form(announce, user)
|> :xmerl.export_simple_content(:xmerl_xml)
|> to_string

assert clean(expected) == clean(announce_xml)
end

test "a like activity" do
note = insert(:note)
user = insert(:user)
{:ok, like, _note} = ActivityPub.like(user, note)

updated_at = like.updated_at
|> NaiveDateTime.to_iso8601
inserted_at = like.inserted_at
|> NaiveDateTime.to_iso8601

tuple = ActivityRepresenter.to_simple_form(like, user)
refute is_nil(tuple)

res = :xmerl.export_simple_content(tuple, :xmerl_xml) |> IO.iodata_to_binary

expected = """
<activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
<id>#{like.data["id"]}</id>
<title>New favorite by #{user.nickname}</title>
<content type="html">#{user.nickname} favorited something</content>
<published>#{inserted_at}</published>
<updated>#{updated_at}</updated>
<activity:object>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<id>#{note.data["id"]}</id>
</activity:object>
<ostatus:conversation>#{like.data["context"]}</ostatus:conversation>
<link href="#{like.data["context"]}" rel="ostatus:conversation" />
<link rel="self" type="application/atom+xml" href="#{like.data["id"]}"/>
<thr:in-reply-to ref="#{note.data["id"]}" />
<link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="#{note.data["actor"]}"/>
"""

assert clean(res) == clean(expected)
end

test "an unknown activity" do
tuple = ActivityRepresenter.to_simple_form(%Activity{}, nil)
assert is_nil(tuple)


+ 3
- 2
test/web/ostatus/feed_representer_test.exs Näytä tiedosto

@@ -22,12 +22,13 @@ defmodule Pleroma.Web.OStatus.FeedRepresenterTest do
|> :xmerl.export_simple_content(:xmerl_xml)

expected = """
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0">
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0">
<id>#{OStatus.feed_path(user)}</id>
<title>#{user.nickname}'s timeline</title>
<updated>#{most_recent_update}</updated>
<link rel="hub" href="#{OStatus.pubsub_path(user)}" />
<link rel="self" href="#{OStatus.feed_path(user)}" />
<link rel="salmon" href="#{OStatus.salmon_path(user)}" />
<link rel="self" href="#{OStatus.feed_path(user)}" type="application/atom+xml" />
<author>
#{user_xml}
</author>


+ 11
- 0
test/web/ostatus/ostatus_controller_test.exs Näytä tiedosto

@@ -12,4 +12,15 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do

assert response(conn, 200)
end

test "gets an object", %{conn: conn} do
note_activity = insert(:note_activity)
[_, uuid] = hd Regex.scan(~r/.+\/([\w-]+)$/, note_activity.data["object"]["id"])
url = "/objects/#{uuid}"

conn = conn
|> get(url)

assert response(conn, 200)
end
end

+ 194
- 0
test/web/ostatus/ostatus_test.exs Näytä tiedosto

@@ -0,0 +1,194 @@
defmodule Pleroma.Web.OStatusTest do
use Pleroma.DataCase
alias Pleroma.Web.OStatus
alias Pleroma.Web.XML
alias Pleroma.{Object, Repo}

test "don't insert create notes twice" do
incoming = File.read!("test/fixtures/incoming_note_activity.xml")
{:ok, [_activity]} = OStatus.handle_incoming(incoming)
assert {:ok, [{:error, "duplicate activity"}]} == OStatus.handle_incoming(incoming)
end

test "handle incoming note - GS, Salmon" do
incoming = File.read!("test/fixtures/incoming_note_activity.xml")
{:ok, [activity]} = OStatus.handle_incoming(incoming)

assert activity.data["type"] == "Create"
assert activity.data["object"]["type"] == "Note"
assert activity.data["object"]["id"] == "tag:gs.example.org:4040,2017-04-23:noticeId=29:objectType=note"
assert activity.data["published"] == "2017-04-23T14:51:03+00:00"
assert activity.data["context"] == "tag:gs.example.org:4040,2017-04-23:objectType=thread:nonce=f09e22f58abd5c7b"
assert "http://pleroma.example.org:4000/users/lain3" in activity.data["to"]
assert activity.local == false
end

test "handle incoming notes - GS, subscription" do
incoming = File.read!("test/fixtures/ostatus_incoming_post.xml")
{:ok, [activity]} = OStatus.handle_incoming(incoming)

assert activity.data["type"] == "Create"
assert activity.data["object"]["type"] == "Note"
assert activity.data["object"]["actor"] == "https://social.heldscal.la/user/23211"
assert activity.data["object"]["content"] == "Will it blend?"
end

test "handle incoming notes with attachments - GS, subscription" do
incoming = File.read!("test/fixtures/incoming_websub_gnusocial_attachments.xml")
{:ok, [activity]} = OStatus.handle_incoming(incoming)

assert activity.data["type"] == "Create"
assert activity.data["object"]["type"] == "Note"
assert activity.data["object"]["actor"] == "https://social.heldscal.la/user/23211"
assert activity.data["object"]["attachment"] |> length == 2
end

test "handle incoming notes - Mastodon, salmon, reply" do
# It uses the context of the replied to object
Repo.insert!(%Object{
data: %{
"id" => "https://pleroma.soykaf.com/objects/c237d966-ac75-4fe3-a87a-d89d71a3a7a4",
"context" => "2hu"
}})
incoming = File.read!("test/fixtures/incoming_reply_mastodon.xml")
{:ok, [activity]} = OStatus.handle_incoming(incoming)

assert activity.data["type"] == "Create"
assert activity.data["object"]["type"] == "Note"
assert activity.data["object"]["actor"] == "https://mastodon.social/users/lambadalambda"
assert activity.data["context"] == "2hu"
end

test "handle incoming notes - GS, subscription, reply" do
incoming = File.read!("test/fixtures/ostatus_incoming_reply.xml")
{:ok, [activity]} = OStatus.handle_incoming(incoming)

assert activity.data["type"] == "Create"
assert activity.data["object"]["type"] == "Note"
assert activity.data["object"]["actor"] == "https://social.heldscal.la/user/23211"
assert activity.data["object"]["content"] == "@<a href=\"https://gs.archae.me/user/4687\" class=\"h-card u-url p-nickname mention\" title=\"shpbot\">shpbot</a> why not indeed."
assert activity.data["object"]["inReplyTo"] == "tag:gs.archae.me,2017-04-30:noticeId=778260:objectType=note"
end

test "handle incoming retweets - GS, subscription" do
incoming = File.read!("test/fixtures/share-gs.xml")
{:ok, [[activity, retweeted_activity]]} = OStatus.handle_incoming(incoming)

assert activity.data["type"] == "Announce"
assert activity.data["actor"] == "https://social.heldscal.la/user/23211"
assert activity.data["object"] == retweeted_activity.data["object"]["id"]
refute activity.local
assert retweeted_activity.data["type"] == "Create"
assert retweeted_activity.data["actor"] == "https://pleroma.soykaf.com/users/lain"
refute retweeted_activity.local
end

test "handle incoming retweets - Mastodon, salmon" do
incoming = File.read!("test/fixtures/share.xml")
{:ok, [[activity, retweeted_activity]]} = OStatus.handle_incoming(incoming)

assert activity.data["type"] == "Announce"
assert activity.data["actor"] == "https://mastodon.social/users/lambadalambda"
assert activity.data["object"] == retweeted_activity.data["object"]["id"]
refute activity.local
assert retweeted_activity.data["type"] == "Create"
assert retweeted_activity.data["actor"] == "https://pleroma.soykaf.com/users/lain"
refute retweeted_activity.local
end

test "handle incoming replies" do
incoming = File.read!("test/fixtures/incoming_note_activity_answer.xml")
{:ok, [activity]} = OStatus.handle_incoming(incoming)

assert activity.data["type"] == "Create"
assert activity.data["object"]["type"] == "Note"
assert activity.data["object"]["inReplyTo"] == "http://pleroma.example.org:4000/objects/55bce8fc-b423-46b1-af71-3759ab4670bc"
assert "http://pleroma.example.org:4000/users/lain5" in activity.data["to"]
end

describe "new remote user creation" do
test "tries to use the information in poco fields" do
# TODO make test local
uri = "https://social.heldscal.la/user/23211"

{:ok, user} = OStatus.find_or_make_user(uri)

user = Repo.get(Pleroma.User, user.id)
assert user.name == "Constance Variable"
assert user.nickname == "lambadalambda@social.heldscal.la"
assert user.local == false
assert user.info["uri"] == uri
assert user.ap_id == uri
assert user.avatar["type"] == "Image"

{:ok, user_again} = OStatus.find_or_make_user(uri)

assert user == user_again
end

test "find_make_or_update_user takes an author element and returns an updated user" do
# TODO make test local
uri = "https://social.heldscal.la/user/23211"

{:ok, user} = OStatus.find_or_make_user(uri)
change = Ecto.Changeset.change(user, %{avatar: nil})

{:ok, user} = Repo.update(change)
refute user.avatar

doc = XML.parse_document(File.read!("test/fixtures/23211.atom"))
[author] = :xmerl_xpath.string('//author[1]', doc)
{:ok, user} = OStatus.find_make_or_update_user(author)
assert user.avatar["type"] == "Image"

{:ok, user_again} = OStatus.find_make_or_update_user(author)
assert user_again == user
end
end

describe "gathering user info from a user id" do
test "it returns user info in a hash" do
user = "shp@social.heldscal.la"

# TODO: make test local
{:ok, data} = OStatus.gather_user_info(user)

expected = %{
"hub" => "https://social.heldscal.la/main/push/hub",
"magic_key" => "RSA.wQ3i9UA0qmAxZ0WTIp4a-waZn_17Ez1pEEmqmqoooRsG1_BvpmOvLN0G2tEcWWxl2KOtdQMCiPptmQObeZeuj48mdsDZ4ArQinexY2hCCTcbV8Xpswpkb8K05RcKipdg07pnI7tAgQ0VWSZDImncL6YUGlG5YN8b5TjGOwk2VG8=.AQAB",
"name" => "shp",
"nickname" => "shp",
"salmon" => "https://social.heldscal.la/main/salmon/user/29191",
"subject" => "acct:shp@social.heldscal.la",
"topic" => "https://social.heldscal.la/api/statuses/user_timeline/29191.atom",
"uri" => "https://social.heldscal.la/user/29191",
"host" => "social.heldscal.la",
"fqn" => user,
"avatar" => %{"type" => "Image", "url" => [%{"href" => "https://social.heldscal.la/avatar/29191-original-20170421154949.jpeg", "mediaType" => "image/jpeg", "type" => "Link"}]}
}
assert data == expected
end

test "it works with the uri" do
user = "https://social.heldscal.la/user/29191"

# TODO: make test local
{:ok, data} = OStatus.gather_user_info(user)

expected = %{
"hub" => "https://social.heldscal.la/main/push/hub",
"magic_key" => "RSA.wQ3i9UA0qmAxZ0WTIp4a-waZn_17Ez1pEEmqmqoooRsG1_BvpmOvLN0G2tEcWWxl2KOtdQMCiPptmQObeZeuj48mdsDZ4ArQinexY2hCCTcbV8Xpswpkb8K05RcKipdg07pnI7tAgQ0VWSZDImncL6YUGlG5YN8b5TjGOwk2VG8=.AQAB",
"name" => "shp",
"nickname" => "shp",
"salmon" => "https://social.heldscal.la/main/salmon/user/29191",
"subject" => "https://social.heldscal.la/user/29191",
"topic" => "https://social.heldscal.la/api/statuses/user_timeline/29191.atom",
"uri" => "https://social.heldscal.la/user/29191",
"host" => "social.heldscal.la",
"fqn" => user,
"avatar" => %{"type" => "Image", "url" => [%{"href" => "https://social.heldscal.la/avatar/29191-original-20170421154949.jpeg", "mediaType" => "image/jpeg", "type" => "Link"}]}
}
assert data == expected
end
end
end

+ 73
- 0
test/web/salmon/salmon_test.exs Näytä tiedosto

@@ -1,6 +1,8 @@
defmodule Pleroma.Web.Salmon.SalmonTest do
use Pleroma.DataCase
alias Pleroma.Web.Salmon
alias Pleroma.{Repo, Activity, User}
import Pleroma.Factory

@magickey "RSA.pu0s-halox4tu7wmES1FVSx6u-4wc0YrUFXcqWXZG4-27UmbCOpMQftRCldNRfyA-qLbz-eqiwQhh-1EwUvjsD4cYbAHNGHwTvDOyx5AKthQUP44ykPv7kjKGh3DWKySJvcs9tlUG87hlo7AvnMo9pwRS_Zz2CacQ-MKaXyDepk=.AQAB"

@@ -16,4 +18,75 @@ defmodule Pleroma.Web.Salmon.SalmonTest do
{:ok, salmon} = File.read("test/fixtures/salmon.xml")
assert Salmon.decode_and_validate(@wrong_magickey, salmon) == :error
end

test "generates an RSA private key pem" do
{:ok, key} = Salmon.generate_rsa_pem
assert is_binary(key)
assert Regex.match?(~r/RSA/, key)
end

test "it encodes a magic key from a public key" do
key = Salmon.decode_key(@magickey)
magic_key = Salmon.encode_key(key)

assert @magickey == magic_key
end

test "returns a public and private key from a pem" do
pem = File.read!("test/fixtures/private_key.pem")
{:ok, private, public} = Salmon.keys_from_pem(pem)

assert elem(private, 0) == :RSAPrivateKey
assert elem(public, 0) == :RSAPublicKey
end

test "encodes an xml payload with a private key" do
doc = File.read!("test/fixtures/incoming_note_activity.xml")
pem = File.read!("test/fixtures/private_key.pem")
{:ok, private, public} = Salmon.keys_from_pem(pem)

# Let's try a roundtrip.
{:ok, salmon} = Salmon.encode(private, doc)
{:ok, decoded_doc} = Salmon.decode_and_validate(Salmon.encode_key(public), salmon)

assert doc == decoded_doc
end

test "it gets a magic key" do
# TODO: Make test local
salmon = File.read!("test/fixtures/salmon2.xml")
{:ok, key} = Salmon.fetch_magic_key(salmon)

assert key == "RSA.uzg6r1peZU0vXGADWxGJ0PE34WvmhjUmydbX5YYdOiXfODVLwCMi1umGoqUDm-mRu4vNEdFBVJU1CpFA7dKzWgIsqsa501i2XqElmEveXRLvNRWFB6nG03Q5OUY2as8eE54BJm0p20GkMfIJGwP6TSFb-ICp3QjzbatuSPJ6xCE=.AQAB"
end

test "it pushes an activity to remote accounts it's addressed to" do
user_data = %{
info: %{
"salmon" => "http://example.org/salmon"
},
local: false
}

mentioned_user = insert(:user, user_data)
note = insert(:note)
activity_data = %{
"id" => Pleroma.Web.ActivityPub.ActivityPub.generate_activity_id,
"type" => "Create",
"actor" => note.data["actor"],
"to" => note.data["to"] ++ [mentioned_user.ap_id],
"object" => note.data,
"published_at" => DateTime.utc_now() |> DateTime.to_iso8601,
"context" => note.data["context"]
}

{:ok, activity} = Repo.insert(%Activity{data: activity_data})
user = Repo.get_by(User, ap_id: activity.data["actor"])
{:ok, user} = Pleroma.Web.WebFinger.ensure_keys_present(user)

poster = fn (url, data, headers) ->
assert url == "http://example.org/salmon"
end
Salmon.publish(user, activity, poster)
end
end

+ 7
- 4
test/web/twitter_api/representers/activity_representer_test.exs Näytä tiedosto

@@ -69,6 +69,8 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenterTest do
content = HtmlSanitizeEx.strip_tags(content_html)
date = DateTime.from_naive!(~N[2016-05-24 13:26:08.003], "Etc/UTC") |> DateTime.to_iso8601

{:ok, convo_object} = Object.context_mapping("2hu") |> Repo.insert

activity = %Activity{
id: 1,
data: %{
@@ -84,14 +86,15 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenterTest do
"type" => "Note",
"content" => content_html,
"inReplyToStatusId" => 213123,
"statusnetConversationId" => 4711,
"attachment" => [
object
],
"like_count" => 5,
"announcement_count" => 3
"announcement_count" => 3,
"context" => "2hu"
},
"published" => date
"published" => date,
"context" => "2hu"
}
}

@@ -106,7 +109,7 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ActivityRepresenterTest do
"is_post_verb" => true,
"created_at" => "Tue May 24 13:26:08 +0000 2016",
"in_reply_to_status_id" => 213123,
"statusnet_conversation_id" => 4711,
"statusnet_conversation_id" => convo_object.id,
"attachments" => [
ObjectRepresenter.to_map(object)
],


+ 4
- 2
test/web/twitter_api/representers/user_representer_test.exs Näytä tiedosto

@@ -48,7 +48,8 @@ defmodule Pleroma.Web.TwitterAPI.Representers.UserRepresenterTest do
"profile_image_url_profile_size" => image,
"profile_image_url_original" => image,
"following" => false,
"rights" => %{}
"rights" => %{},
"statusnet_profile_url" => user.ap_id
}

assert represented == UserRepresenter.to_map(user)
@@ -72,7 +73,8 @@ defmodule Pleroma.Web.TwitterAPI.Representers.UserRepresenterTest do
"profile_image_url_profile_size" => image,
"profile_image_url_original" => image,
"following" => true,
"rights" => %{}
"rights" => %{},
"statusnet_profile_url" => user.ap_id
}

assert represented == UserRepresenter.to_map(user, %{for: follower})


+ 4
- 3
test/web/twitter_api/twitter_api_controller_test.exs Näytä tiedosto

@@ -84,12 +84,13 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
describe "GET /statusnet/conversation/:id.json" do
test "returns the statuses in the conversation", %{conn: conn} do
{:ok, _user} = UserBuilder.insert
{:ok, _activity} = ActivityBuilder.insert(%{"statusnetConversationId" => 1, "context" => "2hu"})
{:ok, _activity_two} = ActivityBuilder.insert(%{"statusnetConversationId" => 1,"context" => "2hu"})
{:ok, _activity} = ActivityBuilder.insert(%{"context" => "2hu"})
{:ok, _activity_two} = ActivityBuilder.insert(%{"context" => "2hu"})
{:ok, _activity_three} = ActivityBuilder.insert(%{"context" => "3hu"})

{:ok, object} = Object.context_mapping("2hu") |> Repo.insert
conn = conn
|> get("/api/statusnet/conversation/1.json")
|> get("/api/statusnet/conversation/#{object.id}.json")

response = json_response(conn, 200)



+ 46
- 10
test/web/twitter_api/twitter_api_test.exs Näytä tiedosto

@@ -33,19 +33,18 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do

{ :ok, activity = %Activity{} } = TwitterAPI.create_status(user, input)

assert get_in(activity.data, ["object", "content"]) == "Hello again, <a href='shp'>@shp</a>.<br>This is on another line."
assert get_in(activity.data, ["object", "content"]) == "Hello again, <a href='shp'>@shp</a>.<br>This is on another line.<br><a href='http://example.org/image.jpg'>http://example.org/image.jpg</a>"
assert get_in(activity.data, ["object", "type"]) == "Note"
assert get_in(activity.data, ["object", "actor"]) == user.ap_id
assert get_in(activity.data, ["actor"]) == user.ap_id
assert Enum.member?(get_in(activity.data, ["to"]), User.ap_followers(user))
assert Enum.member?(get_in(activity.data, ["to"]), "https://www.w3.org/ns/activitystreams#Public")
assert Enum.member?(get_in(activity.data, ["to"]), "shp")
assert activity.local == true

# Add a context + 'statusnet_conversation_id'
# Add a context
assert is_binary(get_in(activity.data, ["context"]))
assert is_binary(get_in(activity.data, ["object", "context"]))
assert get_in(activity.data, ["object", "statusnetConversationId"]) == activity.id
assert get_in(activity.data, ["statusnetConversationId"]) == activity.id

assert is_list(activity.data["object"]["attachment"])

@@ -69,15 +68,14 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do

assert get_in(reply.data, ["context"]) == get_in(activity.data, ["context"])
assert get_in(reply.data, ["object", "context"]) == get_in(activity.data, ["object", "context"])
assert get_in(reply.data, ["statusnetConversationId"]) == get_in(activity.data, ["statusnetConversationId"])
assert get_in(reply.data, ["object", "statusnetConversationId"]) == get_in(activity.data, ["object", "statusnetConversationId"])
assert get_in(reply.data, ["object", "inReplyTo"]) == get_in(activity.data, ["object", "id"])
assert get_in(reply.data, ["object", "inReplyToStatusId"]) == activity.id
assert Enum.member?(get_in(reply.data, ["to"]), "some_cool_id")
end

test "fetch public statuses" do
test "fetch public statuses, excluding remote ones." do
%{ public: activity, user: user } = ActivityBuilder.public_and_non_public
insert(:note_activity, %{local: false})

follower = insert(:user, following: [User.ap_followers(user)])

@@ -87,6 +85,18 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
assert Enum.at(statuses, 0) == ActivityRepresenter.to_map(activity, %{user: user, for: follower})
end

test "fetch whole known network statuses" do
%{ public: activity, user: user } = ActivityBuilder.public_and_non_public
insert(:note_activity, %{local: false})

follower = insert(:user, following: [User.ap_followers(user)])

statuses = TwitterAPI.fetch_public_and_external_statuses(follower)

assert length(statuses) == 2
assert Enum.at(statuses, 0) == ActivityRepresenter.to_map(activity, %{user: user, for: follower})
end

test "fetch friends' statuses" do
user = insert(:user, %{following: ["someguy/followers"]})
{:ok, activity} = ActivityBuilder.insert(%{"to" => ["someguy/followers"]})
@@ -201,11 +211,13 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do

test "fetch statuses in a context using the conversation id" do
{:ok, user} = UserBuilder.insert()
{:ok, activity} = ActivityBuilder.insert(%{"statusnetConversationId" => 1, "context" => "2hu"})
{:ok, activity_two} = ActivityBuilder.insert(%{"statusnetConversationId" => 1,"context" => "2hu"})
{:ok, activity} = ActivityBuilder.insert(%{"context" => "2hu"})
{:ok, activity_two} = ActivityBuilder.insert(%{"context" => "2hu"})
{:ok, _activity_three} = ActivityBuilder.insert(%{"context" => "3hu"})

statuses = TwitterAPI.fetch_conversation(user, 1)
{:ok, object} = Object.context_mapping("2hu") |> Repo.insert

statuses = TwitterAPI.fetch_conversation(user, object.id)

assert length(statuses) == 2
assert Enum.at(statuses, 0)["id"] == activity.id
@@ -314,9 +326,33 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
refute Repo.get_by(User, nickname: "lain")
end

test "it assigns an integer conversation_id" do
note_activity = insert(:note_activity)
user = User.get_cached_by_ap_id(note_activity.data["actor"])
status = ActivityRepresenter.to_map(note_activity, %{user: user})

assert is_number(status["statusnet_conversation_id"])
end

setup do
Supervisor.terminate_child(Pleroma.Supervisor, Cachex)
Supervisor.restart_child(Pleroma.Supervisor, Cachex)
:ok
end

describe "context_to_conversation_id" do
test "creates a mapping object" do
conversation_id = TwitterAPI.context_to_conversation_id("random context")
object = Object.get_by_ap_id("random context")

assert conversation_id == object.id
end

test "returns an existing mapping for an existing object" do
{:ok, object} = Object.context_mapping("random context") |> Repo.insert
conversation_id = TwitterAPI.context_to_conversation_id("random context")

assert conversation_id == object.id
end
end
end

+ 51
- 1
test/web/web_finger/web_finger_test.exs Näytä tiedosto

@@ -1,11 +1,61 @@
defmodule Pleroma.Web.WebFingerTest do
use Pleroma.DataCase
alias Pleroma.Web.WebFinger
import Pleroma.Factory

describe "host meta" do
test "returns a link to the xml lrdd" do
host_info = Pleroma.Web.WebFinger.host_meta
host_info = WebFinger.host_meta()

assert String.contains?(host_info, Pleroma.Web.base_url)
end
end

describe "incoming webfinger request" do
test "works for fqns" do
user = insert(:user)

{:ok, result} = WebFinger.webfinger("#{user.nickname}@#{Pleroma.Web.Endpoint.host}")
assert is_binary(result)
end

test "works for ap_ids" do
user = insert(:user)

{:ok, result} = WebFinger.webfinger(user.ap_id)
assert is_binary(result)
end
end

describe "fingering" do
test "returns the info for a user" do
user = "shp@social.heldscal.la"

getter = fn(_url, _headers, [params: [resource: ^user]]) ->
{:ok, %{status_code: 200, body: File.read!("test/fixtures/webfinger.xml")}}
end

{:ok, data} = WebFinger.finger(user, getter)

assert data["magic_key"] == "RSA.wQ3i9UA0qmAxZ0WTIp4a-waZn_17Ez1pEEmqmqoooRsG1_BvpmOvLN0G2tEcWWxl2KOtdQMCiPptmQObeZeuj48mdsDZ4ArQinexY2hCCTcbV8Xpswpkb8K05RcKipdg07pnI7tAgQ0VWSZDImncL6YUGlG5YN8b5TjGOwk2VG8=.AQAB"
assert data["topic"] == "https://social.heldscal.la/api/statuses/user_timeline/29191.atom"
assert data["subject"] == "acct:shp@social.heldscal.la"
assert data["salmon"] == "https://social.heldscal.la/main/salmon/user/29191"
end
end

describe "ensure_keys_present" do
test "it creates keys for a user and stores them in info" do
user = insert(:user)
refute is_binary(user.info["keys"])
{:ok, user} = WebFinger.ensure_keys_present(user)
assert is_binary(user.info["keys"])
end

test "it doesn't create keys if there already are some" do
user = insert(:user, %{info: %{"keys" => "xxx"}})
{:ok, user} = WebFinger.ensure_keys_present(user)
assert user.info["keys"] == "xxx"
end
end
end

+ 61
- 0
test/web/websub/websub_controller_test.exs Näytä tiedosto

@@ -1,6 +1,9 @@
defmodule Pleroma.Web.Websub.WebsubControllerTest do
use Pleroma.Web.ConnCase
import Pleroma.Factory
alias Pleroma.Web.Websub.WebsubClientSubscription
alias Pleroma.{Repo, Activity}
alias Pleroma.Web.Websub

test "websub subscription request", %{conn: conn} do
user = insert(:user)
@@ -20,4 +23,62 @@ defmodule Pleroma.Web.Websub.WebsubControllerTest do

assert response(conn, 202) == "Accepted"
end

test "websub subscription confirmation", %{conn: conn} do
websub = insert(:websub_client_subscription)

params = %{
"hub.mode" => "subscribe",
"hub.topic" => websub.topic,
"hub.challenge" => "some challenge",
"hub.lease_seconds" => 100
}

conn = conn
|> get("/push/subscriptions/#{websub.id}", params)

websub = Repo.get(WebsubClientSubscription, websub.id)

assert response(conn, 200) == "some challenge"
assert websub.state == "accepted"

# TODO valid_until
end

test "handles incoming feed updates", %{conn: conn} do
websub = insert(:websub_client_subscription)
doc = "some stuff"
signature = Websub.sign(websub.secret, doc)

conn = conn
|> put_req_header("x-hub-signature", "sha1=" <> signature)
|> put_req_header("content-type", "application/atom+xml")
|> post("/push/subscriptions/#{websub.id}", doc)

assert response(conn, 200) == "OK"

assert length(Repo.all(Activity)) == 1
end

test "rejects incoming feed updates with the wrong signature", %{conn: conn} do
websub = insert(:websub_client_subscription)
doc = "some stuff"
signature = Websub.sign("wrong secret", doc)

conn = conn
|> put_req_header("x-hub-signature", "sha1=" <> signature)
|> put_req_header("content-type", "application/atom+xml")
|> post("/push/subscriptions/#{websub.id}", doc)

assert response(conn, 500) == "Error"

assert length(Repo.all(Activity)) == 0
end
end

defmodule Pleroma.Web.OStatusMock do
import Pleroma.Factory
def handle_incoming(_doc) do
insert(:note_activity)
end
end

+ 89
- 2
test/web/websub/websub_test.exs Näytä tiedosto

@@ -3,11 +3,13 @@ defmodule Pleroma.Web.WebsubMock do
{:ok, sub}
end
end

defmodule Pleroma.Web.WebsubTest do
use Pleroma.DataCase
alias Pleroma.Web.Websub
alias Pleroma.Web.Websub.WebsubServerSubscription
import Pleroma.Factory
alias Pleroma.Web.Router.Helpers

test "a verification of a request that is accepted" do
sub = insert(:websub_subscription)
@@ -58,7 +60,6 @@ defmodule Pleroma.Web.WebsubTest do
"hub.lease_seconds" => "100"
}


{:ok, subscription } = Websub.incoming_subscription_request(user, data)
assert subscription.topic == Pleroma.Web.OStatus.feed_path(user)
assert subscription.state == "requested"
@@ -78,7 +79,6 @@ defmodule Pleroma.Web.WebsubTest do
"hub.lease_seconds" => "100"
}


{:ok, subscription } = Websub.incoming_subscription_request(user, data)
assert subscription.topic == Pleroma.Web.OStatus.feed_path(user)
assert subscription.state == sub.state
@@ -87,4 +87,91 @@ defmodule Pleroma.Web.WebsubTest do
assert length(Repo.all(WebsubServerSubscription)) == 1
assert subscription.id == sub.id
end

def accepting_verifier(subscription) do
{:ok, %{ subscription | state: "accepted" }}
end

test "initiate a subscription for a given user and topic" do
subscriber = insert(:user)
user = insert(:user, %{info: %{ "topic" => "some_topic", "hub" => "some_hub"}})

{:ok, websub} = Websub.subscribe(subscriber, user, &accepting_verifier/1)
assert websub.subscribers == [subscriber.ap_id]
assert websub.topic == "some_topic"
assert websub.hub == "some_hub"
assert is_binary(websub.secret)
assert websub.user == user
assert websub.state == "accepted"
end

test "discovers the hub and canonical url" do
topic = "https://mastodon.social/users/lambadalambda.atom"

getter = fn(^topic) ->
doc = File.read!("test/fixtures/lambadalambda.atom")
{:ok, %{status_code: 200, body: doc}}
end

{:ok, discovered} = Websub.gather_feed_data(topic, getter)
expected = %{
"hub" => "https://mastodon.social/api/push",
"uri" => "https://mastodon.social/users/lambadalambda",
"nickname" => "lambadalambda",
"name" => "Critical Value",
"host" => "mastodon.social",
"avatar" => %{"type" => "Image", "url" => [%{"href" => "https://files.mastodon.social/accounts/avatars/000/000/264/original/1429214160519.gif?1492379244", "mediaType" => "image/gif", "type" => "Link"}]}
}

assert expected == discovered
end

test "calls the hub, requests topic" do
hub = "https://social.heldscal.la/main/push/hub"
topic = "https://social.heldscal.la/api/statuses/user_timeline/23211.atom"
websub = insert(:websub_client_subscription, %{hub: hub, topic: topic})

poster = fn (^hub, {:form, data}, _headers) ->
assert Keyword.get(data, :"hub.mode") == "subscribe"
assert Keyword.get(data, :"hub.callback") == Helpers.websub_url(Pleroma.Web.Endpoint, :websub_subscription_confirmation, websub.id)
{:ok, %{status_code: 202}}
end

task = Task.async(fn -> Websub.request_subscription(websub, poster) end)

change = Ecto.Changeset.change(websub, %{state: "accepted"})
{:ok, _} = Repo.update(change)

{:ok, websub} = Task.await(task)

assert websub.state == "accepted"
end

test "rejects the subscription if it can't be accepted" do
hub = "https://social.heldscal.la/main/push/hub"
topic = "https://social.heldscal.la/api/statuses/user_timeline/23211.atom"
websub = insert(:websub_client_subscription, %{hub: hub, topic: topic})

poster = fn (^hub, {:form, _data}, _headers) ->
{:ok, %{status_code: 202}}
end

{:error, websub} = Websub.request_subscription(websub, poster, 1000)
assert websub.state == "rejected"

websub = insert(:websub_client_subscription, %{hub: hub, topic: topic})
poster = fn (^hub, {:form, _data}, _headers) ->
{:ok, %{status_code: 400}}
end

{:error, websub} = Websub.request_subscription(websub, poster, 1000)
assert websub.state == "rejected"
end

test "sign a text" do
signed = Websub.sign("secret", "text")
assert signed == "B8392C23690CCF871F37EC270BE1582DEC57A503" |> String.downcase

signed = Websub.sign("secret", [["て"], ['す']])
end
end

Loading…
Peruuta
Tallenna