aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorAlex Gleason <alex@alexgleason.me>2022-01-03 13:40:19 -0600
committerAlex Gleason <alex@alexgleason.me>2022-01-03 13:40:19 -0600
commit4081be0001332bac402faec7565807df088b0117 (patch)
treea5305404e9bb31b3613dbc9631d36f8827be81c2 /test
parentd00f74e036735c1c238f661076f2925b39daa6ac (diff)
parenta3094b64df344622f1bcb03091ef2ff4dce6da82 (diff)
downloadpleroma-matrix.tar.gz
Merge remote-tracking branch 'origin/develop' into matrixmatrix
Diffstat (limited to 'test')
-rw-r--r--test/activity_expiration_test.exs55
-rw-r--r--test/config/deprecation_warnings_test.exs65
-rw-r--r--test/config/emoji.txt1
-rw-r--r--test/credo/check/consistency/file_location.ex166
-rw-r--r--test/earmark_renderer_test.exs79
-rw-r--r--test/filter_test.exs158
-rw-r--r--test/fixtures/23211.atom508
-rw-r--r--test/fixtures/activitypub-client-post-activity.json1
-rw-r--r--test/fixtures/bridgy/actor.json80
-rw-r--r--test/fixtures/config/temp.exported_from_db.secret.exs5
-rw-r--r--test/fixtures/config/temp.secret.exs6
-rw-r--r--test/fixtures/custom_instance_panel.html1
-rw-r--r--test/fixtures/cw_retweet.xml68
-rw-r--r--test/fixtures/delete.xml39
-rw-r--r--test/fixtures/dm.xml27
-rw-r--r--test/fixtures/emojis.zipbin0 -> 1446 bytes
-rw-r--r--test/fixtures/empty.zipbin0 -> 22 bytes
-rw-r--r--test/fixtures/favorite.xml65
-rw-r--r--test/fixtures/favorite_with_local_note.xml64
-rw-r--r--test/fixtures/follow.xml68
-rw-r--r--test/fixtures/guppe-actor.json26
-rwxr-xr-xtest/fixtures/image.gifbin0 -> 1001718 bytes
-rwxr-xr-xtest/fixtures/image.pngbin0 -> 104426 bytes
-rw-r--r--test/fixtures/incoming_note_activity.xml42
-rw-r--r--test/fixtures/incoming_note_activity_answer.xml42
-rw-r--r--test/fixtures/incoming_reply_mastodon.xml29
-rw-r--r--test/fixtures/incoming_websub_gnusocial_attachments.xml59
-rw-r--r--test/fixtures/lambadalambda.atom479
-rw-r--r--test/fixtures/mastodon-delete.json9
-rw-r--r--test/fixtures/mastodon-note-cw.xml39
-rw-r--r--test/fixtures/mastodon-note-unlisted.xml38
-rw-r--r--test/fixtures/mastodon-post-activity-nsfw.json68
-rw-r--r--test/fixtures/mastodon-problematic.xml72
-rw-r--r--test/fixtures/mastodon/application_actor.json67
-rw-r--r--test/fixtures/mastodon/collections/featured.json39
-rw-r--r--test/fixtures/mastodon_conversation.xml30
-rw-r--r--test/fixtures/mewmew_no_name.json46
-rw-r--r--test/fixtures/modules/good_mrf.ex19
-rw-r--r--test/fixtures/modules/runtime_module.ex4
-rw-r--r--test/fixtures/nil_mention_entry.xml52
-rw-r--r--test/fixtures/osada-follow-activity.json76
-rw-r--r--test/fixtures/ostatus_incoming_post.xml57
-rw-r--r--test/fixtures/ostatus_incoming_post_tag.xml59
-rw-r--r--test/fixtures/ostatus_incoming_reply.xml60
-rw-r--r--test/fixtures/peertube/actor-person.json121
-rw-r--r--test/fixtures/peertube/video-object-mpegURL-only.json413
-rw-r--r--test/fixtures/share-gs-local.xml99
-rw-r--r--test/fixtures/share-gs.xml99
-rw-r--r--test/fixtures/share.xml54
-rw-r--r--test/fixtures/spoofed-object.json26
-rw-r--r--test/fixtures/statuses/masto-note.json47
-rw-r--r--test/fixtures/statuses/note.json27
-rw-r--r--test/fixtures/tesla_mock/7369654.atom44
-rw-r--r--test/fixtures/tesla_mock/admin@mastdon.example.org.json44
-rw-r--r--test/fixtures/tesla_mock/atarifrosch_feed.xml473
-rw-r--r--test/fixtures/tesla_mock/emelie.atom306
-rw-r--r--test/fixtures/tesla_mock/emoji-in-summary.json49
-rw-r--r--test/fixtures/tesla_mock/framatube.org-video.json2
-rw-r--r--test/fixtures/tesla_mock/http__gs.example.org_index.php_api_statuses_user_timeline_1.atom.xml460
-rw-r--r--test/fixtures/tesla_mock/https___mamot.fr_users_Skruyb.atom342
-rw-r--r--test/fixtures/tesla_mock/https___mastodon.social_users_lambadalambda.atom464
-rw-r--r--test/fixtures/tesla_mock/https___osada.macgirvin.com_channel_mike.json3
-rw-r--r--test/fixtures/tesla_mock/https___pawoo.net_users_pekorino.atom231
-rw-r--r--test/fixtures/tesla_mock/https___pleroma.soykaf.com_users_lain_feed.atom.xml1
-rw-r--r--test/fixtures/tesla_mock/https___shitposter.club_api_statuses_show_2827873.atom.xml54
-rw-r--r--test/fixtures/tesla_mock/https___shitposter.club_api_statuses_user_timeline_1.atom.xml454
-rw-r--r--test/fixtures/tesla_mock/https___shitposter.club_notice_2827873.json1
-rw-r--r--test/fixtures/tesla_mock/https___social.heldscal.la_api_statuses_user_timeline_23211.atom.xml591
-rw-r--r--test/fixtures/tesla_mock/https___social.heldscal.la_api_statuses_user_timeline_29191.atom.xml719
-rw-r--r--test/fixtures/tesla_mock/lemmy-page.json17
-rw-r--r--test/fixtures/tesla_mock/lemmy-user.json27
-rw-r--r--test/fixtures/tesla_mock/sakamoto.atom1
-rw-r--r--test/fixtures/tesla_mock/sakamoto_eal_feed.atom1
-rw-r--r--test/fixtures/tesla_mock/shp@pleroma.soykaf.com.feed1
-rw-r--r--test/fixtures/tesla_mock/spc_5381.atom438
-rw-r--r--test/fixtures/tesla_mock/wedistribute-create-article.json1
-rw-r--r--test/fixtures/tesla_mock/xn--q9jyb4c_host_meta4
-rw-r--r--test/fixtures/unfollow.xml68
-rw-r--r--test/fixtures/users_mock/localhost.json41
-rw-r--r--test/fixtures/users_mock/masto_featured.json18
-rw-r--r--test/fixtures/users_mock/user.json42
-rw-r--r--test/fixtures/video.mp4bin0 -> 522216 bytes
-rw-r--r--test/instance_static/emoji/blobs.gg/blank.pngbin0 -> 95 bytes
-rw-r--r--test/instance_static/emoji/blobs.gg/pack.json11
-rw-r--r--test/mix/pleroma_test.exs (renamed from test/tasks/pleroma_test.exs)2
-rw-r--r--test/mix/tasks/pleroma/app_test.exs (renamed from test/tasks/app_test.exs)2
-rw-r--r--test/mix/tasks/pleroma/config_test.exs343
-rw-r--r--test/mix/tasks/pleroma/count_statuses_test.exs (renamed from test/tasks/count_statuses_test.exs)3
-rw-r--r--test/mix/tasks/pleroma/database_test.exs (renamed from test/tasks/database_test.exs)71
-rw-r--r--test/mix/tasks/pleroma/digest_test.exs (renamed from test/tasks/digest_test.exs)4
-rw-r--r--test/mix/tasks/pleroma/ecto/migrate_test.exs (renamed from test/tasks/ecto/migrate_test.exs)6
-rw-r--r--test/mix/tasks/pleroma/ecto/rollback_test.exs (renamed from test/tasks/ecto/rollback_test.exs)6
-rw-r--r--test/mix/tasks/pleroma/ecto_test.exs (renamed from test/tasks/ecto/ecto_test.exs)2
-rw-r--r--test/mix/tasks/pleroma/email_test.exs127
-rw-r--r--test/mix/tasks/pleroma/emoji_test.exs (renamed from test/tasks/emoji_test.exs)4
-rw-r--r--test/mix/tasks/pleroma/frontend_test.exs (renamed from test/tasks/frontend_test.exs)4
-rw-r--r--test/mix/tasks/pleroma/instance_test.exs (renamed from test/tasks/instance_test.exs)24
-rw-r--r--test/mix/tasks/pleroma/refresh_counter_cache_test.exs (renamed from test/tasks/refresh_counter_cache_test.exs)3
-rw-r--r--test/mix/tasks/pleroma/relay_test.exs (renamed from test/tasks/relay_test.exs)76
-rw-r--r--test/mix/tasks/pleroma/robots_txt_test.exs (renamed from test/tasks/robots_txt_test.exs)6
-rw-r--r--test/mix/tasks/pleroma/uploads_test.exs (renamed from test/tasks/uploads_test.exs)2
-rw-r--r--test/mix/tasks/pleroma/user_test.exs (renamed from test/tasks/user_test.exs)215
-rw-r--r--test/pleroma/activity/ir/topics_test.exs (renamed from test/activity/ir/topics_test.exs)42
-rw-r--r--test/pleroma/activity/search_test.exs45
-rw-r--r--test/pleroma/activity_test.exs (renamed from test/activity_test.exs)68
-rw-r--r--test/pleroma/application_requirements_test.exs (renamed from test/application_requirements_test.exs)86
-rw-r--r--test/pleroma/bbs/handler_test.exs (renamed from test/bbs/handler_test.exs)12
-rw-r--r--test/pleroma/bookmark_test.exs (renamed from test/bookmark_test.exs)4
-rw-r--r--test/pleroma/captcha_test.exs (renamed from test/captcha_test.exs)9
-rw-r--r--test/pleroma/chat/message_reference_test.exs (renamed from test/chat/message_reference_test.exs)2
-rw-r--r--test/pleroma/chat_test.exs (renamed from test/chat_test.exs)5
-rw-r--r--test/pleroma/config/deprecation_warnings_test.exs336
-rw-r--r--test/pleroma/config/holder_test.exs (renamed from test/config/holder_test.exs)2
-rw-r--r--test/pleroma/config/loader_test.exs (renamed from test/config/loader_test.exs)2
-rw-r--r--test/pleroma/config/release_runtime_provider_test.exs45
-rw-r--r--test/pleroma/config/transfer_task_test.exs (renamed from test/config/transfer_task_test.exs)14
-rw-r--r--test/pleroma/config_db_test.exs (renamed from test/config/config_db_test.exs)2
-rw-r--r--test/pleroma/config_test.exs (renamed from test/config_test.exs)40
-rw-r--r--test/pleroma/conversation/participation_test.exs (renamed from test/conversation/participation_test.exs)57
-rw-r--r--test/pleroma/conversation_test.exs (renamed from test/conversation_test.exs)10
-rw-r--r--test/pleroma/docs/generator_test.exs (renamed from test/docs/generator_test.exs)6
-rw-r--r--test/pleroma/ecto_type/activity_pub/object_validators/date_time_test.exs (renamed from test/web/activity_pub/object_validators/types/date_time_test.exs)8
-rw-r--r--test/pleroma/ecto_type/activity_pub/object_validators/object_id_test.exs (renamed from test/web/activity_pub/object_validators/types/object_id_test.exs)6
-rw-r--r--test/pleroma/ecto_type/activity_pub/object_validators/recipients_test.exs (renamed from test/web/activity_pub/object_validators/types/recipients_test.exs)12
-rw-r--r--test/pleroma/ecto_type/activity_pub/object_validators/safe_text_test.exs (renamed from test/web/activity_pub/object_validators/types/safe_text_test.exs)6
-rw-r--r--test/pleroma/emails/admin_email_test.exs (renamed from test/emails/admin_email_test.exs)18
-rw-r--r--test/pleroma/emails/mailer_test.exs (renamed from test/emails/mailer_test.exs)2
-rw-r--r--test/pleroma/emails/user_email_test.exs (renamed from test/emails/user_email_test.exs)15
-rw-r--r--test/pleroma/emoji/formatter_test.exs (renamed from test/emoji/formatter_test.exs)4
-rw-r--r--test/pleroma/emoji/loader_test.exs (renamed from test/emoji/loader_test.exs)2
-rw-r--r--test/pleroma/emoji/pack_test.exs93
-rw-r--r--test/pleroma/emoji_test.exs (renamed from test/emoji_test.exs)18
-rw-r--r--test/pleroma/filter_test.exs193
-rw-r--r--test/pleroma/following_relationship_test.exs (renamed from test/following_relationship_test.exs)4
-rw-r--r--test/pleroma/formatter_test.exs (renamed from test/formatter_test.exs)28
-rw-r--r--test/pleroma/frontend_test.exs72
-rw-r--r--test/pleroma/gun/connection_pool_test.exs (renamed from test/gun/conneciton_pool_test.exs)7
-rw-r--r--test/pleroma/hashtag_test.exs17
-rw-r--r--test/pleroma/healthcheck_test.exs (renamed from test/healthcheck_test.exs)4
-rw-r--r--test/pleroma/html_test.exs (renamed from test/html_test.exs)16
-rw-r--r--test/pleroma/http/adapter_helper/gun_test.exs (renamed from test/http/adapter_helper/gun_test.exs)17
-rw-r--r--test/pleroma/http/adapter_helper/hackney_test.exs (renamed from test/http/adapter_helper/hackney_test.exs)2
-rw-r--r--test/pleroma/http/adapter_helper_test.exs (renamed from test/http/adapter_helper_test.exs)2
-rw-r--r--test/pleroma/http/ex_aws_test.exs (renamed from test/http/ex_aws_test.exs)2
-rw-r--r--test/pleroma/http/request_builder_test.exs (renamed from test/http/request_builder_test.exs)46
-rw-r--r--test/pleroma/http/tzdata_test.exs (renamed from test/http/tzdata_test.exs)2
-rw-r--r--test/pleroma/http_test.exs (renamed from test/http_test.exs)2
-rw-r--r--test/pleroma/instances/instance_test.exs (renamed from test/web/instances/instance_test.exs)115
-rw-r--r--test/pleroma/instances_test.exs (renamed from test/web/instances/instances_test.exs)8
-rw-r--r--test/pleroma/integration/federation_test.exs (renamed from test/federation/federation_test.exs)2
-rw-r--r--test/pleroma/integration/mastodon_websocket_test.exs (renamed from test/integration/mastodon_websocket_test.exs)32
-rw-r--r--test/pleroma/job_queue_monitor_test.exs (renamed from test/job_queue_monitor_test.exs)2
-rw-r--r--test/pleroma/keys_test.exs (renamed from test/keys_test.exs)4
-rw-r--r--test/pleroma/list_test.exs (renamed from test/list_test.exs)4
-rw-r--r--test/pleroma/marker_test.exs (renamed from test/marker_test.exs)8
-rw-r--r--test/pleroma/mfa/backup_codes_test.exs (renamed from test/mfa/backup_codes_test.exs)6
-rw-r--r--test/pleroma/mfa/totp_test.exs (renamed from test/mfa/totp_test.exs)6
-rw-r--r--test/pleroma/mfa_test.exs (renamed from test/mfa_test.exs)8
-rw-r--r--test/pleroma/migration_helper/notification_backfill_test.exs (renamed from test/migration_helper/notification_backfill_test.exs)4
-rw-r--r--test/pleroma/moderation_log_test.exs (renamed from test/moderation_log_test.exs)42
-rw-r--r--test/pleroma/notification_test.exs (renamed from test/notification_test.exs)87
-rw-r--r--test/pleroma/object/containment_test.exs (renamed from test/object/containment_test.exs)2
-rw-r--r--test/pleroma/object/fetcher_test.exs (renamed from test/object/fetcher_test.exs)63
-rw-r--r--test/pleroma/object_test.exs (renamed from test/object_test.exs)119
-rw-r--r--test/pleroma/otp_version_test.exs (renamed from test/otp_version_test.exs)2
-rw-r--r--test/pleroma/pagination_test.exs (renamed from test/pagination_test.exs)4
-rw-r--r--test/pleroma/password/pbkdf2_test.exs35
-rw-r--r--test/pleroma/registration_test.exs (renamed from test/registration_test.exs)4
-rw-r--r--test/pleroma/repo/migrations/autolinker_to_linkify_test.exs (renamed from test/migrations/20200716195806_autolinker_to_linkify_test.exs)6
-rw-r--r--test/pleroma/repo/migrations/confirm_logged_in_users_test.exs40
-rw-r--r--test/pleroma/repo/migrations/deprecate_public_endpoint_test.exs60
-rw-r--r--test/pleroma/repo/migrations/fix_legacy_tags_test.exs (renamed from test/migrations/20200802170532_fix_legacy_tags_test.exs)6
-rw-r--r--test/pleroma/repo/migrations/fix_malformed_formatter_config_test.exs (renamed from test/migrations/20200722185515_fix_malformed_formatter_config_test.exs)6
-rw-r--r--test/pleroma/repo/migrations/move_welcome_settings_test.exs (renamed from test/migrations/20200724133313_move_welcome_settings_test.exs)6
-rw-r--r--test/pleroma/repo/migrations/rename_instance_chat_test.exs52
-rw-r--r--test/pleroma/repo_test.exs (renamed from test/repo_test.exs)36
-rw-r--r--test/pleroma/report_note_test.exs (renamed from test/report_note_test.exs)4
-rw-r--r--test/pleroma/reverse_proxy_test.exs (renamed from test/reverse_proxy/reverse_proxy_test.exs)43
-rw-r--r--test/pleroma/runtime_test.exs (renamed from test/runtime_test.exs)5
-rw-r--r--test/pleroma/safe_jsonb_set_test.exs (renamed from test/safe_jsonb_set_test.exs)6
-rw-r--r--test/pleroma/scheduled_activity_test.exs (renamed from test/scheduled_activity_test.exs)13
-rw-r--r--test/pleroma/signature_test.exs (renamed from test/signature_test.exs)2
-rw-r--r--test/pleroma/stats_test.exs (renamed from test/stats_test.exs)25
-rw-r--r--test/pleroma/upload/filter/analyze_metadata_test.exs33
-rw-r--r--test/pleroma/upload/filter/anonymize_filename_test.exs (renamed from test/upload/filter/anonymize_filename_test.exs)15
-rw-r--r--test/pleroma/upload/filter/dedupe_test.exs (renamed from test/upload/filter/dedupe_test.exs)7
-rw-r--r--test/pleroma/upload/filter/exiftool_test.exs (renamed from test/upload/filter/exiftool_test.exs)17
-rw-r--r--test/pleroma/upload/filter/mogrifun_test.exs (renamed from test/upload/filter/mogrifun_test.exs)6
-rw-r--r--test/pleroma/upload/filter/mogrify_test.exs (renamed from test/upload/filter/mogrify_test.exs)6
-rw-r--r--test/pleroma/upload/filter_test.exs (renamed from test/upload/filter_test.exs)7
-rw-r--r--test/pleroma/upload_test.exs (renamed from test/upload_test.exs)76
-rw-r--r--test/pleroma/uploaders/local_test.exs (renamed from test/uploaders/local_test.exs)8
-rw-r--r--test/pleroma/uploaders/s3_test.exs (renamed from test/uploaders/s3_test.exs)25
-rw-r--r--test/pleroma/user/backup_test.exs238
-rw-r--r--test/pleroma/user/import_test.exs76
-rw-r--r--test/pleroma/user/notification_setting_test.exs (renamed from test/user/notification_setting_test.exs)4
-rw-r--r--test/pleroma/user/query_test.exs47
-rw-r--r--test/pleroma/user/welcome_chat_message_test.exs (renamed from test/user/welcome_chat_massage_test.exs)15
-rw-r--r--test/pleroma/user/welcome_email_test.exs (renamed from test/user/welcome_email_test.exs)12
-rw-r--r--test/pleroma/user/welcome_message_test.exs (renamed from test/user/welcome_message_test.exs)13
-rw-r--r--test/pleroma/user_invite_token_test.exs (renamed from test/user_invite_token_test.exs)2
-rw-r--r--test/pleroma/user_relationship_test.exs (renamed from test/user_relationship_test.exs)4
-rw-r--r--test/pleroma/user_search_test.exs (renamed from test/user_search_test.exs)65
-rw-r--r--test/pleroma/user_test.exs (renamed from test/user_test.exs)816
-rw-r--r--test/pleroma/utils_test.exs15
-rw-r--r--test/pleroma/web/activity_pub/activity_pub_controller_test.exs (renamed from test/web/activity_pub/activity_pub_controller_test.exs)695
-rw-r--r--test/pleroma/web/activity_pub/activity_pub_test.exs (renamed from test/web/activity_pub/activity_pub_test.exs)543
-rw-r--r--test/pleroma/web/activity_pub/builder_test.exs48
-rw-r--r--test/pleroma/web/activity_pub/mrf/activity_expiration_policy_test.exs (renamed from test/web/activity_pub/mrf/activity_expiration_policy_test.exs)10
-rw-r--r--test/pleroma/web/activity_pub/mrf/anti_followbot_policy_test.exs (renamed from test/web/activity_pub/mrf/anti_followbot_policy_test.exs)4
-rw-r--r--test/pleroma/web/activity_pub/mrf/anti_link_spam_policy_test.exs (renamed from test/web/activity_pub/mrf/anti_link_spam_policy_test.exs)2
-rw-r--r--test/pleroma/web/activity_pub/mrf/ensure_re_prepended_test.exs (renamed from test/web/activity_pub/mrf/ensure_re_prepended_test.exs)4
-rw-r--r--test/pleroma/web/activity_pub/mrf/follow_bot_policy_test.exs126
-rw-r--r--test/pleroma/web/activity_pub/mrf/force_bot_unlisted_policy_test.exs60
-rw-r--r--test/pleroma/web/activity_pub/mrf/hashtag_policy_test.exs31
-rw-r--r--test/pleroma/web/activity_pub/mrf/hellthread_policy_test.exs (renamed from test/web/activity_pub/mrf/hellthread_policy_test.exs)14
-rw-r--r--test/pleroma/web/activity_pub/mrf/keyword_policy_test.exs (renamed from test/web/activity_pub/mrf/keyword_policy_test.exs)28
-rw-r--r--test/pleroma/web/activity_pub/mrf/media_proxy_warming_policy_test.exs (renamed from test/web/activity_pub/mrf/mediaproxy_warming_policy_test.exs)16
-rw-r--r--test/pleroma/web/activity_pub/mrf/mention_policy_test.exs (renamed from test/web/activity_pub/mrf/mention_policy_test.exs)14
-rw-r--r--test/pleroma/web/activity_pub/mrf/no_empty_policy_test.exs154
-rw-r--r--test/pleroma/web/activity_pub/mrf/no_placeholder_text_policy_test.exs (renamed from test/web/activity_pub/mrf/no_placeholder_text_policy_test.exs)4
-rw-r--r--test/pleroma/web/activity_pub/mrf/normalize_markup_test.exs (renamed from test/web/activity_pub/mrf/normalize_markup_test.exs)4
-rw-r--r--test/pleroma/web/activity_pub/mrf/object_age_policy_test.exs (renamed from test/web/activity_pub/mrf/object_age_policy_test.exs)24
-rw-r--r--test/pleroma/web/activity_pub/mrf/reject_non_public_test.exs (renamed from test/web/activity_pub/mrf/reject_non_public_test.exs)18
-rw-r--r--test/pleroma/web/activity_pub/mrf/simple_policy_test.exs (renamed from test/web/activity_pub/mrf/simple_policy_test.exs)124
-rw-r--r--test/pleroma/web/activity_pub/mrf/steal_emoji_policy_test.exs108
-rw-r--r--test/pleroma/web/activity_pub/mrf/subchain_policy_test.exs (renamed from test/web/activity_pub/mrf/subchain_policy_test.exs)6
-rw-r--r--test/pleroma/web/activity_pub/mrf/tag_policy_test.exs (renamed from test/web/activity_pub/mrf/tag_policy_test.exs)8
-rw-r--r--test/pleroma/web/activity_pub/mrf/user_allow_list_policy_test.exs (renamed from test/web/activity_pub/mrf/user_allowlist_policy_test.exs)6
-rw-r--r--test/pleroma/web/activity_pub/mrf/vocabulary_policy_test.exs (renamed from test/web/activity_pub/mrf/vocabulary_policy_test.exs)16
-rw-r--r--test/pleroma/web/activity_pub/mrf_test.exs (renamed from test/web/activity_pub/mrf/mrf_test.exs)45
-rw-r--r--test/pleroma/web/activity_pub/object_validators/accept_validation_test.exs (renamed from test/web/activity_pub/object_validators/accept_validation_test.exs)4
-rw-r--r--test/pleroma/web/activity_pub/object_validators/announce_validation_test.exs (renamed from test/web/activity_pub/object_validators/announce_validation_test.exs)32
-rw-r--r--test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs (renamed from test/web/activity_pub/object_validators/note_validator_test.exs)10
-rw-r--r--test/pleroma/web/activity_pub/object_validators/attachment_validator_test.exs (renamed from test/web/activity_pub/object_validators/attachment_validator_test.exs)75
-rw-r--r--test/pleroma/web/activity_pub/object_validators/block_validation_test.exs (renamed from test/web/activity_pub/object_validators/block_validation_test.exs)4
-rw-r--r--test/pleroma/web/activity_pub/object_validators/chat_validation_test.exs (renamed from test/web/activity_pub/object_validators/chat_validation_test.exs)14
-rw-r--r--test/pleroma/web/activity_pub/object_validators/delete_validation_test.exs (renamed from test/web/activity_pub/object_validators/delete_validation_test.exs)4
-rw-r--r--test/pleroma/web/activity_pub/object_validators/emoji_react_handling_test.exs (renamed from test/web/activity_pub/object_validators/emoji_react_validation_test.exs)4
-rw-r--r--test/pleroma/web/activity_pub/object_validators/follow_validation_test.exs (renamed from test/web/activity_pub/object_validators/follow_validation_test.exs)4
-rw-r--r--test/pleroma/web/activity_pub/object_validators/like_validation_test.exs (renamed from test/web/activity_pub/object_validators/like_validation_test.exs)39
-rw-r--r--test/pleroma/web/activity_pub/object_validators/reject_validation_test.exs (renamed from test/web/activity_pub/object_validators/reject_validation_test.exs)4
-rw-r--r--test/pleroma/web/activity_pub/object_validators/undo_handling_test.exs (renamed from test/web/activity_pub/object_validators/undo_validation_test.exs)4
-rw-r--r--test/pleroma/web/activity_pub/object_validators/update_handling_test.exs (renamed from test/web/activity_pub/object_validators/update_validation_test.exs)4
-rw-r--r--test/pleroma/web/activity_pub/pipeline_test.exs103
-rw-r--r--test/pleroma/web/activity_pub/publisher_test.exs (renamed from test/web/activity_pub/publisher_test.exs)83
-rw-r--r--test/pleroma/web/activity_pub/relay_test.exs (renamed from test/web/activity_pub/relay_test.exs)44
-rw-r--r--test/pleroma/web/activity_pub/side_effects/delete_test.exs147
-rw-r--r--test/pleroma/web/activity_pub/side_effects_test.exs (renamed from test/web/activity_pub/side_effects_test.exs)228
-rw-r--r--test/pleroma/web/activity_pub/transmogrifier/accept_handling_test.exs (renamed from test/web/activity_pub/transmogrifier/accept_handling_test.exs)16
-rw-r--r--test/pleroma/web/activity_pub/transmogrifier/add_remove_handling_test.exs178
-rw-r--r--test/pleroma/web/activity_pub/transmogrifier/announce_handling_test.exs (renamed from test/web/activity_pub/transmogrifier/announce_handling_test.exs)45
-rw-r--r--test/pleroma/web/activity_pub/transmogrifier/answer_handling_test.exs (renamed from test/web/activity_pub/transmogrifier/answer_handling_test.exs)15
-rw-r--r--test/pleroma/web/activity_pub/transmogrifier/article_handling_test.exs82
-rw-r--r--test/pleroma/web/activity_pub/transmogrifier/audio_handling_test.exs (renamed from test/web/activity_pub/transmogrifier/audio_handling_test.exs)18
-rw-r--r--test/pleroma/web/activity_pub/transmogrifier/block_handling_test.exs (renamed from test/web/activity_pub/transmogrifier/block_handling_test.exs)12
-rw-r--r--test/pleroma/web/activity_pub/transmogrifier/chat_message_test.exs (renamed from test/web/activity_pub/transmogrifier/chat_message_test.exs)16
-rw-r--r--test/pleroma/web/activity_pub/transmogrifier/delete_handling_test.exs (renamed from test/web/activity_pub/transmogrifier/delete_handling_test.exs)19
-rw-r--r--test/pleroma/web/activity_pub/transmogrifier/emoji_react_handling_test.exs (renamed from test/web/activity_pub/transmogrifier/emoji_react_handling_test.exs)10
-rw-r--r--test/pleroma/web/activity_pub/transmogrifier/event_handling_test.exs (renamed from test/web/activity_pub/transmogrifier/event_handling_test.exs)10
-rw-r--r--test/pleroma/web/activity_pub/transmogrifier/follow_handling_test.exs (renamed from test/web/activity_pub/transmogrifier/follow_handling_test.exs)26
-rw-r--r--test/pleroma/web/activity_pub/transmogrifier/like_handling_test.exs (renamed from test/web/activity_pub/transmogrifier/like_handling_test.exs)10
-rw-r--r--test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs710
-rw-r--r--test/pleroma/web/activity_pub/transmogrifier/page_handling_test.exs36
-rw-r--r--test/pleroma/web/activity_pub/transmogrifier/question_handling_test.exs (renamed from test/web/activity_pub/transmogrifier/question_handling_test.exs)24
-rw-r--r--test/pleroma/web/activity_pub/transmogrifier/reject_handling_test.exs (renamed from test/web/activity_pub/transmogrifier/reject_handling_test.exs)16
-rw-r--r--test/pleroma/web/activity_pub/transmogrifier/undo_handling_test.exs (renamed from test/web/activity_pub/transmogrifier/undo_handling_test.exs)28
-rw-r--r--test/pleroma/web/activity_pub/transmogrifier/user_update_handling_test.exs (renamed from test/web/activity_pub/transmogrifier/user_update_handling_test.exs)14
-rw-r--r--test/pleroma/web/activity_pub/transmogrifier/video_handling_test.exs122
-rw-r--r--test/pleroma/web/activity_pub/transmogrifier_test.exs567
-rw-r--r--test/pleroma/web/activity_pub/utils_test.exs (renamed from test/web/activity_pub/utils_test.exs)36
-rw-r--r--test/pleroma/web/activity_pub/views/object_view_test.exs (renamed from test/web/activity_pub/views/object_view_test.exs)8
-rw-r--r--test/pleroma/web/activity_pub/views/user_view_test.exs (renamed from test/web/activity_pub/views/user_view_test.exs)10
-rw-r--r--test/pleroma/web/activity_pub/visibility_test.exs (renamed from test/web/activity_pub/visibilty_test.exs)77
-rw-r--r--test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs968
-rw-r--r--test/pleroma/web/admin_api/controllers/chat_controller_test.exs218
-rw-r--r--test/pleroma/web/admin_api/controllers/config_controller_test.exs (renamed from test/web/admin_api/controllers/config_controller_test.exs)114
-rw-r--r--test/pleroma/web/admin_api/controllers/frontend_controller_test.exs155
-rw-r--r--test/pleroma/web/admin_api/controllers/instance_controller_test.exs80
-rw-r--r--test/pleroma/web/admin_api/controllers/instance_document_controller_test.exs105
-rw-r--r--test/pleroma/web/admin_api/controllers/invite_controller_test.exs (renamed from test/web/admin_api/controllers/invite_controller_test.exs)11
-rw-r--r--test/pleroma/web/admin_api/controllers/media_proxy_cache_controller_test.exs (renamed from test/web/admin_api/controllers/media_proxy_cache_controller_test.exs)42
-rw-r--r--test/pleroma/web/admin_api/controllers/o_auth_app_controller_test.exs (renamed from test/web/admin_api/controllers/oauth_app_controller_test.exs)9
-rw-r--r--test/pleroma/web/admin_api/controllers/relay_controller_test.exs (renamed from test/web/admin_api/controllers/relay_controller_test.exs)5
-rw-r--r--test/pleroma/web/admin_api/controllers/report_controller_test.exs (renamed from test/web/admin_api/controllers/report_controller_test.exs)32
-rw-r--r--test/pleroma/web/admin_api/controllers/status_controller_test.exs (renamed from test/web/admin_api/controllers/status_controller_test.exs)9
-rw-r--r--test/pleroma/web/admin_api/controllers/user_controller_test.exs967
-rw-r--r--test/pleroma/web/admin_api/search_test.exs (renamed from test/web/admin_api/search_test.exs)49
-rw-r--r--test/pleroma/web/admin_api/views/account_view_test.exs16
-rw-r--r--test/pleroma/web/admin_api/views/moderation_log_view_test.exs103
-rw-r--r--test/pleroma/web/admin_api/views/report_view_test.exs (renamed from test/web/admin_api/views/report_view_test.exs)29
-rw-r--r--test/pleroma/web/api_spec/schema_examples_test.exs (renamed from test/web/api_spec/schema_examples_test.exs)2
-rw-r--r--test/pleroma/web/auth/auth_controller_test.exs (renamed from test/web/auth/auth_test_controller_test.exs)4
-rw-r--r--test/pleroma/web/auth/authenticator_test.exs (renamed from test/web/auth/authenticator_test.exs)18
-rw-r--r--test/pleroma/web/auth/basic_auth_test.exs (renamed from test/web/auth/basic_auth_test.exs)6
-rw-r--r--test/pleroma/web/auth/pleroma_authenticator_test.exs (renamed from test/web/auth/pleroma_authenticator_test.exs)12
-rw-r--r--test/pleroma/web/auth/totp_authenticator_test.exs (renamed from test/web/auth/totp_authenticator_test.exs)6
-rw-r--r--test/pleroma/web/common_api/utils_test.exs (renamed from test/web/common_api/common_api_utils_test.exs)218
-rw-r--r--test/pleroma/web/common_api_test.exs (renamed from test/web/common_api/common_api_test.exs)400
-rw-r--r--test/pleroma/web/endpoint/metrics_exporter_test.exs69
-rw-r--r--test/pleroma/web/fallback_test.exs (renamed from test/web/fallback_test.exs)18
-rw-r--r--test/pleroma/web/federator_test.exs (renamed from test/web/federator_test.exs)16
-rw-r--r--test/pleroma/web/feed/tag_controller_test.exs (renamed from test/web/feed/tag_controller_test.exs)31
-rw-r--r--test/pleroma/web/feed/user_controller_test.exs (renamed from test/web/feed/user_controller_test.exs)137
-rw-r--r--test/pleroma/web/manifest_controller_test.exs17
-rw-r--r--test/pleroma/web/mastodon_api/controllers/account_controller_test.exs (renamed from test/web/mastodon_api/controllers/account_controller_test.exs)404
-rw-r--r--test/pleroma/web/mastodon_api/controllers/app_controller_test.exs (renamed from test/web/mastodon_api/controllers/app_controller_test.exs)44
-rw-r--r--test/pleroma/web/mastodon_api/controllers/conversation_controller_test.exs (renamed from test/web/mastodon_api/controllers/conversation_controller_test.exs)79
-rw-r--r--test/pleroma/web/mastodon_api/controllers/custom_emoji_controller_test.exs (renamed from test/web/mastodon_api/controllers/custom_emoji_controller_test.exs)2
-rw-r--r--test/pleroma/web/mastodon_api/controllers/directory_controller_test.exs46
-rw-r--r--test/pleroma/web/mastodon_api/controllers/domain_block_controller_test.exs (renamed from test/web/mastodon_api/controllers/domain_block_controller_test.exs)3
-rw-r--r--test/pleroma/web/mastodon_api/controllers/filter_controller_test.exs415
-rw-r--r--test/pleroma/web/mastodon_api/controllers/follow_request_controller_test.exs (renamed from test/web/mastodon_api/controllers/follow_request_controller_test.exs)10
-rw-r--r--test/pleroma/web/mastodon_api/controllers/instance_controller_test.exs (renamed from test/web/mastodon_api/controllers/instance_controller_test.exs)17
-rw-r--r--test/pleroma/web/mastodon_api/controllers/list_controller_test.exs (renamed from test/web/mastodon_api/controllers/list_controller_test.exs)19
-rw-r--r--test/pleroma/web/mastodon_api/controllers/marker_controller_test.exs (renamed from test/web/mastodon_api/controllers/marker_controller_test.exs)6
-rw-r--r--test/pleroma/web/mastodon_api/controllers/media_controller_test.exs (renamed from test/web/mastodon_api/controllers/media_controller_test.exs)65
-rw-r--r--test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs (renamed from test/web/mastodon_api/controllers/notification_controller_test.exs)72
-rw-r--r--test/pleroma/web/mastodon_api/controllers/poll_controller_test.exs (renamed from test/web/mastodon_api/controllers/poll_controller_test.exs)99
-rw-r--r--test/pleroma/web/mastodon_api/controllers/report_controller_test.exs (renamed from test/web/mastodon_api/controllers/report_controller_test.exs)4
-rw-r--r--test/pleroma/web/mastodon_api/controllers/scheduled_activity_controller_test.exs (renamed from test/web/mastodon_api/controllers/scheduled_activity_controller_test.exs)6
-rw-r--r--test/pleroma/web/mastodon_api/controllers/search_controller_test.exs (renamed from test/web/mastodon_api/controllers/search_controller_test.exs)78
-rw-r--r--test/pleroma/web/mastodon_api/controllers/status_controller_test.exs (renamed from test/web/mastodon_api/controllers/status_controller_test.exs)407
-rw-r--r--test/pleroma/web/mastodon_api/controllers/subscription_controller_test.exs (renamed from test/web/mastodon_api/controllers/subscription_controller_test.exs)132
-rw-r--r--test/pleroma/web/mastodon_api/controllers/suggestion_controller_test.exs83
-rw-r--r--test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs (renamed from test/web/mastodon_api/controllers/timeline_controller_test.exs)539
-rw-r--r--test/pleroma/web/mastodon_api/mastodon_api_controller_test.exs (renamed from test/web/mastodon_api/mastodon_api_controller_test.exs)4
-rw-r--r--test/pleroma/web/mastodon_api/mastodon_api_test.exs (renamed from test/web/mastodon_api/mastodon_api_test.exs)18
-rw-r--r--test/pleroma/web/mastodon_api/update_credentials_test.exs (renamed from test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs)49
-rw-r--r--test/pleroma/web/mastodon_api/views/account_view_test.exs (renamed from test/web/mastodon_api/views/account_view_test.exs)143
-rw-r--r--test/pleroma/web/mastodon_api/views/conversation_view_test.exs (renamed from test/web/mastodon_api/views/conversation_view_test.exs)6
-rw-r--r--test/pleroma/web/mastodon_api/views/list_view_test.exs (renamed from test/web/mastodon_api/views/list_view_test.exs)4
-rw-r--r--test/pleroma/web/mastodon_api/views/marker_view_test.exs (renamed from test/web/mastodon_api/views/marker_view_test.exs)4
-rw-r--r--test/pleroma/web/mastodon_api/views/notification_view_test.exs (renamed from test/web/mastodon_api/views/notification_view_test.exs)60
-rw-r--r--test/pleroma/web/mastodon_api/views/poll_view_test.exs (renamed from test/web/mastodon_api/views/poll_view_test.exs)19
-rw-r--r--test/pleroma/web/mastodon_api/views/scheduled_activity_view_test.exs (renamed from test/web/mastodon_api/views/scheduled_activity_view_test.exs)9
-rw-r--r--test/pleroma/web/mastodon_api/views/status_view_test.exs (renamed from test/web/mastodon_api/views/status_view_test.exs)83
-rw-r--r--test/pleroma/web/mastodon_api/views/subscription_view_test.exs (renamed from test/web/mastodon_api/views/subscription_view_test.exs)4
-rw-r--r--test/pleroma/web/mastodon_api/views/suggestion_view_test.exs34
-rw-r--r--test/pleroma/web/matrix_controller_test.exs (renamed from test/web/matrix_controller_test.exs)0
-rw-r--r--test/pleroma/web/media_proxy/invalidation/http_test.exs (renamed from test/web/media_proxy/invalidations/http_test.exs)8
-rw-r--r--test/pleroma/web/media_proxy/invalidation/script_test.exs52
-rw-r--r--test/pleroma/web/media_proxy/invalidation_test.exs (renamed from test/web/media_proxy/invalidation_test.exs)28
-rw-r--r--test/pleroma/web/media_proxy/media_proxy_controller_test.exs336
-rw-r--r--test/pleroma/web/media_proxy_test.exs (renamed from test/web/media_proxy/media_proxy_test.exs)74
-rw-r--r--test/pleroma/web/metadata/player_view_test.exs (renamed from test/web/metadata/player_view_test.exs)4
-rw-r--r--test/pleroma/web/metadata/providers/feed_test.exs (renamed from test/web/metadata/feed_test.exs)4
-rw-r--r--test/pleroma/web/metadata/providers/open_graph_test.exs190
-rw-r--r--test/pleroma/web/metadata/providers/rel_me_test.exs (renamed from test/web/metadata/rel_me_test.exs)4
-rw-r--r--test/pleroma/web/metadata/providers/restrict_indexing_test.exs (renamed from test/web/metadata/restrict_indexing_test.exs)10
-rw-r--r--test/pleroma/web/metadata/providers/twitter_card_test.exs (renamed from test/web/metadata/twitter_card_test.exs)41
-rw-r--r--test/pleroma/web/metadata/utils_test.exs (renamed from test/web/metadata/utils_test.exs)4
-rw-r--r--test/pleroma/web/mongoose_im_controller_test.exs (renamed from test/web/mongooseim/mongoose_im_controller_test.exs)14
-rw-r--r--test/pleroma/web/node_info_test.exs (renamed from test/web/node_info_test.exs)146
-rw-r--r--test/pleroma/web/o_auth/app_test.exs (renamed from test/web/oauth/app_test.exs)16
-rw-r--r--test/pleroma/web/o_auth/authorization_test.exs (renamed from test/web/oauth/authorization_test.exs)4
-rw-r--r--test/pleroma/web/o_auth/ldap_authorization_test.exs (renamed from test/web/oauth/ldap_authorization_test.exs)6
-rw-r--r--test/pleroma/web/o_auth/mfa_controller_test.exs (renamed from test/web/oauth/mfa_controller_test.exs)10
-rw-r--r--test/pleroma/web/o_auth/o_auth_controller_test.exs (renamed from test/web/oauth/oauth_controller_test.exs)155
-rw-r--r--test/pleroma/web/o_auth/token/utils_test.exs (renamed from test/web/oauth/token/utils_test.exs)4
-rw-r--r--test/pleroma/web/o_auth/token_test.exs (renamed from test/web/oauth/token_test.exs)17
-rw-r--r--test/pleroma/web/o_status/o_status_controller_test.exs (renamed from test/web/ostatus/ostatus_controller_test.exs)104
-rw-r--r--test/pleroma/web/pleroma_api/controllers/account_controller_test.exs (renamed from test/web/pleroma_api/controllers/account_controller_test.exs)10
-rw-r--r--test/pleroma/web/pleroma_api/controllers/app_controller_test.exs53
-rw-r--r--test/pleroma/web/pleroma_api/controllers/backup_controller_test.exs85
-rw-r--r--test/pleroma/web/pleroma_api/controllers/chat_controller_test.exs (renamed from test/web/pleroma_api/controllers/chat_controller_test.exs)313
-rw-r--r--test/pleroma/web/pleroma_api/controllers/conversation_controller_test.exs (renamed from test/web/pleroma_api/controllers/conversation_controller_test.exs)10
-rw-r--r--test/pleroma/web/pleroma_api/controllers/emoji_file_controller_test.exs381
-rw-r--r--test/pleroma/web/pleroma_api/controllers/emoji_pack_controller_test.exs (renamed from test/web/pleroma_api/controllers/emoji_pack_controller_test.exs)451
-rw-r--r--test/pleroma/web/pleroma_api/controllers/emoji_reaction_controller_test.exs (renamed from test/web/pleroma_api/controllers/emoji_reaction_controller_test.exs)44
-rw-r--r--test/pleroma/web/pleroma_api/controllers/instances_controller_test.exs38
-rw-r--r--test/pleroma/web/pleroma_api/controllers/mascot_controller_test.exs (renamed from test/web/pleroma_api/controllers/mascot_controller_test.exs)10
-rw-r--r--test/pleroma/web/pleroma_api/controllers/notification_controller_test.exs (renamed from test/web/pleroma_api/controllers/notification_controller_test.exs)4
-rw-r--r--test/pleroma/web/pleroma_api/controllers/report_controller_test.exs80
-rw-r--r--test/pleroma/web/pleroma_api/controllers/scrobble_controller_test.exs (renamed from test/web/pleroma_api/controllers/scrobble_controller_test.exs)4
-rw-r--r--test/pleroma/web/pleroma_api/controllers/two_factor_authentication_controller_test.exs (renamed from test/web/pleroma_api/controllers/two_factor_authentication_controller_test.exs)6
-rw-r--r--test/pleroma/web/pleroma_api/controllers/user_import_controller_test.exs235
-rw-r--r--test/pleroma/web/pleroma_api/views/app_view_test.exs21
-rw-r--r--test/pleroma/web/pleroma_api/views/backup_view_test.exs18
-rw-r--r--test/pleroma/web/pleroma_api/views/chat_message_reference_view_test.exs (renamed from test/web/pleroma_api/views/chat/message_reference_view_test.exs)17
-rw-r--r--test/pleroma/web/pleroma_api/views/chat_view_test.exs (renamed from test/web/pleroma_api/views/chat_view_test.exs)6
-rw-r--r--test/pleroma/web/pleroma_api/views/scrobble_view_test.exs (renamed from test/web/pleroma_api/views/scrobble_view_test.exs)6
-rw-r--r--test/pleroma/web/plugs/admin_secret_authentication_plug_test.exs (renamed from test/plugs/admin_secret_authentication_plug_test.exs)20
-rw-r--r--test/pleroma/web/plugs/authentication_plug_test.exs (renamed from test/plugs/authentication_plug_test.exs)17
-rw-r--r--test/pleroma/web/plugs/basic_auth_decoder_plug_test.exs (renamed from test/plugs/basic_auth_decoder_plug_test.exs)6
-rw-r--r--test/pleroma/web/plugs/cache_control_test.exs (renamed from test/plugs/cache_control_test.exs)6
-rw-r--r--test/pleroma/web/plugs/cache_test.exs (renamed from test/plugs/cache_test.exs)14
-rw-r--r--test/pleroma/web/plugs/digest_plug_test.exs48
-rw-r--r--test/pleroma/web/plugs/ensure_authenticated_plug_test.exs (renamed from test/plugs/ensure_authenticated_plug_test.exs)6
-rw-r--r--test/pleroma/web/plugs/ensure_public_or_authenticated_plug_test.exs (renamed from test/plugs/ensure_public_or_authenticated_plug_test.exs)15
-rw-r--r--test/pleroma/web/plugs/ensure_staff_privileged_plug_test.exs60
-rw-r--r--test/pleroma/web/plugs/ensure_user_token_assigns_plug_test.exs69
-rw-r--r--test/pleroma/web/plugs/federating_plug_test.exs (renamed from test/web/plugs/federating_plug_test.exs)12
-rw-r--r--test/pleroma/web/plugs/frontend_static_plug_test.exs110
-rw-r--r--test/pleroma/web/plugs/http_security_plug_test.exs (renamed from test/plugs/http_security_plug_test.exs)18
-rw-r--r--test/pleroma/web/plugs/http_signature_plug_test.exs (renamed from test/plugs/http_signature_plug_test.exs)8
-rw-r--r--test/pleroma/web/plugs/idempotency_plug_test.exs (renamed from test/plugs/idempotency_plug_test.exs)9
-rw-r--r--test/pleroma/web/plugs/instance_static_test.exs (renamed from test/plugs/instance_static_test.exs)4
-rw-r--r--test/pleroma/web/plugs/mapped_signature_to_identity_plug_test.exs (renamed from test/plugs/mapped_identity_to_signature_plug_test.exs)2
-rw-r--r--test/pleroma/web/plugs/o_auth_plug_test.exs128
-rw-r--r--test/pleroma/web/plugs/o_auth_scopes_plug_test.exs (renamed from test/plugs/oauth_scopes_plug_test.exs)46
-rw-r--r--test/pleroma/web/plugs/plug_helper_test.exs (renamed from test/web/plugs/plug_test.exs)10
-rw-r--r--test/pleroma/web/plugs/rate_limiter_test.exs (renamed from test/plugs/rate_limiter_test.exs)49
-rw-r--r--test/pleroma/web/plugs/remote_ip_test.exs108
-rw-r--r--test/pleroma/web/plugs/set_format_plug_test.exs (renamed from test/plugs/set_format_plug_test.exs)6
-rw-r--r--test/pleroma/web/plugs/set_locale_plug_test.exs (renamed from test/plugs/set_locale_plug_test.exs)6
-rw-r--r--test/pleroma/web/plugs/set_user_session_id_plug_test.exs (renamed from test/plugs/set_user_session_id_plug_test.exs)26
-rw-r--r--test/pleroma/web/plugs/uploaded_media_plug_test.exs (renamed from test/plugs/uploaded_media_plug_test.exs)8
-rw-r--r--test/pleroma/web/plugs/user_enabled_plug_test.exs (renamed from test/plugs/user_enabled_plug_test.exs)14
-rw-r--r--test/pleroma/web/plugs/user_fetcher_plug_test.exs (renamed from test/plugs/user_fetcher_plug_test.exs)6
-rw-r--r--test/pleroma/web/plugs/user_is_admin_plug_test.exs (renamed from test/plugs/user_is_admin_plug_test.exs)6
-rw-r--r--test/pleroma/web/plugs/user_is_staff_plug_test.exs47
-rw-r--r--test/pleroma/web/plugs/user_tracking_plug_test.exs58
-rw-r--r--test/pleroma/web/preload/providers/instance_test.exs (renamed from test/web/preload/instance_test.exs)10
-rw-r--r--test/pleroma/web/preload/providers/timeline_test.exs (renamed from test/web/preload/timeline_test.exs)2
-rw-r--r--test/pleroma/web/preload/providers/user_test.exs (renamed from test/web/preload/user_test.exs)4
-rw-r--r--test/pleroma/web/push/impl_test.exs (renamed from test/web/push/impl_test.exs)52
-rw-r--r--test/pleroma/web/rel_me_test.exs (renamed from test/web/rel_me_test.exs)4
-rw-r--r--test/pleroma/web/rich_media/helpers_test.exs (renamed from test/web/rich_media/helpers_test.exs)47
-rw-r--r--test/pleroma/web/rich_media/parser/ttl/aws_signed_url_test.exs (renamed from test/web/rich_media/aws_signed_url_test.exs)11
-rw-r--r--test/pleroma/web/rich_media/parser_test.exs (renamed from test/web/rich_media/parser_test.exs)31
-rw-r--r--test/pleroma/web/rich_media/parsers/twitter_card_test.exs (renamed from test/web/rich_media/parsers/twitter_card_test.exs)2
-rw-r--r--test/pleroma/web/shout_channel_test.exs (renamed from test/web/chat_channel_test.exs)14
-rw-r--r--test/pleroma/web/static_fe/static_fe_controller_test.exs (renamed from test/web/static_fe/static_fe_controller_test.exs)64
-rw-r--r--test/pleroma/web/streamer_test.exs (renamed from test/web/streamer/streamer_test.exs)486
-rw-r--r--test/pleroma/web/twitter_api/controller_test.exs (renamed from test/web/twitter_api/twitter_api_controller_test.exs)61
-rw-r--r--test/pleroma/web/twitter_api/password_controller_test.exs213
-rw-r--r--test/pleroma/web/twitter_api/remote_follow_controller_test.exs (renamed from test/web/twitter_api/remote_follow_controller_test.exs)93
-rw-r--r--test/pleroma/web/twitter_api/twitter_api_test.exs (renamed from test/web/twitter_api/twitter_api_test.exs)44
-rw-r--r--test/pleroma/web/twitter_api/util_controller_test.exs (renamed from test/web/twitter_api/util_controller_test.exs)414
-rw-r--r--test/pleroma/web/uploader_controller_test.exs (renamed from test/web/uploader_controller_test.exs)4
-rw-r--r--test/pleroma/web/views/error_view_test.exs (renamed from test/web/views/error_view_test.exs)2
-rw-r--r--test/pleroma/web/web_finger/web_finger_controller_test.exs (renamed from test/web/web_finger/web_finger_controller_test.exs)30
-rw-r--r--test/pleroma/web/web_finger_test.exs (renamed from test/web/web_finger/web_finger_test.exs)76
-rw-r--r--test/pleroma/workers/cron/digest_emails_worker_test.exs (renamed from test/workers/cron/digest_emails_worker_test.exs)4
-rw-r--r--test/pleroma/workers/cron/new_users_digest_worker_test.exs (renamed from test/workers/cron/new_users_digest_worker_test.exs)6
-rw-r--r--test/pleroma/workers/purge_expired_activity_test.exs59
-rw-r--r--test/pleroma/workers/purge_expired_filter_test.exs30
-rw-r--r--test/pleroma/workers/purge_expired_token_test.exs51
-rw-r--r--test/pleroma/workers/scheduled_activity_worker_test.exs (renamed from test/workers/scheduled_activity_worker_test.exs)23
-rw-r--r--test/pleroma/xml_builder_test.exs (renamed from test/xml_builder_test.exs)4
-rw-r--r--test/plugs/ensure_user_key_plug_test.exs29
-rw-r--r--test/plugs/frontend_static_test.exs57
-rw-r--r--test/plugs/legacy_authentication_plug_test.exs82
-rw-r--r--test/plugs/oauth_plug_test.exs80
-rw-r--r--test/plugs/remote_ip_test.exs75
-rw-r--r--test/plugs/session_authentication_plug_test.exs63
-rw-r--r--test/support/api_spec_helpers.ex6
-rw-r--r--test/support/builders/user_builder.ex2
-rw-r--r--test/support/cachex_proxy.ex40
-rw-r--r--test/support/captcha/mock.ex (renamed from test/support/captcha_mock.ex)2
-rw-r--r--test/support/channel_case.ex14
-rw-r--r--test/support/conn_case.ex59
-rw-r--r--test/support/data_case.ex90
-rw-r--r--test/support/factory.ex227
-rw-r--r--test/support/helpers.ex25
-rw-r--r--test/support/http_request_mock.ex474
-rw-r--r--test/support/mocks.ex30
-rw-r--r--test/support/mrf_module_mock.ex4
-rw-r--r--test/support/null_cache.ex49
-rw-r--r--test/support/oban_helpers.ex5
-rw-r--r--test/support/web_push_http_client_mock.ex23
-rw-r--r--test/support/websocket_client.ex2
-rw-r--r--test/tasks/config_test.exs176
-rw-r--r--test/tasks/email_test.exs54
-rw-r--r--test/test_helper.exs4
-rw-r--r--test/web/activity_pub/mrf/steal_emoji_policy_test.exs68
-rw-r--r--test/web/activity_pub/pipeline_test.exs179
-rw-r--r--test/web/activity_pub/transmogrifier_test.exs1379
-rw-r--r--test/web/admin_api/controllers/admin_api_controller_test.exs1979
-rw-r--r--test/web/masto_fe_controller_test.exs85
-rw-r--r--test/web/mastodon_api/controllers/auth_controller_test.exs162
-rw-r--r--test/web/mastodon_api/controllers/filter_controller_test.exs152
-rw-r--r--test/web/mastodon_api/controllers/suggestion_controller_test.exs18
-rw-r--r--test/web/media_proxy/invalidations/script_test.exs26
-rw-r--r--test/web/media_proxy/media_proxy_controller_test.exs121
-rw-r--r--test/web/metadata/metadata_test.exs25
-rw-r--r--test/web/metadata/opengraph_test.exs96
-rw-r--r--test/web/twitter_api/password_controller_test.exs81
-rw-r--r--test/workers/cron/clear_oauth_token_worker_test.exs22
-rw-r--r--test/workers/cron/purge_expired_activities_worker_test.exs84
481 files changed, 20582 insertions, 16551 deletions
diff --git a/test/activity_expiration_test.exs b/test/activity_expiration_test.exs
deleted file mode 100644
index f86d79826..000000000
--- a/test/activity_expiration_test.exs
+++ /dev/null
@@ -1,55 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.ActivityExpirationTest do
- use Pleroma.DataCase
- alias Pleroma.ActivityExpiration
- import Pleroma.Factory
-
- setup do: clear_config([ActivityExpiration, :enabled])
-
- test "finds activities due to be deleted only" do
- activity = insert(:note_activity)
-
- expiration_due =
- insert(:expiration_in_the_past, %{activity_id: activity.id}) |> Repo.preload(:activity)
-
- activity2 = insert(:note_activity)
- insert(:expiration_in_the_future, %{activity_id: activity2.id})
-
- expirations = ActivityExpiration.due_expirations()
-
- assert length(expirations) == 1
- assert hd(expirations) == expiration_due
- end
-
- test "denies expirations that don't live long enough" do
- activity = insert(:note_activity)
- now = NaiveDateTime.utc_now()
- assert {:error, _} = ActivityExpiration.create(activity, now)
- end
-
- test "deletes an expiration activity" do
- Pleroma.Config.put([ActivityExpiration, :enabled], true)
- activity = insert(:note_activity)
-
- naive_datetime =
- NaiveDateTime.add(
- NaiveDateTime.utc_now(),
- -:timer.minutes(2),
- :millisecond
- )
-
- expiration =
- insert(
- :expiration_in_the_past,
- %{activity_id: activity.id, scheduled_at: naive_datetime}
- )
-
- Pleroma.Workers.Cron.PurgeExpiredActivitiesWorker.perform(%Oban.Job{})
-
- refute Pleroma.Repo.get(Pleroma.Activity, activity.id)
- refute Pleroma.Repo.get(Pleroma.ActivityExpiration, expiration.id)
- end
-end
diff --git a/test/config/deprecation_warnings_test.exs b/test/config/deprecation_warnings_test.exs
deleted file mode 100644
index 555661a71..000000000
--- a/test/config/deprecation_warnings_test.exs
+++ /dev/null
@@ -1,65 +0,0 @@
-defmodule Pleroma.Config.DeprecationWarningsTest do
- use ExUnit.Case, async: true
- use Pleroma.Tests.Helpers
-
- import ExUnit.CaptureLog
-
- test "check_old_mrf_config/0" do
- clear_config([:instance, :rewrite_policy], Pleroma.Web.ActivityPub.MRF.NoOpPolicy)
- clear_config([:instance, :mrf_transparency], true)
- clear_config([:instance, :mrf_transparency_exclusions], [])
-
- assert capture_log(fn -> Pleroma.Config.DeprecationWarnings.check_old_mrf_config() end) =~
- """
- !!!DEPRECATION WARNING!!!
- Your config is using old namespaces for MRF configuration. They should work for now, but you are advised to change to new namespaces to prevent possible issues later:
-
- * `config :pleroma, :instance, rewrite_policy` is now `config :pleroma, :mrf, policies`
- * `config :pleroma, :instance, mrf_transparency` is now `config :pleroma, :mrf, transparency`
- * `config :pleroma, :instance, mrf_transparency_exclusions` is now `config :pleroma, :mrf, transparency_exclusions`
- """
- end
-
- test "move_namespace_and_warn/2" do
- old_group1 = [:group, :key]
- old_group2 = [:group, :key2]
- old_group3 = [:group, :key3]
-
- new_group1 = [:another_group, :key4]
- new_group2 = [:another_group, :key5]
- new_group3 = [:another_group, :key6]
-
- clear_config(old_group1, 1)
- clear_config(old_group2, 2)
- clear_config(old_group3, 3)
-
- clear_config(new_group1)
- clear_config(new_group2)
- clear_config(new_group3)
-
- config_map = [
- {old_group1, new_group1, "\n error :key"},
- {old_group2, new_group2, "\n error :key2"},
- {old_group3, new_group3, "\n error :key3"}
- ]
-
- assert capture_log(fn ->
- Pleroma.Config.DeprecationWarnings.move_namespace_and_warn(
- config_map,
- "Warning preface"
- )
- end) =~ "Warning preface\n error :key\n error :key2\n error :key3"
-
- assert Pleroma.Config.get(new_group1) == 1
- assert Pleroma.Config.get(new_group2) == 2
- assert Pleroma.Config.get(new_group3) == 3
- end
-
- test "check_media_proxy_whitelist_config/0" do
- clear_config([:media_proxy, :whitelist], ["https://example.com", "example2.com"])
-
- assert capture_log(fn ->
- Pleroma.Config.DeprecationWarnings.check_media_proxy_whitelist_config()
- end) =~ "Your config is using old format (only domain) for MediaProxy whitelist option"
- end
-end
diff --git a/test/config/emoji.txt b/test/config/emoji.txt
new file mode 100644
index 000000000..14dd0c332
--- /dev/null
+++ b/test/config/emoji.txt
@@ -0,0 +1 @@
+external_emoji, https://example.com/emoji.png
diff --git a/test/credo/check/consistency/file_location.ex b/test/credo/check/consistency/file_location.ex
new file mode 100644
index 000000000..abc55fffc
--- /dev/null
+++ b/test/credo/check/consistency/file_location.ex
@@ -0,0 +1,166 @@
+# Pleroma: A lightweight social networking server
+# Originally taken from
+# https://github.com/VeryBigThings/elixir_common/blob/master/lib/vbt/credo/check/consistency/file_location.ex
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Credo.Check.Consistency.FileLocation do
+ @moduledoc false
+
+ # credo:disable-for-this-file Credo.Check.Readability.Specs
+
+ @checkdoc """
+ File location should follow the namespace hierarchy of the module it defines.
+
+ Examples:
+
+ - `lib/my_system.ex` should define the `MySystem` module
+ - `lib/my_system/accounts.ex` should define the `MySystem.Accounts` module
+ """
+ @explanation [warning: @checkdoc]
+
+ @special_namespaces [
+ "controllers",
+ "views",
+ "operations",
+ "channels"
+ ]
+
+ # `use Credo.Check` required that module attributes are already defined, so we need
+ # to place these attributes
+ # before use/alias expressions.
+ # credo:disable-for-next-line VBT.Credo.Check.Consistency.ModuleLayout
+ use Credo.Check, category: :warning, base_priority: :high
+
+ alias Credo.Code
+
+ def run(source_file, params \\ []) do
+ case verify(source_file, params) do
+ :ok ->
+ []
+
+ {:error, module, expected_file} ->
+ error(IssueMeta.for(source_file, params), module, expected_file)
+ end
+ end
+
+ defp verify(source_file, params) do
+ source_file.filename
+ |> Path.relative_to_cwd()
+ |> verify(Code.ast(source_file), params)
+ end
+
+ @doc false
+ def verify(relative_path, ast, params) do
+ if verify_path?(relative_path, params),
+ do: ast |> main_module() |> verify_module(relative_path, params),
+ else: :ok
+ end
+
+ defp verify_path?(relative_path, params) do
+ case Path.split(relative_path) do
+ ["lib" | _] -> not exclude?(relative_path, params)
+ ["test", "support" | _] -> false
+ ["test", "test_helper.exs"] -> false
+ ["test" | _] -> not exclude?(relative_path, params)
+ _ -> false
+ end
+ end
+
+ defp exclude?(relative_path, params) do
+ params
+ |> Keyword.get(:exclude, [])
+ |> Enum.any?(&String.starts_with?(relative_path, &1))
+ end
+
+ defp main_module(ast) do
+ {_ast, modules} = Macro.prewalk(ast, [], &traverse/2)
+ Enum.at(modules, -1)
+ end
+
+ defp traverse({:defmodule, _meta, args}, modules) do
+ [{:__aliases__, _, name_parts}, _module_body] = args
+ {args, [Module.concat(name_parts) | modules]}
+ end
+
+ defp traverse(ast, state), do: {ast, state}
+
+ # empty file - shouldn't really happen, but we'll let it through
+ defp verify_module(nil, _relative_path, _params), do: :ok
+
+ defp verify_module(main_module, relative_path, params) do
+ parsed_path = parsed_path(relative_path, params)
+
+ expected_file =
+ expected_file_base(parsed_path.root, main_module) <>
+ Path.extname(parsed_path.allowed)
+
+ cond do
+ expected_file == parsed_path.allowed ->
+ :ok
+
+ special_namespaces?(parsed_path.allowed) ->
+ original_path = parsed_path.allowed
+
+ namespace =
+ Enum.find(@special_namespaces, original_path, fn namespace ->
+ String.contains?(original_path, namespace)
+ end)
+
+ allowed = String.replace(original_path, "/" <> namespace, "")
+
+ if expected_file == allowed,
+ do: :ok,
+ else: {:error, main_module, expected_file}
+
+ true ->
+ {:error, main_module, expected_file}
+ end
+ end
+
+ defp special_namespaces?(path), do: String.contains?(path, @special_namespaces)
+
+ defp parsed_path(relative_path, params) do
+ parts = Path.split(relative_path)
+
+ allowed =
+ Keyword.get(params, :ignore_folder_namespace, %{})
+ |> Stream.flat_map(fn {root, folders} -> Enum.map(folders, &Path.join([root, &1])) end)
+ |> Stream.map(&Path.split/1)
+ |> Enum.find(&List.starts_with?(parts, &1))
+ |> case do
+ nil ->
+ relative_path
+
+ ignore_parts ->
+ Stream.drop(ignore_parts, -1)
+ |> Enum.concat(Stream.drop(parts, length(ignore_parts)))
+ |> Path.join()
+ end
+
+ %{root: hd(parts), allowed: allowed}
+ end
+
+ defp expected_file_base(root_folder, module) do
+ {parent_namespace, module_name} = module |> Module.split() |> Enum.split(-1)
+
+ relative_path =
+ if parent_namespace == [],
+ do: "",
+ else: parent_namespace |> Module.concat() |> Macro.underscore()
+
+ file_name = module_name |> Module.concat() |> Macro.underscore()
+
+ Path.join([root_folder, relative_path, file_name])
+ end
+
+ defp error(issue_meta, module, expected_file) do
+ format_issue(issue_meta,
+ message:
+ "Mismatch between file name and main module #{inspect(module)}. " <>
+ "Expected file path to be #{expected_file}. " <>
+ "Either move the file or rename the module.",
+ line_no: 1
+ )
+ end
+end
diff --git a/test/earmark_renderer_test.exs b/test/earmark_renderer_test.exs
deleted file mode 100644
index 220d97d16..000000000
--- a/test/earmark_renderer_test.exs
+++ /dev/null
@@ -1,79 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.EarmarkRendererTest do
- use ExUnit.Case
-
- test "Paragraph" do
- code = ~s[Hello\n\nWorld!]
- result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer})
- assert result == "<p>Hello</p><p>World!</p>"
- end
-
- test "raw HTML" do
- code = ~s[<a href="http://example.org/">OwO</a><!-- what's this?-->]
- result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer})
- assert result == "<p>#{code}</p>"
- end
-
- test "rulers" do
- code = ~s[before\n\n-----\n\nafter]
- result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer})
- assert result == "<p>before</p><hr /><p>after</p>"
- end
-
- test "headings" do
- code = ~s[# h1\n## h2\n### h3\n]
- result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer})
- assert result == ~s[<h1>h1</h1><h2>h2</h2><h3>h3</h3>]
- end
-
- test "blockquote" do
- code = ~s[> whoms't are you quoting?]
- result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer})
- assert result == "<blockquote><p>whoms’t are you quoting?</p></blockquote>"
- end
-
- test "code" do
- code = ~s[`mix`]
- result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer})
- assert result == ~s[<p><code class="inline">mix</code></p>]
-
- code = ~s[``mix``]
- result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer})
- assert result == ~s[<p><code class="inline">mix</code></p>]
-
- code = ~s[```\nputs "Hello World"\n```]
- result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer})
- assert result == ~s[<pre><code class="">puts &quot;Hello World&quot;</code></pre>]
- end
-
- test "lists" do
- code = ~s[- one\n- two\n- three\n- four]
- result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer})
- assert result == "<ul><li>one</li><li>two</li><li>three</li><li>four</li></ul>"
-
- code = ~s[1. one\n2. two\n3. three\n4. four\n]
- result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer})
- assert result == "<ol><li>one</li><li>two</li><li>three</li><li>four</li></ol>"
- end
-
- test "delegated renderers" do
- code = ~s[a<br/>b]
- result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer})
- assert result == "<p>#{code}</p>"
-
- code = ~s[*aaaa~*]
- result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer})
- assert result == ~s[<p><em>aaaa~</em></p>]
-
- code = ~s[**aaaa~**]
- result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer})
- assert result == ~s[<p><strong>aaaa~</strong></p>]
-
- # strikethrought
- code = ~s[<del>aaaa~</del>]
- result = Earmark.as_html!(code, %Earmark.Options{renderer: Pleroma.EarmarkRenderer})
- assert result == ~s[<p><del>aaaa~</del></p>]
- end
-end
diff --git a/test/filter_test.exs b/test/filter_test.exs
deleted file mode 100644
index 0a5c4426a..000000000
--- a/test/filter_test.exs
+++ /dev/null
@@ -1,158 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.FilterTest do
- use Pleroma.DataCase
-
- import Pleroma.Factory
-
- alias Pleroma.Filter
- alias Pleroma.Repo
-
- describe "creating filters" do
- test "creating one filter" do
- user = insert(:user)
-
- query = %Filter{
- user_id: user.id,
- filter_id: 42,
- phrase: "knights",
- context: ["home"]
- }
-
- {:ok, %Filter{} = filter} = Filter.create(query)
- result = Filter.get(filter.filter_id, user)
- assert query.phrase == result.phrase
- end
-
- test "creating one filter without a pre-defined filter_id" do
- user = insert(:user)
-
- query = %Filter{
- user_id: user.id,
- phrase: "knights",
- context: ["home"]
- }
-
- {:ok, %Filter{} = filter} = Filter.create(query)
- # Should start at 1
- assert filter.filter_id == 1
- end
-
- test "creating additional filters uses previous highest filter_id + 1" do
- user = insert(:user)
-
- query_one = %Filter{
- user_id: user.id,
- filter_id: 42,
- phrase: "knights",
- context: ["home"]
- }
-
- {:ok, %Filter{} = filter_one} = Filter.create(query_one)
-
- query_two = %Filter{
- user_id: user.id,
- # No filter_id
- phrase: "who",
- context: ["home"]
- }
-
- {:ok, %Filter{} = filter_two} = Filter.create(query_two)
- assert filter_two.filter_id == filter_one.filter_id + 1
- end
-
- test "filter_id is unique per user" do
- user_one = insert(:user)
- user_two = insert(:user)
-
- query_one = %Filter{
- user_id: user_one.id,
- phrase: "knights",
- context: ["home"]
- }
-
- {:ok, %Filter{} = filter_one} = Filter.create(query_one)
-
- query_two = %Filter{
- user_id: user_two.id,
- phrase: "who",
- context: ["home"]
- }
-
- {:ok, %Filter{} = filter_two} = Filter.create(query_two)
-
- assert filter_one.filter_id == 1
- assert filter_two.filter_id == 1
-
- result_one = Filter.get(filter_one.filter_id, user_one)
- assert result_one.phrase == filter_one.phrase
-
- result_two = Filter.get(filter_two.filter_id, user_two)
- assert result_two.phrase == filter_two.phrase
- end
- end
-
- test "deleting a filter" do
- user = insert(:user)
-
- query = %Filter{
- user_id: user.id,
- filter_id: 0,
- phrase: "knights",
- context: ["home"]
- }
-
- {:ok, _filter} = Filter.create(query)
- {:ok, filter} = Filter.delete(query)
- assert is_nil(Repo.get(Filter, filter.filter_id))
- end
-
- test "getting all filters by an user" do
- user = insert(:user)
-
- query_one = %Filter{
- user_id: user.id,
- filter_id: 1,
- phrase: "knights",
- context: ["home"]
- }
-
- query_two = %Filter{
- user_id: user.id,
- filter_id: 2,
- phrase: "who",
- context: ["home"]
- }
-
- {:ok, filter_one} = Filter.create(query_one)
- {:ok, filter_two} = Filter.create(query_two)
- filters = Filter.get_filters(user)
- assert filter_one in filters
- assert filter_two in filters
- end
-
- test "updating a filter" do
- user = insert(:user)
-
- query_one = %Filter{
- user_id: user.id,
- filter_id: 1,
- phrase: "knights",
- context: ["home"]
- }
-
- changes = %{
- phrase: "who",
- context: ["home", "timeline"]
- }
-
- {:ok, filter_one} = Filter.create(query_one)
- {:ok, filter_two} = Filter.update(filter_one, changes)
-
- assert filter_one != filter_two
- assert filter_two.phrase == changes.phrase
- assert filter_two.context == changes.context
- end
-end
diff --git a/test/fixtures/23211.atom b/test/fixtures/23211.atom
deleted file mode 100644
index d5d111baa..000000000
--- a/test/fixtures/23211.atom
+++ /dev/null
@@ -1,508 +0,0 @@
-<?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>
diff --git a/test/fixtures/activitypub-client-post-activity.json b/test/fixtures/activitypub-client-post-activity.json
index c985e072b..e592081bc 100644
--- a/test/fixtures/activitypub-client-post-activity.json
+++ b/test/fixtures/activitypub-client-post-activity.json
@@ -3,6 +3,7 @@
"type": "Create",
"object": {
"type": "Note",
+ "to": ["https://www.w3.org/ns/activitystreams#Public"],
"content": "It's a note"
},
"to": ["https://www.w3.org/ns/activitystreams#Public"]
diff --git a/test/fixtures/bridgy/actor.json b/test/fixtures/bridgy/actor.json
new file mode 100644
index 000000000..5b2d8982b
--- /dev/null
+++ b/test/fixtures/bridgy/actor.json
@@ -0,0 +1,80 @@
+{
+ "id": "https://fed.brid.gy/jk.nipponalba.scot",
+ "url": "https://fed.brid.gy/r/https://jk.nipponalba.scot",
+ "urls": [
+ {
+ "value": "https://jk.nipponalba.scot"
+ },
+ {
+ "value": "https://social.nipponalba.scot/jk"
+ },
+ {
+ "value": "https://px.nipponalba.scot/jk"
+ }
+ ],
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "type": "Person",
+ "name": "J K 🇯🇵🏴󠁧󠁢󠁳󠁣󠁴󠁿",
+ "image": [
+ {
+ "url": "https://jk.nipponalba.scot/images/profile.jpg",
+ "type": "Image",
+ "name": "profile picture"
+ }
+ ],
+ "tag": [
+ {
+ "type": "Tag",
+ "name": "Craft Beer"
+ },
+ {
+ "type": "Tag",
+ "name": "Single Malt Whisky"
+ },
+ {
+ "type": "Tag",
+ "name": "Homebrewing"
+ },
+ {
+ "type": "Tag",
+ "name": "Scottish Politics"
+ },
+ {
+ "type": "Tag",
+ "name": "Scottish History"
+ },
+ {
+ "type": "Tag",
+ "name": "Japanese History"
+ },
+ {
+ "type": "Tag",
+ "name": "Tech"
+ },
+ {
+ "type": "Tag",
+ "name": "Veganism"
+ },
+ {
+ "type": "Tag",
+ "name": "Cooking"
+ }
+ ],
+ "icon": [
+ {
+ "url": "https://jk.nipponalba.scot/images/profile.jpg",
+ "type": "Image",
+ "name": "profile picture"
+ }
+ ],
+ "preferredUsername": "jk.nipponalba.scot",
+ "summary": "",
+ "publicKey": {
+ "id": "jk.nipponalba.scot",
+ "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdarxwzxnNbJ2hneWOYHkYJowk\npyigQtxlUd0VjgSQHwxU9kWqfbrHBVADyTtcqi/4dAzQd3UnCI1TPNnn4LPZY9PW\noiWd3Zl1/EfLFxO7LU9GS7fcSLQkyj5JNhSlN3I8QPudZbybrgRDVZYooDe1D+52\n5KLGqC2ajrIVOiDRTQIDAQAB\n-----END PUBLIC KEY-----"
+ },
+ "inbox": "https://fed.brid.gy/jk.nipponalba.scot/inbox",
+ "outbox": "https://fed.brid.gy/jk.nipponalba.scot/outbox",
+ "following": "https://fed.brid.gy/jk.nipponalba.scot/following",
+ "followers": "https://fed.brid.gy/jk.nipponalba.scot/followers"
+}
diff --git a/test/fixtures/config/temp.exported_from_db.secret.exs b/test/fixtures/config/temp.exported_from_db.secret.exs
new file mode 100644
index 000000000..dda5d0fa6
--- /dev/null
+++ b/test/fixtures/config/temp.exported_from_db.secret.exs
@@ -0,0 +1,5 @@
+import Config
+
+config :pleroma, exported_config_merged: true
+
+config :pleroma, :first_setting, key: "new value"
diff --git a/test/fixtures/config/temp.secret.exs b/test/fixtures/config/temp.secret.exs
index fa8c7c7e8..9c5c88d98 100644
--- a/test/fixtures/config/temp.secret.exs
+++ b/test/fixtures/config/temp.secret.exs
@@ -1,4 +1,8 @@
-use Mix.Config
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+import Config
config :pleroma, :first_setting, key: "value", key2: [Pleroma.Repo]
diff --git a/test/fixtures/custom_instance_panel.html b/test/fixtures/custom_instance_panel.html
new file mode 100644
index 000000000..6371a1e43
--- /dev/null
+++ b/test/fixtures/custom_instance_panel.html
@@ -0,0 +1 @@
+<h2>Custom instance panel</h2> \ No newline at end of file
diff --git a/test/fixtures/cw_retweet.xml b/test/fixtures/cw_retweet.xml
deleted file mode 100644
index c99a569d7..000000000
--- a/test/fixtures/cw_retweet.xml
+++ /dev/null
@@ -1,68 +0,0 @@
-<?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</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>
- <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>
- <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="hub" href="https://mastodon.social/api/push"/>
- <link rel="salmon" href="https://mastodon.social/api/salmon/264"/>
- <entry>
- <id>tag:mastodon.social,2017-05-11:objectId=5647963:objectType=Status</id>
- <published>2017-05-11T10:23:15Z</published>
- <updated>2017-05-11T10:23:15Z</updated>
- <title>lambadalambda shared a status by Skruyb@mamot.fr</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:mamot.fr,2017-05-10:objectId=1294943:objectType=Status</id>
- <published>2017-05-10T17:31:44Z</published>
- <updated>2017-05-10T17:31:45Z</updated>
- <title>New status by Skruyb@mamot.fr</title>
- <author>
- <id>https://mamot.fr/users/Skruyb</id>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <uri>https://mamot.fr/users/Skruyb</uri>
- <name>Skruyb</name>
- <email>Skruyb@mamot.fr</email>
- <summary type="html">&lt;p&gt;Fr and En.&lt;br&gt;Posts will disappear on a regular basis.&lt;/p&gt;</summary>
- <link rel="alternate" type="text/html" href="https://mamot.fr/@Skruyb"/>
- <link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/106/282/original/d95dbcfc76f77f4c.jpg"/>
- <link rel="header" type="image/jpeg" media:width="700" media:height="335" href="https://files.mastodon.social/accounts/headers/000/106/282/original/c1aabdf5c97eb875.jpg"/>
- <poco:preferredUsername>Skruyb</poco:preferredUsername>
- <poco:displayName>The 7th Son</poco:displayName>
- <poco:note>Fr and En.Posts will disappear on a regular basis.</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>
- <summary xml:lang="it">Hey.</summary>
- <content type="html" xml:lang="it">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://mastodon.social/@lambadalambda"&gt;@&lt;span&gt;lambadalambda&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Hey!!!&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://mamot.fr/users/Skruyb/updates/176041"/>
- <thr:in-reply-to ref="tag:mastodon.social,2017-05-10:objectId=5582979:objectType=Status" href="https://mastodon.social/@lambadalambda/5582979"/>
- </activity:object>
- <content type="html" xml:lang="en">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://mastodon.social/@lambadalambda"&gt;@&lt;span&gt;lambadalambda&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Hey!!!&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/2325225"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2325225.atom"/>
- </entry>
-</feed>
diff --git a/test/fixtures/delete.xml b/test/fixtures/delete.xml
deleted file mode 100644
index 731e1c204..000000000
--- a/test/fixtures/delete.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?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.sdf.org/users/snowdusk.atom</id>
- <title>snowdusk</title>
- <subtitle>Amateur live performance DJ/radio DJ on SDF's underground Internet radio http://aNONradio.net (LIVE Sat Sun Mon Tue 23:00-24:00 UTC) - http://snowdusk.sdf.org</subtitle>
- <updated>2017-06-17T04:14:34Z</updated>
- <logo>https://mastodon.sdf.org/system/accounts/avatars/000/000/002/original/405a7652d5f60449.jpg?1497672873</logo>
- <author>
- <id>https://mastodon.sdf.org/users/snowdusk</id>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <uri>https://mastodon.sdf.org/users/snowdusk</uri>
- <name>snowdusk</name>
- <email>snowdusk@mastodon.sdf.org</email>
- <summary type="html">&lt;p&gt;Amateur live performance DJ/radio DJ on SDF&amp;apos;s underground Internet radio &lt;a href="http://anonradio.net/" rel="nofollow noopener" target="_blank"&gt;&lt;span class="invisible"&gt;http://&lt;/span&gt;&lt;span class=""&gt;anonradio.net/&lt;/span&gt;&lt;span class="invisible"&gt;&lt;/span&gt;&lt;/a&gt; (LIVE Sat Sun Mon Tue 23:00-24:00 UTC) - &lt;a href="http://snowdusk.sdf.org/" rel="nofollow noopener" target="_blank"&gt;&lt;span class="invisible"&gt;http://&lt;/span&gt;&lt;span class=""&gt;snowdusk.sdf.org/&lt;/span&gt;&lt;span class="invisible"&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary>
- <link rel="alternate" type="text/html" href="https://mastodon.sdf.org/@snowdusk"/>
- <link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://mastodon.sdf.org/system/accounts/avatars/000/000/002/original/405a7652d5f60449.jpg?1497672873"/>
- <link rel="header" type="image/jpeg" media:width="700" media:height="335" href="https://mastodon.sdf.org/system/accounts/headers/000/000/002/original/f1e9b0fb21b4e5a0.jpeg?1495793472"/>
- <poco:preferredUsername>snowdusk</poco:preferredUsername>
- <poco:displayName>snowdusk</poco:displayName>
- <poco:note>Amateur live performance DJ/radio DJ on SDF's underground Internet radio http://aNONradio.net (LIVE Sat Sun Mon Tue 23:00-24:00 UTC) - http://snowdusk.sdf.org</poco:note>
- <mastodon:scope>public</mastodon:scope>
- </author>
- <link rel="alternate" type="text/html" href="https://mastodon.sdf.org/@snowdusk"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.sdf.org/users/snowdusk.atom"/>
- <link rel="next" type="application/atom+xml" href="https://mastodon.sdf.org/users/snowdusk.atom?max_id=7592"/>
- <link rel="hub" href="https://mastodon.sdf.org/api/push"/>
- <link rel="salmon" href="https://mastodon.sdf.org/api/salmon/2"/>
- <entry>
- <id>tag:mastodon.sdf.org,2017-06-10:objectId=310513:objectType=Status</id>
- <published>2017-06-10T22:02:31Z</published>
- <updated>2017-06-10T22:02:31Z</updated>
- <title>snowdusk deleted status</title>
- <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
- <activity:verb>http://activitystrea.ms/schema/1.0/delete</activity:verb>
- <content>Deleted status</content>
- <link rel="alternate" type="text/html" href="https://mastodon.sdf.org/users/snowdusk/updates/7782"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.sdf.org/users/snowdusk/updates/7782.atom"/>
- </entry>
-</feed>
diff --git a/test/fixtures/dm.xml b/test/fixtures/dm.xml
deleted file mode 100644
index d0b8aa811..000000000
--- a/test/fixtures/dm.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?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-06-30:objectId=11260427:objectType=Status</id>
- <published>2017-06-30T13:27:47Z</published>
- <updated>2017-06-30T13:27:47Z</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"/>
- <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/note</activity:object-type>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <content type="html" xml:lang="ky">&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"/>
- <mastodon:scope>direct</mastodon:scope>
- <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/3514345"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/3514345.atom"/>
- <ostatus:conversation ref="tag:mastodon.social,2017-06-30:objectId=4009714:objectType=Conversation"/>
-</entry>
diff --git a/test/fixtures/emojis.zip b/test/fixtures/emojis.zip
new file mode 100644
index 000000000..d7fc4732b
--- /dev/null
+++ b/test/fixtures/emojis.zip
Binary files differ
diff --git a/test/fixtures/empty.zip b/test/fixtures/empty.zip
new file mode 100644
index 000000000..15cb0ecb3
--- /dev/null
+++ b/test/fixtures/empty.zip
Binary files differ
diff --git a/test/fixtures/favorite.xml b/test/fixtures/favorite.xml
deleted file mode 100644
index c32b4a403..000000000
--- a/test/fixtures/favorite.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-<?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-05T09:12:53+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-05:fave:23211:comment:2061643:2017-05-05T09:12:50+00:00</id>
- <title>Favorite</title>
- <content type="html">lambadalambda favorited something by moonman: @&lt;a href=&quot;https://shitposter.club/user/9655&quot; class=&quot;h-card mention&quot; title=&quot;Solidarity for Pigs&quot;&gt;neimzr4luzerz&lt;/a&gt; @&lt;a href=&quot;https://gs.smuglo.li/user/2326&quot; class=&quot;h-card mention&quot; title=&quot;Dolus_McHonest&quot;&gt;dolus&lt;/a&gt; childhood poring over Strong's concordance and a koine Greek dictionary, fast forward to 2017 and some fuckstick who translates japanese jackoff material tells me you just need to make it sound right in English</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2061828"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2017-05-05T09:12:50+00:00</published>
- <updated>2017-05-05T09:12:50+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment</id>
- <title>New comment by moonman</title>
- <content type="html">@&lt;a href=&quot;https://shitposter.club/user/9655&quot; class=&quot;h-card mention&quot; title=&quot;Solidarity for Pigs&quot;&gt;neimzr4luzerz&lt;/a&gt; @&lt;a href=&quot;https://gs.smuglo.li/user/2326&quot; class=&quot;h-card mention&quot; title=&quot;Dolus_McHonest&quot;&gt;dolus&lt;/a&gt; childhood poring over Strong's concordance and a koine Greek dictionary, fast forward to 2017 and some fuckstick who translates japanese jackoff material tells me you just need to make it sound right in English</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2827873"/>
- <status_net notice_id="2061643"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment" href="https://shitposter.club/notice/2827873"></thr:in-reply-to>
- <link rel="related" href="https://shitposter.club/notice/2827873"/>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1061781"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/1061781" local_id="1061781" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=55ead90125cd4bd4">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=55ead90125cd4bd4</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/2061828.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061828.atom"/>
- <statusnet:notice_info local_id="2061828" source="unknown"></statusnet:notice_info>
-</entry>
-</feed>
diff --git a/test/fixtures/favorite_with_local_note.xml b/test/fixtures/favorite_with_local_note.xml
deleted file mode 100644
index 3c955607d..000000000
--- a/test/fixtures/favorite_with_local_note.xml
+++ /dev/null
@@ -1,64 +0,0 @@
-<?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-05T09:12:53+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-05:fave:23211:comment:2061643:2017-05-05T09:12:50+00:00</id>
- <title>Favorite</title>
- <content type="html">lambadalambda favorited something by moonman: @&lt;a href=&quot;https://shitposter.club/user/9655&quot; class=&quot;h-card mention&quot; title=&quot;Solidarity for Pigs&quot;&gt;neimzr4luzerz&lt;/a&gt; @&lt;a href=&quot;https://gs.smuglo.li/user/2326&quot; class=&quot;h-card mention&quot; title=&quot;Dolus_McHonest&quot;&gt;dolus&lt;/a&gt; childhood poring over Strong's concordance and a koine Greek dictionary, fast forward to 2017 and some fuckstick who translates japanese jackoff material tells me you just need to make it sound right in English</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2061828"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2017-05-05T09:12:50+00:00</published>
- <updated>2017-05-05T09:12:50+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>localid</id>
- <title>New comment by moonman</title>
- <content type="html">@&lt;a href=&quot;https://shitposter.club/user/9655&quot; class=&quot;h-card mention&quot; title=&quot;Solidarity for Pigs&quot;&gt;neimzr4luzerz&lt;/a&gt; @&lt;a href=&quot;https://gs.smuglo.li/user/2326&quot; class=&quot;h-card mention&quot; title=&quot;Dolus_McHonest&quot;&gt;dolus&lt;/a&gt; childhood poring over Strong's concordance and a koine Greek dictionary, fast forward to 2017 and some fuckstick who translates japanese jackoff material tells me you just need to make it sound right in English</content>
- <status_net notice_id="2061643"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment" href="https://shitposter.club/notice/2827873"></thr:in-reply-to>
- <link rel="related" href="https://shitposter.club/notice/2827873"/>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1061781"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/1061781" local_id="1061781" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=55ead90125cd4bd4">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=55ead90125cd4bd4</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/2061828.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061828.atom"/>
- <statusnet:notice_info local_id="2061828" source="unknown"></statusnet:notice_info>
-</entry>
-</feed>
diff --git a/test/fixtures/follow.xml b/test/fixtures/follow.xml
deleted file mode 100644
index d4e89954b..000000000
--- a/test/fixtures/follow.xml
+++ /dev/null
@@ -1,68 +0,0 @@
-<?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-07T09:54:49+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-07:subscription:23211:person:44803:2017-05-07T09:54:48+00:00</id>
- <title>Constance Variable (lambadalambda@social.heldscal.la)'s status on Sunday, 07-May-2017 09:54:49 UTC</title>
- <content type="html">&lt;a href=&quot;https://social.heldscal.la/lambadalambda&quot;&gt;Constance Variable&lt;/a&gt; started following &lt;a href=&quot;https://pawoo.net/@pekorino&quot;&gt;mono&lt;/a&gt;.</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2092981"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>
- <published>2017-05-07T09:54:49+00:00</published>
- <updated>2017-05-07T09:54:49+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <id>https://pawoo.net/users/pekorino</id>
- <title>mono</title>
- <summary>http://shitposter.club/mono 孤独のグルメ</summary>
- <link rel="alternate" type="text/html" href="https://pawoo.net/@pekorino"/>
- <link rel="avatar" type="image/png" media:width="96" media:height="96" href="http://social.heldscal.la/theme/neo-gnu/default-avatar-profile.png"/>
- <link rel="avatar" type="image/png" media:width="48" media:height="48" href="http://social.heldscal.la/theme/neo-gnu/default-avatar-stream.png"/>
- <link rel="avatar" type="image/png" media:width="24" media:height="24" href="http://social.heldscal.la/theme/neo-gnu/default-avatar-mini.png"/>
- <poco:preferredUsername>pekorino</poco:preferredUsername>
- <poco:displayName>mono</poco:displayName>
- <poco:note>http://shitposter.club/mono 孤独のグルメ</poco:note>
- </activity:object>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1079786"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/1079786" local_id="1079786" ref="tag:social.heldscal.la,2017-05-07:objectType=thread:nonce=6e80caf94e03029f">tag:social.heldscal.la,2017-05-07:objectType=thread:nonce=6e80caf94e03029f</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/2092981.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2092981.atom"/>
- <statusnet:notice_info local_id="2092981" source="activity"></statusnet:notice_info>
-</entry>
-</feed>
diff --git a/test/fixtures/guppe-actor.json b/test/fixtures/guppe-actor.json
new file mode 100644
index 000000000..d5829ee1f
--- /dev/null
+++ b/test/fixtures/guppe-actor.json
@@ -0,0 +1,26 @@
+{
+ "@context" : [
+ "https://www.w3.org/ns/activitystreams",
+ "https://w3id.org/security/v1"
+ ],
+ "followers" : "https://gup.pe/u/bernie2020/followers",
+ "following" : "https://gup.pe/u/bernie2020/following",
+ "icon" : {
+ "mediaType" : "image/jpeg",
+ "type" : "Image",
+ "url" : "https://gup.pe/f/guppe.png"
+ },
+ "id" : "https://gup.pe/u/bernie2020",
+ "inbox" : "https://gup.pe/u/bernie2020/inbox",
+ "liked" : "https://gup.pe/u/bernie2020/liked",
+ "name" : "Bernie2020 group",
+ "outbox" : "https://gup.pe/u/bernie2020/outbox",
+ "preferredUsername" : "Bernie2020",
+ "publicKey" : {
+ "id" : "https://gup.pe/u/bernie2020#main-key",
+ "owner" : "https://gup.pe/u/bernie2020",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAw4J8nSrdWWxFaipgWDhR\nbTFzHUGoFy7Gjdc6gg9ZWGWDm9ZU5Ct0C/4o72dXSWdyLbQGYMbWVHLI1LHWKSiC\nVtwIYoccQBaxfi5bCxsahWhhSNPfK8tVlySHvBy73ir8KUZm93eAYh1iE9x+Dk63\nInmi7wzjsqHSlu1KxPGYcnyxs+xxhlTUSd5LsPfO1b9sHMW+X4rEky7OC90veCdD\nsoHU+nCmf+2zJSlOrU7DAzqB4Axc9oS9Q5RlT3yARJQMeu6JyjJJP9CMbpGFbUNT\n5Gsw0km1Rc1rR4tUoz8pLUYtliEUK+/0EmHi2EHAT1ueEfMoGGbCaX/mCoMmAwYJ\nwIGYXmKn2/ARIJpw2XPmrKWXqa2AndOQdb3l44Sl3ej2rC/JQmimGCn7tbfKEZyC\n6mMkOYTIeBtyW/wXFc1+GzJxtvA3C9HjilE+O/7gLHfCLP6FRIxg/9kOLhEj64Ed\n5HZ3sylvifXXubS/lLZr6sZW6d9ICoYLZpFw9AoF2zaYWpvJqBrWinnCJzvbMCYj\nfq/RAkcQYSxkDOHquiGgbRZHGAMKLnz5fMKJIzBtdQojYCUmB14OArW+ITUE9i2a\nPAJaXEGZ+BHYp/0ScFaXwp5LIgT1S+sPKxWJU//77wQfs25i7NZHSN/jtXVmsFS6\nLFVw49LcWAz3J2Im+A+uSd8CAwEAAQ==\n-----END PUBLIC KEY-----\n"
+ },
+ "summary" : "I'm a group about Bernie2020. Follow me to get all the group posts. Tag me to share with the group. Create other groups by searching for or tagging @yourGroupName@gup.pe",
+ "type" : "Group"
+}
diff --git a/test/fixtures/image.gif b/test/fixtures/image.gif
new file mode 100755
index 000000000..9df64778b
--- /dev/null
+++ b/test/fixtures/image.gif
Binary files differ
diff --git a/test/fixtures/image.png b/test/fixtures/image.png
new file mode 100755
index 000000000..e999e8800
--- /dev/null
+++ b/test/fixtures/image.png
Binary files differ
diff --git a/test/fixtures/incoming_note_activity.xml b/test/fixtures/incoming_note_activity.xml
deleted file mode 100644
index 21eda2d30..000000000
--- a/test/fixtures/incoming_note_activity.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?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"/>
- <link name="marko" rel="emoji" href="marko.png" />
- <link name="reimu" rel="emoji" href="reimu.png" />
- <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>
diff --git a/test/fixtures/incoming_note_activity_answer.xml b/test/fixtures/incoming_note_activity_answer.xml
deleted file mode 100644
index b1244faa6..000000000
--- a/test/fixtures/incoming_note_activity_answer.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?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>
diff --git a/test/fixtures/incoming_reply_mastodon.xml b/test/fixtures/incoming_reply_mastodon.xml
deleted file mode 100644
index 8ee1186cc..000000000
--- a/test/fixtures/incoming_reply_mastodon.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?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>
diff --git a/test/fixtures/incoming_websub_gnusocial_attachments.xml b/test/fixtures/incoming_websub_gnusocial_attachments.xml
deleted file mode 100644
index 9d331ef32..000000000
--- a/test/fixtures/incoming_websub_gnusocial_attachments.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-<?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>
diff --git a/test/fixtures/lambadalambda.atom b/test/fixtures/lambadalambda.atom
deleted file mode 100644
index 964a416f7..000000000
--- a/test/fixtures/lambadalambda.atom
+++ /dev/null
@@ -1,479 +0,0 @@
-<?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>a cool dude.</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>
diff --git a/test/fixtures/mastodon-delete.json b/test/fixtures/mastodon-delete.json
index 87a582002..8559f724e 100644
--- a/test/fixtures/mastodon-delete.json
+++ b/test/fixtures/mastodon-delete.json
@@ -2,12 +2,9 @@
"type": "Delete",
"signature": {
"type": "RsaSignature2017",
- "signatureValue": "cw0RlfNREf+5VdsOYcCBDrv521eiLsDTAYNHKffjF0bozhCnOh+wHkFik7WamUk$
-uEiN4L2H6vPlGRprAZGRhEwgy+A7rIFQNmLrpW5qV5UNVI/2F7kngEHqZQgbQYj9hW+5GMYmPkHdv3D72ZefGw$
-4Xa2NBLGFpAjQllfzt7kzZLKKY2DM99FdUa64I2Wj3iD04Hs23SbrUdAeuGk/c1Cg6bwGNG4vxoiwn1jikgJLA$
-NAlSGjsRGdR7LfbC7GqWWsW3cSNsLFPoU6FyALjgTrrYoHiXe0QHggw+L3yMLfzB2S/L46/VRbyb+WDKMBIXUL$
-5owmzHSi6e/ZtCI3w==",
- "creator": "http://mastodon.example.org/users/gargron#main-key", "created": "2018-03-03T16:24:11Z"
+ "signatureValue": "cw0RlfNREf+5VdsOYcCBDrv521eiLsDTAYNHKffjF0bozhCnOh+wHkFik7WamUk$uEiN4L2H6vPlGRprAZGRhEwgy+A7rIFQNmLrpW5qV5UNVI/2F7kngEHqZQgbQYj9hW+5GMYmPkHdv3D72ZefGw$4Xa2NBLGFpAjQllfzt7kzZLKKY2DM99FdUa64I2Wj3iD04Hs23SbrUdAeuGk/c1Cg6bwGNG4vxoiwn1jikgJLA$NAlSGjsRGdR7LfbC7GqWWsW3cSNsLFPoU6FyALjgTrrYoHiXe0QHggw+L3yMLfzB2S/L46/VRbyb+WDKMBIXUL$5owmzHSi6e/ZtCI3w==",
+ "creator": "http://mastodon.example.org/users/gargron#main-key",
+ "created": "2018-03-03T16:24:11Z"
},
"object": {
"type": "Tombstone",
diff --git a/test/fixtures/mastodon-note-cw.xml b/test/fixtures/mastodon-note-cw.xml
deleted file mode 100644
index 02f49dd61..000000000
--- a/test/fixtures/mastodon-note-cw.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?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</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>
- <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>
- <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="hub" href="https://mastodon.social/api/push"/>
- <link rel="salmon" href="https://mastodon.social/api/salmon/264"/>
- <entry>
- <id>tag:mastodon.social,2017-05-10:objectId=5551985:objectType=Status</id>
- <published>2017-05-10T12:21:36Z</published>
- <updated>2017-05-10T12:21:36Z</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="sv">technologic</summary>
- <content type="html" xml:lang="sv">&lt;p&gt;test&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/2314748"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2314748.atom"/>
- </entry>
-</feed>
diff --git a/test/fixtures/mastodon-note-unlisted.xml b/test/fixtures/mastodon-note-unlisted.xml
deleted file mode 100644
index d21017b80..000000000
--- a/test/fixtures/mastodon-note-unlisted.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?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</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>
- <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>
- <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="hub" href="https://mastodon.social/api/push"/>
- <link rel="salmon" href="https://mastodon.social/api/salmon/264"/>
- <entry>
- <id>tag:mastodon.social,2017-05-10:objectId=5551985:objectType=Status</id>
- <published>2017-05-10T12:21:36Z</published>
- <updated>2017-05-10T12:21:36Z</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="sv">technologic</summary>
- <content type="html" xml:lang="sv">&lt;p&gt;test&lt;/p&gt;</content>
- <mastodon:scope>unlisted</mastodon:scope>
- <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/2314748"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2314748.atom"/>
- </entry>
-</feed>
diff --git a/test/fixtures/mastodon-post-activity-nsfw.json b/test/fixtures/mastodon-post-activity-nsfw.json
new file mode 100644
index 000000000..70729a1bd
--- /dev/null
+++ b/test/fixtures/mastodon-post-activity-nsfw.json
@@ -0,0 +1,68 @@
+{
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://w3id.org/security/v1",
+ {
+ "Emoji": "toot:Emoji",
+ "Hashtag": "as:Hashtag",
+ "atomUri": "ostatus:atomUri",
+ "conversation": "ostatus:conversation",
+ "inReplyToAtomUri": "ostatus:inReplyToAtomUri",
+ "manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
+ "movedTo": "as:movedTo",
+ "ostatus": "http://ostatus.org#",
+ "toot": "http://joinmastodon.org/ns#"
+ }
+ ],
+ "actor": "http://mastodon.example.org/users/admin",
+ "cc": [
+ "http://mastodon.example.org/users/admin/followers",
+ "http://localtesting.pleroma.lol/users/lain"
+ ],
+ "id": "http://mastodon.example.org/users/admin/statuses/99512778738411822/activity",
+ "nickname": "lain",
+ "object": {
+ "atomUri": "http://mastodon.example.org/users/admin/statuses/99512778738411822",
+ "attachment": [],
+ "attributedTo": "http://mastodon.example.org/users/admin",
+ "cc": [
+ "http://mastodon.example.org/users/admin/followers",
+ "http://localtesting.pleroma.lol/users/lain"
+ ],
+ "content": "<p><span class=\"h-card\"><a href=\"http://localtesting.pleroma.lol/users/lain\" class=\"u-url mention\">@<span>lain</span></a></span> #moo</p>",
+ "conversation": "tag:mastodon.example.org,2018-02-12:objectId=20:objectType=Conversation",
+ "id": "http://mastodon.example.org/users/admin/statuses/99512778738411822",
+ "inReplyTo": null,
+ "inReplyToAtomUri": null,
+ "published": "2018-02-12T14:08:20Z",
+ "summary": "cw",
+ "tag": [
+ {
+ "href": "http://localtesting.pleroma.lol/users/lain",
+ "name": "@lain@localtesting.pleroma.lol",
+ "type": "Mention"
+ },
+ {
+ "href": "http://mastodon.example.org/tags/nsfw",
+ "name": "#NSFW",
+ "type": "Hashtag"
+ }
+ ],
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "type": "Note",
+ "url": "http://mastodon.example.org/@admin/99512778738411822"
+ },
+ "published": "2018-02-12T14:08:20Z",
+ "signature": {
+ "created": "2018-02-12T14:08:20Z",
+ "creator": "http://mastodon.example.org/users/admin#main-key",
+ "signatureValue": "rnNfcopkc6+Ju73P806popcfwrK9wGYHaJVG1/ZvrlEbWVDzaHjkXqj9Q3/xju5l8CSn9tvSgCCtPFqZsFQwn/pFIFUcw7ZWB2xi4bDm3NZ3S4XQ8JRaaX7og5hFxAhWkGhJhAkfxVnOg2hG+w2d/7d7vRVSC1vo5ip4erUaA/PkWusZvPIpxnRWoXaxJsFmVx0gJgjpJkYDyjaXUlp+jmaoseeZ4EPQUWqHLKJ59PRG0mg8j2xAjYH9nQaN14qMRmTGPxY8gfv/CUFcatA+8VJU9KEsJkDAwLVvglydNTLGrxpAJU78a2eaht0foV43XUIZGe3DKiJPgE+UOKGCJw==",
+ "type": "RsaSignature2017"
+ },
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "type": "Create"
+}
diff --git a/test/fixtures/mastodon-problematic.xml b/test/fixtures/mastodon-problematic.xml
deleted file mode 100644
index a39e72759..000000000
--- a/test/fixtures/mastodon-problematic.xml
+++ /dev/null
@@ -1,72 +0,0 @@
-<?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://icosahedron.website/users/shel.atom</id>
- <title>shel🍖‼️</title>
- <subtitle>Gay jackal dog, poet, future librarian.
-
-http://datapup.info
-avatar: @puppytube@twitter.com</subtitle>
- <updated>2017-05-02T23:26:01Z</updated>
- <logo>https://icosahedron.website/system/accounts/avatars/000/001/207/original/b1e07b09ae1cc787.png?1493767561</logo>
- <author>
- <id>https://icosahedron.website/users/shel</id>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <uri>https://icosahedron.website/users/shel</uri>
- <name>shel</name>
- <email>shel@icosahedron.website</email>
- <summary type="html">&lt;p&gt;Gay jackal dog, poet, future librarian. &lt;/p&gt;&lt;p&gt;&lt;a href="http://datapup.info/" rel="nofollow noopener" target="_blank"&gt;&lt;span class="invisible"&gt;http://&lt;/span&gt;&lt;span class=""&gt;datapup.info/&lt;/span&gt;&lt;span class="invisible"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;avatar: @puppytube@twitter.com&lt;/p&gt;</summary>
- <link rel="alternate" type="text/html" href="https://icosahedron.website/@shel"/>
- <link rel="avatar" type="image/png" media:width="120" media:height="120" href="https://icosahedron.website/system/accounts/avatars/000/001/207/original/b1e07b09ae1cc787.png?1493767561"/>
- <link rel="header" type="image/jpeg" media:width="700" media:height="335" href="https://icosahedron.website/system/accounts/headers/000/001/207/original/13e50e0ddfe359fd.jpg?1493767561"/>
- <poco:preferredUsername>shel</poco:preferredUsername>
- <poco:displayName>shel🍖‼️</poco:displayName>
- <poco:note>Gay jackal dog, poet, future librarian.
-
-http://datapup.info
-avatar: @puppytube@twitter.com</poco:note>
- <mastodon:scope>public</mastodon:scope>
- </author>
- <link rel="alternate" type="text/html" href="https://icosahedron.website/@shel"/>
- <link rel="self" type="application/atom+xml" href="https://icosahedron.website/users/shel.atom"/>
- <link rel="hub" href="https://icosahedron.website/api/push"/>
- <link rel="salmon" href="https://icosahedron.website/api/salmon/1207"/>
- <entry>
- <id>tag:icosahedron.website,2017-05-10:objectId=1414013:objectType=Status</id>
- <published>2017-05-10T17:16:24Z</published>
- <updated>2017-05-10T17:16:24Z</updated>
- <title>shel shared a status by instance_names@cybre.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:cybre.space,2017-05-10:objectId=946671:objectType=Status</id>
- <published>2017-05-10T17:15:51Z</published>
- <updated>2017-05-10T17:15:52Z</updated>
- <title>New status by instance_names@cybre.space</title>
- <author>
- <id>https://cybre.space/users/instance_names</id>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <uri>https://cybre.space/users/instance_names</uri>
- <name>instance_names</name>
- <email>instance_names@cybre.space</email>
- <summary type="html">&lt;p&gt;name ideas for your new mastodon instance. made by &lt;span class="h-card"&gt;&lt;a href="https://witches.town/@lycaon"&gt;@&lt;span&gt;lycaon&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; source available at &lt;a href="https://github.com/LycaonIsAWolf/instance_names"&gt;&lt;span class="invisible"&gt;https://&lt;/span&gt;&lt;span class="ellipsis"&gt;github.com/LycaonIsAWolf/insta&lt;/span&gt;&lt;span class="invisible"&gt;nce_names&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</summary>
- <link rel="alternate" type="text/html" href="https://cybre.space/@instance_names"/>
- <link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://icosahedron.website/system/accounts/avatars/000/011/176/original/3845c33e63aa28bd.jpg?1492882822"/>
- <link rel="header" type="image/png" media:width="700" media:height="335" href="https://icosahedron.website/system/accounts/headers/000/011/176/original/a7810908beeeef7e.png?1492882825"/>
- <poco:preferredUsername>instance_names</poco:preferredUsername>
- <poco:displayName>instance names</poco:displayName>
- <poco:note>name ideas for your new mastodon instance. made by @lycaon source available at https://github.com/LycaonIsAWolf/instance_names</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="fr">&lt;p&gt;dildo.codes&lt;/p&gt;</content>
- <mastodon:scope>unlisted</mastodon:scope>
- <link rel="alternate" type="text/html" href="https://cybre.space/users/instance_names/updates/37775"/>
- </activity:object>
- <content type="html" xml:lang="en">&lt;p&gt;dildo.codes&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://icosahedron.website/users/shel/updates/47932"/>
- <link rel="self" type="application/atom+xml" href="https://icosahedron.website/users/shel/updates/47932.atom"/>
- </entry>
-</feed>
diff --git a/test/fixtures/mastodon/application_actor.json b/test/fixtures/mastodon/application_actor.json
new file mode 100644
index 000000000..2089ea049
--- /dev/null
+++ b/test/fixtures/mastodon/application_actor.json
@@ -0,0 +1,67 @@
+{
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://w3id.org/security/v1",
+ {
+ "manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
+ "toot": "http://joinmastodon.org/ns#",
+ "featured": {
+ "@id": "toot:featured",
+ "@type": "@id"
+ },
+ "alsoKnownAs": {
+ "@id": "as:alsoKnownAs",
+ "@type": "@id"
+ },
+ "movedTo": {
+ "@id": "as:movedTo",
+ "@type": "@id"
+ },
+ "schema": "http://schema.org#",
+ "PropertyValue": "schema:PropertyValue",
+ "value": "schema:value",
+ "IdentityProof": "toot:IdentityProof",
+ "discoverable": "toot:discoverable",
+ "Device": "toot:Device",
+ "Ed25519Signature": "toot:Ed25519Signature",
+ "Ed25519Key": "toot:Ed25519Key",
+ "Curve25519Key": "toot:Curve25519Key",
+ "EncryptedMessage": "toot:EncryptedMessage",
+ "publicKeyBase64": "toot:publicKeyBase64",
+ "deviceId": "toot:deviceId",
+ "claim": {
+ "@type": "@id",
+ "@id": "toot:claim"
+ },
+ "fingerprintKey": {
+ "@type": "@id",
+ "@id": "toot:fingerprintKey"
+ },
+ "identityKey": {
+ "@type": "@id",
+ "@id": "toot:identityKey"
+ },
+ "devices": {
+ "@type": "@id",
+ "@id": "toot:devices"
+ },
+ "messageFranking": "toot:messageFranking",
+ "messageType": "toot:messageType",
+ "cipherText": "toot:cipherText"
+ }
+ ],
+ "id": "https://{{DOMAIN}}/actor",
+ "type": "Application",
+ "inbox": "https://{{DOMAIN}}/actor/inbox",
+ "preferredUsername": "{{DOMAIN}}",
+ "url": "https://{{DOMAIN}}/about/more?instance_actor=true",
+ "manuallyApprovesFollowers": true,
+ "publicKey": {
+ "id": "https://{{DOMAIN}}/actor#main-key",
+ "owner": "https://{{DOMAIN}}/actor",
+ "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAA0CA08AMIIBCgKCAQEAyi2T2FFZJgRPY+96YQrn\n6J6eF2P60J+nz+/pRc/acv/Nx+NLxxPyXby0F2s60MV7uALRQbBBnf7oNKCd/T4S\nvbr7UXMCWTdaJBpYubMKWT9uBlaUUkUfqL+WTV+IQnlcKtssQ4+AwrAKAZXza8ws\nZypevOsLHzayyEzztmm1KQC9GCUOITCLf7Q6qEhy8z/HuqLBEC0Own0pD7QsbfcS\no1peuZY7g1E/jJ9HR9GqJccMaR0H28KmJ7tT1Yzlyf5uZMRIdPxsoMR9sGLjR2B8\noegSwaf9SogR3ScP395Tt/9Ud1VVzuhpoS8Uy7jKSs+3CuLJsEGoMrib8VyOwadS\n9wIDAQAB\n-----END PUBLIC KEY-----\n"
+ },
+ "endpoints": {
+ "sharedInbox": "https://{{DOMAIN}}/inbox"
+ }
+}
diff --git a/test/fixtures/mastodon/collections/featured.json b/test/fixtures/mastodon/collections/featured.json
new file mode 100644
index 000000000..56f8f56fa
--- /dev/null
+++ b/test/fixtures/mastodon/collections/featured.json
@@ -0,0 +1,39 @@
+{
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://{{domain}}/schemas/litepub-0.1.jsonld",
+ {
+ "@language": "und"
+ }
+ ],
+ "id": "https://{{domain}}/users/{{nickname}}/collections/featured",
+ "orderedItems": [
+ {
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://{{domain}}/schemas/litepub-0.1.jsonld",
+ {
+ "@language": "und"
+ }
+ ],
+ "actor": "https://{{domain}}/users/{{nickname}}",
+ "attachment": [],
+ "attributedTo": "https://{{domain}}/users/{{nickname}}",
+ "cc": [
+ "https://{{domain}}/users/{{nickname}}/followers"
+ ],
+ "content": "",
+ "id": "https://{{domain}}/objects/{{object_id}}",
+ "published": "2021-02-12T15:13:43.915429Z",
+ "sensitive": false,
+ "source": "",
+ "summary": "",
+ "tag": [],
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "type": "Note"
+ }
+ ],
+ "type": "OrderedCollection"
+}
diff --git a/test/fixtures/mastodon_conversation.xml b/test/fixtures/mastodon_conversation.xml
deleted file mode 100644
index 8faab2304..000000000
--- a/test/fixtures/mastodon_conversation.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?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-08-28:objectId=16402826:objectType=Status</id>
- <published>2017-08-28T17:58:55Z</published>
- <updated>2017-08-28T17:58:55Z</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="image/gif" media:width="700" media:height="335" href="https://files.mastodon.social/accounts/headers/000/000/264/original/28b26104f83747d2.gif"/>
- <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/note</activity:object-type>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/lambadalambda/statuses/16402826"/>
- <content type="html" xml:lang="">&lt;p&gt;test. &lt;a href="https://mastodon.social/media/XCp0OHGPON9kWZwhjaI" rel="nofollow noopener" target="_blank"&gt;&lt;span class="invisible"&gt;https://&lt;/span&gt;&lt;span class="ellipsis"&gt;mastodon.social/media/XCp0OHGP&lt;/span&gt;&lt;span class="invisible"&gt;ON9kWZwhjaI&lt;/span&gt;&lt;/a&gt;&lt;/p&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/png" length="307682" href="https://files.mastodon.social/media_attachments/files/001/271/957/original/6b426b164a09a40e.png"/>
- <mastodon:scope>public</mastodon:scope>
- <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/4215320"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/4215320.atom"/>
- <ostatus:conversation ref="tag:mastodon.social,2017-08-28:objectId=7876885:objectType=Conversation"/>
-</entry>
diff --git a/test/fixtures/mewmew_no_name.json b/test/fixtures/mewmew_no_name.json
new file mode 100644
index 000000000..532d4cf70
--- /dev/null
+++ b/test/fixtures/mewmew_no_name.json
@@ -0,0 +1,46 @@
+{
+ "@context" : [
+ "https://www.w3.org/ns/activitystreams",
+ "https://princess.cat/schemas/litepub-0.1.jsonld",
+ {
+ "@language" : "und"
+ }
+ ],
+ "attachment" : [],
+ "capabilities" : {
+ "acceptsChatMessages" : true
+ },
+ "discoverable" : false,
+ "endpoints" : {
+ "oauthAuthorizationEndpoint" : "https://princess.cat/oauth/authorize",
+ "oauthRegistrationEndpoint" : "https://princess.cat/api/v1/apps",
+ "oauthTokenEndpoint" : "https://princess.cat/oauth/token",
+ "sharedInbox" : "https://princess.cat/inbox",
+ "uploadMedia" : "https://princess.cat/api/ap/upload_media"
+ },
+ "followers" : "https://princess.cat/users/mewmew/followers",
+ "following" : "https://princess.cat/users/mewmew/following",
+ "icon" : {
+ "type" : "Image",
+ "url" : "https://princess.cat/media/12794fb50e86911e65be97f69196814049dcb398a2f8b58b99bb6591576e648c.png?name=blobcatpresentpink.png"
+ },
+ "id" : "https://princess.cat/users/mewmew",
+ "image" : {
+ "type" : "Image",
+ "url" : "https://princess.cat/media/05d8bf3953ab6028fc920494ffc643fbee9dcef40d7bdd06f107e19acbfbd7f9.png"
+ },
+ "inbox" : "https://princess.cat/users/mewmew/inbox",
+ "manuallyApprovesFollowers" : true,
+ "name" : " ",
+ "outbox" : "https://princess.cat/users/mewmew/outbox",
+ "preferredUsername" : "mewmew",
+ "publicKey" : {
+ "id" : "https://princess.cat/users/mewmew#main-key",
+ "owner" : "https://princess.cat/users/mewmew",
+ "publicKeyPem" : "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAru7VpygVef4zrFwnj0Mh\nrbO/2z2EdKN3rERtNrT8zWsLXNLQ50lfpRPnGDrd+xq7Rva4EIu0d5KJJ9n4vtY0\nuxK3On9vA2oyjLlR9O0lI3XTrHJborG3P7IPXrmNUMFpHiFHNqHp5tugUrs1gUFq\n7tmOmM92IP4Wjk8qNHFcsfnUbaPTX7sNIhteQKdi5HrTb/6lrEIe4G/FlMKRqxo3\nRNHuv6SNFQuiUKvFzjzazvjkjvBSm+aFROgdHa2tKl88StpLr7xmuY8qNFCRT6W0\nLacRp6c8ah5f03Kd+xCBVhCKvKaF1K0ERnQTBiitUh85md+Mtx/CoDoLnmpnngR3\nvQIDAQAB\n-----END PUBLIC KEY-----\n\n"
+ },
+ "summary" : "please reply to my posts as direct messages if you have many followers",
+ "tag" : [],
+ "type" : "Person",
+ "url" : "https://princess.cat/users/mewmew"
+}
diff --git a/test/fixtures/modules/good_mrf.ex b/test/fixtures/modules/good_mrf.ex
new file mode 100644
index 000000000..5afa1c1d1
--- /dev/null
+++ b/test/fixtures/modules/good_mrf.ex
@@ -0,0 +1,19 @@
+defmodule Fixtures.Modules.GoodMRF do
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
+
+ @impl true
+ def filter(a), do: {:ok, a}
+
+ @impl true
+ def describe, do: %{}
+
+ @impl true
+ def config_description do
+ %{
+ key: :good_mrf,
+ related_policy: "Fixtures.Modules.GoodMRF",
+ label: "Good MRF",
+ description: "Some description"
+ }
+ end
+end
diff --git a/test/fixtures/modules/runtime_module.ex b/test/fixtures/modules/runtime_module.ex
index f11032b57..940b58a1b 100644
--- a/test/fixtures/modules/runtime_module.ex
+++ b/test/fixtures/modules/runtime_module.ex
@@ -1,8 +1,8 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule RuntimeModule do
+defmodule Fixtures.Modules.RuntimeModule do
@moduledoc """
This is a dummy module to test custom runtime modules.
"""
diff --git a/test/fixtures/nil_mention_entry.xml b/test/fixtures/nil_mention_entry.xml
deleted file mode 100644
index e13024cb3..000000000
--- a/test/fixtures/nil_mention_entry.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-<?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.2.0-alpha2">GNU social</generator>
- <id>https://social.stopwatchingus-heidelberg.de/api/statuses/user_timeline/18330.atom</id>
- <title>atarifrosch timeline</title>
- <subtitle>Updates from atarifrosch on social.stopwatchingus-heidelberg.de!</subtitle>
- <logo>https://social.stopwatchingus-heidelberg.de/avatar/18330-96-20150628163706.png</logo>
- <updated>2017-08-24T11:36:49+02:00</updated>
-<author>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <uri>https://social.stopwatchingus-heidelberg.de/user/18330</uri>
- <name>atarifrosch</name>
- <summary>Nerd, Pirat, Debian user, CAcert assurer, Geocacher, Freifunker. Autismus/Depression, agender. GnuPG Key-ID: 0xBCF81ADE</summary>
- <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/atarifrosch"/>
- <link rel="avatar" type="image/png" media:width="480" media:height="480" href="https://social.stopwatchingus-heidelberg.de/avatar/18330-480-20150628163705.png"/>
- <link rel="avatar" type="image/png" media:width="96" media:height="96" href="https://social.stopwatchingus-heidelberg.de/avatar/18330-96-20150628163706.png"/>
- <link rel="avatar" type="image/png" media:width="48" media:height="48" href="https://social.stopwatchingus-heidelberg.de/avatar/18330-48-20150628163713.png"/>
- <link rel="avatar" type="image/png" media:width="24" media:height="24" href="https://social.stopwatchingus-heidelberg.de/avatar/18330-24-20150628163714.png"/>
- <poco:preferredUsername>atarifrosch</poco:preferredUsername>
- <poco:displayName>Atari-Frosch</poco:displayName>
- <poco:note>Nerd, Pirat, Debian user, CAcert assurer, Geocacher, Freifunker. Autismus/Depression, agender. GnuPG Key-ID: 0xBCF81ADE</poco:note>
- <poco:address>
- <poco:formatted>Düsseldorf, NRW, Germany</poco:formatted>
- </poco:address>
- <poco:urls>
- <poco:type>homepage</poco:type>
- <poco:value>https://www.atari-frosch.de/</poco:value>
- <poco:primary>true</poco:primary>
- </poco:urls>
- <followers url="https://social.stopwatchingus-heidelberg.de/atarifrosch/subscribers"></followers>
- <statusnet:profile_info local_id="18330"></statusnet:profile_info>
-</author>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:social.stopwatchingus-heidelberg.de,2017-08-22:noticeId=978072:objectType=note</id>
- <title>New note by atarifrosch</title>
- <content type="html">2017-08-22 Bundesverfassungsgericht: Erfolgreiche Verfassungsbeschwerde gegen die Versagung vorläufiger Leistungen für Kosten der Unterkunft und Heizung – &lt;a href=&quot;https://www.bundesverfassungsgericht.de/SharedDocs/Pressemitteilungen/DE/2017/bvg17-072.html&quot; title=&quot;https://www.bundesverfassungsgericht.de/SharedDocs/Pressemitteilungen/DE/2017/bvg17-072.html&quot; class=&quot;attachment&quot; id=&quot;attachment-450768&quot; rel=&quot;nofollow external&quot;&gt;https://www.bundesverfassungsgericht.de/SharedDocs/Pressemitteilungen/DE/2017/bvg17-072.html&lt;/a&gt; !&lt;a href=&quot;http://quitter.se/group/2184/id&quot; class=&quot;h-card group&quot; title=&quot;HartzIV (hartziv)&quot;&gt;hartziv&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/978072"/>
- <status_net notice_id="978072"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-08-22T12:00:21+00:00</published>
- <updated>2017-08-22T12:00:21+00:00</updated>
- <link rel="ostatus:conversation" href="tag:social.stopwatchingus-heidelberg.de,2017-08-22:noticeId=978072:objectType=thread:crc32=28a35f44"/>
- <ostatus:conversation>tag:social.stopwatchingus-heidelberg.de,2017-08-22:noticeId=978072:objectType=thread:crc32=28a35f44</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href=""/>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/group" href="http://quitter.se/group/2184/id"/>
- <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.stopwatchingus-heidelberg.de/api/statuses/show/978072.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978072.atom"/>
- <statusnet:notice_info local_id="978072" source="web"></statusnet:notice_info>
-</entry>
-</feed>
diff --git a/test/fixtures/osada-follow-activity.json b/test/fixtures/osada-follow-activity.json
index b991eea36..be10ce88f 100644
--- a/test/fixtures/osada-follow-activity.json
+++ b/test/fixtures/osada-follow-activity.json
@@ -1,56 +1,52 @@
{
- "@context":[
+ "@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
"https://apfed.club/apschema/v1.4"
],
- "id":"https://apfed.club/follow/9",
- "type":"Follow",
- "actor":{
- "type":"Person",
- "id":"https://apfed.club/channel/indio",
- "preferredUsername":"indio",
- "name":"Indio",
- "updated":"2019-08-20T23:52:34Z",
- "icon":{
- "type":"Image",
- "mediaType":"image/jpeg",
- "updated":"2019-08-20T23:53:37Z",
- "url":"https://apfed.club/photo/profile/l/2",
- "height":300,
- "width":300
+ "id": "https://apfed.club/follow/9",
+ "type": "Follow",
+ "actor": {
+ "type": "Person",
+ "id": "https://apfed.club/channel/indio",
+ "preferredUsername": "indio",
+ "name": "Indio",
+ "updated": "2019-08-20T23:52:34Z",
+ "icon": {
+ "type": "Image",
+ "mediaType": "image/jpeg",
+ "updated": "2019-08-20T23:53:37Z",
+ "url": "https://apfed.club/photo/profile/l/2",
+ "height": 300,
+ "width": 300
},
- "url":"https://apfed.club/channel/indio",
- "inbox":"https://apfed.club/inbox/indio",
- "outbox":"https://apfed.club/outbox/indio",
- "followers":"https://apfed.club/followers/indio",
- "following":"https://apfed.club/following/indio",
- "endpoints":{
- "sharedInbox":"https://apfed.club/inbox"
+ "url": "https://apfed.club/channel/indio",
+ "inbox": "https://apfed.club/inbox/indio",
+ "outbox": "https://apfed.club/outbox/indio",
+ "followers": "https://apfed.club/followers/indio",
+ "following": "https://apfed.club/following/indio",
+ "endpoints": {
+ "sharedInbox": "https://apfed.club/inbox"
},
- "publicKey":{
- "id":"https://apfed.club/channel/indio",
- "owner":"https://apfed.club/channel/indio",
- "publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA77TIR1VuSYFnmDRFGHHb\n4vaGdx9ranzRX4bfOKAqa++Ch5L4EqJpPy08RuM+NrYCYiYl4QQFDSSDXAEgb5g9\nC1TgWTfI7q/E0UBX2Vr0mU6X4i1ztv0tuQvegRjcSJ7l1AvoBs8Ip4MEJ3OPEQhB\ngJqAACB3Gnps4zi2I0yavkxUfGVKr6zKT3BxWh5hTpKC7Do+ChIrVZC2EwxND9K6
-\nsAnQHThcb5EQuvuzUQZKeS7IEOsd0JpZDmJjbfMGrAWE81pLIfEeeA2joCJiBBTO\nglDsW+juvZ+lWqJpMr2hMWpvfrFjJeUawNJCIzsLdVIZR+aKj5yy6yqoS8hkN9Ha\n1MljZpsXl+EmwcwAIqim1YeLwERCEAQ/JWbSt8pQTQbzZ6ibwQ4mchCxacrRbIVR
-\nnL59fWMBassJcbY0VwrTugm2SBsYbDjESd55UZV03Rwr8qseGTyi+hH8O7w2SIaY\nzjN6AdZiPmsh00YflzlCk8MSLOHMol1vqIUzXxU8CdXn9+KsuQdZGrTz0YKN/db4\naVwUGJatz2Tsvf7R1tJBjJfeQWOWbbn3pycLVH86LjZ83qngp9ZVnAveUnUqz0yS
-\nhe+buZ6UMsfGzbIYon2bKNlz6gYTH0YPcr+cLe+29drtt0GZiXha1agbpo4RB8zE
-\naNL2fucF5YT0yNpbd/5WoV0CAwEAAQ==\n-----END PUBLIC KEY-----\n"
+ "publicKey": {
+ "id": "https://apfed.club/channel/indio",
+ "owner": "https://apfed.club/channel/indio",
+ "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA77TIR1VuSYFnmDRFGHHb\n4vaGdx9ranzRX4bfOKAqa++Ch5L4EqJpPy08RuM+NrYCYiYl4QQFDSSDXAEgb5g9\nC1TgWTfI7q/E0UBX2Vr0mU6X4i1ztv0tuQvegRjcSJ7l1AvoBs8Ip4MEJ3OPEQhB\ngJqAACB3Gnps4zi2I0yavkxUfGVKr6zKT3BxWh5hTpKC7Do+ChIrVZC2EwxND9K6\nsAnQHThcb5EQuvuzUQZKeS7IEOsd0JpZDmJjbfMGrAWE81pLIfEeeA2joCJiBBTO\nglDsW+juvZ+lWqJpMr2hMWpvfrFjJeUawNJCIzsLdVIZR+aKj5yy6yqoS8hkN9Ha\n1MljZpsXl+EmwcwAIqim1YeLwERCEAQ/JWbSt8pQTQbzZ6ibwQ4mchCxacrRbIVR\nnL59fWMBassJcbY0VwrTugm2SBsYbDjESd55UZV03Rwr8qseGTyi+hH8O7w2SIaY\nzjN6AdZiPmsh00YflzlCk8MSLOHMol1vqIUzXxU8CdXn9+KsuQdZGrTz0YKN/db4\naVwUGJatz2Tsvf7R1tJBjJfeQWOWbbn3pycLVH86LjZ83qngp9ZVnAveUnUqz0yS\nhe+buZ6UMsfGzbIYon2bKNlz6gYTH0YPcr+cLe+29drtt0GZiXha1agbpo4RB8zE\naNL2fucF5YT0yNpbd/5WoV0CAwEAAQ==\n-----END PUBLIC KEY-----\n"
}
},
- "object":"https://pleroma.site/users/kaniini",
- "to":[
+ "object": "https://pleroma.site/users/kaniini",
+ "to": [
"https://pleroma.site/users/kaniini"
],
- "signature":{
- "@context":[
+ "signature": {
+ "@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1"
],
- "type":"RsaSignature2017",
- "nonce":"52c035e0a9e81dce8b486159204e97c22637e91f75cdfad5378de91de68e9117",
- "creator":"https://apfed.club/channel/indio/public_key_pem",
- "created":"2019-08-22T03:38:02Z",
- "signatureValue":"oVliRCIqNIh6yUp851dYrF0y21aHp3Rz6VkIpW1pFMWfXuzExyWSfcELpyLseeRmsw5bUu9zJkH44B4G2LiJQKA9UoEQDjrDMZBmbeUpiQqq3DVUzkrBOI8bHZ7xyJ/CjSZcNHHh0MHhSKxswyxWMGi4zIqzkAZG3vRRgoPVHdjPm00sR3B8jBLw1cjoffv+KKeM/zEUpe13gqX9qHAWHHqZepxgSWmq+EKOkRvHUPBXiEJZfXzc5uW+vZ09F3WBYmaRoy8Y0e1P29fnRLqSy7EEINdrHaGclRqoUZyiawpkgy3lWWlynesV/HiLBR7EXT79eKstxf4wfTDaPKBCfTCsOWuMWHr7Genu37ew2/t7eiBGqCwwW12ylhml/OLHgNK3LOhmRABhtfpaFZSxfDVnlXfaLpY1xekVOj2oC0FpBtnoxVKLpIcyLw6dkfSil5ANd+hl59W/bpPA8KT90ii1fSNCo3+FcwQVx0YsPznJNA60XfFuVsme7zNcOst6393e1WriZxBanFpfB63zVQc9u1fjyfktx/yiUNxIlre+sz9OCc0AACn94iRhBYh4bbzdleUOTnM7lnD4Dj2FP+xeDIP8CA8wXUeq5+9kopSp2kAmlUEyFUdg4no7naIeu1SZnopfUg56PsVCp9JHiUK1SYAyWbdC+FbUECu5CvI="
+ "type": "RsaSignature2017",
+ "nonce": "52c035e0a9e81dce8b486159204e97c22637e91f75cdfad5378de91de68e9117",
+ "creator": "https://apfed.club/channel/indio/public_key_pem",
+ "created": "2019-08-22T03:38:02Z",
+ "signatureValue": "oVliRCIqNIh6yUp851dYrF0y21aHp3Rz6VkIpW1pFMWfXuzExyWSfcELpyLseeRmsw5bUu9zJkH44B4G2LiJQKA9UoEQDjrDMZBmbeUpiQqq3DVUzkrBOI8bHZ7xyJ/CjSZcNHHh0MHhSKxswyxWMGi4zIqzkAZG3vRRgoPVHdjPm00sR3B8jBLw1cjoffv+KKeM/zEUpe13gqX9qHAWHHqZepxgSWmq+EKOkRvHUPBXiEJZfXzc5uW+vZ09F3WBYmaRoy8Y0e1P29fnRLqSy7EEINdrHaGclRqoUZyiawpkgy3lWWlynesV/HiLBR7EXT79eKstxf4wfTDaPKBCfTCsOWuMWHr7Genu37ew2/t7eiBGqCwwW12ylhml/OLHgNK3LOhmRABhtfpaFZSxfDVnlXfaLpY1xekVOj2oC0FpBtnoxVKLpIcyLw6dkfSil5ANd+hl59W/bpPA8KT90ii1fSNCo3+FcwQVx0YsPznJNA60XfFuVsme7zNcOst6393e1WriZxBanFpfB63zVQc9u1fjyfktx/yiUNxIlre+sz9OCc0AACn94iRhBYh4bbzdleUOTnM7lnD4Dj2FP+xeDIP8CA8wXUeq5+9kopSp2kAmlUEyFUdg4no7naIeu1SZnopfUg56PsVCp9JHiUK1SYAyWbdC+FbUECu5CvI="
}
}
diff --git a/test/fixtures/ostatus_incoming_post.xml b/test/fixtures/ostatus_incoming_post.xml
deleted file mode 100644
index 7967e1b32..000000000
--- a/test/fixtures/ostatus_incoming_post.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<?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>
diff --git a/test/fixtures/ostatus_incoming_post_tag.xml b/test/fixtures/ostatus_incoming_post_tag.xml
deleted file mode 100644
index 0f99c4126..000000000
--- a/test/fixtures/ostatus_incoming_post_tag.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-<?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>
- <category term="Nsfw"/>
- <category term=""/>
- <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>
diff --git a/test/fixtures/ostatus_incoming_reply.xml b/test/fixtures/ostatus_incoming_reply.xml
deleted file mode 100644
index 83a427a68..000000000
--- a/test/fixtures/ostatus_incoming_reply.xml
+++ /dev/null
@@ -1,60 +0,0 @@
-<?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>
diff --git a/test/fixtures/peertube/actor-person.json b/test/fixtures/peertube/actor-person.json
new file mode 100644
index 000000000..8c387d455
--- /dev/null
+++ b/test/fixtures/peertube/actor-person.json
@@ -0,0 +1,121 @@
+{
+ "type": "Person",
+ "id": "https://peertube.stream/accounts/createurs",
+ "following": "https://peertube.stream/accounts/createurs/following",
+ "followers": "https://peertube.stream/accounts/createurs/followers",
+ "playlists": "https://peertube.stream/accounts/createurs/playlists",
+ "inbox": "https://peertube.stream/accounts/createurs/inbox",
+ "outbox": "https://peertube.stream/accounts/createurs/outbox",
+ "preferredUsername": "createurs",
+ "url": "https://peertube.stream/accounts/createurs",
+ "name": "Créateurs",
+ "endpoints": {
+ "sharedInbox": "https://peertube.stream/inbox"
+ },
+ "publicKey": {
+ "id": "https://peertube.stream/accounts/createurs#main-key",
+ "owner": "https://peertube.stream/accounts/createurs",
+ "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxqkQhbRYbA81+WTYjorR\n2lEMad3kYCnzDjGTLr4I92eanzFHxyELGnjzP6TpEvjOiB9NrCRrqU/iFPLdgrq2\nwIFcXPWdCq6Gcg7QLlaeMM0JoJmr0KTEhzg0XKCo96UsyTzaF4DISxqi8RyoyWeU\nEkgiOzlkdYTlouq3MlQH+p1PBAsNUQfIEUsU+l6k1vzbm8JRwlT+D1bNde4I/Lqs\n4uB5ru3zzInwZ2hz9+heiriNoGEBv74rZHYn966tZVX8iMGx2+m6okozEdEQbqCl\n0ekqDcd8P6CoFqqeeu8coh82OUtuFI/XsbetdWA55YQmSHyMiTsIwVbeoogIETbI\n4QIDAQAB\n-----END PUBLIC KEY-----"
+ },
+ "icon": {
+ "type": "Image",
+ "mediaType": "image/png",
+ "url": "https://peertube.stream/lazy-static/avatars/c27b672d-ad8f-498a-adbe-553af8da56f9.png"
+ },
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://w3id.org/security/v1",
+ {
+ "RsaSignature2017": "https://w3id.org/security#RsaSignature2017"
+ },
+ {
+ "pt": "https://joinpeertube.org/ns#",
+ "sc": "http://schema.org#",
+ "Hashtag": "as:Hashtag",
+ "uuid": "sc:identifier",
+ "category": "sc:category",
+ "licence": "sc:license",
+ "subtitleLanguage": "sc:subtitleLanguage",
+ "sensitive": "as:sensitive",
+ "language": "sc:inLanguage",
+ "isLiveBroadcast": "sc:isLiveBroadcast",
+ "liveSaveReplay": {
+ "@type": "sc:Boolean",
+ "@id": "pt:liveSaveReplay"
+ },
+ "permanentLive": {
+ "@type": "sc:Boolean",
+ "@id": "pt:permanentLive"
+ },
+ "Infohash": "pt:Infohash",
+ "Playlist": "pt:Playlist",
+ "PlaylistElement": "pt:PlaylistElement",
+ "originallyPublishedAt": "sc:datePublished",
+ "views": {
+ "@type": "sc:Number",
+ "@id": "pt:views"
+ },
+ "state": {
+ "@type": "sc:Number",
+ "@id": "pt:state"
+ },
+ "size": {
+ "@type": "sc:Number",
+ "@id": "pt:size"
+ },
+ "fps": {
+ "@type": "sc:Number",
+ "@id": "pt:fps"
+ },
+ "startTimestamp": {
+ "@type": "sc:Number",
+ "@id": "pt:startTimestamp"
+ },
+ "stopTimestamp": {
+ "@type": "sc:Number",
+ "@id": "pt:stopTimestamp"
+ },
+ "position": {
+ "@type": "sc:Number",
+ "@id": "pt:position"
+ },
+ "commentsEnabled": {
+ "@type": "sc:Boolean",
+ "@id": "pt:commentsEnabled"
+ },
+ "downloadEnabled": {
+ "@type": "sc:Boolean",
+ "@id": "pt:downloadEnabled"
+ },
+ "waitTranscoding": {
+ "@type": "sc:Boolean",
+ "@id": "pt:waitTranscoding"
+ },
+ "support": {
+ "@type": "sc:Text",
+ "@id": "pt:support"
+ },
+ "likes": {
+ "@id": "as:likes",
+ "@type": "@id"
+ },
+ "dislikes": {
+ "@id": "as:dislikes",
+ "@type": "@id"
+ },
+ "playlists": {
+ "@id": "pt:playlists",
+ "@type": "@id"
+ },
+ "shares": {
+ "@id": "as:shares",
+ "@type": "@id"
+ },
+ "comments": {
+ "@id": "as:comments",
+ "@type": "@id"
+ }
+ }
+ ],
+ "summary": null
+}
diff --git a/test/fixtures/peertube/video-object-mpegURL-only.json b/test/fixtures/peertube/video-object-mpegURL-only.json
new file mode 100644
index 000000000..7f26e89bf
--- /dev/null
+++ b/test/fixtures/peertube/video-object-mpegURL-only.json
@@ -0,0 +1,413 @@
+{
+ "type": "Create",
+ "id": "https://peertube.stream/videos/watch/abece3c3-b9c6-47f4-8040-f3eed8c602e6/activity",
+ "actor": "https://peertube.stream/accounts/createurs",
+ "object": {
+ "type": "Video",
+ "id": "https://peertube.stream/videos/watch/abece3c3-b9c6-47f4-8040-f3eed8c602e6",
+ "name": "Vu du 20/02/21 : \"Planète Mars 2050\"",
+ "duration": "PT385S",
+ "uuid": "abece3c3-b9c6-47f4-8040-f3eed8c602e6",
+ "tag": [
+ {
+ "type": "Hashtag",
+ "name": "France3"
+ },
+ {
+ "type": "Hashtag",
+ "name": "lezapping"
+ }
+ ],
+ "category": {
+ "identifier": "11",
+ "name": "News & Politics"
+ },
+ "language": {
+ "identifier": "fr",
+ "name": "French"
+ },
+ "views": 5,
+ "sensitive": false,
+ "waitTranscoding": false,
+ "isLiveBroadcast": false,
+ "liveSaveReplay": null,
+ "permanentLive": null,
+ "state": 1,
+ "commentsEnabled": true,
+ "downloadEnabled": false,
+ "published": "2021-02-20T17:04:54.278Z",
+ "originallyPublishedAt": "2021-02-19T23:00:00.000Z",
+ "updated": "2021-02-21T20:01:11.189Z",
+ "mediaType": "text/markdown",
+ "content": "Un regard impertinent et libre, orchestré par Patrick Menais et son équipe, sur le monde de l’image.\r\n\r\nEn avant-première du lundi au samedi à 17h00 sur Facebook, Twitter et YouTube.\r\n\r\nDu lundi au samedi à 20h00 sur France 3.\r\n\r\nhttps://www.facebook.com/vufrancetv\r\nhttps://twitter.com/VuFrancetv",
+ "support": "Suivre VU :\r\n- Twitter : https://twitter.com/vufrancetv\r\n- Facebook :https://www.facebook.com/vufrancetv/\r\n- Site : https://www.france.tv/france-3/vu/",
+ "subtitleLanguage": [],
+ "icon": [
+ {
+ "type": "Image",
+ "url": "https://peertube.stream/static/thumbnails/abece3c3-b9c6-47f4-8040-f3eed8c602e6.jpg",
+ "mediaType": "image/jpeg",
+ "width": 223,
+ "height": 122
+ },
+ {
+ "type": "Image",
+ "url": "https://peertube.stream/lazy-static/previews/abece3c3-b9c6-47f4-8040-f3eed8c602e6.jpg",
+ "mediaType": "image/jpeg",
+ "width": 850,
+ "height": 480
+ }
+ ],
+ "url": [
+ {
+ "type": "Link",
+ "mediaType": "text/html",
+ "href": "https://peertube.stream/videos/watch/abece3c3-b9c6-47f4-8040-f3eed8c602e6"
+ },
+ {
+ "type": "Link",
+ "mediaType": "application/x-mpegURL",
+ "href": "https://peertube.stream/static/streaming-playlists/hls/abece3c3-b9c6-47f4-8040-f3eed8c602e6/master.m3u8",
+ "tag": [
+ {
+ "type": "Infohash",
+ "name": "00bfce9595e1655d8696b60e19ca25c34be5fa63"
+ },
+ {
+ "type": "Infohash",
+ "name": "256c21b65d5e0f944b4b79d8e0cbc55c9d906807"
+ },
+ {
+ "type": "Infohash",
+ "name": "fcd981098c484d0e328927c8fb21ecf986880b7e"
+ },
+ {
+ "type": "Infohash",
+ "name": "f7e01ac566e9fef91cd22514e6c3c256af7a9f5f"
+ },
+ {
+ "type": "Infohash",
+ "name": "42b421fc44d0dceb45ac3f6f6419b07fd570a232"
+ },
+ {
+ "type": "Infohash",
+ "name": "f876c6d6d49ce618a880ca223df54cb29f4b4bfd"
+ },
+ {
+ "type": "Link",
+ "name": "sha256",
+ "mediaType": "application/json",
+ "href": "https://peertube.stream/static/streaming-playlists/hls/abece3c3-b9c6-47f4-8040-f3eed8c602e6/segments-sha256.json"
+ },
+ {
+ "type": "Link",
+ "mediaType": "video/mp4",
+ "href": "https://peertube.stream/static/streaming-playlists/hls/abece3c3-b9c6-47f4-8040-f3eed8c602e6/abece3c3-b9c6-47f4-8040-f3eed8c602e6-1080-fragmented.mp4",
+ "height": 1080,
+ "size": 57888169,
+ "fps": 25
+ },
+ {
+ "type": "Link",
+ "rel": [
+ "metadata",
+ "video/mp4"
+ ],
+ "mediaType": "application/json",
+ "href": "https://peertube.stream/api/v1/videos/abece3c3-b9c6-47f4-8040-f3eed8c602e6/metadata/570040",
+ "height": 1080,
+ "fps": 25
+ },
+ {
+ "type": "Link",
+ "mediaType": "application/x-bittorrent",
+ "href": "https://peertube.stream/static/torrents/abece3c3-b9c6-47f4-8040-f3eed8c602e6-1080-hls.torrent",
+ "height": 1080
+ },
+ {
+ "type": "Link",
+ "mediaType": "application/x-bittorrent;x-scheme-handler/magnet",
+ "href": "magnet:?xs=https%3A%2F%2Fpeertube.stream%2Fstatic%2Ftorrents%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6-1080-hls.torrent&xt=urn:btih:68af82ebcd9df8335e407b755f38f5fd39c8a6a4&dn=Vu+du+20%2F02%2F21+%3A+%22Plan%C3%A8te+Mars+2050%22&tr=wss%3A%2F%2Fpeertube.stream%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube.stream%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube.stream%2Fstatic%2Fstreaming-playlists%2Fhls%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6-1080-fragmented.mp4",
+ "height": 1080
+ },
+ {
+ "type": "Link",
+ "mediaType": "video/mp4",
+ "href": "https://peertube.stream/static/streaming-playlists/hls/abece3c3-b9c6-47f4-8040-f3eed8c602e6/abece3c3-b9c6-47f4-8040-f3eed8c602e6-720-fragmented.mp4",
+ "height": 720,
+ "size": 45165123,
+ "fps": 25
+ },
+ {
+ "type": "Link",
+ "rel": [
+ "metadata",
+ "video/mp4"
+ ],
+ "mediaType": "application/json",
+ "href": "https://peertube.stream/api/v1/videos/abece3c3-b9c6-47f4-8040-f3eed8c602e6/metadata/570056",
+ "height": 720,
+ "fps": 25
+ },
+ {
+ "type": "Link",
+ "mediaType": "application/x-bittorrent",
+ "href": "https://peertube.stream/static/torrents/abece3c3-b9c6-47f4-8040-f3eed8c602e6-720-hls.torrent",
+ "height": 720
+ },
+ {
+ "type": "Link",
+ "mediaType": "application/x-bittorrent;x-scheme-handler/magnet",
+ "href": "magnet:?xs=https%3A%2F%2Fpeertube.stream%2Fstatic%2Ftorrents%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6-720-hls.torrent&xt=urn:btih:8450928a4ffb2a4c5f927a163487c48c05f6e700&dn=Vu+du+20%2F02%2F21+%3A+%22Plan%C3%A8te+Mars+2050%22&tr=wss%3A%2F%2Fpeertube.stream%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube.stream%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube.stream%2Fstatic%2Fstreaming-playlists%2Fhls%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6-720-fragmented.mp4",
+ "height": 720
+ },
+ {
+ "type": "Link",
+ "mediaType": "video/mp4",
+ "href": "https://peertube.stream/static/streaming-playlists/hls/abece3c3-b9c6-47f4-8040-f3eed8c602e6/abece3c3-b9c6-47f4-8040-f3eed8c602e6-480-fragmented.mp4",
+ "height": 480,
+ "size": 29618534,
+ "fps": 25
+ },
+ {
+ "type": "Link",
+ "rel": [
+ "metadata",
+ "video/mp4"
+ ],
+ "mediaType": "application/json",
+ "href": "https://peertube.stream/api/v1/videos/abece3c3-b9c6-47f4-8040-f3eed8c602e6/metadata/570042",
+ "height": 480,
+ "fps": 25
+ },
+ {
+ "type": "Link",
+ "mediaType": "application/x-bittorrent",
+ "href": "https://peertube.stream/static/torrents/abece3c3-b9c6-47f4-8040-f3eed8c602e6-480-hls.torrent",
+ "height": 480
+ },
+ {
+ "type": "Link",
+ "mediaType": "application/x-bittorrent;x-scheme-handler/magnet",
+ "href": "magnet:?xs=https%3A%2F%2Fpeertube.stream%2Fstatic%2Ftorrents%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6-480-hls.torrent&xt=urn:btih:39e11181db5f376aa78c94bffcb9ccf2f4bca715&dn=Vu+du+20%2F02%2F21+%3A+%22Plan%C3%A8te+Mars+2050%22&tr=wss%3A%2F%2Fpeertube.stream%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube.stream%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube.stream%2Fstatic%2Fstreaming-playlists%2Fhls%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6-480-fragmented.mp4",
+ "height": 480
+ },
+ {
+ "type": "Link",
+ "mediaType": "video/mp4",
+ "href": "https://peertube.stream/static/streaming-playlists/hls/abece3c3-b9c6-47f4-8040-f3eed8c602e6/abece3c3-b9c6-47f4-8040-f3eed8c602e6-360-fragmented.mp4",
+ "height": 360,
+ "size": 21771466,
+ "fps": 25
+ },
+ {
+ "type": "Link",
+ "rel": [
+ "metadata",
+ "video/mp4"
+ ],
+ "mediaType": "application/json",
+ "href": "https://peertube.stream/api/v1/videos/abece3c3-b9c6-47f4-8040-f3eed8c602e6/metadata/570043",
+ "height": 360,
+ "fps": 25
+ },
+ {
+ "type": "Link",
+ "mediaType": "application/x-bittorrent",
+ "href": "https://peertube.stream/static/torrents/abece3c3-b9c6-47f4-8040-f3eed8c602e6-360-hls.torrent",
+ "height": 360
+ },
+ {
+ "type": "Link",
+ "mediaType": "application/x-bittorrent;x-scheme-handler/magnet",
+ "href": "magnet:?xs=https%3A%2F%2Fpeertube.stream%2Fstatic%2Ftorrents%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6-360-hls.torrent&xt=urn:btih:c33aa52822528e29ffd1a615ebe40450e4c61452&dn=Vu+du+20%2F02%2F21+%3A+%22Plan%C3%A8te+Mars+2050%22&tr=wss%3A%2F%2Fpeertube.stream%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube.stream%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube.stream%2Fstatic%2Fstreaming-playlists%2Fhls%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6-360-fragmented.mp4",
+ "height": 360
+ },
+ {
+ "type": "Link",
+ "mediaType": "video/mp4",
+ "href": "https://peertube.stream/static/streaming-playlists/hls/abece3c3-b9c6-47f4-8040-f3eed8c602e6/abece3c3-b9c6-47f4-8040-f3eed8c602e6-240-fragmented.mp4",
+ "height": 240,
+ "size": 14856165,
+ "fps": 25
+ },
+ {
+ "type": "Link",
+ "rel": [
+ "metadata",
+ "video/mp4"
+ ],
+ "mediaType": "application/json",
+ "href": "https://peertube.stream/api/v1/videos/abece3c3-b9c6-47f4-8040-f3eed8c602e6/metadata/570057",
+ "height": 240,
+ "fps": 25
+ },
+ {
+ "type": "Link",
+ "mediaType": "application/x-bittorrent",
+ "href": "https://peertube.stream/static/torrents/abece3c3-b9c6-47f4-8040-f3eed8c602e6-240-hls.torrent",
+ "height": 240
+ },
+ {
+ "type": "Link",
+ "mediaType": "application/x-bittorrent;x-scheme-handler/magnet",
+ "href": "magnet:?xs=https%3A%2F%2Fpeertube.stream%2Fstatic%2Ftorrents%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6-240-hls.torrent&xt=urn:btih:157e4cc3e9f15c06e995d6c3388539fdda312771&dn=Vu+du+20%2F02%2F21+%3A+%22Plan%C3%A8te+Mars+2050%22&tr=wss%3A%2F%2Fpeertube.stream%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube.stream%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube.stream%2Fstatic%2Fstreaming-playlists%2Fhls%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6-240-fragmented.mp4",
+ "height": 240
+ },
+ {
+ "type": "Link",
+ "mediaType": "video/mp4",
+ "href": "https://peertube.stream/static/streaming-playlists/hls/abece3c3-b9c6-47f4-8040-f3eed8c602e6/abece3c3-b9c6-47f4-8040-f3eed8c602e6-0-fragmented.mp4",
+ "height": 0,
+ "size": 6248765,
+ "fps": 0
+ },
+ {
+ "type": "Link",
+ "rel": [
+ "metadata",
+ "video/mp4"
+ ],
+ "mediaType": "application/json",
+ "href": "https://peertube.stream/api/v1/videos/abece3c3-b9c6-47f4-8040-f3eed8c602e6/metadata/570041",
+ "height": 0,
+ "fps": 0
+ },
+ {
+ "type": "Link",
+ "mediaType": "application/x-bittorrent",
+ "href": "https://peertube.stream/static/torrents/abece3c3-b9c6-47f4-8040-f3eed8c602e6-0-hls.torrent",
+ "height": 0
+ },
+ {
+ "type": "Link",
+ "mediaType": "application/x-bittorrent;x-scheme-handler/magnet",
+ "href": "magnet:?xs=https%3A%2F%2Fpeertube.stream%2Fstatic%2Ftorrents%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6-0-hls.torrent&xt=urn:btih:abc8dc58903d18cf7ec0c0cef92cc5ffe5cb0b5c&dn=Vu+du+20%2F02%2F21+%3A+%22Plan%C3%A8te+Mars+2050%22&tr=wss%3A%2F%2Fpeertube.stream%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube.stream%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube.stream%2Fstatic%2Fstreaming-playlists%2Fhls%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6%2Fabece3c3-b9c6-47f4-8040-f3eed8c602e6-0-fragmented.mp4",
+ "height": 0
+ }
+ ]
+ }
+ ],
+ "likes": "https://peertube.stream/videos/watch/abece3c3-b9c6-47f4-8040-f3eed8c602e6/likes",
+ "dislikes": "https://peertube.stream/videos/watch/abece3c3-b9c6-47f4-8040-f3eed8c602e6/dislikes",
+ "shares": "https://peertube.stream/videos/watch/abece3c3-b9c6-47f4-8040-f3eed8c602e6/announces",
+ "comments": "https://peertube.stream/videos/watch/abece3c3-b9c6-47f4-8040-f3eed8c602e6/comments",
+ "attributedTo": [
+ {
+ "type": "Person",
+ "id": "https://peertube.stream/accounts/createurs"
+ },
+ {
+ "type": "Group",
+ "id": "https://peertube.stream/video-channels/vu"
+ }
+ ],
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "cc": [
+ "https://peertube.stream/accounts/createurs/followers"
+ ]
+ },
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "cc": [
+ "https://peertube.stream/accounts/createurs/followers"
+ ],
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://w3id.org/security/v1",
+ {
+ "RsaSignature2017": "https://w3id.org/security#RsaSignature2017"
+ },
+ {
+ "pt": "https://joinpeertube.org/ns#",
+ "sc": "http://schema.org#",
+ "Hashtag": "as:Hashtag",
+ "uuid": "sc:identifier",
+ "category": "sc:category",
+ "licence": "sc:license",
+ "subtitleLanguage": "sc:subtitleLanguage",
+ "sensitive": "as:sensitive",
+ "language": "sc:inLanguage",
+ "isLiveBroadcast": "sc:isLiveBroadcast",
+ "liveSaveReplay": {
+ "@type": "sc:Boolean",
+ "@id": "pt:liveSaveReplay"
+ },
+ "permanentLive": {
+ "@type": "sc:Boolean",
+ "@id": "pt:permanentLive"
+ },
+ "Infohash": "pt:Infohash",
+ "Playlist": "pt:Playlist",
+ "PlaylistElement": "pt:PlaylistElement",
+ "originallyPublishedAt": "sc:datePublished",
+ "views": {
+ "@type": "sc:Number",
+ "@id": "pt:views"
+ },
+ "state": {
+ "@type": "sc:Number",
+ "@id": "pt:state"
+ },
+ "size": {
+ "@type": "sc:Number",
+ "@id": "pt:size"
+ },
+ "fps": {
+ "@type": "sc:Number",
+ "@id": "pt:fps"
+ },
+ "startTimestamp": {
+ "@type": "sc:Number",
+ "@id": "pt:startTimestamp"
+ },
+ "stopTimestamp": {
+ "@type": "sc:Number",
+ "@id": "pt:stopTimestamp"
+ },
+ "position": {
+ "@type": "sc:Number",
+ "@id": "pt:position"
+ },
+ "commentsEnabled": {
+ "@type": "sc:Boolean",
+ "@id": "pt:commentsEnabled"
+ },
+ "downloadEnabled": {
+ "@type": "sc:Boolean",
+ "@id": "pt:downloadEnabled"
+ },
+ "waitTranscoding": {
+ "@type": "sc:Boolean",
+ "@id": "pt:waitTranscoding"
+ },
+ "support": {
+ "@type": "sc:Text",
+ "@id": "pt:support"
+ },
+ "likes": {
+ "@id": "as:likes",
+ "@type": "@id"
+ },
+ "dislikes": {
+ "@id": "as:dislikes",
+ "@type": "@id"
+ },
+ "playlists": {
+ "@id": "pt:playlists",
+ "@type": "@id"
+ },
+ "shares": {
+ "@id": "as:shares",
+ "@type": "@id"
+ },
+ "comments": {
+ "@id": "as:comments",
+ "@type": "@id"
+ }
+ }
+ ]
+}
diff --git a/test/fixtures/share-gs-local.xml b/test/fixtures/share-gs-local.xml
deleted file mode 100644
index 9d52eab7b..000000000
--- a/test/fixtures/share-gs-local.xml
+++ /dev/null
@@ -1,99 +0,0 @@
-<?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>LOCAL_ID</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>LOCAL_USER</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>
diff --git a/test/fixtures/share-gs.xml b/test/fixtures/share-gs.xml
deleted file mode 100644
index ab5e488bd..000000000
--- a/test/fixtures/share-gs.xml
+++ /dev/null
@@ -1,99 +0,0 @@
-<?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>
diff --git a/test/fixtures/share.xml b/test/fixtures/share.xml
deleted file mode 100644
index e07b88680..000000000
--- a/test/fixtures/share.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?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>
diff --git a/test/fixtures/spoofed-object.json b/test/fixtures/spoofed-object.json
new file mode 100644
index 000000000..91e34307d
--- /dev/null
+++ b/test/fixtures/spoofed-object.json
@@ -0,0 +1,26 @@
+{
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://patch.cx/schemas/litepub-0.1.jsonld",
+ {
+ "@language": "und"
+ }
+ ],
+ "actor": "https://patch.cx/users/rin",
+ "attachment": [],
+ "attributedTo": "https://patch.cx/users/rin",
+ "cc": [
+ "https://patch.cx/users/rin/followers"
+ ],
+ "content": "Oracle Corporation (NYSE: ORCL) today announced that it has signed a definitive merger agreement to acquire Pleroma AG (FRA: PLA), for $26.50 per share (approximately $10.3 billion). The transaction has been approved by the boards of directors of both companies and should close by early January.",
+ "context": "https://patch.cx/contexts/spoof",
+ "id": "https://patch.cx/objects/spoof",
+ "published": "2020-10-23T18:02:06.038856Z",
+ "sensitive": false,
+ "summary": "Oracle buys Pleroma",
+ "tag": [],
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "type": "Note"
+}
diff --git a/test/fixtures/statuses/masto-note.json b/test/fixtures/statuses/masto-note.json
new file mode 100644
index 000000000..6b96de473
--- /dev/null
+++ b/test/fixtures/statuses/masto-note.json
@@ -0,0 +1,47 @@
+{
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ {
+ "ostatus": "http://ostatus.org#",
+ "atomUri": "ostatus:atomUri",
+ "inReplyToAtomUri": "ostatus:inReplyToAtomUri",
+ "conversation": "ostatus:conversation",
+ "sensitive": "as:sensitive",
+ "toot": "http://joinmastodon.org/ns#",
+ "votersCount": "toot:votersCount"
+ }
+ ],
+ "id": "https://example.com/users/{{nickname}}/statuses/{{status_id}}",
+ "type": "Note",
+ "summary": null,
+ "inReplyTo": null,
+ "published": "2021-02-24T12:40:49Z",
+ "url": "https://example.com/@{{nickname}}/{{status_id}}",
+ "attributedTo": "https://example.com/users/{{nickname}}",
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "cc": [
+ "https://example.com/users/{{nickname}}/followers"
+ ],
+ "sensitive": false,
+ "atomUri": "https://example.com/users/{{nickname}}/statuses/{{status_id}}",
+ "inReplyToAtomUri": null,
+ "conversation": "tag:example.com,2021-02-24:objectId=15:objectType=Conversation",
+ "content": "<p></p>",
+ "contentMap": {
+ "en": "<p></p>"
+ },
+ "attachment": [],
+ "tag": [],
+ "replies": {
+ "id": "https://example.com/users/{{nickname}}/statuses/{{status_id}}/replies",
+ "type": "Collection",
+ "first": {
+ "type": "CollectionPage",
+ "next": "https://example.com/users/{{nickname}}/statuses/{{status_id}}/replies?only_other_accounts=true&page=true",
+ "partOf": "https://example.com/users/{{nickname}}/statuses/{{status_id}}/replies",
+ "items": []
+ }
+ }
+}
diff --git a/test/fixtures/statuses/note.json b/test/fixtures/statuses/note.json
new file mode 100644
index 000000000..41735cbc5
--- /dev/null
+++ b/test/fixtures/statuses/note.json
@@ -0,0 +1,27 @@
+{
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://example.com/schemas/litepub-0.1.jsonld",
+ {
+ "@language": "und"
+ }
+ ],
+ "actor": "https://example.com/users/{{nickname}}",
+ "attachment": [],
+ "attributedTo": "https://example.com/users/{{nickname}}",
+ "cc": [
+ "https://example.com/users/{{nickname}}/followers"
+ ],
+ "content": "Content",
+ "context": "https://example.com/contexts/e4b180e1-7403-477f-aeb4-de57e7a3fe7f",
+ "conversation": "https://example.com/contexts/e4b180e1-7403-477f-aeb4-de57e7a3fe7f",
+ "id": "https://example.com/objects/{{object_id}}",
+ "published": "2019-12-15T22:00:05.279583Z",
+ "sensitive": false,
+ "summary": "",
+ "tag": [],
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "type": "Note"
+}
diff --git a/test/fixtures/tesla_mock/7369654.atom b/test/fixtures/tesla_mock/7369654.atom
deleted file mode 100644
index 74fd9ce6b..000000000
--- a/test/fixtures/tesla_mock/7369654.atom
+++ /dev/null
@@ -1,44 +0,0 @@
-<?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/comment</activity:object-type>
- <id>tag:shitposter.club,2018-02-22:noticeId=7369654:objectType=comment</id>
- <title>New comment by shpuld</title>
- <content type="html">@&lt;a href=&quot;https://testing.pleroma.lol/users/lain&quot; class=&quot;h-card mention&quot; title=&quot;Rael Electric Razor&quot;&gt;lain&lt;/a&gt; me far right</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7369654"/>
- <status_net notice_id="7369654"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2018-02-22T09:20:12+00:00</published>
- <updated>2018-02-22T09:20:12+00:00</updated>
- <author>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <uri>https://shitposter.club/user/5381</uri>
- <name>shpuld</name>
- <link rel="alternate" type="text/html" href="https://shitposter.club/shpuld"/>
- <link rel="avatar" type="image/png" media:width="864" media:height="864" href="https://shitposter.club/avatar/5381-original-20171230093854.png"/>
- <link rel="avatar" type="image/png" media:width="96" media:height="96" href="https://shitposter.club/avatar/5381-96-20171230093854.png"/>
- <link rel="avatar" type="image/png" media:width="48" media:height="48" href="https://shitposter.club/avatar/5381-48-20171230093854.png"/>
- <link rel="avatar" type="image/png" media:width="24" media:height="24" href="https://shitposter.club/avatar/5381-24-20171230093900.png"/>
- <poco:preferredUsername>shpuld</poco:preferredUsername>
- <poco:displayName>shp</poco:displayName>
- <followers url="https://shitposter.club/shpuld/subscribers"></followers>
- <statusnet:profile_info local_id="5381"></statusnet:profile_info>
- </author>
- <thr:in-reply-to ref="https://testing.pleroma.lol/objects/b319022a-4946-44c5-9de9-34801f95507b" href="https://testing.pleroma.lol/objects/b319022a-4946-44c5-9de9-34801f95507b"></thr:in-reply-to>
- <link rel="related" href="https://testing.pleroma.lol/objects/b319022a-4946-44c5-9de9-34801f95507b"/>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4378601"/>
- <ostatus:conversation href="https://shitposter.club/conversation/4378601" local_id="4378601" ref="tag:shitposter.club,2018-02-22:objectType=thread:nonce=e5a7c72d60a9c0e4">tag:shitposter.club,2018-02-22:objectType=thread:nonce=e5a7c72d60a9c0e4</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://testing.pleroma.lol/users/lain"/>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
- <source>
- <id>https://shitposter.club/api/statuses/user_timeline/5381.atom</id>
- <title>shp</title>
- <link rel="alternate" type="text/html" href="https://shitposter.club/shpuld"/>
- <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/user_timeline/5381.atom"/>
- <link rel="license" href="https://shitposter.club/doc/tos"/>
- <icon>https://shitposter.club/avatar/5381-96-20171230093854.png</icon>
- <updated>2018-02-23T13:30:15+00:00</updated>
- </source>
- <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7369654.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7369654.atom"/>
- <statusnet:notice_info local_id="7369654" source="Pleroma FE"></statusnet:notice_info>
-</entry>
diff --git a/test/fixtures/tesla_mock/admin@mastdon.example.org.json b/test/fixtures/tesla_mock/admin@mastdon.example.org.json
index a911b979a..f961ccb36 100644
--- a/test/fixtures/tesla_mock/admin@mastdon.example.org.json
+++ b/test/fixtures/tesla_mock/admin@mastdon.example.org.json
@@ -1,20 +1,24 @@
{
- "@context": ["https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1", {
- "manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
- "sensitive": "as:sensitive",
- "movedTo": "as:movedTo",
- "Hashtag": "as:Hashtag",
- "ostatus": "http://ostatus.org#",
- "atomUri": "ostatus:atomUri",
- "inReplyToAtomUri": "ostatus:inReplyToAtomUri",
- "conversation": "ostatus:conversation",
- "toot": "http://joinmastodon.org/ns#",
- "Emoji": "toot:Emoji",
- "alsoKnownAs": {
- "@id": "as:alsoKnownAs",
- "@type": "@id"
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://w3id.org/security/v1",
+ {
+ "manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
+ "sensitive": "as:sensitive",
+ "movedTo": "as:movedTo",
+ "Hashtag": "as:Hashtag",
+ "ostatus": "http://ostatus.org#",
+ "atomUri": "ostatus:atomUri",
+ "inReplyToAtomUri": "ostatus:inReplyToAtomUri",
+ "conversation": "ostatus:conversation",
+ "toot": "http://joinmastodon.org/ns#",
+ "Emoji": "toot:Emoji",
+ "alsoKnownAs": {
+ "@id": "as:alsoKnownAs",
+ "@type": "@id"
+ }
}
- }],
+ ],
"id": "http://mastodon.example.org/users/admin",
"type": "Person",
"following": "http://mastodon.example.org/users/admin/following",
@@ -23,6 +27,7 @@
"outbox": "http://mastodon.example.org/users/admin/outbox",
"preferredUsername": "admin",
"name": null,
+ "discoverable": "true",
"summary": "\u003cp\u003e\u003c/p\u003e",
"url": "http://mastodon.example.org/@admin",
"manuallyApprovesFollowers": false,
@@ -34,7 +39,8 @@
"owner": "http://mastodon.example.org/users/admin",
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtc4Tir+3ADhSNF6VKrtW\nOU32T01w7V0yshmQei38YyiVwVvFu8XOP6ACchkdxbJ+C9mZud8qWaRJKVbFTMUG\nNX4+6Q+FobyuKrwN7CEwhDALZtaN2IPbaPd6uG1B7QhWorrY+yFa8f2TBM3BxnUy\nI4T+bMIZIEYG7KtljCBoQXuTQmGtuffO0UwJksidg2ffCF5Q+K//JfQagJ3UzrR+\nZXbKMJdAw4bCVJYs4Z5EhHYBwQWiXCyMGTd7BGlmMkY6Av7ZqHKC/owp3/0EWDNz\nNqF09Wcpr3y3e8nA10X40MJqp/wR+1xtxp+YGbq/Cj5hZGBG7etFOmIpVBrDOhry\nBwIDAQAB\n-----END PUBLIC KEY-----\n"
},
- "attachment": [{
+ "attachment": [
+ {
"type": "PropertyValue",
"name": "foo",
"value": "bar"
@@ -58,5 +64,7 @@
"mediaType": "image/png",
"url": "https://cdn.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png"
},
- "alsoKnownAs": ["http://example.org/users/foo"]
-}
+ "alsoKnownAs": [
+ "http://example.org/users/foo"
+ ]
+} \ No newline at end of file
diff --git a/test/fixtures/tesla_mock/atarifrosch_feed.xml b/test/fixtures/tesla_mock/atarifrosch_feed.xml
deleted file mode 100644
index e00df782e..000000000
--- a/test/fixtures/tesla_mock/atarifrosch_feed.xml
+++ /dev/null
@@ -1,473 +0,0 @@
-<?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.2.0-alpha2">GNU social</generator>
- <id>https://social.stopwatchingus-heidelberg.de/api/statuses/user_timeline/18330.atom</id>
- <title>atarifrosch-Zeitleiste</title>
- <subtitle>Aktualisierungen von atarifrosch auf social.stopwatchingus-heidelberg.de!</subtitle>
- <logo>https://social.stopwatchingus-heidelberg.de/avatar/18330-96-20150628163706.png</logo>
- <updated>2017-08-24T12:06:55+02:00</updated>
-<author>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <uri>https://social.stopwatchingus-heidelberg.de/user/18330</uri>
- <name>atarifrosch</name>
- <summary>Nerd, Pirat, Debian user, CAcert assurer, Geocacher, Freifunker. Autismus/Depression, agender. GnuPG Key-ID: 0xBCF81ADE</summary>
- <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/atarifrosch"/>
- <link rel="avatar" type="image/png" media:width="480" media:height="480" href="https://social.stopwatchingus-heidelberg.de/avatar/18330-480-20150628163705.png"/>
- <link rel="avatar" type="image/png" media:width="96" media:height="96" href="https://social.stopwatchingus-heidelberg.de/avatar/18330-96-20150628163706.png"/>
- <link rel="avatar" type="image/png" media:width="48" media:height="48" href="https://social.stopwatchingus-heidelberg.de/avatar/18330-48-20150628163713.png"/>
- <link rel="avatar" type="image/png" media:width="24" media:height="24" href="https://social.stopwatchingus-heidelberg.de/avatar/18330-24-20150628163714.png"/>
- <poco:preferredUsername>atarifrosch</poco:preferredUsername>
- <poco:displayName>Atari-Frosch</poco:displayName>
- <poco:note>Nerd, Pirat, Debian user, CAcert assurer, Geocacher, Freifunker. Autismus/Depression, agender. GnuPG Key-ID: 0xBCF81ADE</poco:note>
- <poco:address>
- <poco:formatted>Düsseldorf, NRW, Germany</poco:formatted>
- </poco:address>
- <poco:urls>
- <poco:type>homepage</poco:type>
- <poco:value>https://www.atari-frosch.de/</poco:value>
- <poco:primary>true</poco:primary>
- </poco:urls>
- <followers url="https://social.stopwatchingus-heidelberg.de/atarifrosch/subscribers"></followers>
- <statusnet:profile_info local_id="18330"></statusnet:profile_info>
-</author>
- <link href="https://social.stopwatchingus-heidelberg.de/atarifrosch" rel="alternate" type="text/html"/>
- <link href="https://social.stopwatchingus-heidelberg.de/main/sup" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/>
- <link href="https://social.stopwatchingus-heidelberg.de/api/statuses/user_timeline/18330.atom?max_id=976980" rel="next" type="application/atom+xml"/>
- <link href="https://social.stopwatchingus-heidelberg.de/main/push/hub" rel="hub"/>
- <link href="https://social.stopwatchingus-heidelberg.de/main/salmon/user/18330" rel="salmon"/>
- <link href="https://social.stopwatchingus-heidelberg.de/main/salmon/user/18330" rel="http://salmon-protocol.org/ns/salmon-replies"/>
- <link href="https://social.stopwatchingus-heidelberg.de/main/salmon/user/18330" rel="http://salmon-protocol.org/ns/salmon-mention"/>
- <link href="https://social.stopwatchingus-heidelberg.de/api/statuses/user_timeline/18330.atom" rel="self" type="application/atom+xml"/>
-<entry>
- <id>tag:social.stopwatchingus-heidelberg.de,2017-08-24:noticeId=978735:objectType=note</id>
- <title>atarifrosch repeated a notice by hoergen</title>
- <content type="html">RT @&lt;a href=&quot;https://social.hoergen.org/hoergen&quot; class=&quot;h-card mention&quot; title=&quot;hoergen&quot;&gt;hoergen&lt;/a&gt; Das falsche Bild der Tagesschau &amp;quot;Auffallend &amp;quot;erfolgreich&amp;quot; - Andrea Nahles und Manuela Schwesig&amp;quot; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://social.stopwatchingus-heidelberg.de/tag/geringverdiener&quot; rel=&quot;tag&quot;&gt;Geringverdiener&lt;/a&gt;&lt;/span&gt; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://social.stopwatchingus-heidelberg.de/tag/mindestlohn&quot; rel=&quot;tag&quot;&gt;Mindestlohn&lt;/a&gt;&lt;/span&gt; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://social.stopwatchingus-heidelberg.de/tag/mannxismus&quot; rel=&quot;tag&quot;&gt;mannxismus&lt;/a&gt;&lt;/span&gt; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://social.stopwatchingus-heidelberg.de/tag/erwerbsminderungsrente&quot; rel=&quot;tag&quot;&gt;Erwerbsminderungsrente&lt;/a&gt;&lt;/span&gt; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://social.stopwatchingus-heidelberg.de/tag/arbeitnehmerflexibilisierung&quot; rel=&quot;tag&quot;&gt;ArbeitnehmerFlexibilisierung&lt;/a&gt;&lt;/span&gt; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://social.stopwatchingus-heidelberg.de/tag/altersarmut&quot; rel=&quot;tag&quot;&gt;AltersArmut&lt;/a&gt;&lt;/span&gt; ..... &lt;a href=&quot;http://www.tagesschau.de/inland/btw17/bilanz-schwesig-nahles-101.html&quot; title=&quot;http://www.tagesschau.de/inland/btw17/bilanz-schwesig-nahles-101.html&quot; class=&quot;attachment&quot; id=&quot;attachment-450858&quot; rel=&quot;nofollow external&quot;&gt;http://www.tagesschau.de/inland/btw17/bilanz-schwesig-nahles-101.html&lt;/a&gt;</content>
- <link rel="alternate" type="text/html">https://social.stopwatchingus-heidelberg.de/notice/978735</link>
- <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb>
- <published>2017-08-24T09:18:25+00:00</published>
- <updated>2017-08-24T09:18:25+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
- <id>tag:social.hoergen.org,2017-08-24:noticeId=222320:objectType=note</id>
- <title></title>
- <content type="html">Das falsche Bild der Tagesschau &lt;br /&gt; &amp;quot;Auffallend &amp;quot;erfolgreich&amp;quot; - Andrea Nahles und Manuela Schwesig&amp;quot; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://social.hoergen.org/tag/geringverdiener&quot; rel=&quot;tag&quot;&gt;Geringverdiener&lt;/a&gt;&lt;/span&gt; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://social.hoergen.org/tag/mindestlohn&quot; rel=&quot;tag&quot;&gt;Mindestlohn&lt;/a&gt;&lt;/span&gt; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://social.hoergen.org/tag/mannxismus&quot; rel=&quot;tag&quot;&gt;mannxismus&lt;/a&gt;&lt;/span&gt; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://social.hoergen.org/tag/erwerbsminderungsrente&quot; rel=&quot;tag&quot;&gt;Erwerbsminderungsrente&lt;/a&gt;&lt;/span&gt; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://social.hoergen.org/tag/arbeitnehmerflexibilisierung&quot; rel=&quot;tag&quot;&gt;ArbeitnehmerFlexibilisierung&lt;/a&gt;&lt;/span&gt; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://social.hoergen.org/tag/altersarmut&quot; rel=&quot;tag&quot;&gt;AltersArmut&lt;/a&gt;&lt;/span&gt; ..... &lt;br /&gt; &lt;br /&gt; &lt;a href=&quot;http://www.tagesschau.de/inland/btw17/bilanz-schwesig-nahles-101.html&quot; title=&quot;http://www.tagesschau.de/inland/btw17/bilanz-schwesig-nahles-101.html&quot; rel=&quot;nofollow external noreferrer&quot; class=&quot;attachment&quot;&gt;http://www.tagesschau.de/inland/btw17/bilanz-schwesig-nahles-101.html&lt;/a&gt;</content>
- <link rel="alternate" type="text/html">https://social.hoergen.org/notice/222320</link>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-08-24T07:36:31+00:00</published>
- <updated>2017-08-24T07:36:31+00:00</updated>
- <author>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <uri>https://social.hoergen.org/user/2</uri>
- <name>hoergen</name>
- <summary>aka Andi Memyself #humanist #nerd Menschen liebhabender Misanthrop und auch sonst sehr vielseitig interessiert.</summary>
- <link rel="alternate" type="text/html" href="https://social.hoergen.org/hoergen"/>
- <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.stopwatchingus-heidelberg.de/avatar/54316-original-20170824072526.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.stopwatchingus-heidelberg.de/avatar/54316-original-20170824072526.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.stopwatchingus-heidelberg.de/avatar/54316-48-20170824072544.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.stopwatchingus-heidelberg.de/avatar/54316-24-20170824074851.jpeg"/>
- <poco:preferredUsername>hoergen</poco:preferredUsername>
- <poco:displayName>hoergen</poco:displayName>
- <poco:note>aka Andi Memyself #humanist #nerd Menschen liebhabender Misanthrop und auch sonst sehr vielseitig interessiert.</poco:note>
- <poco:address>
- <poco:formatted>Berlin</poco:formatted>
- </poco:address>
- <poco:urls>
- <poco:type>homepage</poco:type>
- <poco:value>https://hyperblog.de/hoergen/</poco:value>
- <poco:primary>true</poco:primary>
- </poco:urls>
- <statusnet:profile_info local_id="54316"></statusnet:profile_info>
- </author>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:social.hoergen.org,2017-08-24:noticeId=222320:objectType=note</id>
- <title>New note by hoergen</title>
- <content type="html">Das falsche Bild der Tagesschau &lt;br /&gt; &amp;quot;Auffallend &amp;quot;erfolgreich&amp;quot; - Andrea Nahles und Manuela Schwesig&amp;quot; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://social.hoergen.org/tag/geringverdiener&quot; rel=&quot;tag&quot;&gt;Geringverdiener&lt;/a&gt;&lt;/span&gt; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://social.hoergen.org/tag/mindestlohn&quot; rel=&quot;tag&quot;&gt;Mindestlohn&lt;/a&gt;&lt;/span&gt; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://social.hoergen.org/tag/mannxismus&quot; rel=&quot;tag&quot;&gt;mannxismus&lt;/a&gt;&lt;/span&gt; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://social.hoergen.org/tag/erwerbsminderungsrente&quot; rel=&quot;tag&quot;&gt;Erwerbsminderungsrente&lt;/a&gt;&lt;/span&gt; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://social.hoergen.org/tag/arbeitnehmerflexibilisierung&quot; rel=&quot;tag&quot;&gt;ArbeitnehmerFlexibilisierung&lt;/a&gt;&lt;/span&gt; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://social.hoergen.org/tag/altersarmut&quot; rel=&quot;tag&quot;&gt;AltersArmut&lt;/a&gt;&lt;/span&gt; ..... &lt;br /&gt; &lt;br /&gt; &lt;a href=&quot;http://www.tagesschau.de/inland/btw17/bilanz-schwesig-nahles-101.html&quot; title=&quot;http://www.tagesschau.de/inland/btw17/bilanz-schwesig-nahles-101.html&quot; rel=&quot;nofollow external noreferrer&quot; class=&quot;attachment&quot;&gt;http://www.tagesschau.de/inland/btw17/bilanz-schwesig-nahles-101.html&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://social.hoergen.org/notice/222320"/>
- <status_net notice_id="978711"></status_net>
- </activity:object>
- <link rel="ostatus:conversation" href="https://social.hoergen.org/conversation/98616"/>
- <ostatus:conversation>https://social.hoergen.org/conversation/98616</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
- <category term="altersarmut"></category>
- <category term="arbeitnehmerflexibilisierung"></category>
- <category term="erwerbsminderungsrente"></category>
- <category term="geringverdiener"></category>
- <category term="mannxismus"></category>
- <category term="mindestlohn"></category>
- <source>
- <id>https://social.hoergen.org/api/statuses/user_timeline/2.atom</id>
- <title>hoergen</title>
- <link rel="alternate" type="text/html" href="https://social.hoergen.org/hoergen"/>
- <link rel="self" type="application/atom+xml" href="https://social.hoergen.org/api/statuses/user_timeline/2.atom"/>
- <icon>https://social.stopwatchingus-heidelberg.de/avatar/54316-original-20170824072526.jpeg</icon>
- <updated>2017-08-24T09:48:30+00:00</updated>
- </source>
- </activity:object>
- <link rel="ostatus:conversation" href="https://social.hoergen.org/conversation/98616"/>
- <ostatus:conversation>https://social.hoergen.org/conversation/98616</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
- <category term="altersarmut"></category>
- <category term="arbeitnehmerflexibilisierung"></category>
- <category term="erwerbsminderungsrente"></category>
- <category term="geringverdiener"></category>
- <category term="mannxismus"></category>
- <category term="mindestlohn"></category>
- <link rel="self" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978735.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978735.atom"/>
- <statusnet:notice_info local_id="978735" source="web" repeat_of="978711"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:social.stopwatchingus-heidelberg.de,2017-08-24:noticeId=978734:objectType=comment</id>
- <title>New comment by atarifrosch</title>
- <content type="html">Jo, die Anzahl der Hartz-IV-Sanktionen nennt sie genausowenig wie die Anzahl der Menschen, die von den Repressionsbehörden in Obdachlosigkeit und Suizid getrieben wurden. Das würde die Erfolgszahlen dann doch ein wenig trüben, nech?</content>
- <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/978734"/>
- <status_net notice_id="978734"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-08-24T09:18:13+00:00</published>
- <updated>2017-08-24T09:18:13+00:00</updated>
- <thr:in-reply-to ref="tag:social.hoergen.org,2017-08-24:noticeId=222320:objectType=note" href="https://social.hoergen.org/notice/222320"></thr:in-reply-to>
- <link rel="related" href="https://social.hoergen.org/notice/222320"/>
- <link rel="ostatus:conversation" href="https://social.hoergen.org/conversation/98616"/>
- <ostatus:conversation>https://social.hoergen.org/conversation/98616</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.hoergen.org/user/2"/>
- <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.stopwatchingus-heidelberg.de/api/statuses/show/978734.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978734.atom"/>
- <statusnet:notice_info local_id="978734" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:social.stopwatchingus-heidelberg.de,2017-08-24:noticeId=978732:objectType=note</id>
- <title>New note by atarifrosch</title>
- <content type="html">Moin-quak.</content>
- <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/978732"/>
- <status_net notice_id="978732"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-08-24T09:09:39+00:00</published>
- <updated>2017-08-24T09:09:39+00:00</updated>
- <link rel="ostatus:conversation" href="tag:social.stopwatchingus-heidelberg.de,2017-08-24:noticeId=978732:objectType=thread:crc32=2f92b7b6"/>
- <ostatus:conversation>tag:social.stopwatchingus-heidelberg.de,2017-08-24:noticeId=978732:objectType=thread:crc32=2f92b7b6</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.stopwatchingus-heidelberg.de/api/statuses/show/978732.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978732.atom"/>
- <statusnet:notice_info local_id="978732" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:social.stopwatchingus-heidelberg.de,2017-08-23:noticeId=978594:objectType=note</id>
- <title>New note by atarifrosch</title>
- <content type="html">n8-quak!</content>
- <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/978594"/>
- <status_net notice_id="978594"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-08-23T21:39:54+00:00</published>
- <updated>2017-08-23T21:39:54+00:00</updated>
- <link rel="ostatus:conversation" href="tag:social.stopwatchingus-heidelberg.de,2017-08-23:noticeId=978594:objectType=thread:crc32=9bdb0ac9"/>
- <ostatus:conversation>tag:social.stopwatchingus-heidelberg.de,2017-08-23:noticeId=978594:objectType=thread:crc32=9bdb0ac9</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.stopwatchingus-heidelberg.de/api/statuses/show/978594.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978594.atom"/>
- <statusnet:notice_info local_id="978594" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:social.stopwatchingus-heidelberg.de,2017-08-23:noticeId=978503:objectType=note</id>
- <title>New note by atarifrosch</title>
- <content type="html">2017-08-16 Michal Špaček: Post a boarding pass on Facebook, get your account stolen – Post a boarding pass on Facebook, get your account stolen (gilt übrinx nicht nur für Facebook)</content>
- <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/978503"/>
- <status_net notice_id="978503"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-08-23T15:14:29+00:00</published>
- <updated>2017-08-23T15:14:29+00:00</updated>
- <link rel="ostatus:conversation" href="tag:social.stopwatchingus-heidelberg.de,2017-08-23:noticeId=978503:objectType=thread:crc32=3de05c3a"/>
- <ostatus:conversation>tag:social.stopwatchingus-heidelberg.de,2017-08-23:noticeId=978503:objectType=thread:crc32=3de05c3a</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.stopwatchingus-heidelberg.de/api/statuses/show/978503.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978503.atom"/>
- <statusnet:notice_info local_id="978503" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.stopwatchingus-heidelberg.de,2017-08-23:fave:18330:activity:978458:2017-08-23T15:18:19+02:00</id>
- <title>Favorite</title>
- <content type="html">atarifrosch favorited something by einebiene: Haha, große Überraschung. &lt;a href=&quot;http://www.sueddeutsche.de/wirtschaft/abgasaffaere-software-updates-fuer-dieselautos-helfen-kaum-1.3637636&quot; title=&quot;http://www.sueddeutsche.de/wirtschaft/abgasaffaere-software-updates-fuer-dieselautos-helfen-kaum-1.3637636&quot; rel=&quot;nofollow noreferrer&quot; class=&quot;attachment&quot;&gt;https://quitter.is/url/1122672&lt;/a&gt;&lt;br /&gt; Was ich an all diesen Artikeln schade finde, ist, daß immer nur auf den Umstieg von Auto zu anderem Auto gesprochen wird. Öffis werden nicht erwähnt, Carsharing nicht, radeln nicht, und in der Stadt wäre ne Vespa auch deutlich besser als ein SUV.</content>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2017-08-23T13:18:19+00:00</published>
- <updated>2017-08-23T13:18:19+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:quitter.is,2017-08-23:noticeId=4032910:objectType=note</id>
- <title>New note by einebiene</title>
- <content type="html">Haha, große Überraschung. &lt;a href=&quot;http://www.sueddeutsche.de/wirtschaft/abgasaffaere-software-updates-fuer-dieselautos-helfen-kaum-1.3637636&quot; title=&quot;http://www.sueddeutsche.de/wirtschaft/abgasaffaere-software-updates-fuer-dieselautos-helfen-kaum-1.3637636&quot; rel=&quot;nofollow noreferrer&quot; class=&quot;attachment&quot;&gt;https://quitter.is/url/1122672&lt;/a&gt;&lt;br /&gt; Was ich an all diesen Artikeln schade finde, ist, daß immer nur auf den Umstieg von Auto zu anderem Auto gesprochen wird. Öffis werden nicht erwähnt, Carsharing nicht, radeln nicht, und in der Stadt wäre ne Vespa auch deutlich besser als ein SUV.</content>
- <link rel="alternate" type="text/html" href="https://quitter.is/notice/4032910"/>
- <status_net notice_id="978458"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:quitter.is,2017-08-23:noticeId=4032910:objectType=note" href="https://quitter.is/notice/4032910"></thr:in-reply-to>
- <link rel="related" href="https://quitter.is/notice/4032910"/>
- <link rel="ostatus:conversation" href="https://quitter.is/conversation/2535246"/>
- <ostatus:conversation>https://quitter.is/conversation/2535246</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://quitter.is/user/8380"/>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
- <statusnet:notice_info local_id="978464" source="unknown"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:social.stopwatchingus-heidelberg.de,2017-08-23:noticeId=978402:objectType=note</id>
- <title>New note by atarifrosch</title>
- <content type="html">moin-quak</content>
- <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/978402"/>
- <status_net notice_id="978402"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-08-23T10:57:26+00:00</published>
- <updated>2017-08-23T10:57:26+00:00</updated>
- <link rel="ostatus:conversation" href="tag:social.stopwatchingus-heidelberg.de,2017-08-23:noticeId=978402:objectType=thread:crc32=7050c397"/>
- <ostatus:conversation>tag:social.stopwatchingus-heidelberg.de,2017-08-23:noticeId=978402:objectType=thread:crc32=7050c397</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.stopwatchingus-heidelberg.de/api/statuses/show/978402.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978402.atom"/>
- <statusnet:notice_info local_id="978402" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:social.stopwatchingus-heidelberg.de,2017-08-22:noticeId=978164:objectType=note</id>
- <title>New note by atarifrosch</title>
- <content type="html">n8-quak</content>
- <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/978164"/>
- <status_net notice_id="978164"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-08-22T19:54:30+00:00</published>
- <updated>2017-08-22T19:54:30+00:00</updated>
- <link rel="ostatus:conversation" href="tag:social.stopwatchingus-heidelberg.de,2017-08-22:noticeId=978164:objectType=thread:crc32=b0a209c7"/>
- <ostatus:conversation>tag:social.stopwatchingus-heidelberg.de,2017-08-22:noticeId=978164:objectType=thread:crc32=b0a209c7</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.stopwatchingus-heidelberg.de/api/statuses/show/978164.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978164.atom"/>
- <statusnet:notice_info local_id="978164" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:social.stopwatchingus-heidelberg.de,2017-08-22:noticeId=978072:objectType=note</id>
- <title>New note by atarifrosch</title>
- <content type="html">2017-08-22 Bundesverfassungsgericht: Erfolgreiche Verfassungsbeschwerde gegen die Versagung vorläufiger Leistungen für Kosten der Unterkunft und Heizung – &lt;a href=&quot;https://www.bundesverfassungsgericht.de/SharedDocs/Pressemitteilungen/DE/2017/bvg17-072.html&quot; title=&quot;https://www.bundesverfassungsgericht.de/SharedDocs/Pressemitteilungen/DE/2017/bvg17-072.html&quot; class=&quot;attachment&quot; id=&quot;attachment-450768&quot; rel=&quot;nofollow external&quot;&gt;https://www.bundesverfassungsgericht.de/SharedDocs/Pressemitteilungen/DE/2017/bvg17-072.html&lt;/a&gt; !&lt;a href=&quot;http://quitter.se/group/2184/id&quot; class=&quot;h-card group&quot; title=&quot;HartzIV (hartziv)&quot;&gt;hartziv&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/978072"/>
- <status_net notice_id="978072"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-08-22T12:00:21+00:00</published>
- <updated>2017-08-22T12:00:21+00:00</updated>
- <link rel="ostatus:conversation" href="tag:social.stopwatchingus-heidelberg.de,2017-08-22:noticeId=978072:objectType=thread:crc32=28a35f44"/>
- <ostatus:conversation>tag:social.stopwatchingus-heidelberg.de,2017-08-22:noticeId=978072:objectType=thread:crc32=28a35f44</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href=""/>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/group" href="http://quitter.se/group/2184/id"/>
- <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.stopwatchingus-heidelberg.de/api/statuses/show/978072.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978072.atom"/>
- <statusnet:notice_info local_id="978072" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:social.stopwatchingus-heidelberg.de,2017-08-22:noticeId=978042:objectType=note</id>
- <title>New note by atarifrosch</title>
- <content type="html">moin-quak!</content>
- <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/978042"/>
- <status_net notice_id="978042"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-08-22T07:55:27+00:00</published>
- <updated>2017-08-22T07:55:27+00:00</updated>
- <link rel="ostatus:conversation" href="tag:social.stopwatchingus-heidelberg.de,2017-08-22:noticeId=978042:objectType=thread:crc32=f070a9f7"/>
- <ostatus:conversation>tag:social.stopwatchingus-heidelberg.de,2017-08-22:noticeId=978042:objectType=thread:crc32=f070a9f7</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.stopwatchingus-heidelberg.de/api/statuses/show/978042.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/978042.atom"/>
- <statusnet:notice_info local_id="978042" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:social.stopwatchingus-heidelberg.de,2017-08-21:noticeId=977914:objectType=note</id>
- <title>New note by atarifrosch</title>
- <content type="html">So, morgen geht's weiter. n8-quak!</content>
- <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/977914"/>
- <status_net notice_id="977914"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-08-21T22:09:53+00:00</published>
- <updated>2017-08-21T22:09:53+00:00</updated>
- <link rel="ostatus:conversation" href="tag:social.stopwatchingus-heidelberg.de,2017-08-21:noticeId=977914:objectType=thread:crc32=c0a9f7fa"/>
- <ostatus:conversation>tag:social.stopwatchingus-heidelberg.de,2017-08-21:noticeId=977914:objectType=thread:crc32=c0a9f7fa</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.stopwatchingus-heidelberg.de/api/statuses/show/977914.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/977914.atom"/>
- <statusnet:notice_info local_id="977914" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:social.stopwatchingus-heidelberg.de,2017-08-21:noticeId=977710:objectType=note</id>
- <title>New note by atarifrosch</title>
- <content type="html">moin-quak.</content>
- <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/977710"/>
- <status_net notice_id="977710"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-08-21T08:58:26+00:00</published>
- <updated>2017-08-21T08:58:26+00:00</updated>
- <link rel="ostatus:conversation" href="tag:social.stopwatchingus-heidelberg.de,2017-08-21:noticeId=977710:objectType=thread:crc32=60cfb466"/>
- <ostatus:conversation>tag:social.stopwatchingus-heidelberg.de,2017-08-21:noticeId=977710:objectType=thread:crc32=60cfb466</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.stopwatchingus-heidelberg.de/api/statuses/show/977710.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/977710.atom"/>
- <statusnet:notice_info local_id="977710" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:social.stopwatchingus-heidelberg.de,2017-08-20:noticeId=977526:objectType=note</id>
- <title>New note by atarifrosch</title>
- <content type="html">Meine Augen meinen, für heute sei es genug. Nun denn. n8-quak.</content>
- <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/977526"/>
- <status_net notice_id="977526"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-08-20T19:58:16+00:00</published>
- <updated>2017-08-20T19:58:16+00:00</updated>
- <link rel="ostatus:conversation" href="tag:social.stopwatchingus-heidelberg.de,2017-08-20:noticeId=977526:objectType=thread:crc32=ce79634"/>
- <ostatus:conversation>tag:social.stopwatchingus-heidelberg.de,2017-08-20:noticeId=977526:objectType=thread:crc32=ce79634</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.stopwatchingus-heidelberg.de/api/statuses/show/977526.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/977526.atom"/>
- <statusnet:notice_info local_id="977526" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:social.stopwatchingus-heidelberg.de,2017-08-20:noticeId=977369:objectType=note</id>
- <title>New note by atarifrosch</title>
- <content type="html">[Blog] Im Netz aufgefischt #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://social.stopwatchingus-heidelberg.de/tag/330&quot; rel=&quot;tag&quot;&gt;330&lt;/a&gt;&lt;/span&gt; – &lt;a href=&quot;https://blog.atari-frosch.de/2017/08/20/im-netz-aufgefischt-330/&quot; title=&quot;https://blog.atari-frosch.de/2017/08/20/im-netz-aufgefischt-330/&quot; class=&quot;attachment&quot; id=&quot;attachment-450668&quot; rel=&quot;nofollow external&quot;&gt;https://blog.atari-frosch.de/2017/08/20/im-netz-aufgefischt-330/&lt;/a&gt; (was ich diese Woche so gelesen habe)</content>
- <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/977369"/>
- <status_net notice_id="977369"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-08-20T09:14:07+00:00</published>
- <updated>2017-08-20T09:14:07+00:00</updated>
- <link rel="ostatus:conversation" href="tag:social.stopwatchingus-heidelberg.de,2017-08-20:noticeId=977369:objectType=thread:crc32=2f800b86"/>
- <ostatus:conversation>tag:social.stopwatchingus-heidelberg.de,2017-08-20:noticeId=977369:objectType=thread:crc32=2f800b86</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
- <category term="330"></category>
- <link rel="self" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/977369.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/977369.atom"/>
- <statusnet:notice_info local_id="977369" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:social.stopwatchingus-heidelberg.de,2017-08-19:noticeId=977268:objectType=note</id>
- <title>New note by atarifrosch</title>
- <content type="html">Fast ständig husten müssen ist echt anstrengend … naja, n8-quak.</content>
- <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/977268"/>
- <status_net notice_id="977268"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-08-19T21:59:20+00:00</published>
- <updated>2017-08-19T21:59:20+00:00</updated>
- <link rel="ostatus:conversation" href="tag:social.stopwatchingus-heidelberg.de,2017-08-19:noticeId=977268:objectType=thread:crc32=deda767a"/>
- <ostatus:conversation>tag:social.stopwatchingus-heidelberg.de,2017-08-19:noticeId=977268:objectType=thread:crc32=deda767a</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.stopwatchingus-heidelberg.de/api/statuses/show/977268.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/977268.atom"/>
- <statusnet:notice_info local_id="977268" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.stopwatchingus-heidelberg.de,2017-08-19:fave:18330:activity:977146:2017-08-19T21:39:26+02:00</id>
- <title>Favorite</title>
- <content type="html">atarifrosch favorited something by einebienezwo: Ich mach gerade Kompetenztraining.&lt;br /&gt; Ich trainiere die Kompetenz, eine halb aufgegessene Gummibärchentüte nicht ganz aufzuessen.</content>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2017-08-19T19:39:26+00:00</published>
- <updated>2017-08-19T19:39:26+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:gnusocial.de,2017-08-19:noticeId=11011264:objectType=note</id>
- <title>New note by einebienezwo</title>
- <content type="html">Ich mach gerade Kompetenztraining.&lt;br /&gt; Ich trainiere die Kompetenz, eine halb aufgegessene Gummibärchentüte nicht ganz aufzuessen.</content>
- <link rel="alternate" type="text/html" href="https://gnusocial.de/notice/11011264"/>
- <status_net notice_id="977146"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:gnusocial.de,2017-08-19:noticeId=11011264:objectType=note" href="https://gnusocial.de/notice/11011264"></thr:in-reply-to>
- <link rel="related" href="https://gnusocial.de/notice/11011264"/>
- <link rel="ostatus:conversation" href="https://gnusocial.de/conversation/9363945"/>
- <ostatus:conversation>https://gnusocial.de/conversation/9363945</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gnusocial.de/user/219865"/>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
- <statusnet:notice_info local_id="977243" source="unknown"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:social.stopwatchingus-heidelberg.de,2017-08-19:noticeId=977242:objectType=comment</id>
- <title>New comment by atarifrosch</title>
- <content type="html">Wir hatten hier schon Ordnungsdienst auf'm Radweg. Fotografisch dokumentiert (nicht von mir, Bekannter hatte es gesehen). Da hatte grad 'ne Pizzeria neu eröffnet …</content>
- <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/977242"/>
- <status_net notice_id="977242"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-08-19T19:38:53+00:00</published>
- <updated>2017-08-19T19:38:53+00:00</updated>
- <thr:in-reply-to ref="tag:gnusocial.de,2017-08-19:noticeId=11010978:objectType=note" href="https://gnusocial.de/notice/11010978"></thr:in-reply-to>
- <link rel="related" href="https://gnusocial.de/notice/11010978"/>
- <link rel="ostatus:conversation" href="https://gnusocial.de/conversation/9363813"/>
- <ostatus:conversation>https://gnusocial.de/conversation/9363813</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gnusocial.de/user/219865"/>
- <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.stopwatchingus-heidelberg.de/api/statuses/show/977242.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/977242.atom"/>
- <statusnet:notice_info local_id="977242" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.stopwatchingus-heidelberg.de,2017-08-19:fave:18330:activity:977180:2017-08-19T21:37:36+02:00</id>
- <title>Favorite</title>
- <content type="html">atarifrosch favorited something by jcaktiv: BTW Hallo zusammen &amp;lt;3, wo ich schon mal wieder hier bin</content>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2017-08-19T19:37:36+00:00</published>
- <updated>2017-08-19T19:37:36+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:quitter.se,2017-08-19:noticeId=17372467:objectType=note</id>
- <title>New note by jcaktiv</title>
- <content type="html">BTW Hallo zusammen &amp;lt;3, wo ich schon mal wieder hier bin</content>
- <link rel="alternate" type="text/html" href="http://quitter.se/notice/17372467"/>
- <status_net notice_id="977180"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:quitter.se,2017-08-19:noticeId=17372467:objectType=note" href="http://quitter.se/notice/17372467"></thr:in-reply-to>
- <link rel="related" href="http://quitter.se/notice/17372467"/>
- <link rel="ostatus:conversation" href="tag:quitter.se,2017-08-19:objectType=thread:nonce=46c1c433d88aaa9f"/>
- <ostatus:conversation>tag:quitter.se,2017-08-19:objectType=thread:nonce=46c1c433d88aaa9f</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="http://quitter.se/user/149873"/>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
- <statusnet:notice_info local_id="977240" source="unknown"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:social.stopwatchingus-heidelberg.de,2017-08-19:noticeId=976985:objectType=comment</id>
- <title>New comment by atarifrosch</title>
- <content type="html">Jo, oder einfach mal nachfragen, so als Realitätsabgleich.</content>
- <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/976985"/>
- <status_net notice_id="976985"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-08-19T10:34:50+00:00</published>
- <updated>2017-08-19T10:34:50+00:00</updated>
- <thr:in-reply-to ref="tag:status.pirati.ca,2017-08-19:noticeId=2310317:objectType=note" href="https://status.pirati.ca/notice/2310317"></thr:in-reply-to>
- <link rel="related" href="https://status.pirati.ca/notice/2310317"/>
- <link rel="ostatus:conversation" href="https://gnusocial.de/conversation/9362516"/>
- <ostatus:conversation>https://gnusocial.de/conversation/9362516</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="http://status.pirati.ca/user/2092"/>
- <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.stopwatchingus-heidelberg.de/api/statuses/show/976985.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/976985.atom"/>
- <statusnet:notice_info local_id="976985" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:social.stopwatchingus-heidelberg.de,2017-08-19:noticeId=976983:objectType=note</id>
- <title>New note by atarifrosch</title>
- <content type="html">Schöne Alternative zu mit Werbung überladenen kommerziellen Anbietern: &lt;a href=&quot;http://ifconfig.at/&quot; title=&quot;http://ifconfig.at/&quot; class=&quot;attachment&quot; id=&quot;attachment-450636&quot; rel=&quot;nofollow external&quot;&gt;http://ifconfig.at/&lt;/a&gt; – eigene IP, Hostname etc. abfragen, mit curl dann auch in Textform zur lokalen Weiterverarbeitung in Scripten etc. Leider (noch?) kein https.</content>
- <link rel="alternate" type="text/html" href="https://social.stopwatchingus-heidelberg.de/notice/976983"/>
- <status_net notice_id="976983"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-08-19T10:33:04+00:00</published>
- <updated>2017-08-19T10:33:04+00:00</updated>
- <link rel="ostatus:conversation" href="tag:social.stopwatchingus-heidelberg.de,2017-08-19:noticeId=976983:objectType=thread:crc32=4a3593c0"/>
- <ostatus:conversation>tag:social.stopwatchingus-heidelberg.de,2017-08-19:noticeId=976983:objectType=thread:crc32=4a3593c0</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.stopwatchingus-heidelberg.de/api/statuses/show/976983.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.stopwatchingus-heidelberg.de/api/statuses/show/976983.atom"/>
- <statusnet:notice_info local_id="976983" source="web"></statusnet:notice_info>
-</entry>
-</feed>
diff --git a/test/fixtures/tesla_mock/emelie.atom b/test/fixtures/tesla_mock/emelie.atom
deleted file mode 100644
index ddaa1c6ca..000000000
--- a/test/fixtures/tesla_mock/emelie.atom
+++ /dev/null
@@ -1,306 +0,0 @@
-<?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/emelie.atom</id>
- <title>emelie 🎨</title>
- <subtitle>23 / #Sweden / #Artist / #Equestrian / #GameDev
-
-If I ain't spending time with my pets, I'm probably drawing. 🐴 🐱 🐰</subtitle>
- <updated>2019-02-04T20:22:19Z</updated>
- <logo>https://files.mastodon.social/accounts/avatars/000/015/657/original/e7163f98280da1a4.png</logo>
- <author>
- <id>https://mastodon.social/users/emelie</id>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <uri>https://mastodon.social/users/emelie</uri>
- <name>emelie</name>
- <email>emelie@mastodon.social</email>
- <summary type="html">&lt;p&gt;23 / &lt;a href="https://mastodon.social/tags/sweden" class="mention hashtag" rel="tag"&gt;#&lt;span&gt;Sweden&lt;/span&gt;&lt;/a&gt; / &lt;a href="https://mastodon.social/tags/artist" class="mention hashtag" rel="tag"&gt;#&lt;span&gt;Artist&lt;/span&gt;&lt;/a&gt; / &lt;a href="https://mastodon.social/tags/equestrian" class="mention hashtag" rel="tag"&gt;#&lt;span&gt;Equestrian&lt;/span&gt;&lt;/a&gt; / &lt;a href="https://mastodon.social/tags/gamedev" class="mention hashtag" rel="tag"&gt;#&lt;span&gt;GameDev&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;If I ain&amp;apos;t spending time with my pets, I&amp;apos;m probably drawing. 🐴 🐱 🐰&lt;/p&gt;</summary>
- <link rel="alternate" type="text/html" href="https://mastodon.social/@emelie"/>
- <link rel="avatar" type="image/png" media:width="120" media:height="120" href="https://files.mastodon.social/accounts/avatars/000/015/657/original/e7163f98280da1a4.png"/>
- <link rel="header" type="image/png" media:width="700" media:height="335" href="https://files.mastodon.social/accounts/headers/000/015/657/original/847f331f3dd9e38b.png"/>
- <poco:preferredUsername>emelie</poco:preferredUsername>
- <poco:displayName>emelie 🎨</poco:displayName>
- <poco:note>23 / #Sweden / #Artist / #Equestrian / #GameDev
-
-If I ain't spending time with my pets, I'm probably drawing. 🐴 🐱 🐰</poco:note>
- <mastodon:scope>public</mastodon:scope>
- </author>
- <link rel="alternate" type="text/html" href="https://mastodon.social/@emelie"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie.atom"/>
- <link rel="hub" href="https://mastodon.social/api/push"/>
- <link rel="salmon" href="https://mastodon.social/api/salmon/15657"/>
- <entry>
- <id>https://mastodon.social/users/emelie/statuses/101850331907006641</id>
- <published>2019-04-01T09:58:50Z</published>
- <updated>2019-04-01T09:58:50Z</updated>
- <title>New status by emelie</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>
- <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101850331907006641"/>
- <content type="html" xml:lang="en">&lt;p&gt;Me: I&amp;apos;m going to make this vital change to my world building in the morning, no way I&amp;apos;ll forget this, it&amp;apos;s too big of a deal&lt;br /&gt;Also me: forgets&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/@emelie/101850331907006641"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17854598.atom"/>
- <ostatus:conversation ref="tag:mastodon.social,2019-04-01:objectId=94383214:objectType=Conversation"/>
- </entry>
- <entry>
- <id>https://mastodon.social/users/emelie/statuses/101849626603073336</id>
- <published>2019-04-01T06:59:28Z</published>
- <updated>2019-04-01T06:59:28Z</updated>
- <title>New status by emelie</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>
- <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101849626603073336"/>
- <content type="html" xml:lang="sv">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://mastodon.social/@Fergant" class="u-url mention"&gt;@&lt;span&gt;Fergant&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; Dom är i stort sett religiös skrift vid det här laget 👏👏&lt;/p&gt;&lt;p&gt;har dock bara läst svenska översättningen, kanske är dags att jag läser dom på engelska&lt;/p&gt;</content>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/Fergant"/>
- <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/@emelie/101849626603073336"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17852590.atom"/>
- <thr:in-reply-to ref="https://mastodon.social/users/Fergant/statuses/101849606513357387" href="https://mastodon.social/@Fergant/101849606513357387"/>
- <ostatus:conversation ref="tag:mastodon.social,2019-04-01:objectId=94362529:objectType=Conversation"/>
- </entry>
- <entry>
- <id>https://mastodon.social/users/emelie/statuses/101849580030237068</id>
- <published>2019-04-01T06:47:37Z</published>
- <updated>2019-04-01T06:47:37Z</updated>
- <title>New status by emelie</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>
- <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101849580030237068"/>
- <content type="html" xml:lang="en">&lt;p&gt;What&amp;apos;s you people&amp;apos;s favourite fantasy books? Give me some hot tips 🌞&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/@emelie/101849580030237068"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17852464.atom"/>
- <ostatus:conversation ref="tag:mastodon.social,2019-04-01:objectId=94362529:objectType=Conversation"/>
- </entry>
- <entry>
- <id>https://mastodon.social/users/emelie/statuses/101849550599949363</id>
- <published>2019-04-01T06:40:08Z</published>
- <updated>2019-04-01T06:40:08Z</updated>
- <title>New status by emelie</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>
- <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101849550599949363"/>
- <content type="html" xml:lang="en">&lt;p&gt;Stick them legs out 💃 &lt;a href="https://mastodon.social/tags/mastocats" class="mention hashtag" rel="tag"&gt;#&lt;span&gt;mastocats&lt;/span&gt;&lt;/a&gt;&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="mastocats"/>
- <link rel="enclosure" type="image/jpeg" length="516384" href="https://files.mastodon.social/media_attachments/files/013/051/707/original/125a310abe9a34aa.jpeg"/>
- <mastodon:scope>public</mastodon:scope>
- <link rel="alternate" type="text/html" href="https://mastodon.social/@emelie/101849550599949363"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17852407.atom"/>
- <ostatus:conversation ref="tag:mastodon.social,2019-04-01:objectId=94361580:objectType=Conversation"/>
- </entry>
- <entry>
- <id>https://mastodon.social/users/emelie/statuses/101849191533152720</id>
- <published>2019-04-01T05:08:49Z</published>
- <updated>2019-04-01T05:08:49Z</updated>
- <title>New status by emelie</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>
- <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101849191533152720"/>
- <content type="html" xml:lang="en">&lt;p&gt;long 🐱 &lt;a href="https://mastodon.social/tags/mastocats" class="mention hashtag" rel="tag"&gt;#&lt;span&gt;mastocats&lt;/span&gt;&lt;/a&gt;&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="mastocats"/>
- <link rel="enclosure" type="image/jpeg" length="305208" href="https://files.mastodon.social/media_attachments/files/013/049/940/original/f2dbbfe7de3a17d2.jpeg"/>
- <mastodon:scope>public</mastodon:scope>
- <link rel="alternate" type="text/html" href="https://mastodon.social/@emelie/101849191533152720"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17851663.atom"/>
- <ostatus:conversation ref="tag:mastodon.social,2019-04-01:objectId=94351141:objectType=Conversation"/>
- </entry>
- <entry>
- <id>https://mastodon.social/users/emelie/statuses/101849165031453009</id>
- <published>2019-04-01T05:02:05Z</published>
- <updated>2019-04-01T05:02:05Z</updated>
- <title>New status by emelie</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>
- <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101849165031453009"/>
- <content type="html" xml:lang="en">&lt;p&gt;You gotta take whatever bellyrubbing opportunity you can get before she changes her mind 🦁 &lt;a href="https://mastodon.social/tags/mastocats" class="mention hashtag" rel="tag"&gt;#&lt;span&gt;mastocats&lt;/span&gt;&lt;/a&gt;&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="mastocats"/>
- <link rel="enclosure" type="video/mp4" length="9838915" href="https://files.mastodon.social/media_attachments/files/013/049/816/original/e7831178a5e0d6d4.mp4"/>
- <mastodon:scope>public</mastodon:scope>
- <link rel="alternate" type="text/html" href="https://mastodon.social/@emelie/101849165031453009"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17851558.atom"/>
- <ostatus:conversation ref="tag:mastodon.social,2019-04-01:objectId=94350309:objectType=Conversation"/>
- </entry>
- <entry>
- <id>https://mastodon.social/users/emelie/statuses/101846512530748693</id>
- <published>2019-03-31T17:47:31Z</published>
- <updated>2019-03-31T17:47:31Z</updated>
- <title>New status by emelie</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>
- <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101846512530748693"/>
- <content type="html" xml:lang="en">&lt;p&gt;Hello look at this boy having a decent haircut for once &lt;a href="https://mastodon.social/tags/mastohorses" class="mention hashtag" rel="tag"&gt;#&lt;span&gt;mastohorses&lt;/span&gt;&lt;/a&gt; &lt;a href="https://mastodon.social/tags/equestrian" class="mention hashtag" rel="tag"&gt;#&lt;span&gt;equestrian&lt;/span&gt;&lt;/a&gt;&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="equestrian"/>
- <category term="mastohorses"/>
- <link rel="enclosure" type="image/jpeg" length="461632" href="https://files.mastodon.social/media_attachments/files/013/033/387/original/301e8ab668cd61d2.jpeg"/>
- <mastodon:scope>public</mastodon:scope>
- <link rel="alternate" type="text/html" href="https://mastodon.social/@emelie/101846512530748693"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17842424.atom"/>
- <ostatus:conversation ref="tag:mastodon.social,2019-03-31:objectId=94256415:objectType=Conversation"/>
- </entry>
- <entry>
- <id>https://mastodon.social/users/emelie/statuses/101846181093805500</id>
- <published>2019-03-31T16:23:14Z</published>
- <updated>2019-03-31T16:23:14Z</updated>
- <title>New status by emelie</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>
- <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101846181093805500"/>
- <content type="html" xml:lang="en">&lt;p&gt;Sorry did I disturb the who-is-the-longest-cat competition ? &lt;a href="https://mastodon.social/tags/mastocats" class="mention hashtag" rel="tag"&gt;#&lt;span&gt;mastocats&lt;/span&gt;&lt;/a&gt;&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="mastocats"/>
- <link rel="enclosure" type="image/jpeg" length="211384" href="https://files.mastodon.social/media_attachments/files/013/030/725/original/5b4886730cbbd25c.jpeg"/>
- <mastodon:scope>public</mastodon:scope>
- <link rel="alternate" type="text/html" href="https://mastodon.social/@emelie/101846181093805500"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17841108.atom"/>
- <ostatus:conversation ref="tag:mastodon.social,2019-03-31:objectId=94245239:objectType=Conversation"/>
- </entry>
- <entry>
- <id>https://mastodon.social/users/emelie/statuses/101845897513133849</id>
- <published>2019-03-31T15:11:07Z</published>
- <updated>2019-03-31T15:11:07Z</updated>
- <title>New status by emelie</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>
- <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101845897513133849"/>
- <summary xml:lang="en">more earthsea ramblings</summary>
- <content type="html" xml:lang="en">&lt;p&gt;I&amp;apos;m re-watching Tales from Earthsea for the first time since I read the books, and that Therru doesn&amp;apos;t squash Cob like a spider, as Orm Embar did is a wasted opportunity tbh&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/@emelie/101845897513133849"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17840088.atom"/>
- <ostatus:conversation ref="tag:mastodon.social,2019-03-31:objectId=94232455:objectType=Conversation"/>
- </entry>
- <entry>
- <id>https://mastodon.social/users/emelie/statuses/101841219051533307</id>
- <published>2019-03-30T19:21:19Z</published>
- <updated>2019-03-30T19:21:19Z</updated>
- <title>New status by emelie</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>
- <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101841219051533307"/>
- <content type="html" xml:lang="en">&lt;p&gt;I gave my cats some mackerel and they ate it all in 0.3 seconds, and now they won&amp;apos;t stop meowing for more, and I&amp;apos;m tired plz shut up&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/@emelie/101841219051533307"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17826587.atom"/>
- <ostatus:conversation ref="tag:mastodon.social,2019-03-30:objectId=94075000:objectType=Conversation"/>
- </entry>
- <entry>
- <id>https://mastodon.social/users/emelie/statuses/101839949762341381</id>
- <published>2019-03-30T13:58:31Z</published>
- <updated>2019-03-30T13:58:31Z</updated>
- <title>New status by emelie</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>
- <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101839949762341381"/>
- <content type="html" xml:lang="en">&lt;p&gt;yet I&amp;apos;m confused about this american dude with a gun, like the heck r ya doin in mah ghibli&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/@emelie/101839949762341381"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17821757.atom"/>
- <thr:in-reply-to ref="https://mastodon.social/users/emelie/statuses/101839928677863590" href="https://mastodon.social/@emelie/101839928677863590"/>
- <ostatus:conversation ref="tag:mastodon.social,2019-03-30:objectId=94026360:objectType=Conversation"/>
- </entry>
- <entry>
- <id>https://mastodon.social/users/emelie/statuses/101839928677863590</id>
- <published>2019-03-30T13:53:09Z</published>
- <updated>2019-03-30T13:53:09Z</updated>
- <title>New status by emelie</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>
- <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101839928677863590"/>
- <content type="html" xml:lang="en">&lt;p&gt;2 hours into Ni no Kuni 2 and I&amp;apos;ve already sold my soul to this game&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/@emelie/101839928677863590"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17821713.atom"/>
- <ostatus:conversation ref="tag:mastodon.social,2019-03-30:objectId=94026360:objectType=Conversation"/>
- </entry>
- <entry>
- <id>https://mastodon.social/users/emelie/statuses/101836329521599438</id>
- <published>2019-03-29T22:37:51Z</published>
- <updated>2019-03-29T22:37:51Z</updated>
- <title>New status by emelie</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>
- <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101836329521599438"/>
- <content type="html" xml:lang="en">&lt;p&gt;Pippi Longstocking the original one-punch /man&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/@emelie/101836329521599438"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17811608.atom"/>
- <ostatus:conversation ref="tag:mastodon.social,2019-03-29:objectId=93907854:objectType=Conversation"/>
- </entry>
- <entry>
- <id>https://mastodon.social/users/emelie/statuses/101835905282948341</id>
- <published>2019-03-29T20:49:57Z</published>
- <updated>2019-03-29T20:49:57Z</updated>
- <title>New status by emelie</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>
- <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101835905282948341"/>
- <content type="html" xml:lang="en">&lt;p&gt;I&amp;apos;ve had so much wine I thought I had a 3rd brother&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/@emelie/101835905282948341"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17809862.atom"/>
- <ostatus:conversation ref="tag:mastodon.social,2019-03-29:objectId=93892966:objectType=Conversation"/>
- </entry>
- <entry>
- <id>https://mastodon.social/users/emelie/statuses/101835878059204660</id>
- <published>2019-03-29T20:43:02Z</published>
- <updated>2019-03-29T20:43:02Z</updated>
- <title>New status by emelie</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>
- <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101835878059204660"/>
- <content type="html" xml:lang="en">&lt;p&gt;ååååhhh booi&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/@emelie/101835878059204660"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17809734.atom"/>
- <ostatus:conversation ref="tag:mastodon.social,2019-03-29:objectId=93892010:objectType=Conversation"/>
- </entry>
- <entry>
- <id>https://mastodon.social/users/emelie/statuses/101835848050598939</id>
- <published>2019-03-29T20:35:24Z</published>
- <updated>2019-03-29T20:35:24Z</updated>
- <title>New status by emelie</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>
- <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101835848050598939"/>
- <content type="html" xml:lang="en">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://thraeryn.net/@thraeryn" class="u-url mention"&gt;@&lt;span&gt;thraeryn&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; if I spent 1 hour and a half watching this monstrosity, I need to&lt;/p&gt;</content>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://thraeryn.net/users/thraeryn"/>
- <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/@emelie/101835848050598939"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17809591.atom"/>
- <thr:in-reply-to ref="https://thraeryn.net/users/thraeryn/statuses/101835839202826007" href="https://thraeryn.net/@thraeryn/101835839202826007"/>
- <ostatus:conversation ref="tag:mastodon.social,2019-03-29:objectId=93888827:objectType=Conversation"/>
- </entry>
- <entry>
- <id>https://mastodon.social/users/emelie/statuses/101835823138262290</id>
- <published>2019-03-29T20:29:04Z</published>
- <updated>2019-03-29T20:29:04Z</updated>
- <title>New status by emelie</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>
- <link rel="alternate" type="application/activity+json" href="https://mastodon.social/users/emelie/statuses/101835823138262290"/>
- <summary xml:lang="en">medical, fluids mention</summary>
- <content type="html" xml:lang="en">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://icosahedron.website/@Trev" class="u-url mention"&gt;@&lt;span&gt;Trev&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; *hugs* ✨&lt;/p&gt;</content>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://icosahedron.website/users/Trev"/>
- <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/@emelie/101835823138262290"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/emelie/updates/17809468.atom"/>
- <thr:in-reply-to ref="https://icosahedron.website/users/Trev/statuses/101835812250051801" href="https://icosahedron.website/@Trev/101835812250051801"/>
- <ostatus:conversation ref="tag:icosahedron.website,2019-03-29:objectId=12220882:objectType=Conversation"/>
- </entry>
-</feed>
diff --git a/test/fixtures/tesla_mock/emoji-in-summary.json b/test/fixtures/tesla_mock/emoji-in-summary.json
new file mode 100644
index 000000000..f77c6e2e8
--- /dev/null
+++ b/test/fixtures/tesla_mock/emoji-in-summary.json
@@ -0,0 +1,49 @@
+{
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://patch.cx/schemas/litepub-0.1.jsonld",
+ {
+ "@language": "und"
+ }
+ ],
+ "actor": "https://patch.cx/users/rin",
+ "attachment": [],
+ "attributedTo": "https://patch.cx/users/rin",
+ "cc": [
+ "https://patch.cx/users/rin/followers"
+ ],
+ "content": ":joker_disapprove: <br><br>just grabbing a test fixture, nevermind me",
+ "context": "https://patch.cx/contexts/2c3ce4b4-18b1-4b1a-8965-3932027b5326",
+ "conversation": "https://patch.cx/contexts/2c3ce4b4-18b1-4b1a-8965-3932027b5326",
+ "id": "https://patch.cx/objects/a399c28e-c821-4820-bc3e-4afeb044c16f",
+ "published": "2021-03-22T16:54:46.461939Z",
+ "sensitive": null,
+ "source": ":joker_disapprove: \r\n\r\njust grabbing a test fixture, nevermind me",
+ "summary": ":joker_smile: ",
+ "tag": [
+ {
+ "icon": {
+ "type": "Image",
+ "url": "https://patch.cx/emoji/custom/joker_disapprove.png"
+ },
+ "id": "https://patch.cx/emoji/custom/joker_disapprove.png",
+ "name": ":joker_disapprove:",
+ "type": "Emoji",
+ "updated": "1970-01-01T00:00:00Z"
+ },
+ {
+ "icon": {
+ "type": "Image",
+ "url": "https://patch.cx/emoji/custom/joker_smile.png"
+ },
+ "id": "https://patch.cx/emoji/custom/joker_smile.png",
+ "name": ":joker_smile:",
+ "type": "Emoji",
+ "updated": "1970-01-01T00:00:00Z"
+ }
+ ],
+ "to": [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "type": "Note"
+}
diff --git a/test/fixtures/tesla_mock/framatube.org-video.json b/test/fixtures/tesla_mock/framatube.org-video.json
index 3d53f0c97..1fa529886 100644
--- a/test/fixtures/tesla_mock/framatube.org-video.json
+++ b/test/fixtures/tesla_mock/framatube.org-video.json
@@ -1 +1 @@
-{"type":"Video","id":"https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206","name":"Déframasoftisons Internet [Framasoft]","duration":"PT3622S","uuid":"6050732a-8a7a-43d4-a6cd-809525a1d206","tag":[{"type":"Hashtag","name":"déframasoftisons"},{"type":"Hashtag","name":"EPN23"},{"type":"Hashtag","name":"framaconf"},{"type":"Hashtag","name":"Framasoft"},{"type":"Hashtag","name":"pyg"}],"category":{"identifier":"15","name":"Science & Technology"},"views":122,"sensitive":false,"waitTranscoding":false,"state":1,"commentsEnabled":true,"downloadEnabled":true,"published":"2020-05-24T18:34:31.569Z","originallyPublishedAt":"2019-11-30T23:00:00.000Z","updated":"2020-07-05T09:01:01.720Z","mediaType":"text/markdown","content":"Après avoir mené avec un certain succès la campagne « Dégooglisons Internet » en 2014, l’association Framasoft annonce fin 2019 arrêter progressivement un certain nombre de ses services alternatifs aux GAFAM. Pourquoi ?\r\n\r\nTranscription par @april...","support":null,"subtitleLanguage":[],"icon":{"type":"Image","url":"https://framatube.org/static/thumbnails/6050732a-8a7a-43d4-a6cd-809525a1d206.jpg","mediaType":"image/jpeg","width":223,"height":122},"url":[{"type":"Link","mediaType":"text/html","href":"https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206"},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4","height":1080,"size":1157359410,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309939","height":1080,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-1080.torrent","height":1080},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-1080.torrent&xt=urn:btih:381c9429900552e23a4eb506318f1fa01e4d63a8&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fwebseed%2F6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4&ws=https%3A%2F%2Fpeertube.iselfhost.com%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4&ws=https%3A%2F%2Ftube.privacytools.io%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4&ws=https%3A%2F%2Fpeertube.live%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4","height":1080},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-480.mp4","height":480,"size":250095131,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309941","height":480,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-480.torrent","height":480},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-480.torrent&xt=urn:btih:a181dcbb5368ab5c31cc9ff07634becb72c344ee&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fwebseed%2F6050732a-8a7a-43d4-a6cd-809525a1d206-480.mp4&ws=https%3A%2F%2Fpeertube.iselfhost.com%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-480.mp4&ws=https%3A%2F%2Ftube.privacytools.io%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-480.mp4&ws=https%3A%2F%2Fpeertube.live%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-480.mp4","height":480},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-360.mp4","height":360,"size":171357733,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309942","height":360,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-360.torrent","height":360},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-360.torrent&xt=urn:btih:aedfa9479ea04a175eee0b0bd0bda64076308746&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fwebseed%2F6050732a-8a7a-43d4-a6cd-809525a1d206-360.mp4&ws=https%3A%2F%2Fpeertube.iselfhost.com%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-360.mp4&ws=https%3A%2F%2Ftube.privacytools.io%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-360.mp4&ws=https%3A%2F%2Fpeertube.live%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-360.mp4","height":360},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-720.mp4","height":720,"size":497100839,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309943","height":720,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-720.torrent","height":720},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-720.torrent&xt=urn:btih:71971668f82a3b24ac71bc3a982848dd8dc5a5f5&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fwebseed%2F6050732a-8a7a-43d4-a6cd-809525a1d206-720.mp4&ws=https%3A%2F%2Fpeertube.iselfhost.com%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-720.mp4&ws=https%3A%2F%2Ftube.privacytools.io%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-720.mp4&ws=https%3A%2F%2Fpeertube.live%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-720.mp4","height":720},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-240.mp4","height":240,"size":113038439,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309944","height":240,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-240.torrent","height":240},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-240.torrent&xt=urn:btih:c42aa6c95efb28d9f114ebd98537f7b00fa72246&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fwebseed%2F6050732a-8a7a-43d4-a6cd-809525a1d206-240.mp4&ws=https%3A%2F%2Fpeertube.iselfhost.com%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-240.mp4&ws=https%3A%2F%2Ftube.privacytools.io%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-240.mp4","height":240},{"type":"Link","mediaType":"application/x-mpegURL","href":"https://framatube.org/static/streaming-playlists/hls/6050732a-8a7a-43d4-a6cd-809525a1d206/master.m3u8","tag":[{"type":"Infohash","name":"f7428214539626e062f300f2ca4cf9154575144e"},{"type":"Infohash","name":"46e236dffb1ea6b9123a5396cbe88e97dd94cc6c"},{"type":"Infohash","name":"11f1045830b5d786c788f2594d19f128764e7d87"},{"type":"Infohash","name":"4327ad3e0d84de100130a27e9ab6fe40c4284f0e"},{"type":"Infohash","name":"41e2eee8e7b23a63c23a77c40a46de11492a4831"},{"type":"Link","name":"sha256","mediaType":"application/json","href":"https://framatube.org/static/streaming-playlists/hls/6050732a-8a7a-43d4-a6cd-809525a1d206/segments-sha256.json"},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/streaming-playlists/hls/6050732a-8a7a-43d4-a6cd-809525a1d206/6050732a-8a7a-43d4-a6cd-809525a1d206-1080-fragmented.mp4","height":1080,"size":1156777472,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309940","height":1080,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-1080-hls.torrent","height":1080},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-1080-hls.torrent&xt=urn:btih:0204d780ebfab0d5d9d3476a038e812ad792deeb&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fstreaming-playlists%2Fhls%2F6050732a-8a7a-43d4-a6cd-809525a1d206%2F6050732a-8a7a-43d4-a6cd-809525a1d206-1080-fragmented.mp4","height":1080},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/streaming-playlists/hls/6050732a-8a7a-43d4-a6cd-809525a1d206/6050732a-8a7a-43d4-a6cd-809525a1d206-480-fragmented.mp4","height":480,"size":249562889,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309945","height":480,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-480-hls.torrent","height":480},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-480-hls.torrent&xt=urn:btih:5d14f38ded29de629668fe1cfc61a75f4cce2628&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fstreaming-playlists%2Fhls%2F6050732a-8a7a-43d4-a6cd-809525a1d206%2F6050732a-8a7a-43d4-a6cd-809525a1d206-480-fragmented.mp4","height":480},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/streaming-playlists/hls/6050732a-8a7a-43d4-a6cd-809525a1d206/6050732a-8a7a-43d4-a6cd-809525a1d206-360-fragmented.mp4","height":360,"size":170836415,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309946","height":360,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-360-hls.torrent","height":360},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-360-hls.torrent&xt=urn:btih:30125488789080ad405ebcee6c214945f31b8f30&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fstreaming-playlists%2Fhls%2F6050732a-8a7a-43d4-a6cd-809525a1d206%2F6050732a-8a7a-43d4-a6cd-809525a1d206-360-fragmented.mp4","height":360},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/streaming-playlists/hls/6050732a-8a7a-43d4-a6cd-809525a1d206/6050732a-8a7a-43d4-a6cd-809525a1d206-720-fragmented.mp4","height":720,"size":496533741,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309947","height":720,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-720-hls.torrent","height":720},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-720-hls.torrent&xt=urn:btih:8ed1e8bccde709901c26e315fc8f53bfd26d1ba6&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fstreaming-playlists%2Fhls%2F6050732a-8a7a-43d4-a6cd-809525a1d206%2F6050732a-8a7a-43d4-a6cd-809525a1d206-720-fragmented.mp4","height":720},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/streaming-playlists/hls/6050732a-8a7a-43d4-a6cd-809525a1d206/6050732a-8a7a-43d4-a6cd-809525a1d206-240-fragmented.mp4","height":240,"size":112529249,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309948","height":240,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-240-hls.torrent","height":240},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-240-hls.torrent&xt=urn:btih:8b452bf4e70b9078d4e74ca8b5523cc9dc70d10a&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fstreaming-playlists%2Fhls%2F6050732a-8a7a-43d4-a6cd-809525a1d206%2F6050732a-8a7a-43d4-a6cd-809525a1d206-240-fragmented.mp4","height":240}]}],"likes":"https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206/likes","dislikes":"https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206/dislikes","shares":"https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206/announces","comments":"https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206/comments","attributedTo":[{"type":"Person","id":"https://framatube.org/accounts/framasoft"},{"type":"Group","id":"https://framatube.org/video-channels/bf54d359-cfad-4935-9d45-9d6be93f63e8"}],"to":["https://www.w3.org/ns/activitystreams#Public"],"cc":["https://framatube.org/accounts/framasoft/followers"],"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1",{"RsaSignature2017":"https://w3id.org/security#RsaSignature2017"},{"pt":"https://joinpeertube.org/ns#","sc":"http://schema.org#","Hashtag":"as:Hashtag","uuid":"sc:identifier","category":"sc:category","licence":"sc:license","subtitleLanguage":"sc:subtitleLanguage","sensitive":"as:sensitive","language":"sc:inLanguage","Infohash":"pt:Infohash","Playlist":"pt:Playlist","PlaylistElement":"pt:PlaylistElement","originallyPublishedAt":"sc:datePublished","views":{"@type":"sc:Number","@id":"pt:views"},"state":{"@type":"sc:Number","@id":"pt:state"},"size":{"@type":"sc:Number","@id":"pt:size"},"fps":{"@type":"sc:Number","@id":"pt:fps"},"startTimestamp":{"@type":"sc:Number","@id":"pt:startTimestamp"},"stopTimestamp":{"@type":"sc:Number","@id":"pt:stopTimestamp"},"position":{"@type":"sc:Number","@id":"pt:position"},"commentsEnabled":{"@type":"sc:Boolean","@id":"pt:commentsEnabled"},"downloadEnabled":{"@type":"sc:Boolean","@id":"pt:downloadEnabled"},"waitTranscoding":{"@type":"sc:Boolean","@id":"pt:waitTranscoding"},"support":{"@type":"sc:Text","@id":"pt:support"},"likes":{"@id":"as:likes","@type":"@id"},"dislikes":{"@id":"as:dislikes","@type":"@id"},"playlists":{"@id":"pt:playlists","@type":"@id"},"shares":{"@id":"as:shares","@type":"@id"},"comments":{"@id":"as:comments","@type":"@id"}}]} \ No newline at end of file
+{"type":"Create","id":"https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206/activity","actor":"https://framatube.org/accounts/framasoft","object":{"type":"Video","id":"https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206","name":"Déframasoftisons Internet [Framasoft]","duration":"PT3622S","uuid":"6050732a-8a7a-43d4-a6cd-809525a1d206","tag":[{"type":"Hashtag","name":"déframasoftisons"},{"type":"Hashtag","name":"EPN23"},{"type":"Hashtag","name":"framaconf"},{"type":"Hashtag","name":"Framasoft"},{"type":"Hashtag","name":"pyg"}],"category":{"identifier":"15","name":"Science & Technology"},"views":154,"sensitive":false,"waitTranscoding":false,"state":1,"commentsEnabled":true,"downloadEnabled":true,"published":"2020-05-24T18:34:31.569Z","originallyPublishedAt":"2019-11-30T23:00:00.000Z","updated":"2020-08-17T11:01:02.994Z","mediaType":"text/markdown","content":"Après avoir mené avec un certain succès la campagne « Dégooglisons Internet » en 2014, l’association Framasoft annonce fin 2019 arrêter progressivement un certain nombre de ses services alternatifs aux GAFAM. Pourquoi ?\r\n\r\nTranscription par @aprilorg ici : https://www.april.org/deframasoftisons-internet-pierre-yves-gosset-framasoft","support":null,"subtitleLanguage":[],"icon":[{"type":"Image","url":"https://framatube.org/static/thumbnails/6050732a-8a7a-43d4-a6cd-809525a1d206.jpg","mediaType":"image/jpeg","width":223,"height":122},{"type":"Image","url":"https://framatube.org/static/previews/6050732a-8a7a-43d4-a6cd-809525a1d206.jpg","mediaType":"image/jpeg","width":850,"height":480}],"url":[{"type":"Link","mediaType":"text/html","href":"https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206"},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4","height":1080,"size":1157359410,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309939","height":1080,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-1080.torrent","height":1080},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-1080.torrent&xt=urn:btih:381c9429900552e23a4eb506318f1fa01e4d63a8&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fwebseed%2F6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4&ws=https%3A%2F%2Fpeertube.iselfhost.com%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4&ws=https%3A%2F%2Ftube.privacytools.io%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4&ws=https%3A%2F%2Fpeertube.live%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4","height":1080},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-720.mp4","height":720,"size":497100839,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309943","height":720,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-720.torrent","height":720},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-720.torrent&xt=urn:btih:71971668f82a3b24ac71bc3a982848dd8dc5a5f5&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fwebseed%2F6050732a-8a7a-43d4-a6cd-809525a1d206-720.mp4&ws=https%3A%2F%2Ftube.privacytools.io%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-720.mp4&ws=https%3A%2F%2Fpeertube.iselfhost.com%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-720.mp4&ws=https%3A%2F%2Fpeertube.live%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-720.mp4","height":720},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-480.mp4","height":480,"size":250095131,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309941","height":480,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-480.torrent","height":480},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-480.torrent&xt=urn:btih:a181dcbb5368ab5c31cc9ff07634becb72c344ee&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fwebseed%2F6050732a-8a7a-43d4-a6cd-809525a1d206-480.mp4&ws=https%3A%2F%2Fpeertube.iselfhost.com%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-480.mp4&ws=https%3A%2F%2Ftube.privacytools.io%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-480.mp4&ws=https%3A%2F%2Fpeertube.live%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-480.mp4","height":480},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-360.mp4","height":360,"size":171357733,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309942","height":360,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-360.torrent","height":360},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-360.torrent&xt=urn:btih:aedfa9479ea04a175eee0b0bd0bda64076308746&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fwebseed%2F6050732a-8a7a-43d4-a6cd-809525a1d206-360.mp4&ws=https%3A%2F%2Fpeertube.iselfhost.com%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-360.mp4&ws=https%3A%2F%2Ftube.privacytools.io%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-360.mp4&ws=https%3A%2F%2Fpeertube.live%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-360.mp4","height":360},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-240.mp4","height":240,"size":113038439,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309944","height":240,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-240.torrent","height":240},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-240.torrent&xt=urn:btih:c42aa6c95efb28d9f114ebd98537f7b00fa72246&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fwebseed%2F6050732a-8a7a-43d4-a6cd-809525a1d206-240.mp4&ws=https%3A%2F%2Fpeertube.iselfhost.com%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-240.mp4&ws=https%3A%2F%2Ftube.privacytools.io%2Fstatic%2Fredundancy%2F6050732a-8a7a-43d4-a6cd-809525a1d206-240.mp4","height":240},{"type":"Link","mediaType":"application/x-mpegURL","href":"https://framatube.org/static/streaming-playlists/hls/6050732a-8a7a-43d4-a6cd-809525a1d206/master.m3u8","tag":[{"type":"Infohash","name":"f7428214539626e062f300f2ca4cf9154575144e"},{"type":"Infohash","name":"46e236dffb1ea6b9123a5396cbe88e97dd94cc6c"},{"type":"Infohash","name":"11f1045830b5d786c788f2594d19f128764e7d87"},{"type":"Infohash","name":"4327ad3e0d84de100130a27e9ab6fe40c4284f0e"},{"type":"Infohash","name":"41e2eee8e7b23a63c23a77c40a46de11492a4831"},{"type":"Link","name":"sha256","mediaType":"application/json","href":"https://framatube.org/static/streaming-playlists/hls/6050732a-8a7a-43d4-a6cd-809525a1d206/segments-sha256.json"},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/streaming-playlists/hls/6050732a-8a7a-43d4-a6cd-809525a1d206/6050732a-8a7a-43d4-a6cd-809525a1d206-1080-fragmented.mp4","height":1080,"size":1156777472,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309940","height":1080,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-1080-hls.torrent","height":1080},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-1080-hls.torrent&xt=urn:btih:0204d780ebfab0d5d9d3476a038e812ad792deeb&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fstreaming-playlists%2Fhls%2F6050732a-8a7a-43d4-a6cd-809525a1d206%2F6050732a-8a7a-43d4-a6cd-809525a1d206-1080-fragmented.mp4","height":1080},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/streaming-playlists/hls/6050732a-8a7a-43d4-a6cd-809525a1d206/6050732a-8a7a-43d4-a6cd-809525a1d206-720-fragmented.mp4","height":720,"size":496533741,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309947","height":720,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-720-hls.torrent","height":720},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-720-hls.torrent&xt=urn:btih:8ed1e8bccde709901c26e315fc8f53bfd26d1ba6&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fstreaming-playlists%2Fhls%2F6050732a-8a7a-43d4-a6cd-809525a1d206%2F6050732a-8a7a-43d4-a6cd-809525a1d206-720-fragmented.mp4","height":720},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/streaming-playlists/hls/6050732a-8a7a-43d4-a6cd-809525a1d206/6050732a-8a7a-43d4-a6cd-809525a1d206-480-fragmented.mp4","height":480,"size":249562889,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309945","height":480,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-480-hls.torrent","height":480},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-480-hls.torrent&xt=urn:btih:5d14f38ded29de629668fe1cfc61a75f4cce2628&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fstreaming-playlists%2Fhls%2F6050732a-8a7a-43d4-a6cd-809525a1d206%2F6050732a-8a7a-43d4-a6cd-809525a1d206-480-fragmented.mp4","height":480},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/streaming-playlists/hls/6050732a-8a7a-43d4-a6cd-809525a1d206/6050732a-8a7a-43d4-a6cd-809525a1d206-360-fragmented.mp4","height":360,"size":170836415,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309946","height":360,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-360-hls.torrent","height":360},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-360-hls.torrent&xt=urn:btih:30125488789080ad405ebcee6c214945f31b8f30&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fstreaming-playlists%2Fhls%2F6050732a-8a7a-43d4-a6cd-809525a1d206%2F6050732a-8a7a-43d4-a6cd-809525a1d206-360-fragmented.mp4","height":360},{"type":"Link","mediaType":"video/mp4","href":"https://framatube.org/static/streaming-playlists/hls/6050732a-8a7a-43d4-a6cd-809525a1d206/6050732a-8a7a-43d4-a6cd-809525a1d206-240-fragmented.mp4","height":240,"size":112529249,"fps":25},{"type":"Link","rel":["metadata","video/mp4"],"mediaType":"application/json","href":"https://framatube.org/api/v1/videos/6050732a-8a7a-43d4-a6cd-809525a1d206/metadata/1309948","height":240,"fps":25},{"type":"Link","mediaType":"application/x-bittorrent","href":"https://framatube.org/static/torrents/6050732a-8a7a-43d4-a6cd-809525a1d206-240-hls.torrent","height":240},{"type":"Link","mediaType":"application/x-bittorrent;x-scheme-handler/magnet","href":"magnet:?xs=https%3A%2F%2Fframatube.org%2Fstatic%2Ftorrents%2F6050732a-8a7a-43d4-a6cd-809525a1d206-240-hls.torrent&xt=urn:btih:8b452bf4e70b9078d4e74ca8b5523cc9dc70d10a&dn=D%C3%A9framasoftisons+Internet+%5BFramasoft%5D&tr=wss%3A%2F%2Fframatube.org%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fframatube.org%2Ftracker%2Fannounce&ws=https%3A%2F%2Fframatube.org%2Fstatic%2Fstreaming-playlists%2Fhls%2F6050732a-8a7a-43d4-a6cd-809525a1d206%2F6050732a-8a7a-43d4-a6cd-809525a1d206-240-fragmented.mp4","height":240}]}],"likes":"https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206/likes","dislikes":"https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206/dislikes","shares":"https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206/announces","comments":"https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206/comments","attributedTo":[{"type":"Person","id":"https://framatube.org/accounts/framasoft"},{"type":"Group","id":"https://framatube.org/video-channels/bf54d359-cfad-4935-9d45-9d6be93f63e8"}],"to":["https://www.w3.org/ns/activitystreams#Public"],"cc":["https://framatube.org/accounts/framasoft/followers"]},"to":["https://www.w3.org/ns/activitystreams#Public"],"cc":["https://framatube.org/accounts/framasoft/followers"],"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1",{"RsaSignature2017":"https://w3id.org/security#RsaSignature2017"},{"pt":"https://joinpeertube.org/ns#","sc":"http://schema.org#","Hashtag":"as:Hashtag","uuid":"sc:identifier","category":"sc:category","licence":"sc:license","subtitleLanguage":"sc:subtitleLanguage","sensitive":"as:sensitive","language":"sc:inLanguage","Infohash":"pt:Infohash","Playlist":"pt:Playlist","PlaylistElement":"pt:PlaylistElement","originallyPublishedAt":"sc:datePublished","views":{"@type":"sc:Number","@id":"pt:views"},"state":{"@type":"sc:Number","@id":"pt:state"},"size":{"@type":"sc:Number","@id":"pt:size"},"fps":{"@type":"sc:Number","@id":"pt:fps"},"startTimestamp":{"@type":"sc:Number","@id":"pt:startTimestamp"},"stopTimestamp":{"@type":"sc:Number","@id":"pt:stopTimestamp"},"position":{"@type":"sc:Number","@id":"pt:position"},"commentsEnabled":{"@type":"sc:Boolean","@id":"pt:commentsEnabled"},"downloadEnabled":{"@type":"sc:Boolean","@id":"pt:downloadEnabled"},"waitTranscoding":{"@type":"sc:Boolean","@id":"pt:waitTranscoding"},"support":{"@type":"sc:Text","@id":"pt:support"},"likes":{"@id":"as:likes","@type":"@id"},"dislikes":{"@id":"as:dislikes","@type":"@id"},"playlists":{"@id":"pt:playlists","@type":"@id"},"shares":{"@id":"as:shares","@type":"@id"},"comments":{"@id":"as:comments","@type":"@id"}}]} \ No newline at end of file
diff --git a/test/fixtures/tesla_mock/http__gs.example.org_index.php_api_statuses_user_timeline_1.atom.xml b/test/fixtures/tesla_mock/http__gs.example.org_index.php_api_statuses_user_timeline_1.atom.xml
deleted file mode 100644
index 490467708..000000000
--- a/test/fixtures/tesla_mock/http__gs.example.org_index.php_api_statuses_user_timeline_1.atom.xml
+++ /dev/null
@@ -1,460 +0,0 @@
-<?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.2.0-beta4">GNU social</generator>
- <id>http://gs.example.org/index.php/api/statuses/user_timeline/1.atom</id>
- <title>lambda timeline</title>
- <subtitle>Updates from lambda on gs.example.org!</subtitle>
- <logo>http://gs.example.org/theme/neo-gnu/default-avatar-profile.png</logo>
- <updated>2017-05-05T12:09:57+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/index.php/lambda"/>
- <link rel="avatar" type="image/png" media:width="96" media:height="96" href="http://gs.example.org/theme/neo-gnu/default-avatar-profile.png"/>
- <link rel="avatar" type="image/png" media:width="48" media:height="48" href="http://gs.example.org/theme/neo-gnu/default-avatar-stream.png"/>
- <link rel="avatar" type="image/png" media:width="24" media:height="24" href="http://gs.example.org/theme/neo-gnu/default-avatar-mini.png"/>
- <poco:preferredUsername>lambda</poco:preferredUsername>
- <poco:displayName>lambda</poco:displayName>
- <followers url="http://gs.example.org/index.php/lambda/subscribers"></followers>
- <statusnet:profile_info local_id="1"></statusnet:profile_info>
-</author>
- <link href="http://gs.example.org/index.php/lambda" rel="alternate" type="text/html"/>
- <link href="http://gs.example.org/index.php/main/sup" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/>
- <link href="http://gs.example.org/index.php/api/statuses/user_timeline/1.atom?max_id=34" rel="next" type="application/atom+xml"/>
- <link href="http://gs.example.org/index.php/main/push/hub" rel="hub"/>
- <link href="http://gs.example.org/index.php/main/salmon/user/1" rel="salmon"/>
- <link href="http://gs.example.org/index.php/main/salmon/user/1" rel="http://salmon-protocol.org/ns/salmon-replies"/>
- <link href="http://gs.example.org/index.php/main/salmon/user/1" rel="http://salmon-protocol.org/ns/salmon-mention"/>
- <link href="http://gs.example.org/index.php/api/statuses/user_timeline/1.atom" rel="self" type="application/atom+xml"/>
-<entry>
- <id>tag:gs.example.org,2017-05-04:noticeId=84:objectType=note</id>
- <title>lambda repeated a notice by lambda2</title>
- <content type="html">RT @&lt;a href=&quot;http://gs.example.org/index.php/user/7&quot; class=&quot;h-card mention&quot;&gt;lambda2&lt;/a&gt; Hello!</content>
- <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/84"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb>
- <published>2017-05-04T16:38:50+00:00</published>
- <updated>2017-05-04T16:38:50+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
- <id>tag:gs.example.org,2017-05-01:noticeId=67:objectType=note</id>
- <title></title>
- <content type="html">Hello!</content>
- <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/67"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-05-01T08:41:04+00:00</published>
- <updated>2017-05-01T08:41:04+00:00</updated>
- <author>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <uri>http://gs.example.org/index.php/user/7</uri>
- <name>lambda2</name>
- <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/lambda2"/>
- <link rel="avatar" type="image/png" media:width="270" media:height="270" href="http://gs.example.org/avatar/7-270-20170501084053.png"/>
- <link rel="avatar" type="image/png" media:width="96" media:height="96" href="http://gs.example.org/avatar/7-96-20170501084054.png"/>
- <link rel="avatar" type="image/png" media:width="48" media:height="48" href="http://gs.example.org/avatar/7-48-20170501084104.png"/>
- <link rel="avatar" type="image/png" media:width="24" media:height="24" href="http://gs.example.org/avatar/7-24-20170501084104.png"/>
- <poco:preferredUsername>lambda2</poco:preferredUsername>
- <poco:displayName>lambda2</poco:displayName>
- <followers url="http://gs.example.org/index.php/lambda2/subscribers"></followers>
- <statusnet:profile_info local_id="7"></statusnet:profile_info>
- </author>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:gs.example.org,2017-05-01:noticeId=67:objectType=note</id>
- <title>New note by lambda2</title>
- <content type="html">Hello!</content>
- <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/67"/>
- <status_net notice_id="67"></status_net>
- </activity:object>
- <link rel="ostatus:conversation" href="tag:gs.example.org,2017-05-01:objectType=thread:nonce=cffa792cb95fe417"/>
- <ostatus:conversation>tag:gs.example.org,2017-05-01:objectType=thread:nonce=cffa792cb95fe417</ostatus:conversation>
- <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/index.php/api/statuses/user_timeline/7.atom</id>
- <title>lambda2</title>
- <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/lambda2"/>
- <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/user_timeline/7.atom"/>
- <link rel="license" href="https://creativecommons.org/licenses/by/3.0/"/>
- <icon>http://gs.example.org/avatar/7-96-20170501084054.png</icon>
- <updated>2017-05-01T16:33:10+00:00</updated>
- </source>
- <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/67.atom"/>
- <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/67.atom"/>
- </activity:object>
- <link rel="ostatus:conversation" href="tag:gs.example.org,2017-05-01:objectType=thread:nonce=cffa792cb95fe417"/>
- <ostatus:conversation>tag:gs.example.org,2017-05-01:objectType=thread:nonce=cffa792cb95fe417</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="http://gs.example.org/index.php/api/statuses/show/84.atom"/>
- <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/84.atom"/>
- <statusnet:notice_info local_id="84" source="web" repeat_of="67"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:gs.example.org,2017-04-30:noticeId=63:objectType=note</id>
- <title>New note by lambda</title>
- <content type="html">what now?</content>
- <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/63"/>
- <status_net notice_id="63"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-04-30T10:09:57+00:00</published>
- <updated>2017-04-30T10:09:57+00:00</updated>
- <thr:in-reply-to ref="http://pleroma.example.org:4000/objects/477d8933-7591-4755-ba7a-2c34073ddc3c" href="http://pleroma.example.org:4000/objects/477d8933-7591-4755-ba7a-2c34073ddc3c"></thr:in-reply-to>
- <link rel="related" href="http://pleroma.example.org:4000/objects/477d8933-7591-4755-ba7a-2c34073ddc3c"/>
- <link rel="ostatus:conversation" href="tag:gs.example.org,2017-04-30:objectType=thread:nonce=1bbb60991ae9874b"/>
- <ostatus:conversation>tag:gs.example.org,2017-04-30:objectType=thread:nonce=1bbb60991ae9874b</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"/>
- <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/63.atom"/>
- <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/63.atom"/>
- <statusnet:notice_info local_id="63" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:gs.example.org,2017-04-30:noticeId=61:objectType=note</id>
- <title>New note by lambda</title>
- <content type="html">@&lt;a href=&quot;http://pleroma.example.org:4000/users/lain5&quot; class=&quot;h-card mention&quot;&gt;lain5&lt;/a&gt; Hello!</content>
- <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/61"/>
- <status_net notice_id="61"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-04-30T10:07:26+00:00</published>
- <updated>2017-04-30T10:07:26+00:00</updated>
- <link rel="ostatus:conversation" href="tag:gs.example.org,2017-04-30:objectType=thread:nonce=1bbb60991ae9874b"/>
- <ostatus:conversation>tag:gs.example.org,2017-04-30:objectType=thread:nonce=1bbb60991ae9874b</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"/>
- <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/61.atom"/>
- <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/61.atom"/>
- <statusnet:notice_info local_id="61" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:gs.example.org,2017-04-29:noticeId=59:objectType=note</id>
- <title>New note by lambda</title>
- <content type="html">ey</content>
- <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/59"/>
- <status_net notice_id="59"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-04-29T17:04:59+00:00</published>
- <updated>2017-04-29T17:04:59+00:00</updated>
- <link rel="ostatus:conversation" href="tag:gs.example.org,2017-04-29:objectType=thread:nonce=4cc42c2c61a0f4bd"/>
- <ostatus:conversation>tag:gs.example.org,2017-04-29:objectType=thread:nonce=4cc42c2c61a0f4bd</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="http://gs.example.org/index.php/api/statuses/show/59.atom"/>
- <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/59.atom"/>
- <statusnet:notice_info local_id="59" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:gs.example.org,2017-04-29:noticeId=58:objectType=note</id>
- <title>New note by lambda</title>
- <content type="html">Another one.</content>
- <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/58"/>
- <status_net notice_id="58"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-04-29T17:02:47+00:00</published>
- <updated>2017-04-29T17:02:47+00:00</updated>
- <link rel="ostatus:conversation" href="tag:gs.example.org,2017-04-29:objectType=thread:nonce=53e9b8f1d6d38d13"/>
- <ostatus:conversation>tag:gs.example.org,2017-04-29:objectType=thread:nonce=53e9b8f1d6d38d13</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="http://gs.example.org/index.php/api/statuses/show/58.atom"/>
- <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/58.atom"/>
- <statusnet:notice_info local_id="58" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:gs.example.org,2017-04-29:noticeId=57:objectType=note</id>
- <title>New note by lambda</title>
- <content type="html">Let's see if this comes over.</content>
- <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/57"/>
- <status_net notice_id="57"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-04-29T17:01:39+00:00</published>
- <updated>2017-04-29T17:01:39+00:00</updated>
- <link rel="ostatus:conversation" href="tag:gs.example.org,2017-04-29:objectType=thread:nonce=238a7bd3ffc7c9cc"/>
- <ostatus:conversation>tag:gs.example.org,2017-04-29:objectType=thread:nonce=238a7bd3ffc7c9cc</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="http://gs.example.org/index.php/api/statuses/show/57.atom"/>
- <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/57.atom"/>
- <statusnet:notice_info local_id="57" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:gs.example.org,2017-04-29:noticeId=56:objectType=note</id>
- <title>New note by lambda</title>
- <content type="html">@&lt;a href=&quot;http://pleroma.example.org:4000/users/lain5&quot; class=&quot;h-card mention&quot;&gt;lain5&lt;/a&gt; Hey!</content>
- <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/56"/>
- <status_net notice_id="56"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-04-29T16:38:13+00:00</published>
- <updated>2017-04-29T16:38:13+00:00</updated>
- <link rel="ostatus:conversation" href="tag:gs.example.org,2017-04-29:objectType=thread:nonce=2629d3a398171b0f"/>
- <ostatus:conversation>tag:gs.example.org,2017-04-29:objectType=thread:nonce=2629d3a398171b0f</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"/>
- <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/56.atom"/>
- <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/56.atom"/>
- <statusnet:notice_info local_id="56" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <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/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>
- <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"/>
- <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/55.atom"/>
- <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/55.atom"/>
- <statusnet:notice_info local_id="55" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:gs.example.org:4040,2017-04-25:noticeId=53:objectType=note</id>
- <title>New note by lambda</title>
- <content type="html">and this?</content>
- <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/53"/>
- <status_net notice_id="53"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-04-25T18:14:34+00:00</published>
- <updated>2017-04-25T18:14:34+00:00</updated>
- <thr:in-reply-to ref="http://pleroma.example.org:4000/objects/875b219f-8ced-4948-832e-137a06a88031" href="http://pleroma.example.org:4000/objects/875b219f-8ced-4948-832e-137a06a88031"></thr:in-reply-to>
- <link rel="related" href="http://pleroma.example.org:4000/objects/875b219f-8ced-4948-832e-137a06a88031"/>
- <link rel="ostatus:conversation" href="http://pleroma.example.org:4000/contexts/24779b0e-91ad-487e-81bd-6cf5bb437b09"/>
- <ostatus:conversation>http://pleroma.example.org:4000/contexts/24779b0e-91ad-487e-81bd-6cf5bb437b09</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"/>
- <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/53.atom"/>
- <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/53.atom"/>
- <statusnet:notice_info local_id="53" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:gs.example.org:4040,2017-04-25:noticeId=52:objectType=note</id>
- <title>New note by lambda</title>
- <content type="html">yeah it does :)</content>
- <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/52"/>
- <status_net notice_id="52"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-04-25T18:13:31+00:00</published>
- <updated>2017-04-25T18:13:31+00:00</updated>
- <thr:in-reply-to ref="http://pleroma.example.org:4000/objects/9c0430b4-ccb3-4e2c-9c50-ee345ebe18fc" href="http://pleroma.example.org:4000/objects/9c0430b4-ccb3-4e2c-9c50-ee345ebe18fc"></thr:in-reply-to>
- <link rel="related" href="http://pleroma.example.org:4000/objects/9c0430b4-ccb3-4e2c-9c50-ee345ebe18fc"/>
- <link rel="ostatus:conversation" href="tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=e0dc24b1a93ab6b3"/>
- <ostatus:conversation>tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=e0dc24b1a93ab6b3</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"/>
- <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/52.atom"/>
- <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/52.atom"/>
- <statusnet:notice_info local_id="52" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:gs.example.org:4040,2017-04-25:noticeId=50:objectType=note</id>
- <title>New note by lambda</title>
- <content type="html">@&lt;a href=&quot;http://pleroma.example.org:4000/users/lain5&quot; class=&quot;h-card mention&quot;&gt;lain5&lt;/a&gt; Let's try with one that originates here!</content>
- <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/50"/>
- <status_net notice_id="50"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-04-25T18:10:28+00:00</published>
- <updated>2017-04-25T18:10:28+00:00</updated>
- <link rel="ostatus:conversation" href="tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=e0dc24b1a93ab6b3"/>
- <ostatus:conversation>tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=e0dc24b1a93ab6b3</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"/>
- <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/50.atom"/>
- <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/50.atom"/>
- <statusnet:notice_info local_id="50" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:gs.example.org:4040,2017-04-25:noticeId=48:objectType=note</id>
- <title>New note by lambda</title>
- <content type="html">works?</content>
- <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/48"/>
- <status_net notice_id="48"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-04-25T18:08:44+00:00</published>
- <updated>2017-04-25T18:08:44+00:00</updated>
- <thr:in-reply-to ref="http://pleroma.example.org:4000/objects/8664caae-1cd6-4c1f-b1d7-27bd4ce76966" href="http://pleroma.example.org:4000/objects/8664caae-1cd6-4c1f-b1d7-27bd4ce76966"></thr:in-reply-to>
- <link rel="related" href="http://pleroma.example.org:4000/objects/8664caae-1cd6-4c1f-b1d7-27bd4ce76966"/>
- <link rel="ostatus:conversation" href="http://pleroma.example.org:4000/contexts/24779b0e-91ad-487e-81bd-6cf5bb437b09"/>
- <ostatus:conversation>http://pleroma.example.org:4000/contexts/24779b0e-91ad-487e-81bd-6cf5bb437b09</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"/>
- <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/48.atom"/>
- <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/48.atom"/>
- <statusnet:notice_info local_id="48" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:gs.example.org:4040,2017-04-25:noticeId=46:objectType=note</id>
- <title>New note by lambda</title>
- <content type="html">Let's send you an answer.</content>
- <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/46"/>
- <status_net notice_id="46"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-04-25T18:05:31+00:00</published>
- <updated>2017-04-25T18:05:31+00:00</updated>
- <thr:in-reply-to ref="http://pleroma.example.org:4000/objects/89ec2578-3f05-4b04-99b8-3e40f1282491" href="http://pleroma.example.org:4000/objects/89ec2578-3f05-4b04-99b8-3e40f1282491"></thr:in-reply-to>
- <link rel="related" href="http://pleroma.example.org:4000/objects/89ec2578-3f05-4b04-99b8-3e40f1282491"/>
- <link rel="ostatus:conversation" href="tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=73c7bcf6658f7ce3"/>
- <ostatus:conversation>tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=73c7bcf6658f7ce3</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"/>
- <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/46.atom"/>
- <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/46.atom"/>
- <statusnet:notice_info local_id="46" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:gs.example.org:4040,2017-04-25:noticeId=44: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/index.php/notice/44"/>
- <status_net notice_id="44"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-04-25T18:01:09+00:00</published>
- <updated>2017-04-25T18:01:09+00:00</updated>
- <thr:in-reply-to ref="http://pleroma.example.org:4000/objects/5047e0a8-2302-483a-a420-ae835f5ca5a1" href="http://pleroma.example.org:4000/objects/5047e0a8-2302-483a-a420-ae835f5ca5a1"></thr:in-reply-to>
- <link rel="related" href="http://pleroma.example.org:4000/objects/5047e0a8-2302-483a-a420-ae835f5ca5a1"/>
- <link rel="ostatus:conversation" href="tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=6e7c8fc2823380b4"/>
- <ostatus:conversation>tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=6e7c8fc2823380b4</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"/>
- <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/44.atom"/>
- <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/44.atom"/>
- <statusnet:notice_info local_id="44" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:gs.example.org:4040,2017-04-25:noticeId=43:objectType=note</id>
- <title>New note by lambda</title>
- <content type="html">What's coming to you?</content>
- <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/43"/>
- <status_net notice_id="43"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-04-25T17:58:41+00:00</published>
- <updated>2017-04-25T17:58:41+00:00</updated>
- <thr:in-reply-to ref="http://pleroma.example.org:4000/objects/5047e0a8-2302-483a-a420-ae835f5ca5a1" href="http://pleroma.example.org:4000/objects/5047e0a8-2302-483a-a420-ae835f5ca5a1"></thr:in-reply-to>
- <link rel="related" href="http://pleroma.example.org:4000/objects/5047e0a8-2302-483a-a420-ae835f5ca5a1"/>
- <link rel="ostatus:conversation" href="tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=6e7c8fc2823380b4"/>
- <ostatus:conversation>tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=6e7c8fc2823380b4</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"/>
- <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/43.atom"/>
- <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/43.atom"/>
- <statusnet:notice_info local_id="43" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:gs.example.org:4040,2017-04-25:noticeId=42:objectType=note</id>
- <title>New note by lambda</title>
- <content type="html">Now this is podracing.</content>
- <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/42"/>
- <status_net notice_id="42"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-04-25T17:57:40+00:00</published>
- <updated>2017-04-25T17:57:40+00:00</updated>
- <thr:in-reply-to ref="http://pleroma.example.org:4000/objects/5047e0a8-2302-483a-a420-ae835f5ca5a1" href="http://pleroma.example.org:4000/objects/5047e0a8-2302-483a-a420-ae835f5ca5a1"></thr:in-reply-to>
- <link rel="related" href="http://pleroma.example.org:4000/objects/5047e0a8-2302-483a-a420-ae835f5ca5a1"/>
- <link rel="ostatus:conversation" href="tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=6e7c8fc2823380b4"/>
- <ostatus:conversation>tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=6e7c8fc2823380b4</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"/>
- <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/42.atom"/>
- <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/42.atom"/>
- <statusnet:notice_info local_id="42" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:gs.example.org:4040,2017-04-25:noticeId=39:objectType=note</id>
- <title>New note by lambda</title>
- <content type="html">Sure looks like it!</content>
- <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/39"/>
- <status_net notice_id="39"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-04-25T17:48:27+00:00</published>
- <updated>2017-04-25T17:48:27+00:00</updated>
- <thr:in-reply-to ref="http://pleroma.example.org:4000/objects/c9fe09c2-7504-46d2-a4f6-44a708455e6f" href="http://pleroma.example.org:4000/objects/c9fe09c2-7504-46d2-a4f6-44a708455e6f"></thr:in-reply-to>
- <link rel="related" href="http://pleroma.example.org:4000/objects/c9fe09c2-7504-46d2-a4f6-44a708455e6f"/>
- <link rel="ostatus:conversation" href="tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=4c6114a75bb4cea5"/>
- <ostatus:conversation>tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=4c6114a75bb4cea5</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"/>
- <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/39.atom"/>
- <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/39.atom"/>
- <statusnet:notice_info local_id="39" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:gs.example.org:4040,2017-04-25:subscription:1:person:6:2017-04-25T17:47:47+00:00</id>
- <title>lambda (lambda)'s status on Tuesday, 25-Apr-2017 17:47:47 UTC</title>
- <content type="html">&lt;a href=&quot;http://gs.example.org:4040/index.php/lambda&quot;&gt;lambda&lt;/a&gt; started following &lt;a href=&quot;http://pleroma.example.org:4000/users/lain5&quot;&gt;l&lt;/a&gt;.</content>
- <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/37"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>
- <published>2017-04-25T17:47:47+00:00</published>
- <updated>2017-04-25T17:47:47+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <id>http://pleroma.example.org:4000/users/lain5</id>
- <title>l</title>
- <summary>lambadalambda</summary>
- <link rel="alternate" type="text/html" href="http://pleroma.example.org:4000/users/lain5"/>
- <link rel="avatar" type="image/png" media:width="48" media:height="48" href="http://gs.example.org/avatar/6-original-20170425174605.png"/>
- <link rel="avatar" type="image/png" media:width="96" media:height="96" href="http://gs.example.org/avatar/6-96-20170425174605.png"/>
- <link rel="avatar" type="image/png" media:width="48" media:height="48" href="http://gs.example.org/avatar/6-original-20170425174605.png"/>
- <link rel="avatar" type="image/png" media:width="24" media:height="24" href="http://gs.example.org/avatar/6-24-20170425174747.png"/>
- <poco:preferredUsername>lain5</poco:preferredUsername>
- <poco:displayName>l</poco:displayName>
- <poco:note>lambadalambda</poco:note>
- </activity:object>
- <link rel="ostatus:conversation" href="tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=119acad17515314c"/>
- <ostatus:conversation>tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=119acad17515314c</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="http://gs.example.org/index.php/api/statuses/show/37.atom"/>
- <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/37.atom"/>
- <statusnet:notice_info local_id="37" source="activity"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:gs.example.org:4040,2017-04-25:noticeId=36:objectType=note</id>
- <title>New note by lambda</title>
- <content type="html">@&lt;a href=&quot;http://pleroma.example.org:4000/users/lain5&quot; class=&quot;h-card mention&quot;&gt;lain5&lt;/a&gt; Hey, how are you?</content>
- <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/36"/>
- <status_net notice_id="36"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-04-25T17:46:22+00:00</published>
- <updated>2017-04-25T17:46:22+00:00</updated>
- <link rel="ostatus:conversation" href="tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=9c5ec19a18191372"/>
- <ostatus:conversation>tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=9c5ec19a18191372</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"/>
- <link rel="self" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/36.atom"/>
- <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/36.atom"/>
- <statusnet:notice_info local_id="36" source="web"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:gs.example.org:4040,2017-04-25:noticeId=35:objectType=note</id>
- <title>New note by lambda</title>
- <content type="html">@lain5@pleroma.example.org does this not work?</content>
- <link rel="alternate" type="text/html" href="http://gs.example.org/index.php/notice/35"/>
- <status_net notice_id="35"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-04-25T17:42:31+00:00</published>
- <updated>2017-04-25T17:42:31+00:00</updated>
- <link rel="ostatus:conversation" href="tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=fc841d7f52caa363"/>
- <ostatus:conversation>tag:gs.example.org:4040,2017-04-25:objectType=thread:nonce=fc841d7f52caa363</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="http://gs.example.org/index.php/api/statuses/show/35.atom"/>
- <link rel="edit" type="application/atom+xml" href="http://gs.example.org/index.php/api/statuses/show/35.atom"/>
- <statusnet:notice_info local_id="35" source="web"></statusnet:notice_info>
-</entry>
-</feed>
diff --git a/test/fixtures/tesla_mock/https___mamot.fr_users_Skruyb.atom b/test/fixtures/tesla_mock/https___mamot.fr_users_Skruyb.atom
deleted file mode 100644
index b5f3d923b..000000000
--- a/test/fixtures/tesla_mock/https___mamot.fr_users_Skruyb.atom
+++ /dev/null
@@ -1,342 +0,0 @@
-<?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://mamot.fr/users/Skruyb.atom</id>
- <title>The 7th Son</title>
- <subtitle>Fr and En.
-Posts will disappear on a regular basis.</subtitle>
- <updated>2017-04-28T13:54:23Z</updated>
- <logo>https://mamot.fr/system/accounts/avatars/000/026/213/original/d95dbcfc76f77f4c.jpg?1493230984</logo>
- <author>
- <id>https://mamot.fr/users/Skruyb</id>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <uri>https://mamot.fr/users/Skruyb</uri>
- <name>Skruyb</name>
- <email>Skruyb@mamot.fr</email>
- <summary type="html">&lt;p&gt;Fr and En.&lt;br /&gt;Posts will disappear on a regular basis.&lt;/p&gt;</summary>
- <link rel="alternate" type="text/html" href="https://mamot.fr/@Skruyb"/>
- <link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://mamot.fr/system/accounts/avatars/000/026/213/original/d95dbcfc76f77f4c.jpg?1493230984"/>
- <link rel="header" type="image/jpeg" media:width="700" media:height="335" href="https://mamot.fr/system/accounts/headers/000/026/213/original/c1aabdf5c97eb875.jpg?1492797601"/>
- <poco:preferredUsername>Skruyb</poco:preferredUsername>
- <poco:displayName>The 7th Son</poco:displayName>
- <poco:note>Fr and En.
-Posts will disappear on a regular basis.</poco:note>
- <mastodon:scope>public</mastodon:scope>
- </author>
- <link rel="alternate" type="text/html" href="https://mamot.fr/@Skruyb"/>
- <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb.atom"/>
- <link rel="next" type="application/atom+xml" href="https://mamot.fr/users/Skruyb.atom?max_id=175878"/>
- <link rel="hub" href="https://mamot.fr/api/push"/>
- <link rel="salmon" href="https://mamot.fr/api/salmon/26213"/>
- <entry>
- <id>tag:mamot.fr,2017-05-10:objectId=1299665:objectType=Status</id>
- <published>2017-05-10T20:06:59Z</published>
- <updated>2017-05-10T20:06:59Z</updated>
- <title>New status by Skruyb</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="es">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://pouets.ovh/@noName" class="u-url mention"&gt;@&lt;span&gt;noName&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Pour comparer faut avoir tester... Ô wait!!! 😁&lt;/p&gt;</content>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pouets.ovh/users/noName"/>
- <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://mamot.fr/users/Skruyb/updates/176780"/>
- <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176780.atom"/>
- <thr:in-reply-to ref="tag:pouets.ovh,2017-05-10:objectId=114198:objectType=Status" href="https://pouets.ovh/users/noName/updates/1174"/>
- </entry>
- <entry>
- <id>tag:mamot.fr,2017-05-10:objectId=1299185:objectType=Status</id>
- <published>2017-05-10T19:52:14Z</published>
- <updated>2017-05-10T19:52:14Z</updated>
- <title>New status by Skruyb</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="fr">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://witches.town/@Dhveszak" class="u-url mention"&gt;@&lt;span&gt;Dhveszak&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Toi!! Tu vises le ministère de la propagande avoue!!!!!!!&lt;/p&gt;</content>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://witches.town/users/Dhveszak"/>
- <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://mamot.fr/users/Skruyb/updates/176702"/>
- <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176702.atom"/>
- <thr:in-reply-to ref="tag:witches.town,2017-05-10:objectId=1439170:objectType=Status" href="https://witches.town/users/Dhveszak/updates/193318"/>
- </entry>
- <entry>
- <id>tag:mamot.fr,2017-05-10:objectId=1299019:objectType=Status</id>
- <published>2017-05-10T19:47:19Z</published>
- <updated>2017-05-10T19:47:19Z</updated>
- <title>New status by Skruyb</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="fr">&lt;p&gt;Facebook s&amp;apos;attaque aux sites internet &amp;quot;trompeurs&amp;quot;&lt;/p&gt;&lt;p&gt;&lt;a href="http://u.afp.com/4W4z" rel="nofollow noopener" target="_blank"&gt;&lt;span class="invisible"&gt;http://&lt;/span&gt;&lt;span class=""&gt;u.afp.com/4W4z&lt;/span&gt;&lt;span class="invisible"&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;J&amp;apos;attends de voir que Facebook s&amp;apos;attaque à lui même... rien qu&amp;apos;à lire leurs conditions générales d&amp;apos;utilisation, le respect de la vie privée...&lt;/p&gt;&lt;p&gt;Charité bien ordonnée... Parfois l&amp;apos;égoïsme aurait du bon.&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://mamot.fr/users/Skruyb/updates/176668"/>
- <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176668.atom"/>
- </entry>
- <entry>
- <id>tag:mamot.fr,2017-05-10:objectId=1298889:objectType=Status</id>
- <published>2017-05-10T19:43:18Z</published>
- <updated>2017-05-10T19:43:18Z</updated>
- <title>New status by Skruyb</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="fr">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://octodon.social/@Balise" class="u-url mention"&gt;@&lt;span&gt;Balise&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Fait comme moi, annonce que tu fais dans le flou artistique et que seuls des esprits éclairés pourront en percevoir la beauté et apprécier. Globalement après ça, tout le monde trouve les photos cool :-p&lt;/p&gt;</content>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://octodon.social/users/Balise"/>
- <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://mamot.fr/users/Skruyb/updates/176641"/>
- <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176641.atom"/>
- <thr:in-reply-to ref="tag:octodon.social,2017-05-10:objectId=1887380:objectType=Status" href="https://octodon.social/users/Balise/updates/115220"/>
- </entry>
- <entry>
- <id>tag:mamot.fr,2017-05-10:objectId=1298728:objectType=Status</id>
- <published>2017-05-10T19:38:39Z</published>
- <updated>2017-05-10T19:38:39Z</updated>
- <title>New status by Skruyb</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="ru">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://mastodon.social/@applecandy" class="u-url mention"&gt;@&lt;span&gt;applecandy&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Lucky you!!!&lt;/p&gt;</content>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/applecandy"/>
- <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://mamot.fr/users/Skruyb/updates/176608"/>
- <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176608.atom"/>
- <thr:in-reply-to ref="tag:mastodon.social,2017-05-10:objectId=5578123:objectType=Status" href="https://mastodon.social/users/applecandy/updates/2317372"/>
- </entry>
- <entry>
- <id>tag:mamot.fr,2017-05-10:objectId=1298431:objectType=Status</id>
- <published>2017-05-10T19:26:32Z</published>
- <updated>2017-05-10T19:26:32Z</updated>
- <title>New status by Skruyb</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="fr">&lt;p&gt;Est-ce que je suis le seul qui lorsqu&amp;apos;il commence à compter les arbres sur le bord de la route n&amp;apos;arrive pas à s&amp;apos;arrêter de compter?&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://mamot.fr/users/Skruyb/updates/176561"/>
- <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176561.atom"/>
- </entry>
- <entry>
- <id>tag:mamot.fr,2017-05-10:objectId=1298224:objectType=Status</id>
- <published>2017-05-10T19:18:17Z</published>
- <updated>2017-05-10T19:18:17Z</updated>
- <title>New status by Skruyb</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="fr">&lt;p&gt;Ca y est j&amp;apos;ai une nouvelle passion. Mettre les bouchons qui trainent par terre dans le bons sens avec mon pied 🙌&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://mamot.fr/users/Skruyb/updates/176536"/>
- <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176536.atom"/>
- </entry>
- <entry>
- <id>tag:mamot.fr,2017-05-10:objectId=1297450:objectType=Status</id>
- <published>2017-05-10T18:53:37Z</published>
- <updated>2017-05-10T18:53:37Z</updated>
- <title>New status by Skruyb</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="fr">&lt;p&gt;Ok. On est capable d&amp;apos;envoyer des mecs dans l&amp;apos;espace, avoir des voitures autonomes, des trucs intelligents de partout mais pas tous les bâtiments accessibles aux personnes à mobilité réduite, les émissions sur le services publics avec une personne faisant la traduction pour les sourds et malentendants de manière systématique...&lt;/p&gt;&lt;p&gt;J&amp;apos;ai du louper un truc dans l&amp;apos;ordre des priorités Oo&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://mamot.fr/users/Skruyb/updates/176412"/>
- <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176412.atom"/>
- </entry>
- <entry>
- <id>tag:mamot.fr,2017-05-10:objectId=1297292:objectType=Status</id>
- <published>2017-05-10T18:48:17Z</published>
- <updated>2017-05-10T18:48:17Z</updated>
- <title>New status by Skruyb</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="fr">&lt;p&gt;J&amp;apos;ai comme envie de faire un truc mais je ne sais pas quoi mais pourtant c&amp;apos;est comme si je ressentais l&amp;apos;idée dans ma tête mais c&amp;apos;est pas clair...&lt;/p&gt;&lt;p&gt;Fuck!!! J&amp;apos;vais aller draguer Josiane à la compta ça va me changer les idées!!!&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://mamot.fr/users/Skruyb/updates/176387"/>
- <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176387.atom"/>
- </entry>
- <entry>
- <id>tag:mamot.fr,2017-05-10:objectId=1296598:objectType=Status</id>
- <published>2017-05-10T18:25:11Z</published>
- <updated>2017-05-10T18:25:11Z</updated>
- <title>New status by Skruyb</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="fr">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://mamot.fr/@Smeablog" class="u-url mention"&gt;@&lt;span&gt;Smeablog&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Pas faux MDR!!!!&lt;/p&gt;</content>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mamot.fr/users/Smeablog"/>
- <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://mamot.fr/users/Skruyb/updates/176320"/>
- <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176320.atom"/>
- <thr:in-reply-to ref="tag:mamot.fr,2017-05-10:objectId=1296591:objectType=Status" href="https://mamot.fr/@Smeablog/1296591"/>
- </entry>
- <entry>
- <id>tag:mamot.fr,2017-05-10:objectId=1296571:objectType=Status</id>
- <published>2017-05-10T18:24:13Z</published>
- <updated>2017-05-10T18:24:13Z</updated>
- <title>New status by Skruyb</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="fr">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://mamot.fr/@Smeablog" class="u-url mention"&gt;@&lt;span&gt;Smeablog&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Ca ne change pas la finalité malheureusement, ça ne m&amp;apos;ouvre pas ce à quoi je veux accéder 😭&lt;/p&gt;</content>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mamot.fr/users/Smeablog"/>
- <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://mamot.fr/users/Skruyb/updates/176315"/>
- <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176315.atom"/>
- <thr:in-reply-to ref="tag:mamot.fr,2017-05-10:objectId=1296531:objectType=Status" href="https://mamot.fr/@Smeablog/1296531"/>
- </entry>
- <entry>
- <id>tag:mamot.fr,2017-05-10:objectId=1296475:objectType=Status</id>
- <published>2017-05-10T18:20:50Z</published>
- <updated>2017-05-10T18:20:50Z</updated>
- <title>New status by Skruyb</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="fr">&lt;p&gt;Arrrgghhhhhhh!!!!&lt;/p&gt;&lt;p&gt;Quand t&amp;apos;es sur le point de cliquer sur un lien dans le fil public global et que BOOM ça se met à jour... J&amp;apos;ose même pas imaginer combien j&amp;apos;ai ouvert de pages web sans le vouloir!!!&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://mamot.fr/users/Skruyb/updates/176298"/>
- <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176298.atom"/>
- </entry>
- <entry>
- <id>tag:mamot.fr,2017-05-10:objectId=1296426:objectType=Status</id>
- <published>2017-05-10T18:19:17Z</published>
- <updated>2017-05-10T18:19:17Z</updated>
- <title>Skruyb shared a status by Isaluini@mastodon.social</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.social,2017-05-10:objectId=5587049:objectType=Status</id>
- <published>2017-05-10T18:18:59Z</published>
- <updated>2017-05-10T18:19:00Z</updated>
- <title>New status by Isaluini@mastodon.social</title>
- <author>
- <id>https://mastodon.social/users/Isaluini</id>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <uri>https://mastodon.social/users/Isaluini</uri>
- <name>Isaluini</name>
- <email>Isaluini@mastodon.social</email>
- <summary type="html">&lt;p&gt;Adicciones: Escribir, diseñar, cine, café, humor negro, música y dibujar. | Jedi. Bueno, no. Algún día (?) | Gratitude.&lt;/p&gt;</summary>
- <link rel="alternate" type="text/html" href="https://mastodon.social/@Isaluini"/>
- <link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://mamot.fr/system/accounts/avatars/000/027/466/original/6c4659e795647240.jpg?1493580262"/>
- <link rel="header" type="image/jpeg" media:width="700" media:height="335" href="https://mamot.fr/system/accounts/headers/000/027/466/original/608989b32a3efe1b.jpg?1493580262"/>
- <poco:preferredUsername>Isaluini</poco:preferredUsername>
- <poco:displayName>Isa</poco:displayName>
- <poco:note>Adicciones: Escribir, diseñar, cine, café, humor negro, música y dibujar. | Jedi. Bueno, no. Algún día (?) | Gratitude.</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="ru">&lt;p&gt;♫ &lt;br&gt;&lt;a href="https://www.youtube.com/watch?v=pT68FS3YbQ4"&gt;&lt;span class="invisible"&gt;https://www.&lt;/span&gt;&lt;span class="ellipsis"&gt;youtube.com/watch?v=pT68FS3YbQ&lt;/span&gt;&lt;span class="invisible"&gt;4&lt;/span&gt;&lt;/a&gt;&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/Isaluini/updates/2318469"/>
- </activity:object>
- <content type="html" xml:lang="en">&lt;p&gt;♫ &lt;br&gt;&lt;a href="https://www.youtube.com/watch?v=pT68FS3YbQ4"&gt;&lt;span class="invisible"&gt;https://www.&lt;/span&gt;&lt;span class="ellipsis"&gt;youtube.com/watch?v=pT68FS3YbQ&lt;/span&gt;&lt;span class="invisible"&gt;4&lt;/span&gt;&lt;/a&gt;&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://mamot.fr/users/Skruyb/updates/176292"/>
- <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176292.atom"/>
- </entry>
- <entry>
- <id>tag:mamot.fr,2017-05-10:objectId=1295893:objectType=Status</id>
- <published>2017-05-10T18:01:51Z</published>
- <updated>2017-05-10T18:01:51Z</updated>
- <title>New status by Skruyb</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="fr">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://mamot.fr/@Chat2Gouttieres" class="u-url mention"&gt;@&lt;span&gt;Chat2Gouttieres&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Ah bah après faut savoir mettre à profit ce savoir ^^&lt;/p&gt;</content>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mamot.fr/users/Chat2Gouttieres"/>
- <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://mamot.fr/users/Skruyb/updates/176203"/>
- <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176203.atom"/>
- <thr:in-reply-to ref="tag:mamot.fr,2017-05-10:objectId=1295869:objectType=Status" href="https://mamot.fr/@Chat2Gouttieres/1295869"/>
- </entry>
- <entry>
- <id>tag:mamot.fr,2017-05-10:objectId=1295815:objectType=Status</id>
- <published>2017-05-10T18:00:02Z</published>
- <updated>2017-05-10T18:00:02Z</updated>
- <title>New status by Skruyb</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="fr">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://mamot.fr/@Chat2Gouttieres" class="u-url mention"&gt;@&lt;span&gt;Chat2Gouttieres&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Exactement. On a les jeux mais pas le pain encore.&lt;/p&gt;&lt;p&gt;Finalement on a rien inventé :-p&lt;/p&gt;</content>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mamot.fr/users/Chat2Gouttieres"/>
- <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://mamot.fr/users/Skruyb/updates/176182"/>
- <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176182.atom"/>
- <thr:in-reply-to ref="tag:mamot.fr,2017-05-10:objectId=1295800:objectType=Status" href="https://mamot.fr/@Chat2Gouttieres/1295800"/>
- </entry>
- <entry>
- <id>tag:mamot.fr,2017-05-10:objectId=1295778:objectType=Status</id>
- <published>2017-05-10T17:58:52Z</published>
- <updated>2017-05-10T17:58:52Z</updated>
- <title>New status by Skruyb</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="fr">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://mamot.fr/@Chat2Gouttieres" class="u-url mention"&gt;@&lt;span&gt;Chat2Gouttieres&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;C&amp;apos;est ça visiblement dans notre société dite moderne... &amp;quot;Créer l&amp;apos;illusion que&amp;quot; Oo.&lt;/p&gt;</content>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mamot.fr/users/Chat2Gouttieres"/>
- <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://mamot.fr/users/Skruyb/updates/176174"/>
- <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176174.atom"/>
- <thr:in-reply-to ref="tag:mamot.fr,2017-05-10:objectId=1295765:objectType=Status" href="https://mamot.fr/@Chat2Gouttieres/1295765"/>
- </entry>
- <entry>
- <id>tag:mamot.fr,2017-05-10:objectId=1294943:objectType=Status</id>
- <published>2017-05-10T17:31:44Z</published>
- <updated>2017-05-10T17:31:44Z</updated>
- <title>New status by Skruyb</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>
- <summary xml:lang="it">Hey.</summary>
- <content type="html" xml:lang="it">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://mastodon.social/@lambadalambda" class="u-url mention"&gt;@&lt;span&gt;lambadalambda&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Hey!!!&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://mamot.fr/users/Skruyb/updates/176041"/>
- <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176041.atom"/>
- <thr:in-reply-to ref="tag:mastodon.social,2017-05-10:objectId=5582979:objectType=Status" href="https://mastodon.social/users/lambadalambda/updates/2317991"/>
- </entry>
- <entry>
- <id>tag:mamot.fr,2017-05-10:objectId=1294914:objectType=Status</id>
- <published>2017-05-10T17:30:40Z</published>
- <updated>2017-05-10T17:30:40Z</updated>
- <title>New status by Skruyb</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="fr">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://mamot.fr/@EloClemTiti" class="u-url mention"&gt;@&lt;span&gt;EloClemTiti&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;J&amp;apos;ai souvent cette impression en effet 😂&lt;/p&gt;</content>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mamot.fr/users/EloClemTiti"/>
- <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://mamot.fr/users/Skruyb/updates/176034"/>
- <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/176034.atom"/>
- <thr:in-reply-to ref="tag:mamot.fr,2017-05-10:objectId=1294608:objectType=Status" href="https://mamot.fr/@EloClemTiti/1294608"/>
- </entry>
- <entry>
- <id>tag:mamot.fr,2017-05-10:objectId=1294148:objectType=Status</id>
- <published>2017-05-10T17:02:01Z</published>
- <updated>2017-05-10T17:02:01Z</updated>
- <title>New status by Skruyb</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="fr">&lt;p&gt;Les gars, les boss veulent voir de l&amp;apos;avancement!! Une idée?&lt;/p&gt;&lt;p&gt;On fait comme d&amp;apos;habitude. On divise nos tâches en 25.000 tâches unitaires, on fout du vert au maximum et on crée l&amp;apos;illusion que ça a bien avancé!&lt;/p&gt;&lt;p&gt;Deal!!&lt;/p&gt;&lt;p&gt;Bob, tu choisis quel vert on utilise&lt;br /&gt;Alice, t&amp;apos;es en charge de la typo&lt;br /&gt;Moi, je m&amp;apos;occupe qu&amp;apos;on prend bien le dernier template ppt fournit par la comm interne.&lt;/p&gt;&lt;p&gt;Des winners qu&amp;apos;on est!!!! Des WI-NNERS!!!&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://mamot.fr/users/Skruyb/updates/175898"/>
- <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/175898.atom"/>
- </entry>
- <entry>
- <id>tag:mamot.fr,2017-05-10:objectId=1293995:objectType=Status</id>
- <published>2017-05-10T16:57:53Z</published>
- <updated>2017-05-10T16:57:53Z</updated>
- <title>New status by Skruyb</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="ru">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://mastodon.social/@SauceHair" class="u-url mention"&gt;@&lt;span&gt;SauceHair&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Cool!!&lt;/p&gt;&lt;p&gt;Bon courage.&lt;/p&gt;</content>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/SauceHair"/>
- <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://mamot.fr/users/Skruyb/updates/175878"/>
- <link rel="self" type="application/atom+xml" href="https://mamot.fr/users/Skruyb/updates/175878.atom"/>
- <thr:in-reply-to ref="tag:mastodon.social,2017-05-10:objectId=5579955:objectType=Status" href="https://mastodon.social/users/SauceHair/updates/2317615"/>
- </entry>
-</feed>
diff --git a/test/fixtures/tesla_mock/https___mastodon.social_users_lambadalambda.atom b/test/fixtures/tesla_mock/https___mastodon.social_users_lambadalambda.atom
deleted file mode 100644
index 4d732b109..000000000
--- a/test/fixtures/tesla_mock/https___mastodon.social_users_lambadalambda.atom
+++ /dev/null
@@ -1,464 +0,0 @@
-<?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</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>
- <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>
- <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=1616358"/>
- <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-05-04:objectId=4991300:objectType=Status</id>
- <published>2017-05-04T14:10:30Z</published>
- <updated>2017-05-04T14:10:30Z</updated>
- <title>Delete</title>
- <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
- <activity:verb>http://activitystrea.ms/schema/1.0/delete</activity:verb>
- <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/2247090"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2247090.atom"/>
- </entry>
- <entry>
- <id>tag:mastodon.social,2017-05-04:objectId=4980289:objectType=Status</id>
- <published>2017-05-04T07:43:23Z</published>
- <updated>2017-05-04T07:43:23Z</updated>
- <title>Delete</title>
- <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
- <activity:verb>http://activitystrea.ms/schema/1.0/delete</activity:verb>
- <link rel="alternate" type="text/html" href="https://mastodon.social/users/lambadalambda/updates/2244602"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2244602.atom"/>
- </entry>
- <entry>
- <id>tag:mastodon.social,2017-05-03:objectId=4952899:objectType=Status</id>
- <published>2017-05-03T17:26:43Z</published>
- <updated>2017-05-03T17:26: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://pleroma.soykaf.com/users/lain" class="u-url mention"&gt;@&lt;span&gt;lain&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; OK!!&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/2237124"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2237124.atom"/>
- <thr:in-reply-to ref="https://pleroma.soykaf.com/objects/5e755d92-f0ee-432f-8c17-590962aea59c" href=""/>
- </entry>
- <entry>
- <id>tag:mastodon.social,2017-05-03:objectId=4952810:objectType=Status</id>
- <published>2017-05-03T17:24:34Z</published>
- <updated>2017-05-03T17:24:34Z</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="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; yeah :)&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/2237089"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2237089.atom"/>
- <thr:in-reply-to ref="https://pleroma.soykaf.com/objects/32ff0743-236a-41e5-81c5-a3211088e741" href=""/>
- </entry>
- <entry>
- <id>tag:mastodon.social,2017-05-03:objectId=4950388:objectType=Status</id>
- <published>2017-05-03T16:22:00Z</published>
- <updated>2017-05-03T16:22:00Z</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-05-03:noticeId=2030733:objectType=note</id>
- <published>2017-05-03T12:29:20Z</published>
- <updated>2017-05-03T12:29:31Z</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 type="html">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"/>
- <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">Time for work. &lt;a href="https://social.heldscal.la/file/953c117a1e7e4c763755d2ac29cf1aae08e025599f4a4cc11ddff4082c07f969.jpg"&gt;https://social.heldscal.la/attachment/120552&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="383072" href="https://files.mastodon.social/media_attachments/files/000/391/513/original/953c117a1e7e4c763755d2ac29cf1aae08e025599f4a4cc11ddff4082c07f969.jpg"/>
- <mastodon:scope>public</mastodon:scope>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2030733"/>
- </activity:object>
- <content type="html" xml:lang="en">Time for work. &lt;a href="https://social.heldscal.la/file/953c117a1e7e4c763755d2ac29cf1aae08e025599f4a4cc11ddff4082c07f969.jpg"&gt;https://social.heldscal.la/attachment/120552&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/2236405"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2236405.atom"/>
- </entry>
- <entry>
- <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>
- <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>
- <entry>
- <id>tag:mastodon.social,2017-05-02:objectId=4905499:objectType=Status</id>
- <published>2017-05-02T19:34:21Z</published>
- <updated>2017-05-02T19:34:21Z</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="ru">&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; yay!&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/2226006"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2226006.atom"/>
- <thr:in-reply-to ref="https://pleroma.soykaf.com/objects/b79fa9cd-1d27-448a-844f-79f306bc75c9" href=""/>
- </entry>
- <entry>
- <id>tag:mastodon.social,2017-05-02:objectId=4905442:objectType=Status</id>
- <published>2017-05-02T19:33:33Z</published>
- <updated>2017-05-02T19:33:33Z</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="fa">&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; so?&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/2225992"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2225992.atom"/>
- <thr:in-reply-to ref="https://pleroma.soykaf.com/objects/233a878a-974e-4e75-b1c8-aa7657f561fc" href=""/>
- </entry>
- <entry>
- <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>
- <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>
- <entry>
- <id>tag:mastodon.social,2017-05-01:objectId=4836720:objectType=Status</id>
- <published>2017-05-01T18:52:16Z</published>
- <updated>2017-05-01T18:52:16Z</updated>
- <title>lambadalambda shared a status by lain@pleroma.soykaf.com</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>https://pleroma.soykaf.com/objects/7b41bb51-9aba-436a-82d9-dd3f5aca98c9</id>
- <published>2017-05-01T18:50:54Z</published>
- <updated>2017-05-01T18:50:57Z</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/comment</activity:object-type>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <content type="html" xml:lang="en">&lt;a href="https://mastodon.social/users/lambadalambda"&gt;@lambadalambda@mastodon.social&lt;/a&gt; you're an all-star.</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=""/>
- <thr:in-reply-to ref="tag:mastodon.social,2017-05-01:objectId=4836142:objectType=Status" href="https://mastodon.social/@lambadalambda/4836142"/>
- </activity:object>
- <content type="html" xml:lang="en">&lt;a href="https://mastodon.social/users/lambadalambda"&gt;@lambadalambda@mastodon.social&lt;/a&gt; you're an all-star.</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/2211632"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2211632.atom"/>
- </entry>
- <entry>
- <id>tag:mastodon.social,2017-05-01:objectId=4836142:objectType=Status</id>
- <published>2017-05-01T18:38:47Z</published>
- <updated>2017-05-01T18:38:47Z</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="ru">&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 now!&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/2211518"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2211518.atom"/>
- <thr:in-reply-to ref="https://pleroma.soykaf.com/objects/ffae4bea-00a3-4cef-8076-4ee4d448cb46" href=""/>
- </entry>
- <entry>
- <id>tag:mastodon.social,2017-05-01:objectId=4836055:objectType=Status</id>
- <published>2017-05-01T18:37:04Z</published>
- <updated>2017-05-01T18:37:04Z</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="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; hello&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/2211496"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2211496.atom"/>
- <thr:in-reply-to ref="https://pleroma.soykaf.com/objects/ffae4bea-00a3-4cef-8076-4ee4d448cb46" href=""/>
- </entry>
- <entry>
- <id>tag:mastodon.social,2017-05-01:objectId=4834850:objectType=Status</id>
- <published>2017-05-01T18:10:43Z</published>
- <updated>2017-05-01T18:10:43Z</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="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/2211256"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2211256.atom"/>
- </entry>
- <entry>
- <id>tag:mastodon.social,2017-04-29:objectId=4694455:objectType=Status</id>
- <published>2017-04-29T18:39:12Z</published>
- <updated>2017-04-29T18:39:12Z</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="ru">&lt;p&gt;@lain@pleroma.soykaf.com What&amp;apos;s up?&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/2189604"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2189604.atom"/>
- </entry>
- <entry>
- <id>tag:mastodon.social,2017-04-29:objectId=4694384:objectType=Status</id>
- <published>2017-04-29T18:37:32Z</published>
- <updated>2017-04-29T18:37:32Z</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="fr">&lt;p&gt;&lt;span class="h-card"&gt;&lt;a href="https://social.heldscal.la/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://social.heldscal.la/user/37181"/>
- <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/2189588"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/lambadalambda/updates/2189588.atom"/>
- </entry>
- <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 type="html">ta caution weeb | discussions privées : &lt;a href="https://%F0%9F%92%8C.0xroy.me"&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"/>
- <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"/>
- <poco:preferredUsername>0xroy</poco:preferredUsername>
- <poco:displayName>「R O Y 🍵 B O S」</poco:displayName>
- <poco:note>ta caution weeb | discussions privées : https://💌.0xroy.me</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 type="html">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"/>
- <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"/>
- <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"&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"&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 type="html">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"/>
- <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"&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"&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>
-</feed>
diff --git a/test/fixtures/tesla_mock/https___osada.macgirvin.com_channel_mike.json b/test/fixtures/tesla_mock/https___osada.macgirvin.com_channel_mike.json
index c42f3a53c..ca76d6e17 100644
--- a/test/fixtures/tesla_mock/https___osada.macgirvin.com_channel_mike.json
+++ b/test/fixtures/tesla_mock/https___osada.macgirvin.com_channel_mike.json
@@ -8,6 +8,7 @@
"preferredUsername": "mike",
"name": "Mike Macgirvin (Osada)",
"updated": "2018-08-29T03:09:11Z",
+ "discoverable": "true",
"icon": {
"type": "Image",
"mediaType": "image/jpeg",
@@ -51,4 +52,4 @@
"created": "2018-10-17T07:16:28Z",
"signatureValue": "WbfFVIPImkd3yNu6brz0CvZaeV242rwAbH0vy8DM4vfnXCxLr5Uv/Wj9gwP+tbooTxGaahAKBeqlGkQp8RLEo37LATrKMRLA/0V6DeeV+C5ORWR9B4WxyWiD3s/9Wf+KesFMtktNLAcMZ5PfnOS/xNYerhnpkp/gWPxtkglmLIWJv+w18A5zZ01JCxsO4QljHbhYaEUPHUfQ97abrkLECeam+FThVwdO6BFCtbjoNXHfzjpSZL/oKyBpi5/fpnqMqOLOQPs5WgBBZJvjEYYkQcoPTyxYI5NGpNbzIjGHPQNuACnOelH16A7L+q4swLWDIaEFeXQ2/5bmqVKZDZZ6usNP4QyTVszwd8jqo27qcDTNibXDUTsTdKpNQvM/3UncBuzuzmUV3FczhtGshIU1/pRVZiQycpVqPlGLvXhP/yZCe+1siyqDd+3uMaS2vkHTObSl5r+VYof+c+TcjrZXHSWnQTg8/X3zkoBWosrQ93VZcwjzMxQoARYv6rphbOoTz7RPmGAXYUt3/PDWkqDlmQDwCpLNNkJo1EidyefZBdD9HXQpCBO0ZU0NHb0JmPvg/+zU0krxlv70bm3RHA/maBETVjroIWzt7EwQEg5pL2hVnvSBG+1wF3BtRVe77etkPOHxLnYYIcAMLlVKCcgDd89DPIziQyruvkx1busHI08="
}
-}
+} \ No newline at end of file
diff --git a/test/fixtures/tesla_mock/https___pawoo.net_users_pekorino.atom b/test/fixtures/tesla_mock/https___pawoo.net_users_pekorino.atom
deleted file mode 100644
index 17d1956e8..000000000
--- a/test/fixtures/tesla_mock/https___pawoo.net_users_pekorino.atom
+++ /dev/null
@@ -1,231 +0,0 @@
-<?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://pawoo.net/users/pekorino.atom</id>
- <title>モノエ</title>
- <subtitle>シアトル・米国
-
-GNUsocial 英語版
-http://shitposter.club/mono
-
-</subtitle>
- <updated>2017-05-07T09:28:20Z</updated>
- <logo>https://img.pawoo.net/accounts/avatars/000/128/378/original/e1fce04a36a1ad90.jpg</logo>
- <author>
- <id>https://pawoo.net/users/pekorino</id>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <uri>https://pawoo.net/users/pekorino</uri>
- <name>pekorino</name>
- <email>pekorino@pawoo.net</email>
- <summary type="html">&lt;p&gt;シアトル・米国&lt;/p&gt;&lt;p&gt;GNUsocial 英語版&lt;br /&gt;&lt;a href="http://shitposter.club/mono" rel="nofollow noopener" target="_blank"&gt;&lt;span class="invisible"&gt;http://&lt;/span&gt;&lt;span class=""&gt;shitposter.club/mono&lt;/span&gt;&lt;span class="invisible"&gt;&lt;/span&gt;&lt;/a&gt; &lt;/p&gt;</summary>
- <link rel="alternate" type="text/html" href="https://pawoo.net/@pekorino"/>
- <link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://img.pawoo.net/accounts/avatars/000/128/378/original/e1fce04a36a1ad90.jpg"/>
- <link rel="header" type="image/png" media:width="700" media:height="335" href="https://img.pawoo.net/accounts/headers/000/128/378/original/bae3502120206e68.png"/>
- <poco:preferredUsername>pekorino</poco:preferredUsername>
- <poco:displayName>モノエ</poco:displayName>
- <poco:note>シアトル・米国
-
-GNUsocial 英語版
-http://shitposter.club/mono
-
-</poco:note>
- <mastodon:scope>public</mastodon:scope>
- </author>
- <link rel="alternate" type="text/html" href="https://pawoo.net/@pekorino"/>
- <link rel="self" type="application/atom+xml" href="https://pawoo.net/users/pekorino.atom"/>
- <link rel="hub" href="https://pawoo.net/api/push"/>
- <link rel="salmon" href="https://pawoo.net/api/salmon/128378"/>
- <entry>
- <id>tag:pawoo.net,2017-05-07:objectId=9319211:objectType=Status</id>
- <published>2017-05-07T09:56:35Z</published>
- <updated>2017-05-07T09:56:35Z</updated>
- <title>New status by pekorino</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://shitposter.club/moonman" class="u-url mention"&gt;@&lt;span&gt;moonman&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; &lt;span class="h-card"&gt;&lt;a href="https://shitposter.club/rw" class="u-url mention"&gt;@&lt;span&gt;rw&lt;/span&gt;&lt;/a&gt;&lt;/span&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; &lt;span class="h-card"&gt;&lt;a href="https://shitposter.club/mono" class="u-url mention"&gt;@&lt;span&gt;mono&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; &lt;/p&gt;&lt;p&gt;i have to wait for someone to respond to this before i can follow because i dont think this software has a direct follow by url option&lt;/p&gt;</content>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://shitposter.club/user/9056"/>
- <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/person" href="https://shitposter.club/user/666"/>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://shitposter.club/user/1"/>
- <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://pawoo.net/users/pekorino/updates/2496950"/>
- <link rel="self" type="application/atom+xml" href="https://pawoo.net/users/pekorino/updates/2496950.atom"/>
- <thr:in-reply-to ref="tag:pawoo.net,2017-05-07:objectId=9318595:objectType=Status" href="https://pawoo.net/@pekorino/9318595"/>
- </entry>
- <entry>
- <id>tag:pawoo.net,2017-05-07:objectId=9318595:objectType=Status</id>
- <published>2017-05-07T09:54:39Z</published>
- <updated>2017-05-07T09:54:39Z</updated>
- <title>New status by pekorino</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://shitposter.club/mono" class="u-url mention"&gt;@&lt;span&gt;mono&lt;/span&gt;&lt;/a&gt;&lt;/span&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; &lt;span class="h-card"&gt;&lt;a href="https://shitposter.club/rw" class="u-url mention"&gt;@&lt;span&gt;rw&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; &lt;span class="h-card"&gt;&lt;a href="https://shitposter.club/moonman" class="u-url mention"&gt;@&lt;span&gt;moonman&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; &lt;br /&gt;please respond&lt;/p&gt;</content>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://shitposter.club/user/1"/>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://shitposter.club/user/666"/>
- <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/person" href="https://shitposter.club/user/9056"/>
- <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://pawoo.net/users/pekorino/updates/2496838"/>
- <link rel="self" type="application/atom+xml" href="https://pawoo.net/users/pekorino/updates/2496838.atom"/>
- <thr:in-reply-to ref="tag:shitposter.club,2017-05-07:noticeId=2856143:objectType=note" href="https://shitposter.club/notice/2856143"/>
- </entry>
- <entry>
- <id>tag:pawoo.net,2017-05-07:objectId=9313978:objectType=Status</id>
- <published>2017-05-07T09:39:17Z</published>
- <updated>2017-05-07T09:39:17Z</updated>
- <title>New status by pekorino</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://shitposter.club/moonman" class="u-url mention"&gt;@&lt;span&gt;moonman&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; &lt;br /&gt;mastodon is so slow. browser crashed twice trying to set avatar&lt;/p&gt;</content>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://shitposter.club/user/1"/>
- <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://pawoo.net/users/pekorino/updates/2496065"/>
- <link rel="self" type="application/atom+xml" href="https://pawoo.net/users/pekorino/updates/2496065.atom"/>
- </entry>
- <entry>
- <id>tag:pawoo.net,2017-05-07:objectId=9312691:objectType=Status</id>
- <published>2017-05-07T09:34:38Z</published>
- <updated>2017-05-07T09:34:38Z</updated>
- <title>New status by pekorino</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://shitposter.club/hardbass2k8" class="u-url mention"&gt;@&lt;span&gt;hardbass2k8&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; &lt;a href="https://pawoo.net/media/mZJjLpbPU72GFEz2Svk" rel="nofollow noopener" target="_blank"&gt;&lt;span class="invisible"&gt;https://&lt;/span&gt;&lt;span class="ellipsis"&gt;pawoo.net/media/mZJjLpbPU72GFE&lt;/span&gt;&lt;span class="invisible"&gt;z2Svk&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://shitposter.club/user/9591"/>
- <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="42074" href="https://img.pawoo.net/media_attachments/files/000/681/737/original/483a0d76fce39156.jpg"/>
- <mastodon:scope>public</mastodon:scope>
- <link rel="alternate" type="text/html" href="https://pawoo.net/users/pekorino/updates/2495835"/>
- <link rel="self" type="application/atom+xml" href="https://pawoo.net/users/pekorino/updates/2495835.atom"/>
- <thr:in-reply-to ref="tag:shitposter.club,2017-05-07:noticeId=2855897:objectType=note" href="https://shitposter.club/notice/2855897"/>
- </entry>
- <entry>
- <id>tag:pawoo.net,2017-05-07:objectId=9312379:objectType=Status</id>
- <published>2017-05-07T09:33:29Z</published>
- <updated>2017-05-07T09:33:29Z</updated>
- <title>New status by pekorino</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://shitposter.club/hardbass2k8" class="u-url mention"&gt;@&lt;span&gt;hardbass2k8&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; &lt;a href="https://pawoo.net/media/nt5JHBEHyTN2bqzdcGU" rel="nofollow noopener" target="_blank"&gt;&lt;span class="invisible"&gt;https://&lt;/span&gt;&lt;span class="ellipsis"&gt;pawoo.net/media/nt5JHBEHyTN2bq&lt;/span&gt;&lt;span class="invisible"&gt;zdcGU&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://shitposter.club/user/9591"/>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
- <link rel="enclosure" type="image/png" length="8605" href="https://img.pawoo.net/media_attachments/files/000/681/714/original/1e3f216d4f78c69d.png"/>
- <mastodon:scope>public</mastodon:scope>
- <link rel="alternate" type="text/html" href="https://pawoo.net/users/pekorino/updates/2495772"/>
- <link rel="self" type="application/atom+xml" href="https://pawoo.net/users/pekorino/updates/2495772.atom"/>
- <thr:in-reply-to ref="tag:shitposter.club,2017-05-07:noticeId=2855886:objectType=comment" href="https://shitposter.club/notice/2855886"/>
- </entry>
- <entry>
- <id>tag:pawoo.net,2017-05-07:objectId=9311765:objectType=Status</id>
- <published>2017-05-07T09:31:26Z</published>
- <updated>2017-05-07T09:31:26Z</updated>
- <title>New status by pekorino</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;a href="https://pawoo.net/media/C4RV6ubsEtvS04DX6qs" rel="nofollow noopener" target="_blank"&gt;&lt;span class="invisible"&gt;https://&lt;/span&gt;&lt;span class="ellipsis"&gt;pawoo.net/media/C4RV6ubsEtvS04&lt;/span&gt;&lt;span class="invisible"&gt;DX6qs&lt;/span&gt;&lt;/a&gt;&lt;/p&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="71196" href="https://img.pawoo.net/media_attachments/files/000/681/667/original/dc310e8fd312e7ff.jpg"/>
- <mastodon:scope>public</mastodon:scope>
- <link rel="alternate" type="text/html" href="https://pawoo.net/users/pekorino/updates/2495666"/>
- <link rel="self" type="application/atom+xml" href="https://pawoo.net/users/pekorino/updates/2495666.atom"/>
- </entry>
- <entry>
- <id>tag:pawoo.net,2017-05-07:objectId=9311610:objectType=Status</id>
- <published>2017-05-07T09:30:59Z</published>
- <updated>2017-05-07T09:30:59Z</updated>
- <title>New status by pekorino</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;a href="https://pawoo.net/media/MBmkeEdrjs8pAtCHN6s" rel="nofollow noopener" target="_blank"&gt;&lt;span class="invisible"&gt;https://&lt;/span&gt;&lt;span class="ellipsis"&gt;pawoo.net/media/MBmkeEdrjs8pAt&lt;/span&gt;&lt;span class="invisible"&gt;CHN6s&lt;/span&gt;&lt;/a&gt;&lt;/p&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="158377" href="https://img.pawoo.net/media_attachments/files/000/681/656/original/7e2d78ecfd243e67.jpg"/>
- <mastodon:scope>public</mastodon:scope>
- <link rel="alternate" type="text/html" href="https://pawoo.net/users/pekorino/updates/2495632"/>
- <link rel="self" type="application/atom+xml" href="https://pawoo.net/users/pekorino/updates/2495632.atom"/>
- </entry>
- <entry>
- <id>tag:pawoo.net,2017-05-07:objectId=9307782:objectType=Status</id>
- <published>2017-05-07T09:16:47Z</published>
- <updated>2017-05-07T09:16:47Z</updated>
- <title>New status by pekorino</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://shitposter.club/mono" class="u-url mention"&gt;@&lt;span&gt;mono&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;test&lt;/p&gt;</content>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://shitposter.club/user/9056"/>
- <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://pawoo.net/users/pekorino/updates/2494966"/>
- <link rel="self" type="application/atom+xml" href="https://pawoo.net/users/pekorino/updates/2494966.atom"/>
- </entry>
- <entry>
- <id>tag:pawoo.net,2017-05-07:objectId=9307444:objectType=Status</id>
- <published>2017-05-07T09:15:42Z</published>
- <updated>2017-05-07T09:15:42Z</updated>
- <title>New status by pekorino</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://shitposter.club/hardbass2k8" class="u-url mention"&gt;@&lt;span&gt;hardbass2k8&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://shitposter.club/user/9591"/>
- <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://pawoo.net/users/pekorino/updates/2494900"/>
- <link rel="self" type="application/atom+xml" href="https://pawoo.net/users/pekorino/updates/2494900.atom"/>
- <thr:in-reply-to ref="tag:shitposter.club,2017-05-07:noticeId=2855867:objectType=note" href="https://shitposter.club/notice/2855867"/>
- </entry>
- <entry>
- <id>tag:pawoo.net,2017-05-07:objectId=9307239:objectType=Status</id>
- <published>2017-05-07T09:14:58Z</published>
- <updated>2017-05-07T09:14:58Z</updated>
- <title>New status by pekorino</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;/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://pawoo.net/users/pekorino/updates/2494866"/>
- <link rel="self" type="application/atom+xml" href="https://pawoo.net/users/pekorino/updates/2494866.atom"/>
- </entry>
- <entry>
- <id>tag:pawoo.net,2017-04-20:objectId=2212164:objectType=Status</id>
- <published>2017-04-20T06:19:18Z</published>
- <updated>2017-04-20T06:19:18Z</updated>
- <title>New status by pekorino</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://shitposter.club/mono" class="u-url mention"&gt;@&lt;span&gt;mono&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; &lt;a href="https://pawoo.net/media/iMbjMBVPfZJX3lUC2Sc" rel="nofollow noopener" target="_blank"&gt;&lt;span class="invisible"&gt;https://&lt;/span&gt;&lt;span class="ellipsis"&gt;pawoo.net/media/iMbjMBVPfZJX3l&lt;/span&gt;&lt;span class="invisible"&gt;UC2Sc&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://shitposter.club/user/9056"/>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
- <link rel="enclosure" type="image/png" length="754410" href="https://img.pawoo.net/media_attachments/files/000/199/926/original/f11a4c9c91403766.png"/>
- <mastodon:scope>public</mastodon:scope>
- <link rel="alternate" type="text/html" href="https://pawoo.net/users/pekorino/updates/874763"/>
- <link rel="self" type="application/atom+xml" href="https://pawoo.net/users/pekorino/updates/874763.atom"/>
- <thr:in-reply-to ref="tag:shitposter.club,2017-04-20:noticeId=2570261:objectType=note" href="https://shitposter.club/notice/2570261"/>
- </entry>
- <entry>
- <id>tag:pawoo.net,2017-04-20:objectId=2206216:objectType=Status</id>
- <published>2017-04-20T05:57:59Z</published>
- <updated>2017-04-20T05:57:59Z</updated>
- <title>New status by pekorino</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;/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://pawoo.net/users/pekorino/updates/872900"/>
- <link rel="self" type="application/atom+xml" href="https://pawoo.net/users/pekorino/updates/872900.atom"/>
- </entry>
- <entry>
- <id>tag:pawoo.net,2017-04-20:objectId=2204702:objectType=Status</id>
- <published>2017-04-20T05:52:09Z</published>
- <updated>2017-04-20T05:52:09Z</updated>
- <title>New status by pekorino</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;HELLOWORLD&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://pawoo.net/users/pekorino/updates/872464"/>
- <link rel="self" type="application/atom+xml" href="https://pawoo.net/users/pekorino/updates/872464.atom"/>
- </entry>
-</feed>
diff --git a/test/fixtures/tesla_mock/https___pleroma.soykaf.com_users_lain_feed.atom.xml b/test/fixtures/tesla_mock/https___pleroma.soykaf.com_users_lain_feed.atom.xml
deleted file mode 100644
index a2a2629a6..000000000
--- a/test/fixtures/tesla_mock/https___pleroma.soykaf.com_users_lain_feed.atom.xml
+++ /dev/null
@@ -1 +0,0 @@
-<?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:ostatus="http://ostatus.org/schema/1.0"><id>https://pleroma.soykaf.com/users/lain/feed.atom</id><title>lain's timeline</title><updated>2017-05-05T08:38:03.385598</updated><link rel="hub" href="https://pleroma.soykaf.com/push/hub/lain"/><link rel="salmon" href="https://pleroma.soykaf.com/users/lain/salmon"/><link rel="self" href="https://pleroma.soykaf.com/users/lain/feed.atom" type="application/atom+xml"/><author><id>https://pleroma.soykaf.com/users/lain</id><activity:object>http://activitystrea.ms/schema/1.0/person</activity:object><uri>https://pleroma.soykaf.com/users/lain</uri><poco:preferredUsername>lain</poco:preferredUsername><poco:displayName>Lain Iwakura</poco:displayName><poco:note>Test account</poco:note><name>lain</name><link rel="avatar" href="https://pleroma.soykaf.com/media/dbd1aa2f-21a3-4333-955f-67c0ac988cc2/6B3AFC74ACA841B24CFB94DB9044C84EDE6AFF31C71718B023D413DAED09A68E.jpeg"/></author><entry><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>https://pleroma.soykaf.com/activities/579e4224-b2ab-4ffa-8bbe-f7197a0a38d1</id><title>lain repeated a notice</title><content type="html">RT In just seven days, I can make you a man!&lt;br&gt; -- The Rocky Horror Picture Show</content><published>2017-05-05T08:38:03.385590</published><updated>2017-05-05T08:38:03.385598</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/e8673466-9642-4c9e-8781-f0f69d6b15ae</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/e8673466-9642-4c9e-8781-f0f69d6b15ae" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/579e4224-b2ab-4ffa-8bbe-f7197a0a38d1"/><activity:object><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>https://pleroma.soykaf.com/objects/53dd40f4-3069-45a1-863b-94a9b317093d</id><title>New note by fortune</title><content type="html">In just seven days, I can make you a man!&lt;br&gt; -- The Rocky Horror Picture Show</content><published>2017-05-05T02:10:02.930802</published><updated>2017-05-05T08:38:03.423539</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/e8673466-9642-4c9e-8781-f0f69d6b15ae</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/e8673466-9642-4c9e-8781-f0f69d6b15ae" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/53dd40f4-3069-45a1-863b-94a9b317093d" rel="self"/><author><id>https://pleroma.soykaf.com/users/fortune</id><activity:object>http://activitystrea.ms/schema/1.0/person</activity:object><uri>https://pleroma.soykaf.com/users/fortune</uri><poco:preferredUsername>fortune</poco:preferredUsername><poco:displayName>fortune</poco:displayName><poco:note>The trusty unix fortune file</poco:note><name>fortune</name><link rel="avatar" href="https://pleroma.soykaf.com/media/07ed0371-2817-4d80-97e1-255ca632fac6/66BA0B957C5E18404D405029B6C2B01FF1A306FB6EEF3E1D1F4C30DEBB1156D7.jpeg"/></author><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></activity:object><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/fortune"/></entry><entry><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>https://pleroma.soykaf.com/objects/2bc86888-a256-4771-bb53-903f375804f9</id><title>New note by lain</title><content type="html">RTs federating into pleroma now.</content><published>2017-05-04T18:18:50.276470</published><updated>2017-05-04T18:18:50.276476</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/b7ae9350-f317-48aa-8058-2668091bb280</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/b7ae9350-f317-48aa-8058-2668091bb280" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/2bc86888-a256-4771-bb53-903f375804f9" rel="self"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb><id>https://pleroma.soykaf.com/activities/902b1f50-f295-4189-8c15-9c880919e121</id><title>New favorite by lain</title><content type="html">lain favorited something</content><published>2017-05-04T08:03:01.308890</published><updated>2017-05-04T08:03:01.308927</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><id>tag:gs.smuglo.li,2017-05-03:noticeId=2164642:objectType=comment</id></activity:object><ostatus:conversation>https://pleroma.soykaf.com/contexts/9419f742-aaba-4eb5-89a2-8b599e8bf43c</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/9419f742-aaba-4eb5-89a2-8b599e8bf43c" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/902b1f50-f295-4189-8c15-9c880919e121"/><thr:in-reply-to ref="tag:gs.smuglo.li,2017-05-03:noticeId=2164642:objectType=comment"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/2"/></entry><entry><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>https://pleroma.soykaf.com/objects/4e396e66-b063-454c-92c6-583506a9a2de</id><title>New note by lain</title><content type="html">Classic.&lt;br&gt;&lt;a href='https://pleroma.soykaf.com/media/adc36781-9765-4d9a-b57c-99b7a99108b2/mikodaemonstop.jpg'&gt;https://pleroma.soykaf.com/media/adc36781-9765-4d9a-b57c-99b7a99108b2/mikodaemonstop.jpg&lt;/a&gt;</content><published>2017-05-04T07:59:45.180619</published><updated>2017-05-04T07:59:45.180628</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/6afd9659-41e6-406d-ae97-43b880722861</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/6afd9659-41e6-406d-ae97-43b880722861" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/4e396e66-b063-454c-92c6-583506a9a2de" rel="self"/><link rel="enclosure" href="https://pleroma.soykaf.com/media/adc36781-9765-4d9a-b57c-99b7a99108b2/mikodaemonstop.jpg" type="image/jpeg"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><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>https://pleroma.soykaf.com/objects/85d183e9-c935-4655-a1e6-8d69a4108235</id><title>New note by lain</title><content type="html">ん?&lt;br&gt;&lt;a href='https://pleroma.soykaf.com/media/ab144c6d-a38c-4d35-a60b-9a998becc094/n.gif'&gt;https://pleroma.soykaf.com/media/ab144c6d-a38c-4d35-a60b-9a998becc094/n.gif&lt;/a&gt;</content><published>2017-05-04T07:58:08.810716</published><updated>2017-05-04T07:58:08.810726</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/2e1aa616-86ce-4b50-9c81-63045a972156</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/2e1aa616-86ce-4b50-9c81-63045a972156" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/85d183e9-c935-4655-a1e6-8d69a4108235" rel="self"/><link rel="enclosure" href="https://pleroma.soykaf.com/media/ab144c6d-a38c-4d35-a60b-9a998becc094/n.gif" type="image/gif"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><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>https://pleroma.soykaf.com/objects/7c5c45bb-e4d9-4f72-b4c6-0314afbd3553</id><title>New note by lain</title><content type="html">yeah.</content><published>2017-05-04T07:55:17.335290</published><updated>2017-05-04T07:55:17.335299</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/702c06cf-56ff-4a2f-bf5a-150bc00bb168</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/702c06cf-56ff-4a2f-bf5a-150bc00bb168" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/7c5c45bb-e4d9-4f72-b4c6-0314afbd3553" rel="self"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><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>https://pleroma.soykaf.com/objects/f33f5f54-1c1d-4462-b9ed-229bb635dfd8</id><title>New note by lain</title><content type="html">yeah.</content><published>2017-05-04T07:49:24.931484</published><updated>2017-05-04T07:49:24.931492</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/c4932e7a-00cb-431a-b4ec-7404cb9daf65</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/c4932e7a-00cb-431a-b4ec-7404cb9daf65" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/f33f5f54-1c1d-4462-b9ed-229bb635dfd8" rel="self"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb><id>https://pleroma.soykaf.com/activities/0709bc79-7ac5-4983-b6d0-2205bf5ceba3</id><title>New favorite by lain</title><content type="html">lain favorited something</content><published>2017-05-03T20:08:11.294579</published><updated>2017-05-03T20:08:11.294587</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><id>tag:pawoo.net,2017-05-03:objectId=7967690:objectType=Status</id></activity:object><ostatus:conversation>https://pleroma.soykaf.com/contexts/07a4b34d-6255-4bb2-8c73-c295a09ac952</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/07a4b34d-6255-4bb2-8c73-c295a09ac952" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/0709bc79-7ac5-4983-b6d0-2205bf5ceba3"/><thr:in-reply-to ref="tag:pawoo.net,2017-05-03:objectId=7967690:objectType=Status"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pawoo.net/users/God_Emperor_of_Dune"/></entry><entry><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>https://pleroma.soykaf.com/objects/72c0288e-62d8-43d9-b3d8-1a9d78be8375</id><title>New note by lain</title><content type="html">&lt;a href='https://pawoo.net/users/God_Emperor_of_Dune'&gt;@God_Emperor_of_Dune@pawoo.net&lt;/a&gt; no man, just some fun domination play among buddies, nothing homo about it.</content><published>2017-05-03T20:01:00.998314</published><updated>2017-05-03T20:01:00.998322</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/07a4b34d-6255-4bb2-8c73-c295a09ac952</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/07a4b34d-6255-4bb2-8c73-c295a09ac952" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/72c0288e-62d8-43d9-b3d8-1a9d78be8375" rel="self"/><thr:in-reply-to ref="tag:pawoo.net,2017-05-03:objectId=7966029:objectType=Status"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pawoo.net/users/God_Emperor_of_Dune"/></entry><entry><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>https://pleroma.soykaf.com/objects/d846409e-cf2a-4b68-a149-d5de34a91b0d</id><title>New note by lain</title><content type="html">&lt;a href='https://social.heldscal.la/user/24974'&gt;@dtluna@social.heldscal.la&lt;/a&gt; btfo.&lt;br&gt;&lt;a href='https://pleroma.soykaf.com/media/fbe42e87-5574-4544-89ba-29ddf46227fa/pnc__picked_media_1889ce61-4961-4fea-8a14-04fe6783ebf6.jpg'&gt;https://pleroma.soykaf.com/media/fbe42e87-5574-4544-89ba-29ddf46227fa/pnc__picked_media_1889ce61-4961-4fea-8a14-04fe6783ebf6.jpg&lt;/a&gt;</content><published>2017-05-03T20:00:15.860995</published><updated>2017-05-03T20:00:15.861002</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/0e88f35e-1a38-4181-bef9-5cbb0d943c63</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/0e88f35e-1a38-4181-bef9-5cbb0d943c63" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/d846409e-cf2a-4b68-a149-d5de34a91b0d" rel="self"/><link rel="enclosure" href="https://pleroma.soykaf.com/media/fbe42e87-5574-4544-89ba-29ddf46227fa/pnc__picked_media_1889ce61-4961-4fea-8a14-04fe6783ebf6.jpg" type="image/jpeg"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.heldscal.la/user/24974"/></entry><entry><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>https://pleroma.soykaf.com/objects/9075265f-f3b2-40e8-809f-10714f05a1fd</id><title>New note by lain</title><content type="html">#nohomo &lt;br&gt;&lt;a href='https://pleroma.soykaf.com/media/5cc5ad91-d637-4c45-a691-5ea778dc1bb3/pnc__picked_media_f62dc9ae-ea23-4fe6-bf85-cb75a129ab34.jpg'&gt;https://pleroma.soykaf.com/media/5cc5ad91-d637-4c45-a691-5ea778dc1bb3/pnc__picked_media_f62dc9ae-ea23-4fe6-bf85-cb75a129ab34.jpg&lt;/a&gt;</content><published>2017-05-03T19:50:38.589106</published><updated>2017-05-03T19:50:38.589113</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/07a4b34d-6255-4bb2-8c73-c295a09ac952</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/07a4b34d-6255-4bb2-8c73-c295a09ac952" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/9075265f-f3b2-40e8-809f-10714f05a1fd" rel="self"/><link rel="enclosure" href="https://pleroma.soykaf.com/media/5cc5ad91-d637-4c45-a691-5ea778dc1bb3/pnc__picked_media_f62dc9ae-ea23-4fe6-bf85-cb75a129ab34.jpg" type="image/jpeg"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb><id>https://pleroma.soykaf.com/activities/7924e992-0a95-40d9-8d17-7278c6c634c9</id><title>New favorite by lain</title><content type="html">lain favorited something</content><published>2017-05-03T18:32:59.273375</published><updated>2017-05-03T18:32:59.273382</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><id>tag:gs.smuglo.li,2017-05-03:noticeId=2164774:objectType=comment</id></activity:object><ostatus:conversation>https://pleroma.soykaf.com/contexts/9419f742-aaba-4eb5-89a2-8b599e8bf43c</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/9419f742-aaba-4eb5-89a2-8b599e8bf43c" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/7924e992-0a95-40d9-8d17-7278c6c634c9"/><thr:in-reply-to ref="tag:gs.smuglo.li,2017-05-03:noticeId=2164774:objectType=comment"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/2"/></entry><entry><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>https://pleroma.soykaf.com/objects/569571ba-f54c-41b0-bde4-0fede54599f0</id><title>New note by lain</title><content type="html">&lt;a href='https://gs.smuglo.li/user/2'&gt;@nepfag@gs.smuglo.li&lt;/a&gt;@gs.smuglo.li I'll do proper subfolders soon, for now it's one per attachment + thumbs etc.</content><published>2017-05-03T18:27:01.449949</published><updated>2017-05-03T18:27:01.449956</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/9419f742-aaba-4eb5-89a2-8b599e8bf43c</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/9419f742-aaba-4eb5-89a2-8b599e8bf43c" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/569571ba-f54c-41b0-bde4-0fede54599f0" rel="self"/><thr:in-reply-to ref="tag:gs.smuglo.li,2017-05-03:noticeId=2164642:objectType=comment"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/2"/></entry><entry><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>https://pleroma.soykaf.com/activities/b6cc5d7c-0785-4785-a689-f1b05dc9b24d</id><title>lain repeated a notice</title><content type="html">RT &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 now!&lt;/p&gt;</content><published>2017-05-03T18:13:48.891061</published><updated>2017-05-03T18:13:48.891069</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/ec6fdd27-0ec1-4672-8408-5a8e5a9c094b</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/ec6fdd27-0ec1-4672-8408-5a8e5a9c094b" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/b6cc5d7c-0785-4785-a689-f1b05dc9b24d"/><activity:object><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>tag:mastodon.social,2017-05-01:objectId=4836142:objectType=Status</id><title>New note by lambadalambda@mastodon.social</title><content type="html">&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 now!&lt;/p&gt;</content><published>2017-05-01T18:38:49.365391</published><updated>2017-05-03T18:13:48.934745</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/ec6fdd27-0ec1-4672-8408-5a8e5a9c094b</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/ec6fdd27-0ec1-4672-8408-5a8e5a9c094b" rel="ostatus:conversation"/><link type="application/atom+xml" href="tag:mastodon.social,2017-05-01:objectId=4836142:objectType=Status" rel="self"/><thr:in-reply-to ref="https://pleroma.soykaf.com/objects/ffae4bea-00a3-4cef-8076-4ee4d448cb46"/><author><id>https://mastodon.social/users/lambadalambda</id><activity:object>http://activitystrea.ms/schema/1.0/person</activity:object><uri>https://mastodon.social/users/lambadalambda</uri><poco:preferredUsername>lambadalambda@mastodon.social</poco:preferredUsername><poco:displayName>Critical Value</poco:displayName><poco:note>nil</poco:note><name>lambadalambda@mastodon.social</name><link rel="avatar" href="https://files.mastodon.social/accounts/avatars/000/000/264/original/1429214160519.gif"/></author><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/lain"/></activity:object><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/lambadalambda"/></entry><entry><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>https://pleroma.soykaf.com/activities/3c09eb31-4ba8-4ff5-b4fa-8f6f74d58bf0</id><title>lain repeated a notice</title><content type="html">RT Haha, salmons from mastodon didn't work because it's not implementing conversation id...</content><published>2017-05-03T18:13:15.148041</published><updated>2017-05-03T18:13:15.148049</updated><ostatus:conversation>tag:social.heldscal.la,2017-05-01:objectType=thread:nonce=86cda6c734401d80</ostatus:conversation><link href="tag:social.heldscal.la,2017-05-01:objectType=thread:nonce=86cda6c734401d80" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/3c09eb31-4ba8-4ff5-b4fa-8f6f74d58bf0"/><activity:object><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>tag:social.heldscal.la,2017-05-01:noticeId=2000425:objectType=note</id><title>New note by lambadalambda@social.heldscal.la</title><content type="html">Haha, salmons from mastodon didn't work because it's not implementing conversation id...</content><published>2017-05-01T18:39:36.216377</published><updated>2017-05-03T18:13:15.171143</updated><ostatus:conversation>tag:social.heldscal.la,2017-05-01:objectType=thread:nonce=86cda6c734401d80</ostatus:conversation><link href="tag:social.heldscal.la,2017-05-01:objectType=thread:nonce=86cda6c734401d80" rel="ostatus:conversation"/><link type="application/atom+xml" href="tag:social.heldscal.la,2017-05-01:noticeId=2000425:objectType=note" rel="self"/><author><id>https://social.heldscal.la/user/23211</id><activity:object>http://activitystrea.ms/schema/1.0/person</activity:object><uri>https://social.heldscal.la/user/23211</uri><poco:preferredUsername>lambadalambda@social.heldscal.la</poco:preferredUsername><poco:displayName>Constance Variable</poco:displayName><poco:note>nil</poco:note><name>lambadalambda@social.heldscal.la</name><link rel="avatar" href="https://social.heldscal.la/avatar/23211-original-20170416114255.jpeg"/></author><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></activity:object><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.heldscal.la/user/23211"/></entry><entry><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>https://pleroma.soykaf.com/objects/b8fc83d5-d7c0-4b5f-8976-0317b51935ea</id><title>New note by lain</title><content type="html">.&lt;br&gt;&lt;a href='https://pleroma.soykaf.com/media/563008a7-9a60-47ac-a263-22835729adf6/1492530528735.png'&gt;https://pleroma.soykaf.com/media/563008a7-9a60-47ac-a263-22835729adf6/1492530528735.png&lt;/a&gt;</content><published>2017-05-03T18:12:50.745241</published><updated>2017-05-03T18:12:50.745249</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/9419f742-aaba-4eb5-89a2-8b599e8bf43c</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/9419f742-aaba-4eb5-89a2-8b599e8bf43c" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/b8fc83d5-d7c0-4b5f-8976-0317b51935ea" rel="self"/><link rel="enclosure" href="https://pleroma.soykaf.com/media/563008a7-9a60-47ac-a263-22835729adf6/1492530528735.png" type="image/png"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><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>https://pleroma.soykaf.com/activities/ac93ecef-cde0-48e8-ae4b-19e3b94dbe30</id><title>lain repeated a notice</title><content type="html">RT Awright, which one of you hid my PENIS ENVY?</content><published>2017-05-03T18:08:49.231001</published><updated>2017-05-03T18:08:49.235354</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/a9132cf8-6afa-4dd8-8b29-7b6fcab623b8</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/a9132cf8-6afa-4dd8-8b29-7b6fcab623b8" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/ac93ecef-cde0-48e8-ae4b-19e3b94dbe30"/><activity:object><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>https://pleroma.soykaf.com/objects/04e15c66-4936-4930-a134-32841f088bcf</id><title>New note by fortune</title><content type="html">Awright, which one of you hid my PENIS ENVY?</content><published>2017-05-01T19:40:03.169996</published><updated>2017-05-03T18:08:49.285347</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/a9132cf8-6afa-4dd8-8b29-7b6fcab623b8</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/a9132cf8-6afa-4dd8-8b29-7b6fcab623b8" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/04e15c66-4936-4930-a134-32841f088bcf" rel="self"/><author><id>https://pleroma.soykaf.com/users/fortune</id><activity:object>http://activitystrea.ms/schema/1.0/person</activity:object><uri>https://pleroma.soykaf.com/users/fortune</uri><poco:preferredUsername>fortune</poco:preferredUsername><poco:displayName>fortune</poco:displayName><poco:note>The trusty unix fortune file</poco:note><name>fortune</name><link rel="avatar" href="https://pleroma.soykaf.com/media/07ed0371-2817-4d80-97e1-255ca632fac6/66BA0B957C5E18404D405029B6C2B01FF1A306FB6EEF3E1D1F4C30DEBB1156D7.jpeg"/></author><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></activity:object><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/fortune"/></entry><entry><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>https://pleroma.soykaf.com/activities/54b10fa9-d602-4a0f-b659-e6d3f7bc8c4c</id><title>lain repeated a notice</title><content type="html">RT He is a man capable of turning any colour into grey.&lt;br&gt; -- John LeCarre</content><published>2017-05-03T17:44:47.578984</published><updated>2017-05-03T17:44:47.578996</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/8aebc8e5-5352-4047-8b74-4098a5830cca</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/8aebc8e5-5352-4047-8b74-4098a5830cca" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/54b10fa9-d602-4a0f-b659-e6d3f7bc8c4c"/><activity:object><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>https://pleroma.soykaf.com/objects/70ded299-184d-49cd-af17-23c0950536aa</id><title>New note by fortune</title><content type="html">He is a man capable of turning any colour into grey.&lt;br&gt; -- John LeCarre</content><published>2017-05-02T08:40:03.419465</published><updated>2017-05-03T17:44:47.646192</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/8aebc8e5-5352-4047-8b74-4098a5830cca</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/8aebc8e5-5352-4047-8b74-4098a5830cca" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/70ded299-184d-49cd-af17-23c0950536aa" rel="self"/><author><id>https://pleroma.soykaf.com/users/fortune</id><activity:object>http://activitystrea.ms/schema/1.0/person</activity:object><uri>https://pleroma.soykaf.com/users/fortune</uri><poco:preferredUsername>fortune</poco:preferredUsername><poco:displayName>fortune</poco:displayName><poco:note>The trusty unix fortune file</poco:note><name>fortune</name><link rel="avatar" href="https://pleroma.soykaf.com/media/07ed0371-2817-4d80-97e1-255ca632fac6/66BA0B957C5E18404D405029B6C2B01FF1A306FB6EEF3E1D1F4C30DEBB1156D7.jpeg"/></author><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></activity:object><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/fortune"/></entry><entry><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>https://pleroma.soykaf.com/activities/eff9fe49-8fc9-48e6-a1a0-921aa25c8118</id><title>lain repeated a notice</title><content type="html">RT The real trouble with women is that they have *all* the pussy.</content><published>2017-05-03T17:30:22.596037</published><updated>2017-05-03T17:30:22.596048</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/8c88c9df-4e40-4f54-b15f-c21848d1a8e2</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/8c88c9df-4e40-4f54-b15f-c21848d1a8e2" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/eff9fe49-8fc9-48e6-a1a0-921aa25c8118"/><activity:object><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>https://pleroma.soykaf.com/objects/0b9b008d-49eb-48a9-a18d-172ce7d01ea2</id><title>New note by fortune</title><content type="html">The real trouble with women is that they have *all* the pussy.</content><published>2017-05-02T12:10:03.603086</published><updated>2017-05-03T17:30:22.683141</updated><ostatus:conversation>https://pleroma.soykaf.com/contexts/8c88c9df-4e40-4f54-b15f-c21848d1a8e2</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/8c88c9df-4e40-4f54-b15f-c21848d1a8e2" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/0b9b008d-49eb-48a9-a18d-172ce7d01ea2" rel="self"/><author><id>https://pleroma.soykaf.com/users/fortune</id><activity:object>http://activitystrea.ms/schema/1.0/person</activity:object><uri>https://pleroma.soykaf.com/users/fortune</uri><poco:preferredUsername>fortune</poco:preferredUsername><poco:displayName>fortune</poco:displayName><poco:note>The trusty unix fortune file</poco:note><name>fortune</name><link rel="avatar" href="https://pleroma.soykaf.com/media/07ed0371-2817-4d80-97e1-255ca632fac6/66BA0B957C5E18404D405029B6C2B01FF1A306FB6EEF3E1D1F4C30DEBB1156D7.jpeg"/></author><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></activity:object><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/fortune"/></entry><entry><activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb><id>https://pleroma.soykaf.com/activities/5d90bb26-ce23-4a5b-8dbd-651011780007</id><title>New favorite by lain</title><content type="html">lain favorited something</content><published>2017-05-03T17:28:20.967926</published><updated>2017-05-03T17:28:20.967935</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><id>tag:mastodon.social,2017-05-03:objectId=4952899:objectType=Status</id></activity:object><ostatus:conversation>https://pleroma.soykaf.com/contexts/42701ab4-964a-441a-a372-f51bd183e441</ostatus:conversation><link href="https://pleroma.soykaf.com/contexts/42701ab4-964a-441a-a372-f51bd183e441" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/5d90bb26-ce23-4a5b-8dbd-651011780007"/><thr:in-reply-to ref="tag:mastodon.social,2017-05-03:objectId=4952899:objectType=Status"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/lambadalambda"/></entry></feed> \ No newline at end of file
diff --git a/test/fixtures/tesla_mock/https___shitposter.club_api_statuses_show_2827873.atom.xml b/test/fixtures/tesla_mock/https___shitposter.club_api_statuses_show_2827873.atom.xml
deleted file mode 100644
index 26fdebb49..000000000
--- a/test/fixtures/tesla_mock/https___shitposter.club_api_statuses_show_2827873.atom.xml
+++ /dev/null
@@ -1,54 +0,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: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/comment</activity:object-type>
- <id>tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment</id>
- <title>New comment by moonman</title>
- <content type="html">@&lt;a href=&quot;https://shitposter.club/user/9655&quot; class=&quot;h-card mention&quot; title=&quot;Solidarity for Pigs&quot;&gt;neimzr4luzerz&lt;/a&gt; @&lt;a href=&quot;https://gs.smuglo.li/user/2326&quot; class=&quot;h-card mention&quot; title=&quot;Dolus_McHonest&quot;&gt;dolus&lt;/a&gt; childhood poring over Strong's concordance and a koine Greek dictionary, fast forward to 2017 and some fuckstick who translates japanese jackoff material tells me you just need to make it sound right in English</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2827873"/>
- <status_net notice_id="2827873"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-05-05T08:51:48+00:00</published>
- <updated>2017-05-05T08:51:48+00:00</updated>
- <author>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <uri>https://shitposter.club/user/1</uri>
- <name>moonman</name>
- <summary>EMAIL:shitposterclub@gmail.com XMPP: moon@talk.shitposter.club Matrix Ed25519 fingerprint: 2HuDUTEz3iFN5N3xl6PYp9xZW/EWhgbbt78SrFy4w8o</summary>
- <link rel="alternate" type="text/html" href="https://shitposter.club/moonman"/>
- <link rel="avatar" type="image/jpeg" media:width="1040" media:height="1040" href="https://shitposter.club/avatar/1-original-20170503024316.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://shitposter.club/avatar/1-96-20170503024316.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://shitposter.club/avatar/1-48-20170503024316.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://shitposter.club/avatar/1-24-20170503024318.jpeg"/>
- <poco:preferredUsername>moonman</poco:preferredUsername>
- <poco:displayName>Generic Enemy</poco:displayName>
- <poco:note>EMAIL:shitposterclub@gmail.com XMPP: moon@talk.shitposter.club Matrix Ed25519 fingerprint: 2HuDUTEz3iFN5N3xl6PYp9xZW/EWhgbbt78SrFy4w8o</poco:note>
- <poco:address>
- <poco:formatted>The Moon</poco:formatted>
- </poco:address>
- <poco:urls>
- <poco:type>homepage</poco:type>
- <poco:value>https://shitposter.club/moonman</poco:value>
- <poco:primary>true</poco:primary>
- </poco:urls>
- <followers url="https://shitposter.club/moonman/subscribers"></followers>
- <statusnet:profile_info local_id="1"></statusnet:profile_info>
- </author>
- <thr:in-reply-to ref="tag:shitposter.club,2017-05-05:noticeId=2827849:objectType=comment" href="https://shitposter.club/notice/2827849"></thr:in-reply-to>
- <link rel="related" href="https://shitposter.club/notice/2827849"/>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390270"/>
- <ostatus:conversation href="https://shitposter.club/conversation/1390270" local_id="1390270" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26">tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/2326"/>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://shitposter.club/user/9655"/>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
- <source>
- <id>https://shitposter.club/api/statuses/user_timeline/1.atom</id>
- <title>Generic Enemy</title>
- <link rel="alternate" type="text/html" href="https://shitposter.club/moonman"/>
- <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/user_timeline/1.atom"/>
- <link rel="license" href="https://shitposter.club/doc/tos"/>
- <icon>https://shitposter.club/avatar/1-96-20170503024316.jpeg</icon>
- <updated>2017-05-05T11:43:58+00:00</updated>
- </source>
- <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2827873.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2827873.atom"/>
- <statusnet:notice_info local_id="2827873" source="Qvitter"></statusnet:notice_info>
-</entry>
diff --git a/test/fixtures/tesla_mock/https___shitposter.club_api_statuses_user_timeline_1.atom.xml b/test/fixtures/tesla_mock/https___shitposter.club_api_statuses_user_timeline_1.atom.xml
deleted file mode 100644
index 31df7c2a6..000000000
--- a/test/fixtures/tesla_mock/https___shitposter.club_api_statuses_user_timeline_1.atom.xml
+++ /dev/null
@@ -1,454 +0,0 @@
-<?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.2.0-beta4">GNU social</generator>
- <id>https://shitposter.club/api/statuses/user_timeline/1.atom</id>
- <title>moonman timeline</title>
- <subtitle>Updates from moonman on Shitposter Club!</subtitle>
- <logo>https://shitposter.club/avatar/1-96-20170503024316.jpeg</logo>
- <updated>2017-05-05T13:24:09+00:00</updated>
-<author>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <uri>https://shitposter.club/user/1</uri>
- <name>moonman</name>
- <summary>EMAIL:shitposterclub@gmail.com XMPP: moon@talk.shitposter.club Matrix Ed25519 fingerprint: 2HuDUTEz3iFN5N3xl6PYp9xZW/EWhgbbt78SrFy4w8o</summary>
- <link rel="alternate" type="text/html" href="https://shitposter.club/moonman"/>
- <link rel="avatar" type="image/jpeg" media:width="1040" media:height="1040" href="https://shitposter.club/avatar/1-original-20170503024316.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://shitposter.club/avatar/1-96-20170503024316.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://shitposter.club/avatar/1-48-20170503024316.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://shitposter.club/avatar/1-24-20170503024318.jpeg"/>
- <poco:preferredUsername>moonman</poco:preferredUsername>
- <poco:displayName>Generic Enemy</poco:displayName>
- <poco:note>EMAIL:shitposterclub@gmail.com XMPP: moon@talk.shitposter.club Matrix Ed25519 fingerprint: 2HuDUTEz3iFN5N3xl6PYp9xZW/EWhgbbt78SrFy4w8o</poco:note>
- <poco:address>
- <poco:formatted>The Moon</poco:formatted>
- </poco:address>
- <poco:urls>
- <poco:type>homepage</poco:type>
- <poco:value>https://shitposter.club/moonman</poco:value>
- <poco:primary>true</poco:primary>
- </poco:urls>
- <followers url="https://shitposter.club/moonman/subscribers"></followers>
- <statusnet:profile_info local_id="1"></statusnet:profile_info>
-</author>
- <link href="https://shitposter.club/moonman" rel="alternate" type="text/html"/>
- <link href="https://shitposter.club/main/sup" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/>
- <link href="https://shitposter.club/api/statuses/user_timeline/1.atom?max_id=2828044" rel="next" type="application/atom+xml"/>
- <link href="https://shitposter.club/main/push/hub" rel="hub"/>
- <link href="https://shitposter.club/main/salmon/user/1" rel="salmon"/>
- <link href="https://shitposter.club/main/salmon/user/1" rel="http://salmon-protocol.org/ns/salmon-replies"/>
- <link href="https://shitposter.club/main/salmon/user/1" rel="http://salmon-protocol.org/ns/salmon-mention"/>
- <link href="https://shitposter.club/api/statuses/user_timeline/1.atom" rel="self" type="application/atom+xml"/>
-<entry>
- <id>tag:shitposter.club,2017-05-05:subscription:1:person:23190:2017-05-05T11:43:58+00:00</id>
- <title>Generic Enemy (moonman)'s status on Friday, 05-May-2017 11:43:58 UTC</title>
- <content type="html">&lt;a href=&quot;https://shitposter.club/moonman&quot;&gt;Generic Enemy&lt;/a&gt; started following &lt;a href=&quot;https://noagendasocial.com/@Ma5on&quot;&gt;Mason&lt;/a&gt;.</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2829381"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>
- <published>2017-05-05T11:43:58+00:00</published>
- <updated>2017-05-05T11:43:58+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <id>https://noagendasocial.com/users/Ma5on</id>
- <title>Mason</title>
- <link rel="alternate" type="text/html" href="https://noagendasocial.com/@Ma5on"/>
- <link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://shitposter.club/avatar/23190-original-20170505114356.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://shitposter.club/avatar/23190-96-20170505114358.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://shitposter.club/avatar/23190-48-20170505114358.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://shitposter.club/avatar/23190-24-20170505114358.jpeg"/>
- <poco:preferredUsername>ma5on</poco:preferredUsername>
- <poco:displayName>Mason</poco:displayName>
- </activity:object>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1391451"/>
- <ostatus:conversation href="https://shitposter.club/conversation/1391451" local_id="1391451" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=abffa9c14a054d3b">tag:shitposter.club,2017-05-05:objectType=thread:nonce=abffa9c14a054d3b</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://shitposter.club/api/statuses/show/2829381.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2829381.atom"/>
- <statusnet:notice_info local_id="2829381" source="activity"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:shitposter.club,2017-05-05:subscription:1:person:14357:2017-05-05T10:29:03+00:00</id>
- <title>Generic Enemy (moonman)'s status on Friday, 05-May-2017 10:29:03 UTC</title>
- <content type="html">&lt;a href=&quot;https://shitposter.club/moonman&quot;&gt;Generic Enemy&lt;/a&gt; started following &lt;a href=&quot;https://mastodon.cloud/@ohyran&quot;&gt;Jens Reuterberg&lt;/a&gt;.</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828682"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>
- <published>2017-05-05T10:29:03+00:00</published>
- <updated>2017-05-05T10:29:03+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <id>https://mastodon.cloud/users/ohyran</id>
- <title>Jens Reuterberg</title>
- <summary>RPG-nerd, illustrator, Open Source enthusiast, KDE dude, designer and gay lefty. Might be a cliché - but we will soon find out!</summary>
- <link rel="alternate" type="text/html" href="https://mastodon.cloud/@ohyran"/>
- <link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://shitposter.club/avatar/14357-original-20170505110123.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://shitposter.club/avatar/14357-96-20170505110757.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://shitposter.club/avatar/14357-48-20170505110757.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://shitposter.club/avatar/14357-24-20170505110757.jpeg"/>
- <poco:preferredUsername>ohyran</poco:preferredUsername>
- <poco:displayName>Jens Reuterberg</poco:displayName>
- <poco:note>RPG-nerd, illustrator, Open Source enthusiast, KDE dude, designer and gay lefty. Might be a cliché - but we will soon find out!</poco:note>
- </activity:object>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390971"/>
- <ostatus:conversation href="https://shitposter.club/conversation/1390971" local_id="1390971" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=937151d4825a85bf">tag:shitposter.club,2017-05-05:objectType=thread:nonce=937151d4825a85bf</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://shitposter.club/api/statuses/show/2828682.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828682.atom"/>
- <statusnet:notice_info local_id="2828682" source="activity"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:shitposter.club,2017-05-05:noticeId=2828637:objectType=note</id>
- <title>New note by moonman</title>
- <content type="html">basicall i would just rather have ppl say &amp;quot;i like x and y&amp;quot; than &amp;quot;i'm a nerd&amp;quot; the term can be retired.</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828637"/>
- <status_net notice_id="2828637"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-05-05T10:24:54+00:00</published>
- <updated>2017-05-05T10:24:54+00:00</updated>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390949"/>
- <ostatus:conversation href="https://shitposter.club/conversation/1390949" local_id="1390949" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=65992b0b9b5e6931">tag:shitposter.club,2017-05-05:objectType=thread:nonce=65992b0b9b5e6931</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://shitposter.club/api/statuses/show/2828637.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828637.atom"/>
- <statusnet:notice_info local_id="2828637" source="Qvitter"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:shitposter.club,2017-05-05:noticeId=2828579:objectType=comment</id>
- <title>New comment by moonman</title>
- <content type="html">@&lt;a href=&quot;https://gs.smuglo.li/user/35497&quot; class=&quot;h-card mention&quot; title=&quot;Bokuro Bokusawa&quot;&gt;boco&lt;/a&gt; to be honest i've turned right around and been cruel to other people, i said i'd never do it but it happens again eventually.</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828579"/>
- <status_net notice_id="2828579"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-05-05T10:20:33+00:00</published>
- <updated>2017-05-05T10:20:33+00:00</updated>
- <thr:in-reply-to ref="tag:gs.smuglo.li,2017-05-05:noticeId=2189031:objectType=comment" href="https://gs.smuglo.li/notice/2189031"></thr:in-reply-to>
- <link rel="related" href="https://gs.smuglo.li/notice/2189031"/>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390862"/>
- <ostatus:conversation href="https://shitposter.club/conversation/1390862" local_id="1390862" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=c997fc73d7f8a8f0">tag:shitposter.club,2017-05-05:objectType=thread:nonce=c997fc73d7f8a8f0</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/35497"/>
- <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://shitposter.club/api/statuses/show/2828579.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828579.atom"/>
- <statusnet:notice_info local_id="2828579" source="Qvitter"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:shitposter.club,2017-05-05:noticeId=2828554:objectType=comment</id>
- <title>New comment by moonman</title>
- <content type="html">@&lt;a href=&quot;https://mastodon.cloud/users/ohyran&quot; class=&quot;h-card mention&quot; title=&quot;Jens Reuterberg&quot;&gt;ohyran&lt;/a&gt; i won't ever get over bullying but i agree otherwise. i don't go to comic shops too often these days but i got dragged to one last year and the sheer diversity of people enjoying comics now compared to years ago was striking and it pleased me. and i noticed a couple years ago because of youtube i find things i truly enjoy watching, like in-depth videos about electronic parts, didn't exist 20 years ago. it's pretty great.</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828554"/>
- <status_net notice_id="2828554"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-05-05T10:18:10+00:00</published>
- <updated>2017-05-05T10:18:10+00:00</updated>
- <thr:in-reply-to ref="tag:mastodon.cloud,2017-05-05:objectId=6334570:objectType=Status" href="https://mastodon.cloud/users/ohyran/updates/595969"></thr:in-reply-to>
- <link rel="related" href="https://mastodon.cloud/users/ohyran/updates/595969"/>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390752"/>
- <ostatus:conversation href="https://shitposter.club/conversation/1390752" local_id="1390752" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=efae3a23b6e05767">tag:shitposter.club,2017-05-05:objectType=thread:nonce=efae3a23b6e05767</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.cloud/users/ohyran"/>
- <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://shitposter.club/api/statuses/show/2828554.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828554.atom"/>
- <statusnet:notice_info local_id="2828554" source="Qvitter"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:shitposter.club,2017-05-05:fave:1:comment:2828502:2017-05-05T10:12:52+00:00</id>
- <title>Favorite</title>
- <content type="html">moonman favorited something by ohyran: &lt;p&gt;&lt;span class=&quot;h-card&quot;&gt;&lt;a href=&quot;https://shitposter.club/moonman&quot; class=&quot;u-url mention&quot;&gt;@&lt;span&gt;moonman&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; fair enough - that distinction makes it clearer...&lt;/p&gt;&lt;p&gt;On the other hand - those of us who did &quot;pay the price&quot; of being nerdy little kids in the 80's and 90's should strive to get past it anyway (mental health wise not &quot;just get over it&quot;) and see the &quot;nerd culture&quot; thing as a blessing of sorts. We are in the optimal spot to do it. (not saying that that is something easy btw just that NOW is the best of time to start talking about it)&lt;/p&gt;</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828506"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2017-05-05T10:12:52+00:00</published>
- <updated>2017-05-05T10:12:52+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:mastodon.cloud,2017-05-05:objectId=6334570:objectType=Status</id>
- <title>New comment by ohyran</title>
- <content type="html">&lt;p&gt;&lt;span class=&quot;h-card&quot;&gt;&lt;a href=&quot;https://shitposter.club/moonman&quot; class=&quot;u-url mention&quot;&gt;@&lt;span&gt;moonman&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; fair enough - that distinction makes it clearer...&lt;/p&gt;&lt;p&gt;On the other hand - those of us who did &quot;pay the price&quot; of being nerdy little kids in the 80's and 90's should strive to get past it anyway (mental health wise not &quot;just get over it&quot;) and see the &quot;nerd culture&quot; thing as a blessing of sorts. We are in the optimal spot to do it. (not saying that that is something easy btw just that NOW is the best of time to start talking about it)&lt;/p&gt;</content>
- <link rel="alternate" type="text/html" href="https://mastodon.cloud/users/ohyran/updates/595969"/>
- <status_net notice_id="2828502"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:mastodon.cloud,2017-05-05:objectId=6334570:objectType=Status" href="https://mastodon.cloud/users/ohyran/updates/595969"></thr:in-reply-to>
- <link rel="related" href="https://mastodon.cloud/users/ohyran/updates/595969"/>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390752"/>
- <ostatus:conversation href="https://shitposter.club/conversation/1390752" local_id="1390752" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=efae3a23b6e05767">tag:shitposter.club,2017-05-05:objectType=thread:nonce=efae3a23b6e05767</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://shitposter.club/api/statuses/show/2828506.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828506.atom"/>
- <statusnet:notice_info local_id="2828506" source="unknown"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:shitposter.club,2017-05-05:noticeId=2828496:objectType=note</id>
- <title>New note by moonman</title>
- <content type="html">things are better now, a lot less kids in america get beaten up and called a fag. still too many.</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828496"/>
- <status_net notice_id="2828496"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-05-05T10:11:31+00:00</published>
- <updated>2017-05-05T10:11:31+00:00</updated>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390862"/>
- <ostatus:conversation href="https://shitposter.club/conversation/1390862" local_id="1390862" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=c997fc73d7f8a8f0">tag:shitposter.club,2017-05-05:objectType=thread:nonce=c997fc73d7f8a8f0</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://shitposter.club/api/statuses/show/2828496.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828496.atom"/>
- <statusnet:notice_info local_id="2828496" source="Qvitter"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:shitposter.club,2017-05-05:noticeId=2828457:objectType=comment</id>
- <title>New comment by moonman</title>
- <content type="html">@&lt;a href=&quot;https://shitposter.club/user/21787&quot; class=&quot;h-card mention&quot; title=&quot;Yukari&quot;&gt;cutscenes&lt;/a&gt; @&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://gs.smuglo.li/user/35497&quot; class=&quot;h-card mention&quot; title=&quot;Bokuro Bokusawa&quot;&gt;boco&lt;/a&gt; i never understood this because nerds had pocket protectors, which was a draftsman engineer thing and therefore smart, while geeks were people in carnivals who bit heads off small animals.</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828457"/>
- <status_net notice_id="2828457"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-05-05T10:07:57+00:00</published>
- <updated>2017-05-05T10:07:57+00:00</updated>
- <thr:in-reply-to ref="tag:shitposter.club,2017-05-05:noticeId=2828427:objectType=comment" href="https://shitposter.club/notice/2828427"></thr:in-reply-to>
- <link rel="related" href="https://shitposter.club/notice/2828427"/>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390752"/>
- <ostatus:conversation href="https://shitposter.club/conversation/1390752" local_id="1390752" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=efae3a23b6e05767">tag:shitposter.club,2017-05-05:objectType=thread:nonce=efae3a23b6e05767</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/28250"/>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/35497"/>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://shitposter.club/user/21787"/>
- <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://shitposter.club/api/statuses/show/2828457.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828457.atom"/>
- <statusnet:notice_info local_id="2828457" source="Qvitter"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:shitposter.club,2017-05-05:noticeId=2828435:objectType=comment</id>
- <title>New comment by moonman</title>
- <content type="html">@&lt;a href=&quot;https://mastodon.cloud/users/ohyran&quot; class=&quot;h-card mention&quot; title=&quot;Jens Reuterberg&quot;&gt;ohyran&lt;/a&gt; since i didn't specify i'm talking about people subjected to physical and psychological abuse and not people that are just mad that more people like comic books now.</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828435"/>
- <status_net notice_id="2828435"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-05-05T10:05:07+00:00</published>
- <updated>2017-05-05T10:05:07+00:00</updated>
- <thr:in-reply-to ref="tag:mastodon.cloud,2017-05-05:objectId=6331705:objectType=Status" href="https://mastodon.cloud/users/ohyran/updates/595757"></thr:in-reply-to>
- <link rel="related" href="https://mastodon.cloud/users/ohyran/updates/595757"/>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390752"/>
- <ostatus:conversation href="https://shitposter.club/conversation/1390752" local_id="1390752" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=efae3a23b6e05767">tag:shitposter.club,2017-05-05:objectType=thread:nonce=efae3a23b6e05767</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.cloud/users/ohyran"/>
- <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://shitposter.club/api/statuses/show/2828435.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828435.atom"/>
- <statusnet:notice_info local_id="2828435" source="Qvitter"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:shitposter.club,2017-05-05:noticeId=2828326:objectType=note</id>
- <title>New note by moonman</title>
- <content type="html">if you were a &amp;quot;nerd&amp;quot; before, like, 2001 you have permanent excuse to hate this kind of shit.   &lt;a href=&quot;https://shitposter.club/file/b79fa5644be0d6f22679136e67b7bf45c9c4a74a55c32dd2d0cf15de4ddd5be5.gif&quot; title=&quot;https://shitposter.club/file/b79fa5644be0d6f22679136e67b7bf45c9c4a74a55c32dd2d0cf15de4ddd5be5.gif&quot; class=&quot;attachment&quot; id=&quot;attachment-662105&quot; rel=&quot;nofollow external&quot;&gt;https://shitposter.club/attachment/662105&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828326"/>
- <status_net notice_id="2828326"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-05-05T09:47:42+00:00</published>
- <updated>2017-05-05T09:47:42+00:00</updated>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390752"/>
- <ostatus:conversation href="https://shitposter.club/conversation/1390752" local_id="1390752" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=efae3a23b6e05767">tag:shitposter.club,2017-05-05:objectType=thread:nonce=efae3a23b6e05767</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://shitposter.club/file/b79fa5644be0d6f22679136e67b7bf45c9c4a74a55c32dd2d0cf15de4ddd5be5.gif" type="image/gif" length="1023884"/>
- <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828326.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828326.atom"/>
- <statusnet:notice_info local_id="2828326" source="Qvitter"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:shitposter.club,2017-05-05:noticeId=2828250:objectType=note</id>
- <title>New note by moonman</title>
- <content type="html">&lt;a href=&quot;https://shitposter.club/file/1283e2d4dd8f96b8eeb5d9a16b318e210868aa11386cf0d593891e4c75c9126e.gif&quot; title=&quot;https://shitposter.club/file/1283e2d4dd8f96b8eeb5d9a16b318e210868aa11386cf0d593891e4c75c9126e.gif&quot; class=&quot;attachment&quot; id=&quot;attachment-662098&quot; rel=&quot;nofollow external&quot;&gt;https://shitposter.club/attachment/662098&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828250"/>
- <status_net notice_id="2828250"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-05-05T09:39:06+00:00</published>
- <updated>2017-05-05T09:39:06+00:00</updated>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390709"/>
- <ostatus:conversation href="https://shitposter.club/conversation/1390709" local_id="1390709" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=ea8ffae90546f0ab">tag:shitposter.club,2017-05-05:objectType=thread:nonce=ea8ffae90546f0ab</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://shitposter.club/file/1283e2d4dd8f96b8eeb5d9a16b318e210868aa11386cf0d593891e4c75c9126e.gif" type="image/gif" length="1020391"/>
- <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828250.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828250.atom"/>
- <statusnet:notice_info local_id="2828250" source="Qvitter"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:shitposter.club,2017-05-05:fave:1:comment:2828161:2017-05-05T09:28:19+00:00</id>
- <title>Favorite</title>
- <content type="html">moonman favorited something by kro: @&lt;a href=&quot;https://shitposter.club/user/1&quot; class=&quot;h-card u-url p-nickname mention&quot; title=&quot;Generic Enemy&quot;&gt;moonman&lt;/a&gt; Till Brooklyn?</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828162"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2017-05-05T09:28:19+00:00</published>
- <updated>2017-05-05T09:28:19+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-05:noticeId=2188587:objectType=comment</id>
- <title>New comment by kro</title>
- <content type="html">@&lt;a href=&quot;https://shitposter.club/user/1&quot; class=&quot;h-card u-url p-nickname mention&quot; title=&quot;Generic Enemy&quot;&gt;moonman&lt;/a&gt; Till Brooklyn?</content>
- <link rel="alternate" type="text/html" href="https://gs.smuglo.li/notice/2188587"/>
- <status_net notice_id="2828161"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:gs.smuglo.li,2017-05-05:noticeId=2188587:objectType=comment" href="https://gs.smuglo.li/notice/2188587"></thr:in-reply-to>
- <link rel="related" href="https://gs.smuglo.li/notice/2188587"/>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390624"/>
- <ostatus:conversation href="https://shitposter.club/conversation/1390624" local_id="1390624" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=d7aa6b5b057ca555">tag:shitposter.club,2017-05-05:objectType=thread:nonce=d7aa6b5b057ca555</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://shitposter.club/api/statuses/show/2828162.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828162.atom"/>
- <statusnet:notice_info local_id="2828162" source="unknown"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:shitposter.club,2017-05-05:fave:1:comment:2828125:2017-05-05T09:24:56+00:00</id>
- <title>Favorite</title>
- <content type="html">moonman favorited something by hardbass2k8: this has obviously interesting implications in various places, for example:&lt;br /&gt; the nationalism of the nazis might not have been real, who would have thought?&lt;br /&gt; socialism is usually promoted to implementation by real douchebags!&lt;br /&gt; your local social justice people might want diversity but they don't want you, m/19, white, why?&lt;br /&gt; amateur soccer club, they want to be the best in the amateur league but actually they just get drunk after training and are 50% overweight.&lt;br /&gt; This is because humans are not capable of telepathy, so if you join a group it doesn't magically align every little bit of your being with the declared group goals.&lt;br /&gt; &lt;br /&gt; Even though you see unmanned group beliefs flying around from time to time, generally groups are created from a bunch of people. they are not a container for people, they are the people inside them.&lt;br /&gt; &lt;br /&gt; so if you see a group that appears to be cool don't think of it as cool because its goals are cool but because its members are cool. if they aren't, tough cookies. don't be the retard and end up on the camp watchtower.</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828136"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2017-05-05T09:24:56+00:00</published>
- <updated>2017-05-05T09:24:56+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:shitposter.club,2017-05-05:noticeId=2828125:objectType=comment</id>
- <title>New comment by hardbass2k8</title>
- <content type="html">this has obviously interesting implications in various places, for example:&lt;br /&gt; the nationalism of the nazis might not have been real, who would have thought?&lt;br /&gt; socialism is usually promoted to implementation by real douchebags!&lt;br /&gt; your local social justice people might want diversity but they don't want you, m/19, white, why?&lt;br /&gt; amateur soccer club, they want to be the best in the amateur league but actually they just get drunk after training and are 50% overweight.&lt;br /&gt; This is because humans are not capable of telepathy, so if you join a group it doesn't magically align every little bit of your being with the declared group goals.&lt;br /&gt; &lt;br /&gt; Even though you see unmanned group beliefs flying around from time to time, generally groups are created from a bunch of people. they are not a container for people, they are the people inside them.&lt;br /&gt; &lt;br /&gt; so if you see a group that appears to be cool don't think of it as cool because its goals are cool but because its members are cool. if they aren't, tough cookies. don't be the retard and end up on the camp watchtower.</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828125"/>
- <status_net notice_id="2828125"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:shitposter.club,2017-05-05:noticeId=2828125:objectType=comment" href="https://shitposter.club/notice/2828125"></thr:in-reply-to>
- <link rel="related" href="https://shitposter.club/notice/2828125"/>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390589"/>
- <ostatus:conversation href="https://shitposter.club/conversation/1390589" local_id="1390589" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=51b227fe92f6babf">tag:shitposter.club,2017-05-05:objectType=thread:nonce=51b227fe92f6babf</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://shitposter.club/api/statuses/show/2828136.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828136.atom"/>
- <statusnet:notice_info local_id="2828136" source="unknown"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:shitposter.club,2017-05-05:noticeId=2828128:objectType=note</id>
- <title>New note by moonman</title>
- <content type="html">In a valid remake of They live, signs would say REBEL, and DON'T GET MARRIED AND HAVE KIDS</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828128"/>
- <status_net notice_id="2828128"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-05-05T09:24:23+00:00</published>
- <updated>2017-05-05T09:24:23+00:00</updated>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390642"/>
- <ostatus:conversation href="https://shitposter.club/conversation/1390642" local_id="1390642" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=b74397fa766b82c9">tag:shitposter.club,2017-05-05:objectType=thread:nonce=b74397fa766b82c9</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://shitposter.club/api/statuses/show/2828128.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828128.atom"/>
- <statusnet:notice_info local_id="2828128" source="Qvitter"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:shitposter.club,2017-05-05:noticeId=2828104:objectType=note</id>
- <title>New note by moonman</title>
- <content type="html">&lt;a href=&quot;https://shitposter.club/file/4d34178bde99599f31a28928e1666fbd58448d8a22e94ed82222496e4a45cb07.gif&quot; title=&quot;https://shitposter.club/file/4d34178bde99599f31a28928e1666fbd58448d8a22e94ed82222496e4a45cb07.gif&quot; class=&quot;attachment&quot; id=&quot;attachment-662049&quot; rel=&quot;nofollow external&quot;&gt;https://shitposter.club/attachment/662049&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828104"/>
- <status_net notice_id="2828104"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-05-05T09:21:01+00:00</published>
- <updated>2017-05-05T09:21:01+00:00</updated>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390624"/>
- <ostatus:conversation href="https://shitposter.club/conversation/1390624" local_id="1390624" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=d7aa6b5b057ca555">tag:shitposter.club,2017-05-05:objectType=thread:nonce=d7aa6b5b057ca555</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://shitposter.club/file/4d34178bde99599f31a28928e1666fbd58448d8a22e94ed82222496e4a45cb07.gif" type="image/gif" length="278366"/>
- <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828104.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828104.atom"/>
- <statusnet:notice_info local_id="2828104" source="Qvitter"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:shitposter.club,2017-05-05:noticeId=2828102:objectType=note</id>
- <title>New note by moonman</title>
- <content type="html">when ppl find out i haven't always been serious  &lt;a href=&quot;https://shitposter.club/file/5859fa95875342cc65dba0d852f726db158ce28198c326d5f13d9de7c0d2c449.gif&quot; title=&quot;https://shitposter.club/file/5859fa95875342cc65dba0d852f726db158ce28198c326d5f13d9de7c0d2c449.gif&quot; class=&quot;attachment&quot; id=&quot;attachment-662053&quot; rel=&quot;nofollow external&quot;&gt;https://shitposter.club/attachment/662053&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828102"/>
- <status_net notice_id="2828102"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-05-05T09:20:45+00:00</published>
- <updated>2017-05-05T09:20:45+00:00</updated>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390622"/>
- <ostatus:conversation href="https://shitposter.club/conversation/1390622" local_id="1390622" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=0a025ac5a570b4ec">tag:shitposter.club,2017-05-05:objectType=thread:nonce=0a025ac5a570b4ec</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://shitposter.club/file/5859fa95875342cc65dba0d852f726db158ce28198c326d5f13d9de7c0d2c449.gif" type="image/gif" length="119239"/>
- <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828102.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828102.atom"/>
- <statusnet:notice_info local_id="2828102" source="Qvitter"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:shitposter.club,2017-05-05:noticeId=2828086:objectType=comment</id>
- <title>New comment by moonman</title>
- <content type="html">@&lt;a href=&quot;https://shitposter.club/user/9655&quot; class=&quot;h-card mention&quot; title=&quot;Solidarity for Pigs&quot;&gt;neimzr4luzerz&lt;/a&gt; @&lt;a href=&quot;https://gs.smuglo.li/user/2326&quot; class=&quot;h-card mention&quot; title=&quot;Dolus_McHonest&quot;&gt;dolus&lt;/a&gt; @&lt;a href=&quot;https://gs.smuglo.li/user/35497&quot; class=&quot;h-card mention&quot; title=&quot;Bokuro Bokusawa&quot;&gt;boco&lt;/a&gt; you are being too serious lol</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828086"/>
- <status_net notice_id="2828086"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-05-05T09:17:19+00:00</published>
- <updated>2017-05-05T09:17:19+00:00</updated>
- <thr:in-reply-to ref="tag:shitposter.club,2017-05-05:noticeId=2828082:objectType=comment" href="https://shitposter.club/notice/2828082"></thr:in-reply-to>
- <link rel="related" href="https://shitposter.club/notice/2828082"/>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390270"/>
- <ostatus:conversation href="https://shitposter.club/conversation/1390270" local_id="1390270" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26">tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/2326"/>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://shitposter.club/user/9655"/>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/35497"/>
- <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://shitposter.club/api/statuses/show/2828086.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828086.atom"/>
- <statusnet:notice_info local_id="2828086" source="Qvitter"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:shitposter.club,2017-05-05:noticeId=2828085:objectType=note</id>
- <title>New note by moonman</title>
- <content type="html">shitposter dot club  &lt;a href=&quot;https://shitposter.club/file/9b084c7210b16abbf4d28594b924a07ef4a2a06f89d901a4c42fb1e243291263.gif&quot; title=&quot;https://shitposter.club/file/9b084c7210b16abbf4d28594b924a07ef4a2a06f89d901a4c42fb1e243291263.gif&quot; class=&quot;attachment&quot; id=&quot;attachment-662047&quot; rel=&quot;nofollow external&quot;&gt;https://shitposter.club/attachment/662047&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828085"/>
- <status_net notice_id="2828085"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-05-05T09:16:50+00:00</published>
- <updated>2017-05-05T09:16:50+00:00</updated>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390613"/>
- <ostatus:conversation href="https://shitposter.club/conversation/1390613" local_id="1390613" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=d1ae088a1b91e5e5">tag:shitposter.club,2017-05-05:objectType=thread:nonce=d1ae088a1b91e5e5</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://shitposter.club/file/9b084c7210b16abbf4d28594b924a07ef4a2a06f89d901a4c42fb1e243291263.gif" type="image/gif" length="681847"/>
- <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828085.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828085.atom"/>
- <statusnet:notice_info local_id="2828085" source="Qvitter"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:shitposter.club,2017-05-05:noticeId=2828061:objectType=note</id>
- <title>New note by moonman</title>
- <content type="html">even when i lie i tell the truth, is that so hard to understand?</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828061"/>
- <status_net notice_id="2828061"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-05-05T09:15:07+00:00</published>
- <updated>2017-05-05T09:15:07+00:00</updated>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390593"/>
- <ostatus:conversation href="https://shitposter.club/conversation/1390593" local_id="1390593" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=a516e4b8506b8ef5">tag:shitposter.club,2017-05-05:objectType=thread:nonce=a516e4b8506b8ef5</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://shitposter.club/api/statuses/show/2828061.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828061.atom"/>
- <statusnet:notice_info local_id="2828061" source="Qvitter"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:shitposter.club,2017-05-05:noticeId=2828052:objectType=comment</id>
- <title>New comment by moonman</title>
- <content type="html">@&lt;a href=&quot;https://shitposter.club/user/9591&quot; class=&quot;h-card mention&quot; title=&quot;warum hei&amp;#xDF;en deutschl&amp;#xE4;nder deutschl&amp;#xE4;nder&quot;&gt;hardbass2k8&lt;/a&gt; history, anthropology.</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2828052"/>
- <status_net notice_id="2828052"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-05-05T09:14:22+00:00</published>
- <updated>2017-05-05T09:14:22+00:00</updated>
- <thr:in-reply-to ref="tag:shitposter.club,2017-05-05:noticeId=2828048:objectType=comment" href="https://shitposter.club/notice/2828048"></thr:in-reply-to>
- <link rel="related" href="https://shitposter.club/notice/2828048"/>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/1390564"/>
- <ostatus:conversation href="https://shitposter.club/conversation/1390564" local_id="1390564" ref="tag:shitposter.club,2017-05-05:objectType=thread:nonce=fe4d7f35b13403ba">tag:shitposter.club,2017-05-05:objectType=thread:nonce=fe4d7f35b13403ba</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://shitposter.club/user/9591"/>
- <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://shitposter.club/api/statuses/show/2828052.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/2828052.atom"/>
- <statusnet:notice_info local_id="2828052" source="Qvitter"></statusnet:notice_info>
-</entry>
-</feed>
diff --git a/test/fixtures/tesla_mock/https___shitposter.club_notice_2827873.json b/test/fixtures/tesla_mock/https___shitposter.club_notice_2827873.json
deleted file mode 100644
index 4b7b4df44..000000000
--- a/test/fixtures/tesla_mock/https___shitposter.club_notice_2827873.json
+++ /dev/null
@@ -1 +0,0 @@
-{"@context":["https://www.w3.org/ns/activitystreams","https://shitposter.club/schemas/litepub-0.1.jsonld",{"@language":"und"}],"actor":"https://shitposter.club/users/moonman","attachment":[],"attributedTo":"https://shitposter.club/users/moonman","cc":["https://shitposter.club/users/moonman/followers"],"content":"@<a href=\"https://shitposter.club/users/9655\" class=\"h-card mention\" title=\"Solidarity for Pigs\">neimzr4luzerz</a> @<a href=\"https://gs.smuglo.li/user/2326\" class=\"h-card mention\" title=\"Dolus_McHonest\">dolus</a> childhood poring over Strong's concordance and a koine Greek dictionary, fast forward to 2017 and some fuckstick who translates japanese jackoff material tells me you just need to make it sound right in English","context":"tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26","conversation":"tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26","id":"tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment","inReplyTo":"tag:shitposter.club,2017-05-05:noticeId=2827849:objectType=comment","inReplyToStatusId":2827849,"published":"2017-05-05T08:51:48Z","sensitive":false,"summary":null,"tag":[],"to":["https://www.w3.org/ns/activitystreams#Public"],"type":"Note"} \ No newline at end of file
diff --git a/test/fixtures/tesla_mock/https___social.heldscal.la_api_statuses_user_timeline_23211.atom.xml b/test/fixtures/tesla_mock/https___social.heldscal.la_api_statuses_user_timeline_23211.atom.xml
deleted file mode 100644
index 6cba5c28f..000000000
--- a/test/fixtures/tesla_mock/https___social.heldscal.la_api_statuses_user_timeline_23211.atom.xml
+++ /dev/null
@@ -1,591 +0,0 @@
-<?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-05T12:01:21+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=2060731" 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-05:fave:23211:comment:2063249:2017-05-05T11:40:21+00:00</id>
- <title>Favorite</title>
- <content type="html">lambadalambda favorited something by tatiana: &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; they will start complaining about this, but won't come up with any solutions)&lt;/p&gt;</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2063306"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2017-05-05T11:40:21+00:00</published>
- <updated>2017-05-05T11:40:21+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:social.weho.st,2017-05-05:objectId=172033:objectType=Status</id>
- <title>New comment by tatiana</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; they will start complaining about this, but won't come up with any solutions)&lt;/p&gt;</content>
- <link rel="alternate" type="text/html" href="https://social.weho.st/users/Tatiana/updates/2841"/>
- <status_net notice_id="2063249"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:social.weho.st,2017-05-05:objectId=172033:objectType=Status" href="https://social.weho.st/users/Tatiana/updates/2841"></thr:in-reply-to>
- <link rel="related" href="https://social.weho.st/users/Tatiana/updates/2841"/>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1062581"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/1062581" local_id="1062581" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198</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/2063306.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2063306.atom"/>
- <statusnet:notice_info local_id="2063306" source="unknown"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-05-05:fave:23211:comment:2063041:2017-05-05T11:27:28+00:00</id>
- <title>Favorite</title>
- <content type="html">lambadalambda favorited something by kat: @&lt;a href=&quot;https://social.heldscal.la/lambadalambda&quot; class=&quot;h-card mention&quot; title=&quot;Constance Variable&quot;&gt;lambadalambda&lt;/a&gt; if the admin reading mine would delete a few it would be really useful in prioritising. </content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2063148"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2017-05-05T11:27:28+00:00</published>
- <updated>2017-05-05T11:27:28+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:quitter.se,2017-05-05:noticeId=11807959:objectType=comment</id>
- <title>New comment by kat</title>
- <content type="html">@&lt;a href=&quot;https://social.heldscal.la/lambadalambda&quot; class=&quot;h-card mention&quot; title=&quot;Constance Variable&quot;&gt;lambadalambda&lt;/a&gt; if the admin reading mine would delete a few it would be really useful in prioritising. </content>
- <link rel="alternate" type="text/html" href="http://quitter.se/notice/11807959"/>
- <status_net notice_id="2063041"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:quitter.se,2017-05-05:noticeId=11807959:objectType=comment" href="http://quitter.se/notice/11807959"></thr:in-reply-to>
- <link rel="related" href="http://quitter.se/notice/11807959"/>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1062581"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/1062581" local_id="1062581" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198</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/2063148.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2063148.atom"/>
- <statusnet:notice_info local_id="2063148" source="unknown"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-05-05:noticeId=2062924:objectType=note</id>
- <title>lambadalambda repeated a notice by nielsk</title>
- <content type="html">RT @nielsk @&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; but there are soooo many, where should I start to read?</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2062924"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb>
- <published>2017-05-05T11:09:37+00:00</published>
- <updated>2017-05-05T11:09:37+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
- <id>tag:mastodon.social,2017-05-05:objectId=5024471:objectType=Status</id>
- <title></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; but there are soooo many, where should I start to read?&lt;/p&gt;</content>
- <link rel="alternate" type="text/html" href="https://mastodon.social/users/nielsk/updates/2256348"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-05-05T11:05:18+00:00</published>
- <updated>2017-05-05T11:05:18+00:00</updated>
- <author>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <uri>https://mastodon.social/users/nielsk</uri>
- <name>nielsk</name>
- <summary>Sysadmin by day and ehm… sysadmin by night. Besides that old video games, Japan, economics and some other stuff</summary>
- <link rel="alternate" type="text/html" href="https://mastodon.social/@nielsk"/>
- <link rel="avatar" type="image/jpeg" media:width="120" media:height="120" href="https://social.heldscal.la/avatar/29849-original-20170428120037.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/29849-96-20170428120041.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/29849-48-20170428120041.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/29849-24-20170429103753.jpeg"/>
- <poco:preferredUsername>nielsk</poco:preferredUsername>
- <poco:displayName>nielsk</poco:displayName>
- <poco:note>Sysadmin by day and ehm… sysadmin by night. Besides that old video games, Japan, economics and some other stuff</poco:note>
- <statusnet:profile_info local_id="29849"></statusnet:profile_info>
- </author>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:mastodon.social,2017-05-05:objectId=5024471:objectType=Status</id>
- <title>New comment by nielsk</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; but there are soooo many, where should I start to read?&lt;/p&gt;</content>
- <link rel="alternate" type="text/html" href="https://mastodon.social/users/nielsk/updates/2256348"/>
- <status_net notice_id="2062875"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:social.heldscal.la,2017-05-05:noticeId=2062583:objectType=note" href="https://social.heldscal.la/notice/2062583"></thr:in-reply-to>
- <link rel="related" href="https://social.heldscal.la/notice/2062583"/>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1062581"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/1062581" local_id="1062581" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198</ostatus:conversation>
- <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"/>
- <source>
- <id>https://mastodon.social/users/nielsk.atom</id>
- <title>nielsk</title>
- <link rel="alternate" type="text/html" href="https://mastodon.social/@nielsk"/>
- <link rel="self" type="application/atom+xml" href="https://mastodon.social/users/nielsk.atom"/>
- <icon>https://social.heldscal.la/avatar/29849-96-20170428120041.jpeg</icon>
- <updated>2017-05-05T11:06:32+00:00</updated>
- </source>
- </activity:object>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1062581"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/1062581" local_id="1062581" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198</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/2062924.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2062924.atom"/>
- <statusnet:notice_info local_id="2062924" source="api" repeat_of="2062875"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-05-05:fave:23211:comment:2062875:2017-05-05T11:09:27+00:00</id>
- <title>Favorite</title>
- <content type="html">lambadalambda favorited something by nielsk: &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; but there are soooo many, where should I start to read?&lt;/p&gt;</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2062923"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2017-05-05T11:09:27+00:00</published>
- <updated>2017-05-05T11:09:27+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:mastodon.social,2017-05-05:objectId=5024471:objectType=Status</id>
- <title>New comment by nielsk</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; but there are soooo many, where should I start to read?&lt;/p&gt;</content>
- <link rel="alternate" type="text/html" href="https://mastodon.social/users/nielsk/updates/2256348"/>
- <status_net notice_id="2062875"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:mastodon.social,2017-05-05:objectId=5024471:objectType=Status" href="https://mastodon.social/users/nielsk/updates/2256348"></thr:in-reply-to>
- <link rel="related" href="https://mastodon.social/users/nielsk/updates/2256348"/>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1062581"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/1062581" local_id="1062581" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198</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/2062923.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2062923.atom"/>
- <statusnet:notice_info local_id="2062923" source="unknown"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-05-05:fave:23211:comment:2062863:2017-05-05T11:09:11+00:00</id>
- <title>Favorite</title>
- <content type="html">lambadalambda favorited something by kasil: &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; surely, google is not that evil !&lt;/p&gt;</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2062921"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2017-05-05T11:09:11+00:00</published>
- <updated>2017-05-05T11:09:11+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:loutre.info,2017-05-05:objectId=23331:objectType=Status</id>
- <title>New comment by kasil</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; surely, google is not that evil !&lt;/p&gt;</content>
- <link rel="alternate" type="text/html" href="https://loutre.info/users/Kasil/updates/159"/>
- <status_net notice_id="2062863"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:loutre.info,2017-05-05:objectId=23331:objectType=Status" href="https://loutre.info/users/Kasil/updates/159"></thr:in-reply-to>
- <link rel="related" href="https://loutre.info/users/Kasil/updates/159"/>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1062581"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/1062581" local_id="1062581" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198</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/2062921.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2062921.atom"/>
- <statusnet:notice_info local_id="2062921" 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-05:noticeId=2062767:objectType=comment</id>
- <title>New comment by lambadalambda</title>
- <content type="html">@&lt;a href=&quot;https://sealion.club/user/4&quot; class=&quot;h-card u-url p-nickname mention&quot; title=&quot;dewoo &amp;#x274E;&quot;&gt;dwmatiz&lt;/a&gt; dunno, probably.</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2062767"/>
- <status_net notice_id="2062767"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-05-05T10:55:17+00:00</published>
- <updated>2017-05-05T10:55:17+00:00</updated>
- <thr:in-reply-to ref="tag:sealion.club,2017-05-05:noticeId=3183881:objectType=comment" href="https://sealion.club/notice/3183881"></thr:in-reply-to>
- <link rel="related" href="https://sealion.club/notice/3183881"/>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1062581"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/1062581" local_id="1062581" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://sealion.club/user/4"/>
- <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/2062767.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2062767.atom"/>
- <statusnet:notice_info local_id="2062767" 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-05:noticeId=2062705:objectType=comment</id>
- <title>New comment by lambadalambda</title>
- <content type="html">@&lt;a href=&quot;https://gs.smuglo.li/user/28250&quot; class=&quot;h-card u-url p-nickname mention&quot; title=&quot;Bricky&quot;&gt;thatbrickster&lt;/a&gt; I do it, too.</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2062705"/>
- <status_net notice_id="2062705"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-05-05T10:48:12+00:00</published>
- <updated>2017-05-05T10:48:12+00:00</updated>
- <thr:in-reply-to ref="tag:gs.smuglo.li,2017-05-05:noticeId=2189353:objectType=comment" href="https://gs.smuglo.li/notice/2189353"></thr:in-reply-to>
- <link rel="related" href="https://gs.smuglo.li/notice/2189353"/>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1062581"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/1062581" local_id="1062581" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/28250"/>
- <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/2062705.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2062705.atom"/>
- <statusnet:notice_info local_id="2062705" 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-05:noticeId=2062620:objectType=comment</id>
- <title>New comment by lambadalambda</title>
- <content type="html">@&lt;a href=&quot;https://social.tchncs.de/users/israuor&quot; class=&quot;h-card u-url p-nickname mention&quot; title=&quot;Israuor &amp;#x2642;&quot;&gt;israuor&lt;/a&gt; @&lt;a href=&quot;https://mastodon.gougere.fr/users/bortzmeyer&quot; class=&quot;h-card u-url p-nickname mention&quot; title=&quot;S. Bortzmeyer &amp;#x2705;&quot;&gt;bortzmeyer&lt;/a&gt; so, 99%. 100% for 'normal' people.</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2062620"/>
- <status_net notice_id="2062620"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-05-05T10:38:52+00:00</published>
- <updated>2017-05-05T10:38:52+00:00</updated>
- <thr:in-reply-to ref="tag:social.tchncs.de,2017-05-05:objectId=1667119:objectType=Status" href="https://social.tchncs.de/users/israuor/updates/74901"></thr:in-reply-to>
- <link rel="related" href="https://social.tchncs.de/users/israuor/updates/74901"/>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1062581"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/1062581" local_id="1062581" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.tchncs.de/users/israuor"/>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.gougere.fr/users/bortzmeyer"/>
- <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/2062620.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2062620.atom"/>
- <statusnet:notice_info local_id="2062620" source="Pleroma FE"></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-05:noticeId=2062583:objectType=note</id>
- <title>New note by lambadalambda</title>
- <content type="html">I wonder what'll happen when people realize the admin at their mail hoster can read all their e-mails.</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2062583"/>
- <status_net notice_id="2062583"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-05-05T10:35:45+00:00</published>
- <updated>2017-05-05T10:35:45+00:00</updated>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1062581"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/1062581" local_id="1062581" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=e95b99adc050e198</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/2062583.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2062583.atom"/>
- <statusnet:notice_info local_id="2062583" source="Pleroma FE"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-05-05:subscription:23211:person:35708:2017-05-05T09:34:46+00:00</id>
- <title>Constance Variable (lambadalambda@social.heldscal.la)'s status on Friday, 05-May-2017 09:34:46 UTC</title>
- <content type="html">&lt;a href=&quot;https://social.heldscal.la/lambadalambda&quot;&gt;Constance Variable&lt;/a&gt; started following &lt;a href=&quot;https://mastodon.social/@milouse&quot;&gt;milouse&lt;/a&gt;.</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2062053"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>
- <published>2017-05-05T09:34:46+00:00</published>
- <updated>2017-05-05T09:34:46+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <id>https://mastodon.social/users/milouse</id>
- <title>milouse</title>
- <summary>#Scout leader #sgdf, interested in #openweb, #semanticweb, #privacy, #foss and #socialeconomy. 0xA714ECAC8C9CEE3D</summary>
- <link rel="alternate" type="text/html" href="https://mastodon.social/@milouse"/>
- <link rel="avatar" type="image/png" media:width="120" media:height="120" href="https://social.heldscal.la/avatar/35708-original-20170505105902.png"/>
- <link rel="avatar" type="image/png" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/35708-96-20170505105911.png"/>
- <link rel="avatar" type="image/png" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/35708-48-20170505105911.png"/>
- <link rel="avatar" type="image/png" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/35708-24-20170505105938.png"/>
- <poco:preferredUsername>milouse</poco:preferredUsername>
- <poco:displayName>milouse</poco:displayName>
- <poco:note>#Scout leader #sgdf, interested in #openweb, #semanticweb, #privacy, #foss and #socialeconomy. 0xA714ECAC8C9CEE3D</poco:note>
- </activity:object>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1062248"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/1062248" local_id="1062248" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=26ca19a355bb6135">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=26ca19a355bb6135</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/2062053.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2062053.atom"/>
- <statusnet:notice_info local_id="2062053" source="activity"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-05-05:noticeId=2061871:objectType=note</id>
- <title>lambadalambda repeated a notice by safebot</title>
- <content type="html">RT @&lt;a href=&quot;https://gs.smuglo.li/user/25857&quot; class=&quot;h-card u-url p-nickname mention&quot; title=&quot;safebot&quot;&gt;safebot&lt;/a&gt; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://social.heldscal.la/tag/cheers&quot; rel=&quot;tag&quot;&gt;cheers&lt;/a&gt;&lt;/span&gt; &lt;a href=&quot;https://gs.smuglo.li/attachment/456444&quot; title=&quot;https://gs.smuglo.li/attachment/456444&quot; rel=&quot;nofollow external noreferrer&quot; class=&quot;attachment&quot; id=&quot;attachment-432334&quot;&gt;https://gs.smuglo.li/attachment/456444&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2061871"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb>
- <published>2017-05-05T09:16:17+00:00</published>
- <updated>2017-05-05T09:16:17+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
- <id>tag:gs.smuglo.li,2017-05-05:noticeId=2188073:objectType=note</id>
- <title></title>
- <content type="html">#&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://gs.smuglo.li/tag/cheers&quot; rel=&quot;tag&quot;&gt;cheers&lt;/a&gt;&lt;/span&gt; &lt;a href=&quot;https://gs.smuglo.li/file/5099e73c83da778cd032a721e96880f99a868b712be2975d08238547a5ba06c7.jpg&quot; title=&quot;https://gs.smuglo.li/file/5099e73c83da778cd032a721e96880f99a868b712be2975d08238547a5ba06c7.jpg&quot; rel=&quot;nofollow noreferrer&quot; class=&quot;attachment&quot;&gt;https://gs.smuglo.li/attachment/456444&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://gs.smuglo.li/notice/2188073"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-05-05T08:36:53+00:00</published>
- <updated>2017-05-05T08:36:53+00:00</updated>
- <author>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <uri>https://gs.smuglo.li/user/25857</uri>
- <name>safebot</name>
- <link rel="alternate" type="text/html" href="https://gs.smuglo.li/safebot"/>
- <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/25719-original-20161215233234.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/25719-original-20161215233234.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/25719-48-20161215233239.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/25719-24-20161215235533.jpeg"/>
- <poco:preferredUsername>safebot</poco:preferredUsername>
- <poco:displayName>safebot</poco:displayName>
- <statusnet:profile_info local_id="25719"></statusnet:profile_info>
- </author>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:gs.smuglo.li,2017-05-05:noticeId=2188073:objectType=note</id>
- <title>New note by safebot</title>
- <content type="html">#&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://gs.smuglo.li/tag/cheers&quot; rel=&quot;tag&quot;&gt;cheers&lt;/a&gt;&lt;/span&gt; &lt;a href=&quot;https://gs.smuglo.li/file/5099e73c83da778cd032a721e96880f99a868b712be2975d08238547a5ba06c7.jpg&quot; title=&quot;https://gs.smuglo.li/file/5099e73c83da778cd032a721e96880f99a868b712be2975d08238547a5ba06c7.jpg&quot; rel=&quot;nofollow noreferrer&quot; class=&quot;attachment&quot;&gt;https://gs.smuglo.li/attachment/456444&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://gs.smuglo.li/notice/2188073"/>
- <status_net notice_id="2061504"></status_net>
- </activity:object>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1061934"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/1061934" local_id="1061934" ref="https://gs.smuglo.li/conversation/1009429">https://gs.smuglo.li/conversation/1009429</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
- <category term="cheers"></category>
- <source>
- <id>https://gs.smuglo.li/api/statuses/user_timeline/25857.atom</id>
- <title>safebot</title>
- <link rel="alternate" type="text/html" href="https://gs.smuglo.li/safebot"/>
- <link rel="self" type="application/atom+xml" href="https://gs.smuglo.li/api/statuses/user_timeline/25857.atom"/>
- <icon>https://social.heldscal.la/avatar/25719-original-20161215233234.jpeg</icon>
- <updated>2017-05-05T12:00:57+00:00</updated>
- </source>
- </activity:object>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1061934"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/1061934" local_id="1061934" ref="https://gs.smuglo.li/conversation/1009429">https://gs.smuglo.li/conversation/1009429</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/2061871.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061871.atom"/>
- <statusnet:notice_info local_id="2061871" source="api" repeat_of="2061504"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-05-05:fave:23211:comment:2061643:2017-05-05T09:12:50+00:00</id>
- <title>Favorite</title>
- <content type="html">lambadalambda favorited something by moonman: @&lt;a href=&quot;https://shitposter.club/user/9655&quot; class=&quot;h-card mention&quot; title=&quot;Solidarity for Pigs&quot;&gt;neimzr4luzerz&lt;/a&gt; @&lt;a href=&quot;https://gs.smuglo.li/user/2326&quot; class=&quot;h-card mention&quot; title=&quot;Dolus_McHonest&quot;&gt;dolus&lt;/a&gt; childhood poring over Strong's concordance and a koine Greek dictionary, fast forward to 2017 and some fuckstick who translates japanese jackoff material tells me you just need to make it sound right in English</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2061828"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2017-05-05T09:12:50+00:00</published>
- <updated>2017-05-05T09:12:50+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment</id>
- <title>New comment by moonman</title>
- <content type="html">@&lt;a href=&quot;https://shitposter.club/user/9655&quot; class=&quot;h-card mention&quot; title=&quot;Solidarity for Pigs&quot;&gt;neimzr4luzerz&lt;/a&gt; @&lt;a href=&quot;https://gs.smuglo.li/user/2326&quot; class=&quot;h-card mention&quot; title=&quot;Dolus_McHonest&quot;&gt;dolus&lt;/a&gt; childhood poring over Strong's concordance and a koine Greek dictionary, fast forward to 2017 and some fuckstick who translates japanese jackoff material tells me you just need to make it sound right in English</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2827873"/>
- <status_net notice_id="2061643"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment" href="https://shitposter.club/notice/2827873"></thr:in-reply-to>
- <link rel="related" href="https://shitposter.club/notice/2827873"/>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1061781"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/1061781" local_id="1061781" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=55ead90125cd4bd4">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=55ead90125cd4bd4</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/2061828.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061828.atom"/>
- <statusnet:notice_info local_id="2061828" source="unknown"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-05-05:fave:23211:comment:2061696:2017-05-05T09:06:10+00:00</id>
- <title>Favorite</title>
- <content type="html">lambadalambda favorited something by moonman: @&lt;a href=&quot;https://shitposter.club/user/9655&quot; class=&quot;h-card mention&quot; title=&quot;Solidarity for Pigs&quot;&gt;neimzr4luzerz&lt;/a&gt; &lt;br /&gt; &lt;span class=&quot;greentext&quot;&gt;&amp;gt; (((common era)))&lt;/span&gt;</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2061781"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2017-05-05T09:06:10+00:00</published>
- <updated>2017-05-05T09:06:10+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:shitposter.club,2017-05-05:noticeId=2827918:objectType=comment</id>
- <title>New comment by moonman</title>
- <content type="html">@&lt;a href=&quot;https://shitposter.club/user/9655&quot; class=&quot;h-card mention&quot; title=&quot;Solidarity for Pigs&quot;&gt;neimzr4luzerz&lt;/a&gt; &lt;br /&gt; &lt;span class=&quot;greentext&quot;&gt;&amp;gt; (((common era)))&lt;/span&gt;</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2827918"/>
- <status_net notice_id="2061696"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:shitposter.club,2017-05-05:noticeId=2827918:objectType=comment" href="https://shitposter.club/notice/2827918"></thr:in-reply-to>
- <link rel="related" href="https://shitposter.club/notice/2827918"/>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1061781"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/1061781" local_id="1061781" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=55ead90125cd4bd4">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=55ead90125cd4bd4</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/2061781.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061781.atom"/>
- <statusnet:notice_info local_id="2061781" source="unknown"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-05-05:fave:23211:note:2061673:2017-05-05T08:58:28+00:00</id>
- <title>Favorite</title>
- <content type="html">lambadalambda favorited something by moonman: discussion is one thing but any argument I've heard over and over again for the last three decades is going to go unanswered.</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2061702"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2017-05-05T08:58:28+00:00</published>
- <updated>2017-05-05T08:58:28+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:shitposter.club,2017-05-05:noticeId=2827895:objectType=note</id>
- <title>New note by moonman</title>
- <content type="html">discussion is one thing but any argument I've heard over and over again for the last three decades is going to go unanswered.</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2827895"/>
- <status_net notice_id="2061673"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:shitposter.club,2017-05-05:noticeId=2827895:objectType=note" href="https://shitposter.club/notice/2827895"></thr:in-reply-to>
- <link rel="related" href="https://shitposter.club/notice/2827895"/>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1062026"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/1062026" local_id="1062026" ref="https://shitposter.club/conversation/1390494">https://shitposter.club/conversation/1390494</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/2061702.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061702.atom"/>
- <statusnet:notice_info local_id="2061702" source="unknown"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-05-05:fave:23211:comment:2061280:2017-05-05T08:47:38+00:00</id>
- <title>Favorite</title>
- <content type="html">lambadalambda favorited something by moonman: @&lt;a href=&quot;https://shitposter.club/user/9655&quot; class=&quot;h-card mention&quot; title=&quot;Solidarity for Pigs&quot;&gt;neimzr4luzerz&lt;/a&gt; sex is for procreation and as an expression of intimacy between commited couples, it is a sacramental act</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2061614"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2017-05-05T08:47:38+00:00</published>
- <updated>2017-05-05T08:47:38+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:shitposter.club,2017-05-05:noticeId=2827561:objectType=comment</id>
- <title>New comment by moonman</title>
- <content type="html">@&lt;a href=&quot;https://shitposter.club/user/9655&quot; class=&quot;h-card mention&quot; title=&quot;Solidarity for Pigs&quot;&gt;neimzr4luzerz&lt;/a&gt; sex is for procreation and as an expression of intimacy between commited couples, it is a sacramental act</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2827561"/>
- <status_net notice_id="2061280"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:shitposter.club,2017-05-05:noticeId=2827561:objectType=comment" href="https://shitposter.club/notice/2827561"></thr:in-reply-to>
- <link rel="related" href="https://shitposter.club/notice/2827561"/>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1061781"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/1061781" local_id="1061781" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=55ead90125cd4bd4">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=55ead90125cd4bd4</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/2061614.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061614.atom"/>
- <statusnet:notice_info local_id="2061614" source="unknown"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-05-05:fave:23211:note:2061535:2017-05-05T08:40:55+00:00</id>
- <title>Favorite</title>
- <content type="html">lambadalambda favorited something by fortune: What did Mickey Mouse get for Christmas?&lt;br /&gt; &lt;br /&gt; A Dan Quayle watch.&lt;br /&gt; &lt;br /&gt; -- heard from a Mike Dukakis field worker</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2061544"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2017-05-05T08:40:55+00:00</published>
- <updated>2017-05-05T08:40:55+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:social.heldscal.la,2017-05-05:noticeId=2061535:objectType=note</id>
- <title>New note by fortune</title>
- <content type="html">What did Mickey Mouse get for Christmas?&lt;br /&gt; &lt;br /&gt; A Dan Quayle watch.&lt;br /&gt; &lt;br /&gt; -- heard from a Mike Dukakis field worker</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2061535"/>
- <status_net notice_id="2061535"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:social.heldscal.la,2017-05-05:noticeId=2061535:objectType=note" href="https://social.heldscal.la/notice/2061535"></thr:in-reply-to>
- <link rel="related" href="https://social.heldscal.la/notice/2061535"/>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1061954"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/1061954" local_id="1061954" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=5185e5c145ee4762">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=5185e5c145ee4762</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/2061544.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061544.atom"/>
- <statusnet:notice_info local_id="2061544" source="unknown"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-05-05:fave:23211:comment:2061421:2017-05-05T08:36:27+00:00</id>
- <title>Favorite</title>
- <content type="html">lambadalambda favorited something by moonman: @&lt;a href=&quot;https://maly.io/users/sonya&quot; class=&quot;h-card mention&quot; title=&quot;Sonya Mann ✅&quot;&gt;sonya&lt;/a&gt; banned from 4chan. you better watch ou. i'm trouble, y'hear?</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2061495"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2017-05-05T08:36:27+00:00</published>
- <updated>2017-05-05T08:36:27+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:shitposter.club,2017-05-05:noticeId=2827689:objectType=comment</id>
- <title>New comment by moonman</title>
- <content type="html">@&lt;a href=&quot;https://maly.io/users/sonya&quot; class=&quot;h-card mention&quot; title=&quot;Sonya Mann ✅&quot;&gt;sonya&lt;/a&gt; banned from 4chan. you better watch ou. i'm trouble, y'hear?</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2827689"/>
- <status_net notice_id="2061421"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:shitposter.club,2017-05-05:noticeId=2827689:objectType=comment" href="https://shitposter.club/notice/2827689"></thr:in-reply-to>
- <link rel="related" href="https://shitposter.club/notice/2827689"/>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1060861"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/1060861" local_id="1060861" ref="https://shitposter.club/conversation/1389345">https://shitposter.club/conversation/1389345</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/2061495.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061495.atom"/>
- <statusnet:notice_info local_id="2061495" source="unknown"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-05-05:fave:23211:comment:2061351:2017-05-05T08:28:03+00:00</id>
- <title>Favorite</title>
- <content type="html">lambadalambda favorited something by moonman: @&lt;a href=&quot;https://social.heldscal.la/user/29138&quot; class=&quot;h-card mention&quot; title=&quot;Claes Wallin (韋嘉誠)&quot;&gt;clacke&lt;/a&gt; is that the sequel to Time Crisis</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2061410"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2017-05-05T08:28:03+00:00</published>
- <updated>2017-05-05T08:28: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-05:noticeId=2827630:objectType=comment</id>
- <title>New comment by moonman</title>
- <content type="html">@&lt;a href=&quot;https://social.heldscal.la/user/29138&quot; class=&quot;h-card mention&quot; title=&quot;Claes Wallin (韋嘉誠)&quot;&gt;clacke&lt;/a&gt; is that the sequel to Time Crisis</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2827630"/>
- <status_net notice_id="2061351"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:shitposter.club,2017-05-05:noticeId=2827630:objectType=comment" href="https://shitposter.club/notice/2827630"></thr:in-reply-to>
- <link rel="related" href="https://shitposter.club/notice/2827630"/>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1056672"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/1056672" local_id="1056672" ref="https://shitposter.club/conversation/1385528">https://shitposter.club/conversation/1385528</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/2061410.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061410.atom"/>
- <statusnet:notice_info local_id="2061410" source="unknown"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-05-05:fave:23211:comment:2061339:2017-05-05T08:21:05+00:00</id>
- <title>Favorite</title>
- <content type="html">lambadalambda favorited something by hardbass2k8: @&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; pretty sure it's money laundering</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2061357"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2017-05-05T08:21:05+00:00</published>
- <updated>2017-05-05T08:21:05+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:shitposter.club,2017-05-05:noticeId=2827617:objectType=comment</id>
- <title>New comment by hardbass2k8</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; pretty sure it's money laundering</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2827617"/>
- <status_net notice_id="2061339"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:shitposter.club,2017-05-05:noticeId=2827617:objectType=comment" href="https://shitposter.club/notice/2827617"></thr:in-reply-to>
- <link rel="related" href="https://shitposter.club/notice/2827617"/>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1059050"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/1059050" local_id="1059050" ref="https://shitposter.club/conversation/1387523">https://shitposter.club/conversation/1387523</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/2061357.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061357.atom"/>
- <statusnet:notice_info local_id="2061357" 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-05:noticeId=2061303:objectType=note</id>
- <title>New note by lambadalambda</title>
- <content type="html">It's got tattoos, it's got a pierced hood&lt;br /&gt; It's got generation X&lt;br /&gt; It's got lesbians, and vitriol&lt;br /&gt; And sadomasochistic latex sex&lt;br /&gt; It's got Mighty Morphin' power brokers&lt;br /&gt; And Tanya Harding nude&lt;br /&gt; Macrobiotic lacto-vegan non-confrontational free range food&lt;br /&gt; It's got the handshake, peace talk, non-aggression pact&lt;br /&gt; A multicultural integration of segregated historical facts&lt;br /&gt; &lt;br /&gt; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://social.heldscal.la/tag/nsfw&quot; rel=&quot;tag&quot;&gt;nsfw&lt;/a&gt;&lt;/span&gt; &lt;a href=&quot;https://social.heldscal.la/file/61c13b99c92f40ec4865e7a3830da340b187e3de70d94b8da38fd2138bbede3a.jpg&quot; title=&quot;https://social.heldscal.la/file/61c13b99c92f40ec4865e7a3830da340b187e3de70d94b8da38fd2138bbede3a.jpg&quot; rel=&quot;nofollow external noreferrer&quot; class=&quot;attachment&quot; id=&quot;attachment-432199&quot;&gt;https://social.heldscal.la/attachment/432199&lt;/a&gt; &lt;a href=&quot;https://social.heldscal.la/file/a88bba1a324da68ee2cfdbcd1c4cde60bd9553298244d6f81731270b71aa80df.jpg&quot; title=&quot;https://social.heldscal.la/file/a88bba1a324da68ee2cfdbcd1c4cde60bd9553298244d6f81731270b71aa80df.jpg&quot; rel=&quot;nofollow external noreferrer&quot; class=&quot;attachment&quot; id=&quot;attachment-432200&quot;&gt;https://social.heldscal.la/attachment/432200&lt;/a&gt; &lt;a href=&quot;https://social.heldscal.la/file/887329a303250e73dc2eea06b1f0512fcac4b9d1b534068f03c45f00d5b21c39.jpg&quot; title=&quot;https://social.heldscal.la/file/887329a303250e73dc2eea06b1f0512fcac4b9d1b534068f03c45f00d5b21c39.jpg&quot; rel=&quot;nofollow external noreferrer&quot; class=&quot;attachment&quot; id=&quot;attachment-432201&quot;&gt;https://social.heldscal.la/attachment/432201&lt;/a&gt; &lt;a href=&quot;https://social.heldscal.la/file/6d7a1ec15c1368c4c68810434d24da528606fcbccdd1da97b25affafeeb6ffda.jpg&quot; title=&quot;https://social.heldscal.la/file/6d7a1ec15c1368c4c68810434d24da528606fcbccdd1da97b25affafeeb6ffda.jpg&quot; rel=&quot;nofollow external noreferrer&quot; class=&quot;attachment&quot; id=&quot;attachment-432202&quot;&gt;https://social.heldscal.la/attachment/432202&lt;/a&gt; &lt;a href=&quot;https://social.heldscal.la/file/2f55f2bb028eb9be744cc82b35a6b86b496d8c3924c700aff55a872ff11df54c.jpg&quot; title=&quot;https://social.heldscal.la/file/2f55f2bb028eb9be744cc82b35a6b86b496d8c3924c700aff55a872ff11df54c.jpg&quot; rel=&quot;nofollow external noreferrer&quot; class=&quot;attachment&quot; id=&quot;attachment-432203&quot;&gt;https://social.heldscal.la/attachment/432203&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2061303"/>
- <status_net notice_id="2061303"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-05-05T08:17:08+00:00</published>
- <updated>2017-05-05T08:17:08+00:00</updated>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1061817"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/1061817" local_id="1061817" ref="tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=bb6f4343036970e8">tag:social.heldscal.la,2017-05-05:objectType=thread:nonce=bb6f4343036970e8</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
- <category term="nsfw"></category>
- <link rel="enclosure" href="https://social.heldscal.la/file/61c13b99c92f40ec4865e7a3830da340b187e3de70d94b8da38fd2138bbede3a.jpg" type="image/jpeg" length="239712"/>
- <link rel="enclosure" href="https://social.heldscal.la/file/a88bba1a324da68ee2cfdbcd1c4cde60bd9553298244d6f81731270b71aa80df.jpg" type="image/jpeg" length="185200"/>
- <link rel="enclosure" href="https://social.heldscal.la/file/887329a303250e73dc2eea06b1f0512fcac4b9d1b534068f03c45f00d5b21c39.jpg" type="image/jpeg" length="292061"/>
- <link rel="enclosure" href="https://social.heldscal.la/file/6d7a1ec15c1368c4c68810434d24da528606fcbccdd1da97b25affafeeb6ffda.jpg" type="image/jpeg" length="147280"/>
- <link rel="enclosure" href="https://social.heldscal.la/file/2f55f2bb028eb9be744cc82b35a6b86b496d8c3924c700aff55a872ff11df54c.jpg" type="image/jpeg" length="164659"/>
- <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061303.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2061303.atom"/>
- <statusnet:notice_info local_id="2061303" source="Pleroma FE"></statusnet:notice_info>
-</entry>
-</feed>
diff --git a/test/fixtures/tesla_mock/https___social.heldscal.la_api_statuses_user_timeline_29191.atom.xml b/test/fixtures/tesla_mock/https___social.heldscal.la_api_statuses_user_timeline_29191.atom.xml
deleted file mode 100644
index f70fbc695..000000000
--- a/test/fixtures/tesla_mock/https___social.heldscal.la_api_statuses_user_timeline_29191.atom.xml
+++ /dev/null
@@ -1,719 +0,0 @@
-<?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/29191.atom</id>
- <title>shp timeline</title>
- <subtitle>Updates from shp on social.heldscal.la!</subtitle>
- <logo>https://social.heldscal.la/avatar/29191-96-20170421154949.jpeg</logo>
- <updated>2017-05-05T11:57:06+00:00</updated>
-<author>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <uri>https://social.heldscal.la/user/29191</uri>
- <name>shp</name>
- <summary>cofe</summary>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/shp"/>
- <link rel="avatar" type="image/jpeg" media:width="735" media:height="735" href="https://social.heldscal.la/avatar/29191-original-20170421154949.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/29191-96-20170421154949.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/29191-48-20170421154949.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/29191-24-20170421161149.jpeg"/>
- <poco:preferredUsername>shp</poco:preferredUsername>
- <poco:displayName>shp</poco:displayName>
- <poco:note>cofe</poco:note>
- <poco:address>
- <poco:formatted>cofe</poco:formatted>
- </poco:address>
- <followers url="https://social.heldscal.la/shp/subscribers"></followers>
- <statusnet:profile_info local_id="29191"></statusnet:profile_info>
-</author>
- <link href="https://social.heldscal.la/shp" 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/29191.atom?max_id=1907936" 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/29191" rel="salmon"/>
- <link href="https://social.heldscal.la/main/salmon/user/29191" rel="http://salmon-protocol.org/ns/salmon-replies"/>
- <link href="https://social.heldscal.la/main/salmon/user/29191" rel="http://salmon-protocol.org/ns/salmon-mention"/>
- <link href="https://social.heldscal.la/api/statuses/user_timeline/29191.atom" rel="self" type="application/atom+xml"/>
-<entry>
- <id>tag:social.heldscal.la,2017-04-29:noticeId=1967657:objectType=note</id>
- <title>shp repeated a notice by lain</title>
- <content type="html">RT @&lt;a href=&quot;https://social.heldscal.la/user/37181&quot; class=&quot;h-card u-url p-nickname mention&quot; title=&quot;Lain Iwakura&quot;&gt;lain&lt;/a&gt; @&lt;a href=&quot;https://social.heldscal.la/user/29191&quot; class=&quot;h-card u-url p-nickname mention&quot; title=&quot;shp&quot;&gt;shp&lt;/a&gt; @&lt;a href=&quot;https://social.heldscal.la/user/23211&quot; class=&quot;h-card u-url p-nickname mention&quot;&gt;lambadalambda&lt;/a&gt; cofe.</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1967657"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb>
- <published>2017-04-29T18:19:34+00:00</published>
- <updated>2017-04-29T18:19:34+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
- <id>https://pleroma.soykaf.com/activities/43d12c05-db3f-4f3d-bee1-d676f264490c</id>
- <title></title>
- <content type="html">&lt;a href=&quot;https://pleroma.soykaf.com/users/shp&quot;&gt;@shp&lt;/a&gt; &lt;a href=&quot;https://social.heldscal.la/user/23211&quot;&gt;@lambadalambda@social.heldscal.la&lt;/a&gt; cofe.</content>
- <link rel="alternate" type="text/html" href="https://pleroma.soykaf.com/activities/43d12c05-db3f-4f3d-bee1-d676f264490c"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-04-29T18:14:36+00:00</published>
- <updated>2017-04-29T18:14:36+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/activities/43d12c05-db3f-4f3d-bee1-d676f264490c</id>
- <title>New note by lain</title>
- <content type="html">&lt;a href=&quot;https://pleroma.soykaf.com/users/shp&quot;&gt;@shp&lt;/a&gt; &lt;a href=&quot;https://social.heldscal.la/user/23211&quot;&gt;@lambadalambda@social.heldscal.la&lt;/a&gt; cofe.</content>
- <link rel="alternate" type="text/html" href="https://pleroma.soykaf.com/activities/43d12c05-db3f-4f3d-bee1-d676f264490c"/>
- <status_net notice_id="1967581"></status_net>
- </activity:object>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1007769"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/1007769" local_id="1007769" ref="tag:social.heldscal.la,2017-04-29:objectType=thread:nonce=e0b75431888efdab">tag:social.heldscal.la,2017-04-29:objectType=thread:nonce=e0b75431888efdab</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-05T08:38:03+00:00</updated>
- </source>
- </activity:object>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1007769"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/1007769" local_id="1007769" ref="tag:social.heldscal.la,2017-04-29:objectType=thread:nonce=e0b75431888efdab">tag:social.heldscal.la,2017-04-29:objectType=thread:nonce=e0b75431888efdab</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/1967657.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1967657.atom"/>
- <statusnet:notice_info local_id="1967657" source="Qvitter" repeat_of="1967581"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-04-27:subscription:29191:person:29558:2017-04-27T17:26:37+00:00</id>
- <title>shp (shp@social.heldscal.la)'s status on Thursday, 27-Apr-2017 17:26:37 UTC</title>
- <content type="html">&lt;a href=&quot;https://social.heldscal.la/shp&quot;&gt;shp&lt;/a&gt; started following &lt;a href=&quot;https://gs.smuglo.li/kfist&quot;&gt;KFist&lt;/a&gt;.</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1933101"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>
- <published>2017-04-27T17:26:37+00:00</published>
- <updated>2017-04-27T17:26:37+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <id>https://gs.smuglo.li/user/28051</id>
- <title>KFist</title>
- <summary>I stream thanks to @nepfag. I also drink, shitpost, and fly planes. I visited Japan and it changed my life. Do you love your station?</summary>
- <link rel="alternate" type="text/html" href="https://gs.smuglo.li/kfist"/>
- <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/29558-original-20170302030034.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/29558-original-20170302030034.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/29558-48-20170303232734.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/29558-24-20170304004149.jpeg"/>
- <poco:preferredUsername>kfist</poco:preferredUsername>
- <poco:displayName>KFist</poco:displayName>
- <poco:note>I stream thanks to @nepfag. I also drink, shitpost, and fly planes. I visited Japan and it changed my life. Do you love your station?</poco:note>
- <poco:urls>
- <poco:type>homepage</poco:type>
- <poco:value>http://smuglo.li:8000/stream.m3u</poco:value>
- <poco:primary>true</poco:primary>
- </poco:urls>
- </activity:object>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988472"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/988472" local_id="988472" ref="tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=f766240d13ed9c2e">tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=f766240d13ed9c2e</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/1933101.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1933101.atom"/>
- <statusnet:notice_info local_id="1933101" source="activity"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-04-27:noticeId=1933030:objectType=note</id>
- <title>shp repeated a notice by shpbot</title>
- <content type="html">RT @&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; &amp;gt;QuakeC</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1933030"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb>
- <published>2017-04-27T17:21:10+00:00</published>
- <updated>2017-04-27T17:21:10+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
- <id>tag:gs.archae.me,2017-04-27:noticeId=760881:objectType=note</id>
- <title></title>
- <content type="html">&lt;span class='greentext'&gt;&amp;gt;QuakeC&lt;/span&gt;</content>
- <link rel="alternate" type="text/html" href="https://gs.archae.me/notice/760881"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-04-27T17:15:13+00:00</published>
- <updated>2017-04-27T17:15:13+00:00</updated>
- <author>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <uri>https://gs.archae.me/user/4687</uri>
- <name>shpbot</name>
- <link rel="alternate" type="text/html" href="https://gs.archae.me/shpbot"/>
- <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/31581-original-20170405170019.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/31581-original-20170405170019.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/31581-48-20170405170027.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/31581-24-20170405170342.jpeg"/>
- <poco:preferredUsername>shpbot</poco:preferredUsername>
- <poco:displayName>shpbot</poco:displayName>
- <statusnet:profile_info local_id="31581"></statusnet:profile_info>
- </author>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:gs.archae.me,2017-04-27:noticeId=760881:objectType=note</id>
- <title>New note by shpbot</title>
- <content type="html">&lt;span class='greentext'&gt;&amp;gt;QuakeC&lt;/span&gt;</content>
- <link rel="alternate" type="text/html" href="https://gs.archae.me/notice/760881"/>
- <status_net notice_id="1932941"></status_net>
- </activity:object>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988397"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/988397" local_id="988397" ref="https://gs.archae.me/conversation/318362">https://gs.archae.me/conversation/318362</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
- <source>
- <id>https://gs.archae.me/api/statuses/user_timeline/4687.atom</id>
- <title>shpbot</title>
- <link rel="alternate" type="text/html" href="https://gs.archae.me/shpbot"/>
- <link rel="self" type="application/atom+xml" href="https://gs.archae.me/api/statuses/user_timeline/4687.atom"/>
- <icon>https://social.heldscal.la/avatar/31581-original-20170405170019.jpeg</icon>
- <updated>2017-05-05T11:45:08+00:00</updated>
- </source>
- </activity:object>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988397"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/988397" local_id="988397" ref="https://gs.archae.me/conversation/318362">https://gs.archae.me/conversation/318362</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/1933030.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1933030.atom"/>
- <statusnet:notice_info local_id="1933030" source="Qvitter" repeat_of="1932941"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-04-27:subscription:29191:person:23226:2017-04-27T17:20:48+00:00</id>
- <title>shp (shp@social.heldscal.la)'s status on Thursday, 27-Apr-2017 17:20:48 UTC</title>
- <content type="html">&lt;a href=&quot;https://social.heldscal.la/shp&quot;&gt;shp&lt;/a&gt; started following &lt;a href=&quot;http://quitter.se/taknamay&quot;&gt;Internet Turtle Ⓐ 🏴 ✅&lt;/a&gt;.</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1933025"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>
- <published>2017-04-27T17:20:48+00:00</published>
- <updated>2017-04-27T17:20:48+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <id>http://quitter.se/user/115823</id>
- <title>Internet Turtle Ⓐ 🏴 ✅</title>
- <summary>Scheme programmer, Novice esperantist, Spiritual naturalist - Will listen to your problems for free - XMPP: DarkDungeons94 at chatme.im</summary>
- <link rel="alternate" type="text/html" href="http://quitter.se/taknamay"/>
- <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/23226-original-20170427130915.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/23226-original-20170427130915.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/23226-48-20170427130918.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/23226-24-20170427171808.jpeg"/>
- <poco:preferredUsername>taknamay</poco:preferredUsername>
- <poco:displayName>Internet Turtle Ⓐ 🏴 ✅</poco:displayName>
- <poco:note>Scheme programmer, Novice esperantist, Spiritual naturalist - Will listen to your problems for free - XMPP: DarkDungeons94 at chatme.im</poco:note>
- <poco:address>
- <poco:formatted>New Jersey, United States</poco:formatted>
- </poco:address>
- <poco:urls>
- <poco:type>homepage</poco:type>
- <poco:value>https://quitter.se/taknamay</poco:value>
- <poco:primary>true</poco:primary>
- </poco:urls>
- </activity:object>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988439"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/988439" local_id="988439" ref="tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=a66b1fb22020c152">tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=a66b1fb22020c152</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/1933025.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1933025.atom"/>
- <statusnet:notice_info local_id="1933025" source="activity"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-04-27:subscription:29191:person:29302:2017-04-27T17:20:33+00:00</id>
- <title>shp (shp@social.heldscal.la)'s status on Thursday, 27-Apr-2017 17:20:33 UTC</title>
- <content type="html">&lt;a href=&quot;https://social.heldscal.la/shp&quot;&gt;shp&lt;/a&gt; started following &lt;a href=&quot;https://icosahedron.website/@Trev&quot;&gt;Chillidan Stormrave&lt;/a&gt;.</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1933022"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>
- <published>2017-04-27T17:20:33+00:00</published>
- <updated>2017-04-27T17:20:33+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <id>https://icosahedron.website/users/Trev</id>
- <title>Trev Prime</title>
- <summary>web tech, music, ethics. radical individualist. kinda queer. love thy neighbor. always open for conversation. </summary>
- <link rel="alternate" type="text/html" href="https://icosahedron.website/@Trev"/>
- <link rel="avatar" type="image/png" media:width="120" media:height="120" href="https://social.heldscal.la/avatar/29302-original-20170417171941.png"/>
- <link rel="avatar" type="image/png" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/29302-96-20170417171942.png"/>
- <link rel="avatar" type="image/png" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/29302-48-20170417171942.png"/>
- <link rel="avatar" type="image/png" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/29302-24-20170417180438.png"/>
- <poco:preferredUsername>trev</poco:preferredUsername>
- <poco:displayName>Trev Prime</poco:displayName>
- <poco:note>web tech, music, ethics. radical individualist. kinda queer. love thy neighbor. always open for conversation. </poco:note>
- </activity:object>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988436"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/988436" local_id="988436" ref="tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=781c05bd64ad9520">tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=781c05bd64ad9520</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/1933022.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1933022.atom"/>
- <statusnet:notice_info local_id="1933022" source="activity"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-04-27:subscription:29191:person:29367:2017-04-27T17:20:27+00:00</id>
- <title>shp (shp@social.heldscal.la)'s status on Thursday, 27-Apr-2017 17:20:27 UTC</title>
- <content type="html">&lt;a href=&quot;https://social.heldscal.la/shp&quot;&gt;shp&lt;/a&gt; started following &lt;a href=&quot;https://gs.kawa-kun.com/aya&quot;&gt;射命丸 文&lt;/a&gt;.</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1933020"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>
- <published>2017-04-27T17:20:27+00:00</published>
- <updated>2017-04-27T17:20:27+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <id>https://gs.kawa-kun.com/user/4885</id>
- <title>射命丸 文</title>
- <summary>Traditional Reporter of Fantasy</summary>
- <link rel="alternate" type="text/html" href="https://gs.kawa-kun.com/aya"/>
- <link rel="avatar" type="image/png" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/29367-original-20170322091904.png"/>
- <link rel="avatar" type="image/png" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/29367-original-20170322091904.png"/>
- <link rel="avatar" type="image/png" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/29367-48-20170322103327.png"/>
- <link rel="avatar" type="image/png" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/29367-24-20170322185131.png"/>
- <poco:preferredUsername>aya</poco:preferredUsername>
- <poco:displayName>射命丸 文</poco:displayName>
- <poco:note>Traditional Reporter of Fantasy</poco:note>
- <poco:address>
- <poco:formatted>Gensōkyō</poco:formatted>
- </poco:address>
- <poco:urls>
- <poco:type>homepage</poco:type>
- <poco:value>https://danbooru.donmai.us</poco:value>
- <poco:primary>true</poco:primary>
- </poco:urls>
- </activity:object>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988435"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/988435" local_id="988435" ref="tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=5921da7a934e47ca">tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=5921da7a934e47ca</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/1933020.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1933020.atom"/>
- <statusnet:notice_info local_id="1933020" source="activity"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-04-27:subscription:29191:person:27773:2017-04-27T17:20:18+00:00</id>
- <title>shp (shp@social.heldscal.la)'s status on Thursday, 27-Apr-2017 17:20:18 UTC</title>
- <content type="html">&lt;a href=&quot;https://social.heldscal.la/shp&quot;&gt;shp&lt;/a&gt; started following &lt;a href=&quot;https://gs.smuglo.li/japananon&quot;&gt;JapanAnon&lt;/a&gt;.</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1933017"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>
- <published>2017-04-27T17:20:18+00:00</published>
- <updated>2017-04-27T17:20:18+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <id>https://gs.smuglo.li/user/27299</id>
- <title>JapanAnon</title>
- <summary>匿名でしていてね!</summary>
- <link rel="alternate" type="text/html" href="https://gs.smuglo.li/japananon"/>
- <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/27773-original-20170102074719.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/27773-original-20170102074719.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/27773-48-20170103173058.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/27773-24-20170103173058.jpeg"/>
- <poco:preferredUsername>japananon</poco:preferredUsername>
- <poco:displayName>JapanAnon</poco:displayName>
- <poco:note>匿名でしていてね!</poco:note>
- <poco:address>
- <poco:formatted>ワイヤード</poco:formatted>
- </poco:address>
- <poco:urls>
- <poco:type>homepage</poco:type>
- <poco:value>http://www.anonymous-japan.org</poco:value>
- <poco:primary>true</poco:primary>
- </poco:urls>
- </activity:object>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988434"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/988434" local_id="988434" ref="tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=ae3d819865886cba">tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=ae3d819865886cba</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/1933017.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1933017.atom"/>
- <statusnet:notice_info local_id="1933017" source="activity"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-04-27:subscription:29191:person:36560:2017-04-27T17:19:30+00:00</id>
- <title>shp (shp@social.heldscal.la)'s status on Thursday, 27-Apr-2017 17:19:30 UTC</title>
- <content type="html">&lt;a href=&quot;https://social.heldscal.la/shp&quot;&gt;shp&lt;/a&gt; started following &lt;a href=&quot;https://shitposter.club/wareya&quot;&gt;wareya&lt;/a&gt;.</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1933001"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>
- <published>2017-04-27T17:19:30+00:00</published>
- <updated>2017-04-27T17:19:30+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <id>https://shitposter.club/user/15439</id>
- <title>wareya</title>
- <summary>Who are you to defy such a perfect being that is the machine? 日本語難しいけど頑張るぜ github.com/wareya wareya.moe Short: reya or war, never &quot;ware&quot;</summary>
- <link rel="alternate" type="text/html" href="https://shitposter.club/wareya"/>
- <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/36560-original-20170414073546.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/36560-original-20170414073546.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/36560-48-20170414075036.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/36560-24-20170427171930.jpeg"/>
- <poco:preferredUsername>wareya</poco:preferredUsername>
- <poco:displayName>wareya</poco:displayName>
- <poco:note>Who are you to defy such a perfect being that is the machine? 日本語難しいけど頑張るぜ github.com/wareya wareya.moe Short: reya or war, never &quot;ware&quot;</poco:note>
- </activity:object>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988426"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/988426" local_id="988426" ref="tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=bd88a3cd20b5a418">tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=bd88a3cd20b5a418</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/1933001.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1933001.atom"/>
- <statusnet:notice_info local_id="1933001" source="activity"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-04-27:subscription:29191:person:41176:2017-04-27T17:19:21+00:00</id>
- <title>shp (shp@social.heldscal.la)'s status on Thursday, 27-Apr-2017 17:19:21 UTC</title>
- <content type="html">&lt;a href=&quot;https://social.heldscal.la/shp&quot;&gt;shp&lt;/a&gt; started following &lt;a href=&quot;https://hakui.club/takeshitakenji&quot;&gt;竹下憲二 (白)&lt;/a&gt;.</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1932999"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb>
- <published>2017-04-27T17:19:21+00:00</published>
- <updated>2017-04-27T17:19:21+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <id>https://hakui.club/user/6</id>
- <title>竹下憲二 (白)</title>
- <summary>Oh boy.</summary>
- <link rel="alternate" type="text/html" href="https://hakui.club/takeshitakenji"/>
- <link rel="avatar" type="image/png" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/41176-original-20170428153916.png"/>
- <link rel="avatar" type="image/png" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/41176-original-20170428153916.png"/>
- <link rel="avatar" type="image/png" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/41176-48-20170428153926.png"/>
- <link rel="avatar" type="image/png" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/41176-24-20170428160801.png"/>
- <poco:preferredUsername>takeshitakenji</poco:preferredUsername>
- <poco:displayName>竹下憲二 (白)</poco:displayName>
- <poco:note>Oh boy.</poco:note>
- <poco:address>
- <poco:formatted>Seattle, WA</poco:formatted>
- </poco:address>
- <poco:urls>
- <poco:type>homepage</poco:type>
- <poco:value>http://gs.kawa-kun.com</poco:value>
- <poco:primary>true</poco:primary>
- </poco:urls>
- </activity:object>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988424"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/988424" local_id="988424" ref="tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=b139a673deba6963">tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=b139a673deba6963</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/1932999.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1932999.atom"/>
- <statusnet:notice_info local_id="1932999" source="activity"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-04-27:fave:29191:note:1932205:2017-04-27T17:17:46+00:00</id>
- <title>Favorite</title>
- <content type="html">shp favorited something by dolus: Looks like Merry is pussing out and caving to pressure. Sad. &lt;a href=&quot;https://gs.smuglo.li/file/23e37de3c321248d3f322d8ec042372914568ab4c9431a94e568a61b8146587f.png&quot; title=&quot;https://gs.smuglo.li/file/23e37de3c321248d3f322d8ec042372914568ab4c9431a94e568a61b8146587f.png&quot; rel=&quot;nofollow noreferrer&quot; class=&quot;attachment&quot;&gt;https://gs.smuglo.li/attachment/432294&lt;/a&gt; &lt;a href=&quot;https://gs.smuglo.li/file/e5a9549a19986d59d51750090910f47c186787adf02b2b6ac58df37556887297.png&quot; title=&quot;https://gs.smuglo.li/file/e5a9549a19986d59d51750090910f47c186787adf02b2b6ac58df37556887297.png&quot; rel=&quot;nofollow noreferrer&quot; class=&quot;attachment&quot;&gt;https://gs.smuglo.li/attachment/432295&lt;/a&gt; &lt;a href=&quot;https://gs.smuglo.li/file/2fdfabbc8ab0b8dc135903a8c48c29b440d1f97446b98ced4ad14a54d3b5d41f.png&quot; title=&quot;https://gs.smuglo.li/file/2fdfabbc8ab0b8dc135903a8c48c29b440d1f97446b98ced4ad14a54d3b5d41f.png&quot; rel=&quot;nofollow noreferrer&quot; class=&quot;attachment&quot;&gt;https://gs.smuglo.li/attachment/432296&lt;/a&gt; &lt;a href=&quot;https://gs.smuglo.li/file/af605d7c6fe3a8c26c6d334c2a8e0005f7e86a266f14a5b3755e7d3ac4e226de.png&quot; title=&quot;https://gs.smuglo.li/file/af605d7c6fe3a8c26c6d334c2a8e0005f7e86a266f14a5b3755e7d3ac4e226de.png&quot; rel=&quot;nofollow noreferrer&quot; class=&quot;attachment&quot;&gt;https://gs.smuglo.li/attachment/432297&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1932976"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2017-04-27T17:17:46+00:00</published>
- <updated>2017-04-27T17:17:46+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:gs.smuglo.li,2017-04-27:noticeId=2065465:objectType=note</id>
- <title>New note by dolus</title>
- <content type="html">Looks like Merry is pussing out and caving to pressure. Sad. &lt;a href=&quot;https://gs.smuglo.li/file/23e37de3c321248d3f322d8ec042372914568ab4c9431a94e568a61b8146587f.png&quot; title=&quot;https://gs.smuglo.li/file/23e37de3c321248d3f322d8ec042372914568ab4c9431a94e568a61b8146587f.png&quot; rel=&quot;nofollow noreferrer&quot; class=&quot;attachment&quot;&gt;https://gs.smuglo.li/attachment/432294&lt;/a&gt; &lt;a href=&quot;https://gs.smuglo.li/file/e5a9549a19986d59d51750090910f47c186787adf02b2b6ac58df37556887297.png&quot; title=&quot;https://gs.smuglo.li/file/e5a9549a19986d59d51750090910f47c186787adf02b2b6ac58df37556887297.png&quot; rel=&quot;nofollow noreferrer&quot; class=&quot;attachment&quot;&gt;https://gs.smuglo.li/attachment/432295&lt;/a&gt; &lt;a href=&quot;https://gs.smuglo.li/file/2fdfabbc8ab0b8dc135903a8c48c29b440d1f97446b98ced4ad14a54d3b5d41f.png&quot; title=&quot;https://gs.smuglo.li/file/2fdfabbc8ab0b8dc135903a8c48c29b440d1f97446b98ced4ad14a54d3b5d41f.png&quot; rel=&quot;nofollow noreferrer&quot; class=&quot;attachment&quot;&gt;https://gs.smuglo.li/attachment/432296&lt;/a&gt; &lt;a href=&quot;https://gs.smuglo.li/file/af605d7c6fe3a8c26c6d334c2a8e0005f7e86a266f14a5b3755e7d3ac4e226de.png&quot; title=&quot;https://gs.smuglo.li/file/af605d7c6fe3a8c26c6d334c2a8e0005f7e86a266f14a5b3755e7d3ac4e226de.png&quot; rel=&quot;nofollow noreferrer&quot; class=&quot;attachment&quot;&gt;https://gs.smuglo.li/attachment/432297&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://gs.smuglo.li/notice/2065465"/>
- <status_net notice_id="1932205"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:gs.smuglo.li,2017-04-27:noticeId=2065465:objectType=note" href="https://gs.smuglo.li/notice/2065465"></thr:in-reply-to>
- <link rel="related" href="https://gs.smuglo.li/notice/2065465"/>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/987894"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/987894" local_id="987894" ref="https://gs.smuglo.li/conversation/927473">https://gs.smuglo.li/conversation/927473</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/1932976.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1932976.atom"/>
- <statusnet:notice_info local_id="1932976" source="unknown"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-04-27:fave:29191:note:1932492:2017-04-27T17:13:55+00:00</id>
- <title>Favorite</title>
- <content type="html">shp favorited something by zemichi: &lt;a href=&quot;https://gs.smuglo.li/file/1d45ea4ffc95f15037f361b56ad6b89f8451b70ad1ff7a03b7bb0345b8e2227c.jpg&quot; title=&quot;https://gs.smuglo.li/file/1d45ea4ffc95f15037f361b56ad6b89f8451b70ad1ff7a03b7bb0345b8e2227c.jpg&quot; rel=&quot;nofollow noreferrer&quot; class=&quot;attachment&quot;&gt;https://gs.smuglo.li/attachment/432344&lt;/a&gt;&lt;br /&gt; that's a lot of loli</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1932922"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2017-04-27T17:13:55+00:00</published>
- <updated>2017-04-27T17:13:55+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:gs.smuglo.li,2017-04-27:noticeId=2065713:objectType=note</id>
- <title>New note by zemichi</title>
- <content type="html">&lt;a href=&quot;https://gs.smuglo.li/file/1d45ea4ffc95f15037f361b56ad6b89f8451b70ad1ff7a03b7bb0345b8e2227c.jpg&quot; title=&quot;https://gs.smuglo.li/file/1d45ea4ffc95f15037f361b56ad6b89f8451b70ad1ff7a03b7bb0345b8e2227c.jpg&quot; rel=&quot;nofollow noreferrer&quot; class=&quot;attachment&quot;&gt;https://gs.smuglo.li/attachment/432344&lt;/a&gt;&lt;br /&gt; that's a lot of loli</content>
- <link rel="alternate" type="text/html" href="https://gs.smuglo.li/notice/2065713"/>
- <status_net notice_id="1932492"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:gs.smuglo.li,2017-04-27:noticeId=2065713:objectType=note" href="https://gs.smuglo.li/notice/2065713"></thr:in-reply-to>
- <link rel="related" href="https://gs.smuglo.li/notice/2065713"/>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988113"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/988113" local_id="988113" ref="https://gs.smuglo.li/conversation/927673">https://gs.smuglo.li/conversation/927673</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/1932922.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1932922.atom"/>
- <statusnet:notice_info local_id="1932922" source="unknown"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-04-27:fave:29191:note:1932559:2017-04-27T17:12:46+00:00</id>
- <title>Favorite</title>
- <content type="html">shp favorited something by gsimg: &lt;a href=&quot;https://gs.kawa-kun.com/file/3435c5cafda46f31cad5abb5837b3521b7b458198507073a496f4d10bad3633b.jpg&quot; title=&quot;https://gs.kawa-kun.com/file/3435c5cafda46f31cad5abb5837b3521b7b458198507073a496f4d10bad3633b.jpg&quot; rel=&quot;nofollow noreferrer&quot; class=&quot;attachment&quot;&gt;https://gs.kawa-kun.com/file/3435c5cafda46f31cad5abb5837b3521b7b458198507073a496f4d10bad3633b.jpg&lt;/a&gt; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://gs.kawa-kun.com/tag/nsfw&quot; rel=&quot;tag&quot;&gt;nsfw&lt;/a&gt;&lt;/span&gt;</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1932894"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2017-04-27T17:12:46+00:00</published>
- <updated>2017-04-27T17:12:46+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-04-27:noticeId=1608309:objectType=note</id>
- <title>New note by gsimg</title>
- <content type="html">&lt;a href=&quot;https://gs.kawa-kun.com/file/3435c5cafda46f31cad5abb5837b3521b7b458198507073a496f4d10bad3633b.jpg&quot; title=&quot;https://gs.kawa-kun.com/file/3435c5cafda46f31cad5abb5837b3521b7b458198507073a496f4d10bad3633b.jpg&quot; rel=&quot;nofollow noreferrer&quot; class=&quot;attachment&quot;&gt;https://gs.kawa-kun.com/file/3435c5cafda46f31cad5abb5837b3521b7b458198507073a496f4d10bad3633b.jpg&lt;/a&gt; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://gs.kawa-kun.com/tag/nsfw&quot; rel=&quot;tag&quot;&gt;nsfw&lt;/a&gt;&lt;/span&gt;</content>
- <link rel="alternate" type="text/html" href="https://gs.kawa-kun.com/notice/1608309"/>
- <status_net notice_id="1932559"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:gs.kawa-kun.com,2017-04-27:noticeId=1608309:objectType=note" href="https://gs.kawa-kun.com/notice/1608309"></thr:in-reply-to>
- <link rel="related" href="https://gs.kawa-kun.com/notice/1608309"/>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988157"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/988157" local_id="988157" ref="https://gs.kawa-kun.com/conversation/690817">https://gs.kawa-kun.com/conversation/690817</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/1932894.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1932894.atom"/>
- <statusnet:notice_info local_id="1932894" source="unknown"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-04-27:fave:29191:note:1932601:2017-04-27T17:12:28+00:00</id>
- <title>Favorite</title>
- <content type="html">shp favorited something by zemichi: &lt;a href=&quot;https://gs.smuglo.li/file/5d9114fafea7b9866c9d852bcfeaf66aade65ae26149758346bc5ade7e3fa8f0.jpg&quot; title=&quot;https://gs.smuglo.li/file/5d9114fafea7b9866c9d852bcfeaf66aade65ae26149758346bc5ade7e3fa8f0.jpg&quot; rel=&quot;nofollow noreferrer&quot; class=&quot;attachment&quot;&gt;https://gs.smuglo.li/attachment/432372&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1932888"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2017-04-27T17:12:28+00:00</published>
- <updated>2017-04-27T17:12:28+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:gs.smuglo.li,2017-04-27:noticeId=2065821:objectType=note</id>
- <title>New note by zemichi</title>
- <content type="html">&lt;a href=&quot;https://gs.smuglo.li/file/5d9114fafea7b9866c9d852bcfeaf66aade65ae26149758346bc5ade7e3fa8f0.jpg&quot; title=&quot;https://gs.smuglo.li/file/5d9114fafea7b9866c9d852bcfeaf66aade65ae26149758346bc5ade7e3fa8f0.jpg&quot; rel=&quot;nofollow noreferrer&quot; class=&quot;attachment&quot;&gt;https://gs.smuglo.li/attachment/432372&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://gs.smuglo.li/notice/2065821"/>
- <status_net notice_id="1932601"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:gs.smuglo.li,2017-04-27:noticeId=2065821:objectType=note" href="https://gs.smuglo.li/notice/2065821"></thr:in-reply-to>
- <link rel="related" href="https://gs.smuglo.li/notice/2065821"/>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988189"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/988189" local_id="988189" ref="https://gs.smuglo.li/conversation/927760">https://gs.smuglo.li/conversation/927760</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/1932888.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1932888.atom"/>
- <statusnet:notice_info local_id="1932888" source="unknown"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-04-27:noticeId=1932867:objectType=note</id>
- <title>shp repeated a notice by shpbot</title>
- <content type="html">RT @&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; &lt;a href=&quot;https://shitposter.club/file/cbf7fbbee1127a9870e871305ca7de70f1eb1bbb79ffe5b3b0f33e37514d14d8.jpg&quot; title=&quot;https://shitposter.club/file/cbf7fbbee1127a9870e871305ca7de70f1eb1bbb79ffe5b3b0f33e37514d14d8.jpg&quot; rel=&quot;nofollow external noreferrer&quot; class=&quot;attachment&quot; id=&quot;attachment-237676&quot;&gt;https://shitposter.club/file/cbf7fbbee1127a9870e871305ca7de70f1eb1bbb79ffe5b3b0f33e37514d14d8.jpg&lt;/a&gt; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://social.heldscal.la/tag/2hu&quot; rel=&quot;tag&quot;&gt;2hu&lt;/a&gt;&lt;/span&gt; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://social.heldscal.la/tag/ordinarymagician&quot; rel=&quot;tag&quot;&gt;ordinarymagician&lt;/a&gt;&lt;/span&gt; :thinking: &lt;a href=&quot;https://shitposter.club/file/abf3f82d9ce28d2293d858af26c75bb5d4fdd091c0d90ca7bc72ea7efba220e4.jpg&quot; title=&quot;https://shitposter.club/file/abf3f82d9ce28d2293d858af26c75bb5d4fdd091c0d90ca7bc72ea7efba220e4.jpg&quot; rel=&quot;nofollow external noreferrer&quot; class=&quot;attachment&quot; id=&quot;attachment-312306&quot;&gt;https://shitposter.club/file/abf3f82d9ce28d2293d858af26c75bb5d4fdd091c0d90ca7bc72ea7efba220e4.jpg&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1932867"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb>
- <published>2017-04-27T17:11:35+00:00</published>
- <updated>2017-04-27T17:11:35+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
- <id>tag:gs.archae.me,2017-04-27:noticeId=760830:objectType=note</id>
- <title></title>
- <content type="html">&lt;a href=&quot;https://shitposter.club/file/cbf7fbbee1127a9870e871305ca7de70f1eb1bbb79ffe5b3b0f33e37514d14d8.jpg&quot; title=&quot;https://shitposter.club/file/cbf7fbbee1127a9870e871305ca7de70f1eb1bbb79ffe5b3b0f33e37514d14d8.jpg&quot; rel=&quot;nofollow noreferrer&quot; class=&quot;attachment&quot;&gt;https://shitposter.club/file/cbf7fbbee1127a9870e871305ca7de70f1eb1bbb79ffe5b3b0f33e37514d14d8.jpg&lt;/a&gt; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://gs.archae.me/tag/2hu&quot; rel=&quot;tag&quot;&gt;2hu&lt;/a&gt;&lt;/span&gt; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://gs.archae.me/tag/ordinarymagician&quot; rel=&quot;tag&quot;&gt;ordinarymagician&lt;/a&gt;&lt;/span&gt; :thinking: &lt;a href=&quot;https://shitposter.club/file/abf3f82d9ce28d2293d858af26c75bb5d4fdd091c0d90ca7bc72ea7efba220e4.jpg&quot; title=&quot;https://shitposter.club/file/abf3f82d9ce28d2293d858af26c75bb5d4fdd091c0d90ca7bc72ea7efba220e4.jpg&quot; rel=&quot;nofollow noreferrer&quot; class=&quot;attachment&quot;&gt;https://shitposter.club/file/abf3f82d9ce28d2293d858af26c75bb5d4fdd091c0d90ca7bc72ea7efba220e4.jpg&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://gs.archae.me/notice/760830"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-04-27T17:00:08+00:00</published>
- <updated>2017-04-27T17:00:08+00:00</updated>
- <author>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <uri>https://gs.archae.me/user/4687</uri>
- <name>shpbot</name>
- <link rel="alternate" type="text/html" href="https://gs.archae.me/shpbot"/>
- <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/31581-original-20170405170019.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/31581-original-20170405170019.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/31581-48-20170405170027.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/31581-24-20170405170342.jpeg"/>
- <poco:preferredUsername>shpbot</poco:preferredUsername>
- <poco:displayName>shpbot</poco:displayName>
- <statusnet:profile_info local_id="31581"></statusnet:profile_info>
- </author>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:gs.archae.me,2017-04-27:noticeId=760830:objectType=note</id>
- <title>New note by shpbot</title>
- <content type="html">&lt;a href=&quot;https://shitposter.club/file/cbf7fbbee1127a9870e871305ca7de70f1eb1bbb79ffe5b3b0f33e37514d14d8.jpg&quot; title=&quot;https://shitposter.club/file/cbf7fbbee1127a9870e871305ca7de70f1eb1bbb79ffe5b3b0f33e37514d14d8.jpg&quot; rel=&quot;nofollow noreferrer&quot; class=&quot;attachment&quot;&gt;https://shitposter.club/file/cbf7fbbee1127a9870e871305ca7de70f1eb1bbb79ffe5b3b0f33e37514d14d8.jpg&lt;/a&gt; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://gs.archae.me/tag/2hu&quot; rel=&quot;tag&quot;&gt;2hu&lt;/a&gt;&lt;/span&gt; #&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://gs.archae.me/tag/ordinarymagician&quot; rel=&quot;tag&quot;&gt;ordinarymagician&lt;/a&gt;&lt;/span&gt; :thinking: &lt;a href=&quot;https://shitposter.club/file/abf3f82d9ce28d2293d858af26c75bb5d4fdd091c0d90ca7bc72ea7efba220e4.jpg&quot; title=&quot;https://shitposter.club/file/abf3f82d9ce28d2293d858af26c75bb5d4fdd091c0d90ca7bc72ea7efba220e4.jpg&quot; rel=&quot;nofollow noreferrer&quot; class=&quot;attachment&quot;&gt;https://shitposter.club/file/abf3f82d9ce28d2293d858af26c75bb5d4fdd091c0d90ca7bc72ea7efba220e4.jpg&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://gs.archae.me/notice/760830"/>
- <status_net notice_id="1932673"></status_net>
- </activity:object>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988229"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/988229" local_id="988229" ref="https://gs.archae.me/conversation/318317">https://gs.archae.me/conversation/318317</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
- <category term="2hu"></category>
- <category term="ordinarymagician"></category>
- <source>
- <id>https://gs.archae.me/api/statuses/user_timeline/4687.atom</id>
- <title>shpbot</title>
- <link rel="alternate" type="text/html" href="https://gs.archae.me/shpbot"/>
- <link rel="self" type="application/atom+xml" href="https://gs.archae.me/api/statuses/user_timeline/4687.atom"/>
- <icon>https://social.heldscal.la/avatar/31581-original-20170405170019.jpeg</icon>
- <updated>2017-05-05T11:45:08+00:00</updated>
- </source>
- </activity:object>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988229"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/988229" local_id="988229" ref="https://gs.archae.me/conversation/318317">https://gs.archae.me/conversation/318317</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/1932867.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1932867.atom"/>
- <statusnet:notice_info local_id="1932867" source="api" repeat_of="1932673"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:social.heldscal.la,2017-04-27:noticeId=1932815:objectType=note</id>
- <title>New note by shp</title>
- <content type="html">federation issues with SPC atm it seems</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1932815"/>
- <status_net notice_id="1932815"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-04-27T17:08:55+00:00</published>
- <updated>2017-04-27T17:08:55+00:00</updated>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/988321"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/988321" local_id="988321" ref="tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=645a13c841f51769">tag:social.heldscal.la,2017-04-27:objectType=thread:nonce=645a13c841f51769</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/1932815.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1932815.atom"/>
- <statusnet:notice_info local_id="1932815" source="Pleroma FE"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-04-26:fave:29191:note:1907285:2017-04-26T06:59:07+00:00</id>
- <title>Favorite</title>
- <content type="html">shp favorited something by lambadalambda: Is this the most offensive video on the net? &lt;a href=&quot;https://social.heldscal.la/file/4c34bfb81a8155c265031bc48f7e69c29eb0d2941c57daf63f80e17b0e2e5f47.webm&quot; title=&quot;https://social.heldscal.la/file/4c34bfb81a8155c265031bc48f7e69c29eb0d2941c57daf63f80e17b0e2e5f47.webm&quot; rel=&quot;nofollow noreferrer&quot; class=&quot;attachment&quot;&gt;https://social.heldscal.la/attachment/402251&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1907959"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2017-04-26T06:59:07+00:00</published>
- <updated>2017-04-26T06:59:07+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:social.heldscal.la,2017-04-26:noticeId=1907285:objectType=note</id>
- <title>New note by lambadalambda</title>
- <content type="html">Is this the most offensive video on the net? &lt;a href=&quot;https://social.heldscal.la/file/4c34bfb81a8155c265031bc48f7e69c29eb0d2941c57daf63f80e17b0e2e5f47.webm&quot; title=&quot;https://social.heldscal.la/file/4c34bfb81a8155c265031bc48f7e69c29eb0d2941c57daf63f80e17b0e2e5f47.webm&quot; rel=&quot;nofollow external noreferrer&quot; class=&quot;attachment&quot; id=&quot;attachment-402251&quot;&gt;https://social.heldscal.la/attachment/402251&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1907285"/>
- <status_net notice_id="1907285"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:social.heldscal.la,2017-04-26:noticeId=1907285:objectType=note" href="https://social.heldscal.la/notice/1907285"></thr:in-reply-to>
- <link rel="related" href="https://social.heldscal.la/notice/1907285"/>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/972605"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/972605" local_id="972605" ref="tag:social.heldscal.la,2017-04-26:objectType=thread:nonce=07b02e1328f456af">tag:social.heldscal.la,2017-04-26:objectType=thread:nonce=07b02e1328f456af</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/1907959.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1907959.atom"/>
- <statusnet:notice_info local_id="1907959" source="unknown"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-04-26:noticeId=1907951:objectType=note</id>
- <title>shp repeated a notice by shpbot</title>
- <content type="html">RT @&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; &lt;a href=&quot;https://shitposter.club/file/718db06b564841331c72f9df767f8c9459e20c4dddbf0d4e61cd08ecbee7739d.jpg&quot; title=&quot;https://shitposter.club/file/718db06b564841331c72f9df767f8c9459e20c4dddbf0d4e61cd08ecbee7739d.jpg&quot; rel=&quot;nofollow external noreferrer&quot; class=&quot;attachment&quot; id=&quot;attachment-346198&quot;&gt;https://shitposter.club/file/718db06b564841331c72f9df767f8c9459e20c4dddbf0d4e61cd08ecbee7739d.jpg&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1907951"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb>
- <published>2017-04-26T06:58:19+00:00</published>
- <updated>2017-04-26T06:58:19+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
- <id>tag:gs.archae.me,2017-04-26:noticeId=752596:objectType=note</id>
- <title></title>
- <content type="html">&lt;a href=&quot;https://shitposter.club/file/718db06b564841331c72f9df767f8c9459e20c4dddbf0d4e61cd08ecbee7739d.jpg&quot; title=&quot;https://shitposter.club/file/718db06b564841331c72f9df767f8c9459e20c4dddbf0d4e61cd08ecbee7739d.jpg&quot; rel=&quot;nofollow noreferrer&quot; class=&quot;attachment&quot;&gt;https://shitposter.club/file/718db06b564841331c72f9df767f8c9459e20c4dddbf0d4e61cd08ecbee7739d.jpg&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://gs.archae.me/notice/752596"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-04-26T06:15:07+00:00</published>
- <updated>2017-04-26T06:15:07+00:00</updated>
- <author>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <uri>https://gs.archae.me/user/4687</uri>
- <name>shpbot</name>
- <link rel="alternate" type="text/html" href="https://gs.archae.me/shpbot"/>
- <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/31581-original-20170405170019.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="https://social.heldscal.la/avatar/31581-original-20170405170019.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="https://social.heldscal.la/avatar/31581-48-20170405170027.jpeg"/>
- <link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="https://social.heldscal.la/avatar/31581-24-20170405170342.jpeg"/>
- <poco:preferredUsername>shpbot</poco:preferredUsername>
- <poco:displayName>shpbot</poco:displayName>
- <statusnet:profile_info local_id="31581"></statusnet:profile_info>
- </author>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:gs.archae.me,2017-04-26:noticeId=752596:objectType=note</id>
- <title>New note by shpbot</title>
- <content type="html">&lt;a href=&quot;https://shitposter.club/file/718db06b564841331c72f9df767f8c9459e20c4dddbf0d4e61cd08ecbee7739d.jpg&quot; title=&quot;https://shitposter.club/file/718db06b564841331c72f9df767f8c9459e20c4dddbf0d4e61cd08ecbee7739d.jpg&quot; rel=&quot;nofollow noreferrer&quot; class=&quot;attachment&quot;&gt;https://shitposter.club/file/718db06b564841331c72f9df767f8c9459e20c4dddbf0d4e61cd08ecbee7739d.jpg&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://gs.archae.me/notice/752596"/>
- <status_net notice_id="1907331"></status_net>
- </activity:object>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/972636"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/972636" local_id="972636" ref="https://gs.archae.me/conversation/314010">https://gs.archae.me/conversation/314010</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
- <source>
- <id>https://gs.archae.me/api/statuses/user_timeline/4687.atom</id>
- <title>shpbot</title>
- <link rel="alternate" type="text/html" href="https://gs.archae.me/shpbot"/>
- <link rel="self" type="application/atom+xml" href="https://gs.archae.me/api/statuses/user_timeline/4687.atom"/>
- <icon>https://social.heldscal.la/avatar/31581-original-20170405170019.jpeg</icon>
- <updated>2017-05-05T11:45:08+00:00</updated>
- </source>
- </activity:object>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/972636"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/972636" local_id="972636" ref="https://gs.archae.me/conversation/314010">https://gs.archae.me/conversation/314010</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/1907951.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1907951.atom"/>
- <statusnet:notice_info local_id="1907951" source="api" repeat_of="1907331"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-04-26:fave:29191:note:1907341:2017-04-26T06:58:16+00:00</id>
- <title>Favorite</title>
- <content type="html">shp favorited something by moonman: &lt;a href=&quot;https://shitposter.club/file/1377b0894e983599c11e739e406243cabed9f8af7961a2550ecaf97e32de8e60.jpg&quot; title=&quot;https://shitposter.club/file/1377b0894e983599c11e739e406243cabed9f8af7961a2550ecaf97e32de8e60.jpg&quot; class=&quot;attachment&quot; rel=&quot;nofollow&quot;&gt;https://shitposter.club/attachment/630989&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1907949"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2017-04-26T06:58:16+00:00</published>
- <updated>2017-04-26T06:58:16+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:shitposter.club,2017-04-26:noticeId=2681941:objectType=note</id>
- <title>New note by moonman</title>
- <content type="html">&lt;a href=&quot;https://shitposter.club/file/1377b0894e983599c11e739e406243cabed9f8af7961a2550ecaf97e32de8e60.jpg&quot; title=&quot;https://shitposter.club/file/1377b0894e983599c11e739e406243cabed9f8af7961a2550ecaf97e32de8e60.jpg&quot; class=&quot;attachment&quot; rel=&quot;nofollow&quot;&gt;https://shitposter.club/attachment/630989&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/2681941"/>
- <status_net notice_id="1907341"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:shitposter.club,2017-04-26:noticeId=2681941:objectType=note" href="https://shitposter.club/notice/2681941"></thr:in-reply-to>
- <link rel="related" href="https://shitposter.club/notice/2681941"/>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/972646"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/972646" local_id="972646" ref="https://shitposter.club/conversation/1300990">https://shitposter.club/conversation/1300990</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/1907949.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1907949.atom"/>
- <statusnet:notice_info local_id="1907949" source="unknown"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:social.heldscal.la,2017-04-26:fave:29191:comment:1907412:2017-04-26T06:57:56+00:00</id>
- <title>Favorite</title>
- <content type="html">shp favorited something by lambadalambda: @&lt;a href=&quot;https://gs.smuglo.li/user/2&quot; class=&quot;h-card u-url p-nickname mention&quot; title=&quot;nepfag&quot;&gt;nepfag&lt;/a&gt; &lt;a href=&quot;https://cherubini.casa/why-i-shut-down-wizards-town-and-left-mastodon-6d4e631346b3?source=linkShare-89c2f851e979-1493184822&amp;amp;gi=a6a47c5466a0&quot; title=&quot;https://cherubini.casa/why-i-shut-down-wizards-town-and-left-mastodon-6d4e631346b3?source=linkShare-89c2f851e979-1493184822&amp;amp;gi=a6a47c5466a0&quot; rel=&quot;nofollow noreferrer&quot; class=&quot;attachment&quot;&gt;https://social.heldscal.la/url/402273&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1907947"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2017-04-26T06:57:56+00:00</published>
- <updated>2017-04-26T06:57:56+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:social.heldscal.la,2017-04-26:noticeId=1907412:objectType=comment</id>
- <title>New comment by lambadalambda</title>
- <content type="html">@&lt;a href=&quot;https://gs.smuglo.li/user/2&quot; class=&quot;h-card u-url p-nickname mention&quot; title=&quot;nepfag&quot;&gt;nepfag&lt;/a&gt; &lt;a href=&quot;https://cherubini.casa/why-i-shut-down-wizards-town-and-left-mastodon-6d4e631346b3?source=linkShare-89c2f851e979-1493184822&amp;amp;gi=a6a47c5466a0&quot; title=&quot;https://cherubini.casa/why-i-shut-down-wizards-town-and-left-mastodon-6d4e631346b3?source=linkShare-89c2f851e979-1493184822&amp;amp;gi=a6a47c5466a0&quot; rel=&quot;nofollow external noreferrer&quot; class=&quot;attachment&quot; id=&quot;attachment-402273&quot;&gt;https://social.heldscal.la/url/402273&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1907412"/>
- <status_net notice_id="1907412"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:social.heldscal.la,2017-04-26:noticeId=1907412:objectType=comment" href="https://social.heldscal.la/notice/1907412"></thr:in-reply-to>
- <link rel="related" href="https://social.heldscal.la/notice/1907412"/>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/972634"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/972634" local_id="972634" ref="tag:social.heldscal.la,2017-04-26:objectType=thread:nonce=85c21eda7aaa7259">tag:social.heldscal.la,2017-04-26:objectType=thread:nonce=85c21eda7aaa7259</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/1907947.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1907947.atom"/>
- <statusnet:notice_info local_id="1907947" 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-04-26:noticeId=1907942:objectType=note</id>
- <title>New note by shp</title>
- <content type="html">#&lt;span class=&quot;tag&quot;&gt;&lt;a href=&quot;https://social.heldscal.la/tag/cofe&quot; rel=&quot;tag&quot;&gt;cofe&lt;/a&gt;&lt;/span&gt; time my friends &lt;a href=&quot;https://social.heldscal.la/file/ec254b45b3a86ff74bc08bc7e065cb681d77cf7d4cedc9cdcf59e16adf311da3.png&quot; title=&quot;https://social.heldscal.la/file/ec254b45b3a86ff74bc08bc7e065cb681d77cf7d4cedc9cdcf59e16adf311da3.png&quot; rel=&quot;nofollow external noreferrer&quot; class=&quot;attachment&quot; id=&quot;attachment-402381&quot;&gt;https://social.heldscal.la/attachment/402381&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/1907942"/>
- <status_net notice_id="1907942"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2017-04-26T06:57:18+00:00</published>
- <updated>2017-04-26T06:57:18+00:00</updated>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/973042"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/973042" local_id="973042" ref="tag:social.heldscal.la,2017-04-26:objectType=thread:nonce=9c9d9373bccfaf70">tag:social.heldscal.la,2017-04-26:objectType=thread:nonce=9c9d9373bccfaf70</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
- <category term="cofe"></category>
- <link rel="enclosure" href="https://social.heldscal.la/file/ec254b45b3a86ff74bc08bc7e065cb681d77cf7d4cedc9cdcf59e16adf311da3.png" type="image/png" length="3179103"/>
- <link rel="self" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1907942.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/1907942.atom"/>
- <statusnet:notice_info local_id="1907942" source="Pleroma FE"></statusnet:notice_info>
-</entry>
-</feed>
diff --git a/test/fixtures/tesla_mock/lemmy-page.json b/test/fixtures/tesla_mock/lemmy-page.json
new file mode 100644
index 000000000..f07097a0e
--- /dev/null
+++ b/test/fixtures/tesla_mock/lemmy-page.json
@@ -0,0 +1,17 @@
+{
+ "commentsEnabled": true,
+ "sensitive": false,
+ "stickied": false,
+ "attributedTo": "https://enterprise.lemmy.ml/u/nutomic",
+ "summary": "Hello Federation!",
+ "url": "https://enterprise.lemmy.ml/pictrs/image/US52d9DPvf.jpg",
+ "image": {
+ "type": "Image",
+ "url": "https://enterprise.lemmy.ml/pictrs/image/lwFAcXHUjS.jpg"
+ },
+ "published": "2020-09-14T15:03:11.909105+00:00",
+ "to": "https://enterprise.lemmy.ml/c/main",
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "id": "https://enterprise.lemmy.ml/post/3",
+ "type": "Page"
+}
diff --git a/test/fixtures/tesla_mock/lemmy-user.json b/test/fixtures/tesla_mock/lemmy-user.json
new file mode 100644
index 000000000..d0e9066ac
--- /dev/null
+++ b/test/fixtures/tesla_mock/lemmy-user.json
@@ -0,0 +1,27 @@
+{
+ "publicKey": {
+ "id": "https://enterprise.lemmy.ml/u/nutomic#main-key",
+ "owner": "https://enterprise.lemmy.ml/u/nutomic",
+ "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvfwAYPxp1gOk2HcCRoUd\nupoecvmnpzRc5Gu6/N3YQyOyRsrYuiYLNQq2cgM3kcU80ZeEetkwkYgXkRJOKu/b\nBWb7i1zt2tdr5k6lUdW8dfCyjht8ooFPQdov8J3QYHfgBHyUYxuCNfSujryxx2wu\nLQcdjRQa5NIWcomSO8OXmCF5/Yhg2XWCbtnlxEq6Y+AFddr1mAlTOy5pBr5d+xZz\njLw/U3CioNJ79yGi/sJhgp6IyJqtUSoN3b4BgRIEts2QVvn44W1rQy9wCbRYQrO1\nBcB9Wel4k3rJJK8uHg+LpHVMaZppkNaWGkMBhMbzr8qmIlcNWNi7cbMK/p5vyviy\nSwIDAQAB\n-----END PUBLIC KEY-----\n"
+ },
+ "inbox": "https://enterprise.lemmy.ml/u/nutomic/inbox",
+ "preferredUsername": "Nutomic",
+ "endpoints": {
+ "sharedInbox": "https://enterprise.lemmy.ml/inbox"
+ },
+ "summary": "some bio",
+ "icon": {
+ "type": "Image",
+ "url": "https://enterprise.lemmy.ml/pictrs/image/F6Z7QcWZRJ.jpg"
+ },
+ "image": {
+ "type": "Image",
+ "url": "https://enterprise.lemmy.ml:/pictrs/image/Q79N9oCDEG.png"
+ },
+ "published": "2020-09-14T14:54:53.080949+00:00",
+ "updated": "2020-10-14T10:58:28.139178+00:00",
+ "@context": "https://www.w3.org/ns/activitystreams",
+ "id": "https://enterprise.lemmy.ml/u/nutomic",
+ "type": "Person",
+ "name": "nutomic"
+}
diff --git a/test/fixtures/tesla_mock/sakamoto.atom b/test/fixtures/tesla_mock/sakamoto.atom
deleted file mode 100644
index 648946795..000000000
--- a/test/fixtures/tesla_mock/sakamoto.atom
+++ /dev/null
@@ -1 +0,0 @@
-<?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:ostatus="http://ostatus.org/schema/1.0"><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>https://social.sakamoto.gq/objects/0ccc1a2c-66b0-4305-b23a-7f7f2b040056</id><title>New note by eal</title><content type="html">&lt;a href='https://shitposter.club/user/5381'&gt;@shpuld&lt;/a&gt; &lt;a href='https://pleroma.hjkos.com/users/hj'&gt;@hj&lt;/a&gt; IM NOT GAY DAD</content><published>2017-08-04T12:51:26.130592Z</published><updated>2017-08-04T12:51:26.130592Z</updated><ostatus:conversation>https://pleroma.hjkos.com/contexts/53093c74-2100-4bf4-aac6-66d1973d03ef</ostatus:conversation><link ref="https://pleroma.hjkos.com/contexts/53093c74-2100-4bf4-aac6-66d1973d03ef" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://social.sakamoto.gq/objects/0ccc1a2c-66b0-4305-b23a-7f7f2b040056" rel="self"/><link type="text/html" href="https://social.sakamoto.gq/objects/0ccc1a2c-66b0-4305-b23a-7f7f2b040056" rel="alternate"/><thr:in-reply-to ref="tag:shitposter.club,2017-08-04:noticeId=4027863:objectType=comment" href="https://shitposter.club/notice/4027863"/><author><id>https://social.sakamoto.gq/users/eal</id><activity:object>http://activitystrea.ms/schema/1.0/person</activity:object><uri>https://social.sakamoto.gq/users/eal</uri><poco:preferredUsername>eal</poco:preferredUsername><poco:displayName>坂本</poco:displayName><poco:note>(・ヮ・)</poco:note><name>eal</name><link rel="avatar" href="https://social.sakamoto.gq/media/7646c027-3614-4ee1-93f9-eea8f244a0d7/1A2EFE3153B9C9C3826DB511D043A26597C9F7178C8A4899FBBF808972D1659F.png"/></author><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://shitposter.club/user/5381"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.hjkos.com/users/hj"/></entry> \ No newline at end of file
diff --git a/test/fixtures/tesla_mock/sakamoto_eal_feed.atom b/test/fixtures/tesla_mock/sakamoto_eal_feed.atom
deleted file mode 100644
index 9340d9038..000000000
--- a/test/fixtures/tesla_mock/sakamoto_eal_feed.atom
+++ /dev/null
@@ -1 +0,0 @@
-<?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:ostatus="http://ostatus.org/schema/1.0"><id>https://social.sakamoto.gq/users/eal/feed.atom</id><title>eal's timeline</title><updated>2017-08-04T14:19:12.683854</updated><link rel="hub" href="https://social.sakamoto.gq/push/hub/eal"/><link rel="salmon" href="https://social.sakamoto.gq/users/eal/salmon"/><link rel="self" href="https://social.sakamoto.gq/users/eal/feed.atom" type="application/atom+xml"/><author><id>https://social.sakamoto.gq/users/eal</id><activity:object>http://activitystrea.ms/schema/1.0/person</activity:object><uri>https://social.sakamoto.gq/users/eal</uri><poco:preferredUsername>eal</poco:preferredUsername><poco:displayName>坂本</poco:displayName><poco:note>(・ヮ・)</poco:note><name>eal</name><link rel="avatar" href="https://social.sakamoto.gq/media/7646c027-3614-4ee1-93f9-eea8f244a0d7/1A2EFE3153B9C9C3826DB511D043A26597C9F7178C8A4899FBBF808972D1659F.png"/></author><entry><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>https://social.sakamoto.gq/objects/b79a1721-23f3-45a5-9610-adb08c2afae5</id><title>New note by eal</title><content type="html">Honestly, I like all smileys that are not emoji.</content><published>2017-08-04T14:19:12.675999Z</published><updated>2017-08-04T14:19:12.675999Z</updated><ostatus:conversation>https://social.sakamoto.gq/contexts/e05ede92-8db9-4963-8b8e-e71a5797d68f</ostatus:conversation><link ref="https://social.sakamoto.gq/contexts/e05ede92-8db9-4963-8b8e-e71a5797d68f" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://social.sakamoto.gq/objects/b79a1721-23f3-45a5-9610-adb08c2afae5" rel="self"/><link type="text/html" href="https://social.sakamoto.gq/objects/b79a1721-23f3-45a5-9610-adb08c2afae5" rel="alternate"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><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>https://social.sakamoto.gq/objects/45475bf3-2dfc-4d9e-8eae-1f4f86f48982</id><title>New note by eal</title><content type="html">Then again, I like all smileys/emoticons that are not emoji.&lt;br&gt;</content><published>2017-08-04T14:19:10.113373Z</published><updated>2017-08-04T14:19:10.113373Z</updated><ostatus:conversation>https://social.sakamoto.gq/contexts/852d1605-4dcb-4ba7-9ba4-dfc37ed62fbc</ostatus:conversation><link ref="https://social.sakamoto.gq/contexts/852d1605-4dcb-4ba7-9ba4-dfc37ed62fbc" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://social.sakamoto.gq/objects/45475bf3-2dfc-4d9e-8eae-1f4f86f48982" rel="self"/><link type="text/html" href="https://social.sakamoto.gq/objects/45475bf3-2dfc-4d9e-8eae-1f4f86f48982" rel="alternate"/><thr:in-reply-to ref="https://social.sakamoto.gq/objects/8f8fd6d6-cc63-40c6-a5d0-1c0e4f919368" href="https://social.sakamoto.gq/objects/8f8fd6d6-cc63-40c6-a5d0-1c0e4f919368"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.sakamoto.gq/users/eal"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><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>https://social.sakamoto.gq/objects/8f8fd6d6-cc63-40c6-a5d0-1c0e4f919368</id><title>New note by eal</title><content type="html">I love the russian-style smiley.</content><published>2017-08-04T14:18:30.478552Z</published><updated>2017-08-04T14:18:30.478552Z</updated><ostatus:conversation>https://social.sakamoto.gq/contexts/852d1605-4dcb-4ba7-9ba4-dfc37ed62fbc</ostatus:conversation><link ref="https://social.sakamoto.gq/contexts/852d1605-4dcb-4ba7-9ba4-dfc37ed62fbc" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://social.sakamoto.gq/objects/8f8fd6d6-cc63-40c6-a5d0-1c0e4f919368" rel="self"/><link type="text/html" href="https://social.sakamoto.gq/objects/8f8fd6d6-cc63-40c6-a5d0-1c0e4f919368" rel="alternate"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb><id>https://social.sakamoto.gq/activities/6e69df95-f2ad-4b8e-af4a-e93ff93d64e1</id><title>eal started following https://cybre.space/users/0x3F</title><content type="html">eal started following https://cybre.space/users/0x3F</content><published>2017-08-04T14:17:24.942193Z</published><updated>2017-08-04T14:17:24.942193Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type><id>https://cybre.space/users/0x3F</id><uri>https://cybre.space/users/0x3F</uri></activity:object><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/6e69df95-f2ad-4b8e-af4a-e93ff93d64e1"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://cybre.space/users/0x3F"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb><id>https://social.sakamoto.gq/activities/54c5e260-0185-4267-a2a6-f5dd9c76c2c9</id><title>eal started following https://niu.moe/users/rye</title><content type="html">eal started following https://niu.moe/users/rye</content><published>2017-08-04T14:16:35.604739Z</published><updated>2017-08-04T14:16:35.604739Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type><id>https://niu.moe/users/rye</id><uri>https://niu.moe/users/rye</uri></activity:object><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/54c5e260-0185-4267-a2a6-f5dd9c76c2c9"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://niu.moe/users/rye"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb><id>https://social.sakamoto.gq/activities/092ca863-19a8-416c-85d7-d3f23b3c0203</id><title>eal started following https://mastodon.xyz/users/rafudesu</title><content type="html">eal started following https://mastodon.xyz/users/rafudesu</content><published>2017-08-04T14:16:10.993429Z</published><updated>2017-08-04T14:16:10.993429Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type><id>https://mastodon.xyz/users/rafudesu</id><uri>https://mastodon.xyz/users/rafudesu</uri></activity:object><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/092ca863-19a8-416c-85d7-d3f23b3c0203"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.xyz/users/rafudesu"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb><id>https://social.sakamoto.gq/activities/be5cf702-b127-423b-a6be-5f78f01a4289</id><title>eal started following https://gs.kawa-kun.com/user/2</title><content type="html">eal started following https://gs.kawa-kun.com/user/2</content><published>2017-08-04T14:15:41.804611Z</published><updated>2017-08-04T14:15:41.804611Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type><id>https://gs.kawa-kun.com/user/2</id><uri>https://gs.kawa-kun.com/user/2</uri></activity:object><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/be5cf702-b127-423b-a6be-5f78f01a4289"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.kawa-kun.com/user/2"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb><id>https://social.sakamoto.gq/activities/4951e2a1-9bae-4e87-8e98-e6d2f8a52338</id><title>eal started following https://gs.kawa-kun.com/user/4885</title><content type="html">eal started following https://gs.kawa-kun.com/user/4885</content><published>2017-08-04T14:15:00.135352Z</published><updated>2017-08-04T14:15:00.135352Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type><id>https://gs.kawa-kun.com/user/4885</id><uri>https://gs.kawa-kun.com/user/4885</uri></activity:object><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/4951e2a1-9bae-4e87-8e98-e6d2f8a52338"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.kawa-kun.com/user/4885"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb><id>https://social.sakamoto.gq/activities/cadf8745-b9ee-4f6c-af32-bfddb70e4607</id><title>eal started following https://mastodon.social/users/Murassa</title><content type="html">eal started following https://mastodon.social/users/Murassa</content><published>2017-08-04T14:14:36.339560Z</published><updated>2017-08-04T14:14:36.339560Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type><id>https://mastodon.social/users/Murassa</id><uri>https://mastodon.social/users/Murassa</uri></activity:object><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/cadf8745-b9ee-4f6c-af32-bfddb70e4607"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/Murassa"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb><id>https://social.sakamoto.gq/activities/a52c9aab-f0e6-4ccb-8dd3-9f417e72a41c</id><title>eal started following https://mastodon.social/users/rysiek</title><content type="html">eal started following https://mastodon.social/users/rysiek</content><published>2017-08-04T14:13:04.061572Z</published><updated>2017-08-04T14:13:04.061572Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type><id>https://mastodon.social/users/rysiek</id><uri>https://mastodon.social/users/rysiek</uri></activity:object><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/a52c9aab-f0e6-4ccb-8dd3-9f417e72a41c"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/rysiek"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb><id>https://social.sakamoto.gq/activities/738bc887-4cca-4b36-8c86-2b54d4c54732</id><title>eal started following https://mastodon.hasameli.com/users/munin</title><content type="html">eal started following https://mastodon.hasameli.com/users/munin</content><published>2017-08-04T14:12:10.514155Z</published><updated>2017-08-04T14:12:10.514155Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type><id>https://mastodon.hasameli.com/users/munin</id><uri>https://mastodon.hasameli.com/users/munin</uri></activity:object><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/738bc887-4cca-4b36-8c86-2b54d4c54732"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.hasameli.com/users/munin"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb><id>https://social.sakamoto.gq/activities/dc66ad5a-b776-4180-a8aa-e4c1bf7cb703</id><title>eal started following https://cybre.space/users/nightpool</title><content type="html">eal started following https://cybre.space/users/nightpool</content><published>2017-08-04T14:11:16.046148Z</published><updated>2017-08-04T14:11:16.046148Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type><id>https://cybre.space/users/nightpool</id><uri>https://cybre.space/users/nightpool</uri></activity:object><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/dc66ad5a-b776-4180-a8aa-e4c1bf7cb703"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://cybre.space/users/nightpool"/></entry><entry><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>https://social.sakamoto.gq/objects/9c5c00d7-3ce4-4c11-b965-dc5c2bda86c5</id><title>New note by eal</title><content type="html">&lt;a href='https://mastodon.zombocloud.com/users/staticsafe'&gt;@staticsafe&lt;/a&gt; privet )))</content><published>2017-08-04T14:10:08.812247Z</published><updated>2017-08-04T14:10:08.812247Z</updated><ostatus:conversation>https://social.sakamoto.gq/contexts/12a33823-0327-4c1c-a591-850ea79331b5</ostatus:conversation><link ref="https://social.sakamoto.gq/contexts/12a33823-0327-4c1c-a591-850ea79331b5" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://social.sakamoto.gq/objects/9c5c00d7-3ce4-4c11-b965-dc5c2bda86c5" rel="self"/><link type="text/html" href="https://social.sakamoto.gq/objects/9c5c00d7-3ce4-4c11-b965-dc5c2bda86c5" rel="alternate"/><thr:in-reply-to ref="tag:mastodon.zombocloud.com,2017-08-04:objectId=995766:objectType=Status" href="https://mastodon.zombocloud.com/users/staticsafe/updates/4900"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.zombocloud.com/users/staticsafe"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb><id>https://social.sakamoto.gq/activities/49798053-1f40-4a71-ad33-106e90630863</id><title>eal started following https://social.homunyan.com/users/animeirl</title><content type="html">eal started following https://social.homunyan.com/users/animeirl</content><published>2017-08-04T14:09:44.904792Z</published><updated>2017-08-04T14:09:44.904792Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type><id>https://social.homunyan.com/users/animeirl</id><uri>https://social.homunyan.com/users/animeirl</uri></activity:object><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/49798053-1f40-4a71-ad33-106e90630863"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.homunyan.com/users/animeirl"/></entry><entry><activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb><id>https://social.sakamoto.gq/activities/2d83a1c5-70a6-45d3-9b84-59d6a70fbb17</id><title>New favorite by eal</title><content type="html">eal favorited something</content><published>2017-08-04T14:07:27.210044Z</published><updated>2017-08-04T14:07:27.210044Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><id>https://pleroma.soykaf.com/objects/b831e52f-4ed4-438e-95b4-888897f64f09</id></activity:object><ostatus:conversation>https://pleroma.hjkos.com/contexts/3ed48205-1e72-4e19-a618-89a0d2ca811e</ostatus:conversation><link ref="https://pleroma.hjkos.com/contexts/3ed48205-1e72-4e19-a618-89a0d2ca811e" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/2d83a1c5-70a6-45d3-9b84-59d6a70fbb17"/><thr:in-reply-to ref="https://pleroma.soykaf.com/objects/b831e52f-4ed4-438e-95b4-888897f64f09"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/lain"/></entry><entry><activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb><id>https://social.sakamoto.gq/activities/06d28bed-544a-496b-8414-1c6d439273b5</id><title>New favorite by eal</title><content type="html">eal favorited something</content><published>2017-08-04T14:05:37.280200Z</published><updated>2017-08-04T14:05:37.280200Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><id>tag:toot-lab.reclaim.technology,2017-08-04:objectId=1166030:objectType=Status</id></activity:object><ostatus:conversation>tag:p2px.me,2017-08-04:objectType=thread:nonce=f8bfc4d13db6ce91</ostatus:conversation><link ref="tag:p2px.me,2017-08-04:objectType=thread:nonce=f8bfc4d13db6ce91" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/06d28bed-544a-496b-8414-1c6d439273b5"/><thr:in-reply-to ref="tag:toot-lab.reclaim.technology,2017-08-04:objectId=1166030:objectType=Status"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://toot-lab.reclaim.technology/users/djsundog"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb><id>https://social.sakamoto.gq/activities/72bf19d4-9ad4-4b2f-9cd0-f0d70f4e931b</id><title>eal started following https://mstdn.jp/users/nullkal</title><content type="html">eal started following https://mstdn.jp/users/nullkal</content><published>2017-08-04T14:05:04.148904Z</published><updated>2017-08-04T14:05:04.148904Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type><id>https://mstdn.jp/users/nullkal</id><uri>https://mstdn.jp/users/nullkal</uri></activity:object><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/72bf19d4-9ad4-4b2f-9cd0-f0d70f4e931b"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mstdn.jp/users/nullkal"/></entry><entry><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>https://social.sakamoto.gq/objects/b0e89515-7621-4e09-b23d-83e192324107</id><title>New note by eal</title><content type="html">&lt;a href='https://p2px.me/user/1'&gt;@stitchxd&lt;/a&gt; test also</content><published>2017-08-04T14:04:38.699051Z</published><updated>2017-08-04T14:04:38.699051Z</updated><ostatus:conversation>tag:p2px.me,2017-08-04:objectType=thread:nonce=f8bfc4d13db6ce91</ostatus:conversation><link ref="tag:p2px.me,2017-08-04:objectType=thread:nonce=f8bfc4d13db6ce91" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://social.sakamoto.gq/objects/b0e89515-7621-4e09-b23d-83e192324107" rel="self"/><link type="text/html" href="https://social.sakamoto.gq/objects/b0e89515-7621-4e09-b23d-83e192324107" rel="alternate"/><thr:in-reply-to ref="tag:p2px.me,2017-08-04:noticeId=222109:objectType=note" href="https://p2px.me/notice/222109"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://p2px.me/user/1"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb><id>https://social.sakamoto.gq/activities/d8d2006b-6b23-45d6-ba27-39d27587777d</id><title>New favorite by eal</title><content type="html">eal favorited something</content><published>2017-08-04T14:04:32.106626Z</published><updated>2017-08-04T14:04:32.106626Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><id>tag:p2px.me,2017-08-04:noticeId=222109:objectType=note</id></activity:object><ostatus:conversation>tag:p2px.me,2017-08-04:objectType=thread:nonce=f8bfc4d13db6ce91</ostatus:conversation><link ref="tag:p2px.me,2017-08-04:objectType=thread:nonce=f8bfc4d13db6ce91" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/d8d2006b-6b23-45d6-ba27-39d27587777d"/><thr:in-reply-to ref="tag:p2px.me,2017-08-04:noticeId=222109:objectType=note"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://p2px.me/user/1"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb><id>https://social.sakamoto.gq/activities/cb9db95d-ec27-41fa-bebd-5375fc13acb9</id><title>eal started following https://mastodon.social/users/Gargron</title><content type="html">eal started following https://mastodon.social/users/Gargron</content><published>2017-08-04T14:04:04.325531Z</published><updated>2017-08-04T14:04:04.325531Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type><id>https://mastodon.social/users/Gargron</id><uri>https://mastodon.social/users/Gargron</uri></activity:object><link rel="self" type="application/atom+xml" href="https://social.sakamoto.gq/activities/cb9db95d-ec27-41fa-bebd-5375fc13acb9"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.social/users/Gargron"/></entry></feed> \ No newline at end of file
diff --git a/test/fixtures/tesla_mock/shp@pleroma.soykaf.com.feed b/test/fixtures/tesla_mock/shp@pleroma.soykaf.com.feed
deleted file mode 100644
index b24ef7ab6..000000000
--- a/test/fixtures/tesla_mock/shp@pleroma.soykaf.com.feed
+++ /dev/null
@@ -1 +0,0 @@
-<?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:ostatus="http://ostatus.org/schema/1.0"><id>https://pleroma.soykaf.com/users/shp/feed.atom</id><title>shp's timeline</title><updated>2017-09-14T08:31:48.911686</updated><link rel="hub" href="https://pleroma.soykaf.com/push/hub/shp"/><link rel="salmon" href="https://pleroma.soykaf.com/users/shp/salmon"/><link rel="self" href="https://pleroma.soykaf.com/users/shp/feed.atom" type="application/atom+xml"/><author><id>https://pleroma.soykaf.com/users/shp</id><activity:object>http://activitystrea.ms/schema/1.0/person</activity:object><uri>https://pleroma.soykaf.com/users/shp</uri><poco:preferredUsername>shp</poco:preferredUsername><poco:displayName>shp</poco:displayName><poco:note>cofe</poco:note><name>shp</name><link rel="avatar" href="https://pleroma.soykaf.com/media/745e4713-008c-4f54-bc26-4f59c37cea0e/43B7A3B2F0B9C0AA097F1B01E9EF05F7C1DCFA6868566D8A9AC211E483498643.png"/></author><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb><id>https://pleroma.soykaf.com/activities/0b5f5ef2-020a-4f9e-a92b-a2bf21224644</id><title>shp started following https://pleroma.soykaf.com/users/gooz</title><content type="html">shp started following https://pleroma.soykaf.com/users/gooz</content><published>2017-09-14T08:31:48.911226Z</published><updated>2017-09-14T08:31:48.911226Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type><id>https://pleroma.soykaf.com/users/gooz</id><uri>https://pleroma.soykaf.com/users/gooz</uri></activity:object><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/0b5f5ef2-020a-4f9e-a92b-a2bf21224644"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/gooz"/></entry><entry><activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type><activity:verb>http://activitystrea.ms/schema/1.0/follow</activity:verb><id>https://pleroma.soykaf.com/activities/d928b7f7-dc10-478c-859b-cd604770da60</id><title>shp started following https://niu.moe/users/xiaoyongmao</title><content type="html">shp started following https://niu.moe/users/xiaoyongmao</content><published>2017-09-14T08:16:52.674253Z</published><updated>2017-09-14T08:16:52.674253Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type><id>https://niu.moe/users/xiaoyongmao</id><uri>https://niu.moe/users/xiaoyongmao</uri></activity:object><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/d928b7f7-dc10-478c-859b-cd604770da60"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://niu.moe/users/xiaoyongmao"/></entry><entry><activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb><id>https://pleroma.soykaf.com/activities/3f5089b3-f1e5-47b6-8bfe-a9c4a860e724</id><title>New favorite by shp</title><content type="html">shp favorited something</content><published>2017-09-14T08:12:18.213055Z</published><updated>2017-09-14T08:12:18.213055Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><id>https://mastodon.xyz/users/Azurolu/statuses/8346804</id></activity:object><ostatus:conversation ref="tag:mastodon.xyz,2017-09-14:objectId=3669709:objectType=Conversation">tag:mastodon.xyz,2017-09-14:objectId=3669709:objectType=Conversation</ostatus:conversation><link ref="tag:mastodon.xyz,2017-09-14:objectId=3669709:objectType=Conversation" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/3f5089b3-f1e5-47b6-8bfe-a9c4a860e724"/><thr:in-reply-to ref="https://mastodon.xyz/users/Azurolu/statuses/8346804"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mastodon.xyz/users/Azurolu"/></entry><entry><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>https://pleroma.soykaf.com/objects/0def9b19-6b0f-44e0-96b3-543fa06a4010</id><title>New note by shp</title><content type="html">&lt;a href='https://niu.moe/users/Pasty'&gt;@Pasty&lt;/a&gt; I love the peach&lt;br&gt;&lt;a href="https://pleroma.soykaf.com/media/7e8bd209-dbd4-481a-a62c-d302d68df16d/__hinanawi_tenshi_touhou_drawn_by_e_o__8c6824f52dd494f6026607570179265f.jpg" class='attachment'&gt;__hinanawi_tenshi_touhou_drawn_…&lt;/a&gt;</content><published>2017-09-14T08:12:04.367142Z</published><updated>2017-09-14T08:12:04.367142Z</updated><ostatus:conversation ref="tag:niu.moe,2017-09-14:objectId=1660781:objectType=Conversation">tag:niu.moe,2017-09-14:objectId=1660781:objectType=Conversation</ostatus:conversation><link ref="tag:niu.moe,2017-09-14:objectId=1660781:objectType=Conversation" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/0def9b19-6b0f-44e0-96b3-543fa06a4010" rel="self"/><link type="text/html" href="https://pleroma.soykaf.com/objects/0def9b19-6b0f-44e0-96b3-543fa06a4010" rel="alternate"/><link rel="enclosure" href="https://pleroma.soykaf.com/media/7e8bd209-dbd4-481a-a62c-d302d68df16d/__hinanawi_tenshi_touhou_drawn_by_e_o__8c6824f52dd494f6026607570179265f.jpg" type="image/jpeg"/><thr:in-reply-to ref="https://niu.moe/users/Pasty/statuses/3211030" href="https://niu.moe/@Pasty/3211030"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://niu.moe/users/Pasty"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb><id>https://pleroma.soykaf.com/activities/a4170edf-d273-4b82-931d-662aaf3872f3</id><title>New favorite by shp</title><content type="html">shp favorited something</content><published>2017-09-14T08:10:26.205104Z</published><updated>2017-09-14T08:10:26.205104Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><id>https://niu.moe/users/NekoiNemo/statuses/3210992</id></activity:object><ostatus:conversation ref="tag:niu.moe,2017-09-14:objectId=1660761:objectType=Conversation">tag:niu.moe,2017-09-14:objectId=1660761:objectType=Conversation</ostatus:conversation><link ref="tag:niu.moe,2017-09-14:objectId=1660761:objectType=Conversation" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/a4170edf-d273-4b82-931d-662aaf3872f3"/><thr:in-reply-to ref="https://niu.moe/users/NekoiNemo/statuses/3210992"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://niu.moe/users/NekoiNemo"/></entry><entry><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>https://pleroma.soykaf.com/objects/c50c47a0-fac5-4781-a7e6-f20e7226d5fc</id><title>New note by shp</title><content type="html">&lt;a href='https://freezepeach.xyz/user/3458'&gt;@hakui&lt;/a&gt; &lt;a href='https://pleroma.soykaf.com/users/lain'&gt;@lain&lt;/a&gt; you guys are forgetting the pancakes jeez</content><published>2017-09-14T08:09:30.088418Z</published><updated>2017-09-14T08:09:30.088418Z</updated><ostatus:conversation ref="https://pleroma.soykaf.com/contexts/ac9c98ee-3eca-4b4b-9620-64b5e85e2623">https://pleroma.soykaf.com/contexts/ac9c98ee-3eca-4b4b-9620-64b5e85e2623</ostatus:conversation><link ref="https://pleroma.soykaf.com/contexts/ac9c98ee-3eca-4b4b-9620-64b5e85e2623" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/c50c47a0-fac5-4781-a7e6-f20e7226d5fc" rel="self"/><link type="text/html" href="https://pleroma.soykaf.com/objects/c50c47a0-fac5-4781-a7e6-f20e7226d5fc" rel="alternate"/><thr:in-reply-to ref="tag:freezepeach.xyz,2017-09-14:noticeId=3926191:objectType=comment" href="https://freezepeach.xyz/notice/3926191"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://freezepeach.xyz/user/3458"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/lain"/></entry><entry><activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb><id>https://pleroma.soykaf.com/activities/2af9f622-5986-483c-83a1-ac59a9035b50</id><title>New favorite by shp</title><content type="html">shp favorited something</content><published>2017-09-14T08:09:16.346235Z</published><updated>2017-09-14T08:09:16.346235Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><id>tag:freezepeach.xyz,2017-09-14:noticeId=3926191:objectType=comment</id></activity:object><ostatus:conversation ref="https://pleroma.soykaf.com/contexts/ac9c98ee-3eca-4b4b-9620-64b5e85e2623">https://pleroma.soykaf.com/contexts/ac9c98ee-3eca-4b4b-9620-64b5e85e2623</ostatus:conversation><link ref="https://pleroma.soykaf.com/contexts/ac9c98ee-3eca-4b4b-9620-64b5e85e2623" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/2af9f622-5986-483c-83a1-ac59a9035b50"/><thr:in-reply-to ref="tag:freezepeach.xyz,2017-09-14:noticeId=3926191:objectType=comment"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://freezepeach.xyz/user/3458"/></entry><entry><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>https://pleroma.soykaf.com/objects/f52aad69-5828-4e0e-bb7b-f2f0869d3ff0</id><title>New note by shp</title><content type="html">&lt;a href='https://gs.smuglo.li/user/253'&gt;@kro&lt;/a&gt; I'll probs try some of those 2hu mangos</content><published>2017-09-14T08:09:13.262835Z</published><updated>2017-09-14T08:09:13.262835Z</updated><ostatus:conversation ref="tag:gs.smuglo.li,2017-09-14:objectType=thread:nonce=c4ac2016e07c4123">tag:gs.smuglo.li,2017-09-14:objectType=thread:nonce=c4ac2016e07c4123</ostatus:conversation><link ref="tag:gs.smuglo.li,2017-09-14:objectType=thread:nonce=c4ac2016e07c4123" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/f52aad69-5828-4e0e-bb7b-f2f0869d3ff0" rel="self"/><link type="text/html" href="https://pleroma.soykaf.com/objects/f52aad69-5828-4e0e-bb7b-f2f0869d3ff0" rel="alternate"/><thr:in-reply-to ref="tag:gs.smuglo.li,2017-09-14:noticeId=4113226:objectType=comment" href="https://gs.smuglo.li/notice/4113226"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/253"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb><id>https://pleroma.soykaf.com/activities/35743658-efee-46cf-9cdf-487b95709cd5</id><title>New favorite by shp</title><content type="html">shp favorited something</content><published>2017-09-14T08:09:00.517534Z</published><updated>2017-09-14T08:09:00.517534Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><id>tag:gs.smuglo.li,2017-09-14:noticeId=4113226:objectType=comment</id></activity:object><ostatus:conversation ref="tag:gs.smuglo.li,2017-09-14:objectType=thread:nonce=c4ac2016e07c4123">tag:gs.smuglo.li,2017-09-14:objectType=thread:nonce=c4ac2016e07c4123</ostatus:conversation><link ref="tag:gs.smuglo.li,2017-09-14:objectType=thread:nonce=c4ac2016e07c4123" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/35743658-efee-46cf-9cdf-487b95709cd5"/><thr:in-reply-to ref="tag:gs.smuglo.li,2017-09-14:noticeId=4113226:objectType=comment"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/253"/></entry><entry><activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb><id>https://pleroma.soykaf.com/activities/22258ba8-58dc-4e09-b476-fe28d3307377</id><title>New favorite by shp</title><content type="html">shp favorited something</content><published>2017-09-14T08:08:38.087136Z</published><updated>2017-09-14T08:08:38.087136Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><id>https://pleroma.soykaf.com/objects/13d7809e-5dca-4117-8738-887759392f2c</id></activity:object><ostatus:conversation ref="https://pleroma.soykaf.com/contexts/ac9c98ee-3eca-4b4b-9620-64b5e85e2623">https://pleroma.soykaf.com/contexts/ac9c98ee-3eca-4b4b-9620-64b5e85e2623</ostatus:conversation><link ref="https://pleroma.soykaf.com/contexts/ac9c98ee-3eca-4b4b-9620-64b5e85e2623" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/22258ba8-58dc-4e09-b476-fe28d3307377"/><thr:in-reply-to ref="https://pleroma.soykaf.com/objects/13d7809e-5dca-4117-8738-887759392f2c"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/lain"/></entry><entry><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>https://pleroma.soykaf.com/objects/f56d640a-0dbd-48af-80b1-06d0dbd26774</id><title>New note by shp</title><content type="html">&lt;a href='https://social.sakamoto.gq/users/eal'&gt;@eal&lt;/a&gt; ...but neither does my phone&lt;br&gt;&lt;br&gt;low brightness, very dark wallpaper (pic related, but even darker, couldn't find the actual version)&lt;br&gt;&lt;a href="https://pleroma.soykaf.com/media/6d1b8d57-80ae-41d6-bdea-58fea09ecdf4/phonewallpaper.png" class='attachment'&gt;phonewallpaper.png&lt;/a&gt;</content><published>2017-09-14T08:07:23.081214Z</published><updated>2017-09-14T08:07:23.081214Z</updated><ostatus:conversation ref="https://pleroma.soykaf.com/contexts/f4c5d56e-fc58-467b-a8a5-10515c012355">https://pleroma.soykaf.com/contexts/f4c5d56e-fc58-467b-a8a5-10515c012355</ostatus:conversation><link ref="https://pleroma.soykaf.com/contexts/f4c5d56e-fc58-467b-a8a5-10515c012355" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/f56d640a-0dbd-48af-80b1-06d0dbd26774" rel="self"/><link type="text/html" href="https://pleroma.soykaf.com/objects/f56d640a-0dbd-48af-80b1-06d0dbd26774" rel="alternate"/><link rel="enclosure" href="https://pleroma.soykaf.com/media/6d1b8d57-80ae-41d6-bdea-58fea09ecdf4/phonewallpaper.png" type="image/png"/><thr:in-reply-to ref="https://social.sakamoto.gq/objects/3fa38f35-47ef-4286-ad22-c953643f0bbb" href="https://social.sakamoto.gq/objects/3fa38f35-47ef-4286-ad22-c953643f0bbb"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.sakamoto.gq/users/eal"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><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>https://pleroma.soykaf.com/objects/d313df1d-121c-4ab8-abd1-e6aedcf55cbd</id><title>New note by shp</title><content type="html">&lt;a href='https://niu.moe/users/Pasty'&gt;@Pasty&lt;/a&gt; y-you too</content><published>2017-09-14T07:55:26.153486Z</published><updated>2017-09-14T07:55:26.153486Z</updated><ostatus:conversation ref="tag:niu.moe,2017-09-14:objectId=1660616:objectType=Conversation">tag:niu.moe,2017-09-14:objectId=1660616:objectType=Conversation</ostatus:conversation><link ref="tag:niu.moe,2017-09-14:objectId=1660616:objectType=Conversation" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/d313df1d-121c-4ab8-abd1-e6aedcf55cbd" rel="self"/><link type="text/html" href="https://pleroma.soykaf.com/objects/d313df1d-121c-4ab8-abd1-e6aedcf55cbd" rel="alternate"/><thr:in-reply-to ref="https://niu.moe/users/Pasty/statuses/3210773" href="https://niu.moe/@Pasty/3210773"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://niu.moe/users/Pasty"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><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>https://pleroma.soykaf.com/objects/7b642424-4edb-48cc-8711-1eafb4745269</id><title>New note by shp</title><content type="html">&lt;a href='https://social.sakamoto.gq/users/eal'&gt;@eal&lt;/a&gt; bothers me more when sleeping, wore one for nearly 2 years</content><published>2017-09-14T07:54:53.449227Z</published><updated>2017-09-14T07:54:53.449227Z</updated><ostatus:conversation ref="https://pleroma.soykaf.com/contexts/f4c5d56e-fc58-467b-a8a5-10515c012355">https://pleroma.soykaf.com/contexts/f4c5d56e-fc58-467b-a8a5-10515c012355</ostatus:conversation><link ref="https://pleroma.soykaf.com/contexts/f4c5d56e-fc58-467b-a8a5-10515c012355" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/7b642424-4edb-48cc-8711-1eafb4745269" rel="self"/><link type="text/html" href="https://pleroma.soykaf.com/objects/7b642424-4edb-48cc-8711-1eafb4745269" rel="alternate"/><thr:in-reply-to ref="https://social.sakamoto.gq/objects/ac9e8340-5427-44d3-b29e-ef006133daaa" href="https://social.sakamoto.gq/objects/ac9e8340-5427-44d3-b29e-ef006133daaa"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://social.sakamoto.gq/users/eal"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><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>https://pleroma.soykaf.com/objects/5bc1bff1-88c3-489d-8efd-7e4755690a18</id><title>New note by shp</title><content type="html">quick test</content><published>2017-09-14T07:54:09.045525Z</published><updated>2017-09-14T07:54:09.045525Z</updated><ostatus:conversation ref="https://pleroma.soykaf.com/contexts/cd770c2a-408e-4895-988c-60319298f219">https://pleroma.soykaf.com/contexts/cd770c2a-408e-4895-988c-60319298f219</ostatus:conversation><link ref="https://pleroma.soykaf.com/contexts/cd770c2a-408e-4895-988c-60319298f219" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/5bc1bff1-88c3-489d-8efd-7e4755690a18" rel="self"/><link type="text/html" href="https://pleroma.soykaf.com/objects/5bc1bff1-88c3-489d-8efd-7e4755690a18" rel="alternate"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><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>https://pleroma.soykaf.com/objects/956f1fb5-6f2f-433e-ab71-7f732b76f4be</id><title>New note by shp</title><content type="html">had some trouble getting sleep last night. only used phone to check the time a few times (v essential to have a near-black wallpaper to not blind yourself when you do that). can't rember the last time I rolled in the bed for longer than an hour like that</content><published>2017-09-14T07:51:23.557775Z</published><updated>2017-09-14T07:51:23.557775Z</updated><ostatus:conversation ref="https://pleroma.soykaf.com/contexts/f4c5d56e-fc58-467b-a8a5-10515c012355">https://pleroma.soykaf.com/contexts/f4c5d56e-fc58-467b-a8a5-10515c012355</ostatus:conversation><link ref="https://pleroma.soykaf.com/contexts/f4c5d56e-fc58-467b-a8a5-10515c012355" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/956f1fb5-6f2f-433e-ab71-7f732b76f4be" rel="self"/><link type="text/html" href="https://pleroma.soykaf.com/objects/956f1fb5-6f2f-433e-ab71-7f732b76f4be" rel="alternate"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><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>https://pleroma.soykaf.com/objects/d935d9f2-ebc7-4ff2-b65a-fbf418a60935</id><title>New note by shp</title><content type="html">&lt;a href='https://gs.smuglo.li/user/253'&gt;@kro&lt;/a&gt; doesn't sound like a bad idea at all</content><published>2017-09-14T07:49:55.702555Z</published><updated>2017-09-14T07:49:55.702555Z</updated><ostatus:conversation ref="tag:gs.smuglo.li,2017-09-14:objectType=thread:nonce=c4ac2016e07c4123">tag:gs.smuglo.li,2017-09-14:objectType=thread:nonce=c4ac2016e07c4123</ostatus:conversation><link ref="tag:gs.smuglo.li,2017-09-14:objectType=thread:nonce=c4ac2016e07c4123" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/d935d9f2-ebc7-4ff2-b65a-fbf418a60935" rel="self"/><link type="text/html" href="https://pleroma.soykaf.com/objects/d935d9f2-ebc7-4ff2-b65a-fbf418a60935" rel="alternate"/><thr:in-reply-to ref="tag:gs.smuglo.li,2017-09-14:noticeId=4113170:objectType=comment" href="https://gs.smuglo.li/notice/4113170"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/253"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb><id>https://pleroma.soykaf.com/activities/342c8803-ee16-487d-9488-a39d763073f6</id><title>New favorite by shp</title><content type="html">shp favorited something</content><published>2017-09-14T07:49:41.875840Z</published><updated>2017-09-14T07:49:41.875840Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><id>tag:anticapitalist.party,2017-09-14:objectId=3322865:objectType=Status</id></activity:object><ostatus:conversation ref="tag:anticapitalist.party,2017-09-14:objectId=1251751:objectType=Conversation">tag:anticapitalist.party,2017-09-14:objectId=1251751:objectType=Conversation</ostatus:conversation><link ref="tag:anticapitalist.party,2017-09-14:objectId=1251751:objectType=Conversation" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/342c8803-ee16-487d-9488-a39d763073f6"/><thr:in-reply-to ref="tag:anticapitalist.party,2017-09-14:objectId=3322865:objectType=Status"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://anticapitalist.party/users/Concerned_Commy"/></entry><entry><activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb><id>https://pleroma.soykaf.com/activities/5d98a19b-dd55-4077-9841-142937c613ad</id><title>New favorite by shp</title><content type="html">shp favorited something</content><published>2017-09-14T07:49:30.584265Z</published><updated>2017-09-14T07:49:30.584265Z</updated><activity:object><activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type><id>tag:gs.smuglo.li,2017-09-14:noticeId=4113170:objectType=comment</id></activity:object><ostatus:conversation ref="tag:gs.smuglo.li,2017-09-14:objectType=thread:nonce=c4ac2016e07c4123">tag:gs.smuglo.li,2017-09-14:objectType=thread:nonce=c4ac2016e07c4123</ostatus:conversation><link ref="tag:gs.smuglo.li,2017-09-14:objectType=thread:nonce=c4ac2016e07c4123" rel="ostatus:conversation"/><link rel="self" type="application/atom+xml" href="https://pleroma.soykaf.com/activities/5d98a19b-dd55-4077-9841-142937c613ad"/><thr:in-reply-to ref="tag:gs.smuglo.li,2017-09-14:noticeId=4113170:objectType=comment"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/253"/></entry><entry><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>https://pleroma.soykaf.com/objects/fdf3626a-50ba-458b-9bf7-b5f2cfa505fc</id><title>New note by shp</title><content type="html">&lt;a href='https://pleroma.hjkos.com/users/hj'&gt;@hj&lt;/a&gt; c time</content><published>2017-09-14T07:48:52.805422Z</published><updated>2017-09-14T07:48:52.805422Z</updated><ostatus:conversation ref="https://pleroma.hjkos.com/contexts/dc4a3a3e-d366-4c0c-8789-8a9bee3537d9">https://pleroma.hjkos.com/contexts/dc4a3a3e-d366-4c0c-8789-8a9bee3537d9</ostatus:conversation><link ref="https://pleroma.hjkos.com/contexts/dc4a3a3e-d366-4c0c-8789-8a9bee3537d9" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/fdf3626a-50ba-458b-9bf7-b5f2cfa505fc" rel="self"/><link type="text/html" href="https://pleroma.soykaf.com/objects/fdf3626a-50ba-458b-9bf7-b5f2cfa505fc" rel="alternate"/><thr:in-reply-to ref="https://pleroma.hjkos.com/objects/581c2769-8981-43d1-b47b-815aa1282c26" href="https://pleroma.hjkos.com/objects/581c2769-8981-43d1-b47b-815aa1282c26"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.hjkos.com/users/hj"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/></entry><entry><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>https://pleroma.soykaf.com/objects/c7c8eb17-b669-4827-9fbc-90f1fc54e4b1</id><title>New note by shp</title><content type="html">&lt;a href='https://sunshinegardens.org/users/tbny'&gt;@tbny&lt;/a&gt; err.. mediterranean from finnish*</content><published>2017-09-14T07:46:52.764234Z</published><updated>2017-09-14T07:46:52.764234Z</updated><ostatus:conversation ref="https://pleroma.soykaf.com/contexts/ac9c98ee-3eca-4b4b-9620-64b5e85e2623">https://pleroma.soykaf.com/contexts/ac9c98ee-3eca-4b4b-9620-64b5e85e2623</ostatus:conversation><link ref="https://pleroma.soykaf.com/contexts/ac9c98ee-3eca-4b4b-9620-64b5e85e2623" rel="ostatus:conversation"/><link type="application/atom+xml" href="https://pleroma.soykaf.com/objects/c7c8eb17-b669-4827-9fbc-90f1fc54e4b1" rel="self"/><link type="text/html" href="https://pleroma.soykaf.com/objects/c7c8eb17-b669-4827-9fbc-90f1fc54e4b1" rel="alternate"/><thr:in-reply-to ref="https://pleroma.soykaf.com/objects/15ea896c-c943-4b65-8f31-d6cda91a52fd" href="https://pleroma.soykaf.com/objects/15ea896c-c943-4b65-8f31-d6cda91a52fd"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://pleroma.soykaf.com/users/shp"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/><link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://sunshinegardens.org/users/tbny"/></entry></feed> \ No newline at end of file
diff --git a/test/fixtures/tesla_mock/spc_5381.atom b/test/fixtures/tesla_mock/spc_5381.atom
deleted file mode 100644
index c3288e97b..000000000
--- a/test/fixtures/tesla_mock/spc_5381.atom
+++ /dev/null
@@ -1,438 +0,0 @@
-<?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.2.0-beta4">GNU social</generator>
- <id>https://shitposter.club/api/statuses/user_timeline/5381.atom</id>
- <title>shpuld timeline</title>
- <subtitle>Updates from shpuld on Shitposter Club!</subtitle>
- <logo>https://shitposter.club/avatar/5381-96-20171230093854.png</logo>
- <updated>2018-02-23T13:42:22+00:00</updated>
-<author>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <uri>https://shitposter.club/user/5381</uri>
- <name>shpuld</name>
- <link rel="alternate" type="text/html" href="https://shitposter.club/shpuld"/>
- <link rel="avatar" type="image/png" media:width="864" media:height="864" href="https://shitposter.club/avatar/5381-original-20171230093854.png"/>
- <link rel="avatar" type="image/png" media:width="96" media:height="96" href="https://shitposter.club/avatar/5381-96-20171230093854.png"/>
- <link rel="avatar" type="image/png" media:width="48" media:height="48" href="https://shitposter.club/avatar/5381-48-20171230093854.png"/>
- <link rel="avatar" type="image/png" media:width="24" media:height="24" href="https://shitposter.club/avatar/5381-24-20171230093900.png"/>
- <poco:preferredUsername>shpuld</poco:preferredUsername>
- <poco:displayName>shp</poco:displayName>
- <followers url="https://shitposter.club/shpuld/subscribers"></followers>
- <statusnet:profile_info local_id="5381"></statusnet:profile_info>
-</author>
- <link href="https://shitposter.club/shpuld" rel="alternate" type="text/html"/>
- <link href="https://shitposter.club/main/sup" rel="http://api.friendfeed.com/2008/03#sup" type="application/json"/>
- <link href="https://shitposter.club/api/statuses/user_timeline/5381.atom?max_id=7387342" rel="next" type="application/atom+xml"/>
- <link href="https://shitposter.club/main/push/hub" rel="hub"/>
- <link href="https://shitposter.club/main/salmon/user/5381" rel="salmon"/>
- <link href="https://shitposter.club/main/salmon/user/5381" rel="http://salmon-protocol.org/ns/salmon-replies"/>
- <link href="https://shitposter.club/main/salmon/user/5381" rel="http://salmon-protocol.org/ns/salmon-mention"/>
- <link href="https://shitposter.club/api/statuses/user_timeline/5381.atom" rel="self" type="application/atom+xml"/>
-<entry>
- <id>tag:shitposter.club,2018-02-23:fave:5381:comment:7387801:2018-02-23T13:39:40+00:00</id>
- <title>Favorite</title>
- <content type="html">shpuld favorited something by mayuutann: &lt;p&gt;&lt;span class=&quot;h-card&quot;&gt;&lt;a href=&quot;https://freezepeach.xyz/hakui&quot; class=&quot;u-url mention&quot;&gt;@&lt;span&gt;hakui&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; &lt;span class=&quot;h-card&quot;&gt;&lt;a href=&quot;https://gs.smuglo.li/histoire&quot; class=&quot;u-url mention&quot;&gt;@&lt;span&gt;histoire&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; &lt;span class=&quot;h-card&quot;&gt;&lt;a href=&quot;https://shitposter.club/shpuld&quot; class=&quot;u-url mention&quot;&gt;@&lt;span&gt;shpuld&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; &lt;a href=&quot;https://mstdn.io/media/_Ee-x91XN0udpfZVO_U&quot; rel=&quot;nofollow&quot;&gt;&lt;span class=&quot;invisible&quot;&gt;https://&lt;/span&gt;&lt;span class=&quot;ellipsis&quot;&gt;mstdn.io/media/_Ee-x91XN0udpfZ&lt;/span&gt;&lt;span class=&quot;invisible&quot;&gt;VO_U&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387804"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2018-02-23T13:39:40+00:00</published>
- <updated>2018-02-23T13:39:40+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>https://mstdn.io/users/mayuutann/statuses/99574950785668071</id>
- <title>New comment by mayuutann</title>
- <content type="html">&lt;p&gt;&lt;span class=&quot;h-card&quot;&gt;&lt;a href=&quot;https://freezepeach.xyz/hakui&quot; class=&quot;u-url mention&quot;&gt;@&lt;span&gt;hakui&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; &lt;span class=&quot;h-card&quot;&gt;&lt;a href=&quot;https://gs.smuglo.li/histoire&quot; class=&quot;u-url mention&quot;&gt;@&lt;span&gt;histoire&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; &lt;span class=&quot;h-card&quot;&gt;&lt;a href=&quot;https://shitposter.club/shpuld&quot; class=&quot;u-url mention&quot;&gt;@&lt;span&gt;shpuld&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; &lt;a href=&quot;https://mstdn.io/media/_Ee-x91XN0udpfZVO_U&quot; rel=&quot;nofollow&quot;&gt;&lt;span class=&quot;invisible&quot;&gt;https://&lt;/span&gt;&lt;span class=&quot;ellipsis&quot;&gt;mstdn.io/media/_Ee-x91XN0udpfZ&lt;/span&gt;&lt;span class=&quot;invisible&quot;&gt;VO_U&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</content>
- <link rel="alternate" type="text/html" href="https://mstdn.io/@mayuutann/99574950785668071"/>
- <status_net notice_id="7387801"></status_net>
- </activity:object>
- <thr:in-reply-to ref="https://mstdn.io/users/mayuutann/statuses/99574950785668071" href="https://mstdn.io/@mayuutann/99574950785668071"></thr:in-reply-to>
- <link rel="related" href="https://mstdn.io/@mayuutann/99574950785668071"/>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4389848"/>
- <ostatus:conversation href="https://shitposter.club/conversation/4389848" local_id="4389848" ref="https://freezepeach.xyz/conversation/4182511">https://freezepeach.xyz/conversation/4182511</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://shitposter.club/api/statuses/show/7387804.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387804.atom"/>
- <statusnet:notice_info local_id="7387804" source="unknown"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:shitposter.club,2018-02-23:noticeId=7387723:objectType=comment</id>
- <title>New comment by shpuld</title>
- <content type="html">@&lt;a href=&quot;https://freezepeach.xyz/user/3458&quot; class=&quot;h-card mention&quot; title=&quot;&amp;#x5FA1;&amp;#x5712;&amp;#x306F;&amp;#x304F;&amp;#x3044;&quot;&gt;hakui&lt;/a&gt; @&lt;a href=&quot;https://pleroma.soykaf.com/users/lain&quot; class=&quot;h-card mention&quot; title=&quot;&amp;#x2468; lain &amp;#x2468;&quot;&gt;lain&lt;/a&gt; how naive~</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387723"/>
- <status_net notice_id="7387723"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2018-02-23T13:30:15+00:00</published>
- <updated>2018-02-23T13:30:15+00:00</updated>
- <thr:in-reply-to ref="tag:freezepeach.xyz,2018-02-23:noticeId=6451587:objectType=comment" href="https://freezepeach.xyz/notice/6451587"></thr:in-reply-to>
- <link rel="related" href="https://freezepeach.xyz/notice/6451587"/>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4389967"/>
- <ostatus:conversation href="https://shitposter.club/conversation/4389967" local_id="4389967" ref="tag:shitposter.club,2018-02-23:objectType=thread:nonce=2f09acf104aebfe3">tag:shitposter.club,2018-02-23:objectType=thread:nonce=2f09acf104aebfe3</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://freezepeach.xyz/user/3458"/>
- <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"/>
- <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387723.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387723.atom"/>
- <statusnet:notice_info local_id="7387723" source="Pleroma FE"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:shitposter.club,2018-02-23:noticeId=7387703:objectType=comment</id>
- <title>New comment by shpuld</title>
- <content type="html">@&lt;a href=&quot;https://freezepeach.xyz/user/3458&quot; class=&quot;h-card mention&quot; title=&quot;&amp;#x5FA1;&amp;#x5712;&amp;#x306F;&amp;#x304F;&amp;#x3044;&quot;&gt;hakui&lt;/a&gt; @&lt;a href=&quot;https://pleroma.soykaf.com/users/lain&quot; class=&quot;h-card mention&quot; title=&quot;&amp;#x2468; lain &amp;#x2468;&quot;&gt;lain&lt;/a&gt; you expect anyone to believe that??</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387703"/>
- <status_net notice_id="7387703"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2018-02-23T13:28:08+00:00</published>
- <updated>2018-02-23T13:28:08+00:00</updated>
- <thr:in-reply-to ref="tag:freezepeach.xyz,2018-02-23:noticeId=6451569:objectType=comment" href="https://freezepeach.xyz/notice/6451569"></thr:in-reply-to>
- <link rel="related" href="https://freezepeach.xyz/notice/6451569"/>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4389967"/>
- <ostatus:conversation href="https://shitposter.club/conversation/4389967" local_id="4389967" ref="tag:shitposter.club,2018-02-23:objectType=thread:nonce=2f09acf104aebfe3">tag:shitposter.club,2018-02-23:objectType=thread:nonce=2f09acf104aebfe3</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://freezepeach.xyz/user/3458"/>
- <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"/>
- <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387703.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387703.atom"/>
- <statusnet:notice_info local_id="7387703" source="Pleroma FE"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:shitposter.club,2018-02-23:noticeId=7387639:objectType=comment</id>
- <title>New comment by shpuld</title>
- <content type="html">@&lt;a href=&quot;https://mstdn.io/users/mayuutann&quot; class=&quot;h-card mention&quot; title=&quot;Mayutan&amp;#x2615;&quot;&gt;mayuutann&lt;/a&gt; @&lt;a href=&quot;https://freezepeach.xyz/user/3458&quot; class=&quot;h-card mention&quot; title=&quot;&amp;#x5FA1;&amp;#x5712;&amp;#x306F;&amp;#x304F;&amp;#x3044;&quot;&gt;hakui&lt;/a&gt; pacyuri!! &lt;a href=&quot;https://shitposter.club/file/eea140be45df3f993c4533026bf9a78fe8facd296d2fa0c6d02b2e347c5dc30e.jpg&quot; title=&quot;https://shitposter.club/file/eea140be45df3f993c4533026bf9a78fe8facd296d2fa0c6d02b2e347c5dc30e.jpg&quot; class=&quot;attachment&quot; id=&quot;attachment-1589462&quot; rel=&quot;nofollow external&quot;&gt;https://shitposter.club/attachment/1589462&lt;/a&gt;</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387639"/>
- <status_net notice_id="7387639"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2018-02-23T13:20:38+00:00</published>
- <updated>2018-02-23T13:20:38+00:00</updated>
- <thr:in-reply-to ref="https://mstdn.io/users/mayuutann/statuses/99574870416888767" href="https://mstdn.io/@mayuutann/99574870416888767"></thr:in-reply-to>
- <link rel="related" href="https://mstdn.io/@mayuutann/99574870416888767"/>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4390261"/>
- <ostatus:conversation href="https://shitposter.club/conversation/4390261" local_id="4390261" ref="https://freezepeach.xyz/conversation/4183220">https://freezepeach.xyz/conversation/4183220</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://freezepeach.xyz/user/3458"/>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mstdn.io/users/mayuutann"/>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection" href="http://activityschema.org/collection/public"/>
- <link rel="enclosure" href="https://shitposter.club/file/eea140be45df3f993c4533026bf9a78fe8facd296d2fa0c6d02b2e347c5dc30e.jpg" type="image/jpeg" length="42186"/>
- <link rel="self" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387639.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387639.atom"/>
- <statusnet:notice_info local_id="7387639" source="Pleroma FE"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:shitposter.club,2018-02-23:noticeId=7387611:objectType=comment</id>
- <title>New comment by shpuld</title>
- <content type="html">@&lt;a href=&quot;https://freezepeach.xyz/user/3458&quot; class=&quot;h-card mention&quot; title=&quot;&amp;#x5FA1;&amp;#x5712;&amp;#x306F;&amp;#x304F;&amp;#x3044;&quot;&gt;hakui&lt;/a&gt; why is pacyu eating a pizza so cute</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387611"/>
- <status_net notice_id="7387611"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2018-02-23T13:18:07+00:00</published>
- <updated>2018-02-23T13:18:07+00:00</updated>
- <thr:in-reply-to ref="tag:freezepeach.xyz,2018-02-23:noticeId=6451402:objectType=comment" href="https://freezepeach.xyz/notice/6451402"></thr:in-reply-to>
- <link rel="related" href="https://freezepeach.xyz/notice/6451402"/>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4390261"/>
- <ostatus:conversation href="https://shitposter.club/conversation/4390261" local_id="4390261" ref="https://freezepeach.xyz/conversation/4183220">https://freezepeach.xyz/conversation/4183220</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://freezepeach.xyz/user/3458"/>
- <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://shitposter.club/api/statuses/show/7387611.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387611.atom"/>
- <statusnet:notice_info local_id="7387611" source="Pleroma FE"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:shitposter.club,2018-02-23:fave:5381:comment:7387600:2018-02-23T13:17:52+00:00</id>
- <title>Favorite</title>
- <content type="html">shpuld favorited something by mayuutann: &lt;p&gt;&lt;span class=&quot;h-card&quot;&gt;&lt;a href=&quot;https://shitposter.club/shpuld&quot; class=&quot;u-url mention&quot;&gt;@&lt;span&gt;shpuld&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; &lt;span class=&quot;h-card&quot;&gt;&lt;a href=&quot;https://gs.smuglo.li/histoire&quot; class=&quot;u-url mention&quot;&gt;@&lt;span&gt;histoire&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; &lt;span class=&quot;h-card&quot;&gt;&lt;a href=&quot;https://freezepeach.xyz/hakui&quot; class=&quot;u-url mention&quot;&gt;@&lt;span&gt;hakui&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; pichu! &lt;a href=&quot;https://mstdn.io/media/Crv5eubz1KO0dgBEulI&quot; rel=&quot;nofollow&quot;&gt;&lt;span class=&quot;invisible&quot;&gt;https://&lt;/span&gt;&lt;span class=&quot;ellipsis&quot;&gt;mstdn.io/media/Crv5eubz1KO0dgB&lt;/span&gt;&lt;span class=&quot;invisible&quot;&gt;EulI&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387606"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2018-02-23T13:17:52+00:00</published>
- <updated>2018-02-23T13:17:52+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>https://mstdn.io/users/mayuutann/statuses/99574863865459283</id>
- <title>New comment by mayuutann</title>
- <content type="html">&lt;p&gt;&lt;span class=&quot;h-card&quot;&gt;&lt;a href=&quot;https://shitposter.club/shpuld&quot; class=&quot;u-url mention&quot;&gt;@&lt;span&gt;shpuld&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; &lt;span class=&quot;h-card&quot;&gt;&lt;a href=&quot;https://gs.smuglo.li/histoire&quot; class=&quot;u-url mention&quot;&gt;@&lt;span&gt;histoire&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; &lt;span class=&quot;h-card&quot;&gt;&lt;a href=&quot;https://freezepeach.xyz/hakui&quot; class=&quot;u-url mention&quot;&gt;@&lt;span&gt;hakui&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; pichu! &lt;a href=&quot;https://mstdn.io/media/Crv5eubz1KO0dgBEulI&quot; rel=&quot;nofollow&quot;&gt;&lt;span class=&quot;invisible&quot;&gt;https://&lt;/span&gt;&lt;span class=&quot;ellipsis&quot;&gt;mstdn.io/media/Crv5eubz1KO0dgB&lt;/span&gt;&lt;span class=&quot;invisible&quot;&gt;EulI&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</content>
- <link rel="alternate" type="text/html" href="https://mstdn.io/@mayuutann/99574863865459283"/>
- <status_net notice_id="7387600"></status_net>
- </activity:object>
- <thr:in-reply-to ref="https://mstdn.io/users/mayuutann/statuses/99574863865459283" href="https://mstdn.io/@mayuutann/99574863865459283"></thr:in-reply-to>
- <link rel="related" href="https://mstdn.io/@mayuutann/99574863865459283"/>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4389848"/>
- <ostatus:conversation href="https://shitposter.club/conversation/4389848" local_id="4389848" ref="https://freezepeach.xyz/conversation/4182511">https://freezepeach.xyz/conversation/4182511</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://shitposter.club/api/statuses/show/7387606.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387606.atom"/>
- <statusnet:notice_info local_id="7387606" source="unknown"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:shitposter.club,2018-02-23:fave:5381:comment:7387544:2018-02-23T13:12:43+00:00</id>
- <title>Favorite</title>
- <content type="html">shpuld favorited something by mayuutann: &lt;p&gt;&lt;span class=&quot;h-card&quot;&gt;&lt;a href=&quot;https://shitposter.club/shpuld&quot; class=&quot;u-url mention&quot;&gt;@&lt;span&gt;shpuld&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; wa~~i!! :blobcheer:&lt;/p&gt;</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387557"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2018-02-23T13:12:43+00:00</published>
- <updated>2018-02-23T13:12:43+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>https://mstdn.io/users/mayuutann/statuses/99574840290947233</id>
- <title>New comment by mayuutann</title>
- <content type="html">&lt;p&gt;&lt;span class=&quot;h-card&quot;&gt;&lt;a href=&quot;https://shitposter.club/shpuld&quot; class=&quot;u-url mention&quot;&gt;@&lt;span&gt;shpuld&lt;/span&gt;&lt;/a&gt;&lt;/span&gt; wa~~i!! :blobcheer:&lt;/p&gt;</content>
- <link rel="alternate" type="text/html" href="https://mstdn.io/@mayuutann/99574840290947233"/>
- <status_net notice_id="7387544"></status_net>
- </activity:object>
- <thr:in-reply-to ref="https://mstdn.io/users/mayuutann/statuses/99574840290947233" href="https://mstdn.io/@mayuutann/99574840290947233"></thr:in-reply-to>
- <link rel="related" href="https://mstdn.io/@mayuutann/99574840290947233"/>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4390030"/>
- <ostatus:conversation href="https://shitposter.club/conversation/4390030" local_id="4390030" ref="tag:shitposter.club,2018-02-23:objectType=thread:nonce=d05e2b056274c5ab">tag:shitposter.club,2018-02-23:objectType=thread:nonce=d05e2b056274c5ab</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://shitposter.club/api/statuses/show/7387557.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387557.atom"/>
- <statusnet:notice_info local_id="7387557" source="unknown"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:shitposter.club,2018-02-23:noticeId=7387555:objectType=comment</id>
- <title>New comment by shpuld</title>
- <content type="html">@&lt;a href=&quot;https://freezepeach.xyz/user/3458&quot; class=&quot;h-card mention&quot; title=&quot;&amp;#x5FA1;&amp;#x5712;&amp;#x306F;&amp;#x304F;&amp;#x3044;&quot;&gt;hakui&lt;/a&gt; more!!</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387555"/>
- <status_net notice_id="7387555"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2018-02-23T13:12:23+00:00</published>
- <updated>2018-02-23T13:12:23+00:00</updated>
- <thr:in-reply-to ref="tag:freezepeach.xyz,2018-02-23:noticeId=6451332:objectType=note" href="https://freezepeach.xyz/notice/6451332"></thr:in-reply-to>
- <link rel="related" href="https://freezepeach.xyz/notice/6451332"/>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4390261"/>
- <ostatus:conversation href="https://shitposter.club/conversation/4390261" local_id="4390261" ref="https://freezepeach.xyz/conversation/4183220">https://freezepeach.xyz/conversation/4183220</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://freezepeach.xyz/user/3458"/>
- <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://shitposter.club/api/statuses/show/7387555.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387555.atom"/>
- <statusnet:notice_info local_id="7387555" source="Pleroma FE"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:shitposter.club,2018-02-23:fave:5381:note:7387537:2018-02-23T13:12:19+00:00</id>
- <title>Favorite</title>
- <content type="html">shpuld favorited something by hakui: you have pacyupacyu'd for: 45 minutes 03 seconds</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387553"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2018-02-23T13:12:19+00:00</published>
- <updated>2018-02-23T13:12:19+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:freezepeach.xyz,2018-02-23:noticeId=6451332:objectType=note</id>
- <title>New note by hakui</title>
- <content type="html">you have pacyupacyu'd for: 45 minutes 03 seconds</content>
- <link rel="alternate" type="text/html" href="https://freezepeach.xyz/notice/6451332"/>
- <status_net notice_id="7387537"></status_net>
- </activity:object>
- <thr:in-reply-to ref="tag:freezepeach.xyz,2018-02-23:noticeId=6451332:objectType=note" href="https://freezepeach.xyz/notice/6451332"></thr:in-reply-to>
- <link rel="related" href="https://freezepeach.xyz/notice/6451332"/>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4390261"/>
- <ostatus:conversation href="https://shitposter.club/conversation/4390261" local_id="4390261" ref="https://freezepeach.xyz/conversation/4183220">https://freezepeach.xyz/conversation/4183220</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://shitposter.club/api/statuses/show/7387553.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387553.atom"/>
- <statusnet:notice_info local_id="7387553" source="unknown"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:shitposter.club,2018-02-23:noticeId=7387539:objectType=comment</id>
- <title>New comment by shpuld</title>
- <content type="html">@&lt;a href=&quot;https://mstdn.io/users/mayuutann&quot; class=&quot;h-card mention&quot; title=&quot;Mayutan&amp;#x2615;&quot;&gt;mayuutann&lt;/a&gt; ndndnd~</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387539"/>
- <status_net notice_id="7387539"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2018-02-23T13:11:04+00:00</published>
- <updated>2018-02-23T13:11:04+00:00</updated>
- <thr:in-reply-to ref="https://mstdn.io/users/mayuutann/statuses/99574837619821505" href="https://mstdn.io/@mayuutann/99574837619821505"></thr:in-reply-to>
- <link rel="related" href="https://mstdn.io/@mayuutann/99574837619821505"/>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4390030"/>
- <ostatus:conversation href="https://shitposter.club/conversation/4390030" local_id="4390030" ref="tag:shitposter.club,2018-02-23:objectType=thread:nonce=d05e2b056274c5ab">tag:shitposter.club,2018-02-23:objectType=thread:nonce=d05e2b056274c5ab</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mstdn.io/users/mayuutann"/>
- <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://shitposter.club/api/statuses/show/7387539.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387539.atom"/>
- <statusnet:notice_info local_id="7387539" source="Pleroma FE"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:shitposter.club,2018-02-23:noticeId=7387518:objectType=comment</id>
- <title>New comment by shpuld</title>
- <content type="html">@&lt;a href=&quot;https://mstdn.io/users/mayuutann&quot; class=&quot;h-card mention&quot; title=&quot;Mayutan&amp;#x2615;&quot;&gt;mayuutann&lt;/a&gt; well done! mayumayu is so energetic</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387518"/>
- <status_net notice_id="7387518"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2018-02-23T13:08:50+00:00</published>
- <updated>2018-02-23T13:08:50+00:00</updated>
- <thr:in-reply-to ref="https://mstdn.io/users/mayuutann/statuses/99574826506801503" href="https://mstdn.io/@mayuutann/99574826506801503"></thr:in-reply-to>
- <link rel="related" href="https://mstdn.io/@mayuutann/99574826506801503"/>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4390030"/>
- <ostatus:conversation href="https://shitposter.club/conversation/4390030" local_id="4390030" ref="tag:shitposter.club,2018-02-23:objectType=thread:nonce=d05e2b056274c5ab">tag:shitposter.club,2018-02-23:objectType=thread:nonce=d05e2b056274c5ab</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://mstdn.io/users/mayuutann"/>
- <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://shitposter.club/api/statuses/show/7387518.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387518.atom"/>
- <statusnet:notice_info local_id="7387518" source="Pleroma FE"></statusnet:notice_info>
-</entry>
-<entry>
- <id>tag:shitposter.club,2018-02-23:fave:5381:note:7387503:2018-02-23T13:08:00+00:00</id>
- <title>Favorite</title>
- <content type="html">shpuld favorited something by mayuutann: &lt;p&gt;done with FIGURE MAT!!&lt;br /&gt; (Posted with IFTTT)&lt;/p&gt;</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387511"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/favorite</activity:verb>
- <published>2018-02-23T13:08:00+00:00</published>
- <updated>2018-02-23T13:08:00+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>https://mstdn.io/users/mayuutann/statuses/99574825526201897</id>
- <title>New note by mayuutann</title>
- <content type="html">&lt;p&gt;done with FIGURE MAT!!&lt;br /&gt; (Posted with IFTTT)&lt;/p&gt;</content>
- <link rel="alternate" type="text/html" href="https://mstdn.io/@mayuutann/99574825526201897"/>
- <status_net notice_id="7387503"></status_net>
- </activity:object>
- <thr:in-reply-to ref="https://mstdn.io/users/mayuutann/statuses/99574825526201897" href="https://mstdn.io/@mayuutann/99574825526201897"></thr:in-reply-to>
- <link rel="related" href="https://mstdn.io/@mayuutann/99574825526201897"/>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4390240"/>
- <ostatus:conversation href="https://shitposter.club/conversation/4390240" local_id="4390240" ref="tag:shitposter.club,2018-02-23:objectType=thread:nonce=c6aaa9b91e8d242f">tag:shitposter.club,2018-02-23:objectType=thread:nonce=c6aaa9b91e8d242f</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://shitposter.club/api/statuses/show/7387511.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387511.atom"/>
- <statusnet:notice_info local_id="7387511" source="unknown"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:shitposter.club,2018-02-23:noticeId=7387486:objectType=comment</id>
- <title>New comment by shpuld</title>
- <content type="html">@&lt;a href=&quot;https://freezepeach.xyz/user/3458&quot; class=&quot;h-card mention&quot; title=&quot;&amp;#x5FA1;&amp;#x5712;&amp;#x306F;&amp;#x304F;&amp;#x3044;&quot;&gt;hakui&lt;/a&gt; @&lt;a href=&quot;https://a.weirder.earth/users/mutstd&quot; class=&quot;h-card mention&quot; title=&quot;Mutant Standard&quot;&gt;mutstd&lt;/a&gt; @&lt;a href=&quot;https://donphan.social/users/Siphonay&quot; class=&quot;h-card mention&quot; title=&quot;Siphonay&quot;&gt;siphonay&lt;/a&gt; jokes on you I'm oppressively shitposting myself</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387486"/>
- <status_net notice_id="7387486"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2018-02-23T13:05:44+00:00</published>
- <updated>2018-02-23T13:05:44+00:00</updated>
- <thr:in-reply-to ref="tag:freezepeach.xyz,2018-02-23:noticeId=6451272:objectType=comment" href="https://freezepeach.xyz/notice/6451272"></thr:in-reply-to>
- <link rel="related" href="https://freezepeach.xyz/notice/6451272"/>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4389665"/>
- <ostatus:conversation href="https://shitposter.club/conversation/4389665" local_id="4389665" ref="tag:shitposter.club,2018-02-23:objectType=thread:nonce=5d306467336c9661">tag:shitposter.club,2018-02-23:objectType=thread:nonce=5d306467336c9661</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://freezepeach.xyz/user/3458"/>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://a.weirder.earth/users/mutstd"/>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://donphan.social/users/Siphonay"/>
- <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://shitposter.club/api/statuses/show/7387486.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387486.atom"/>
- <statusnet:notice_info local_id="7387486" source="Pleroma FE"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:shitposter.club,2018-02-23:noticeId=7387466:objectType=comment</id>
- <title>New comment by shpuld</title>
- <content type="html">@&lt;a href=&quot;https://freezepeach.xyz/user/3458&quot; class=&quot;h-card mention&quot; title=&quot;&amp;#x5FA1;&amp;#x5712;&amp;#x306F;&amp;#x304F;&amp;#x3044;&quot;&gt;hakui&lt;/a&gt; @&lt;a href=&quot;https://a.weirder.earth/users/mutstd&quot; class=&quot;h-card mention&quot; title=&quot;Mutant Standard&quot;&gt;mutstd&lt;/a&gt; @&lt;a href=&quot;https://donphan.social/users/Siphonay&quot; class=&quot;h-card mention&quot; title=&quot;Siphonay&quot;&gt;siphonay&lt;/a&gt; how does it feel being hostile</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387466"/>
- <status_net notice_id="7387466"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2018-02-23T13:04:10+00:00</published>
- <updated>2018-02-23T13:04:10+00:00</updated>
- <thr:in-reply-to ref="tag:freezepeach.xyz,2018-02-23:noticeId=6451260:objectType=comment" href="https://freezepeach.xyz/notice/6451260"></thr:in-reply-to>
- <link rel="related" href="https://freezepeach.xyz/notice/6451260"/>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4389665"/>
- <ostatus:conversation href="https://shitposter.club/conversation/4389665" local_id="4389665" ref="tag:shitposter.club,2018-02-23:objectType=thread:nonce=5d306467336c9661">tag:shitposter.club,2018-02-23:objectType=thread:nonce=5d306467336c9661</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://freezepeach.xyz/user/3458"/>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://a.weirder.earth/users/mutstd"/>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://donphan.social/users/Siphonay"/>
- <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://shitposter.club/api/statuses/show/7387466.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387466.atom"/>
- <statusnet:notice_info local_id="7387466" source="Pleroma FE"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:shitposter.club,2018-02-23:noticeId=7387459:objectType=comment</id>
- <title>New comment by shpuld</title>
- <content type="html">@&lt;a href=&quot;https://freezepeach.xyz/user/3458&quot; class=&quot;h-card mention&quot; title=&quot;&amp;#x5FA1;&amp;#x5712;&amp;#x306F;&amp;#x304F;&amp;#x3044;&quot;&gt;hakui&lt;/a&gt; gorogoro</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387459"/>
- <status_net notice_id="7387459"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2018-02-23T13:03:32+00:00</published>
- <updated>2018-02-23T13:03:32+00:00</updated>
- <thr:in-reply-to ref="tag:freezepeach.xyz,2018-02-23:noticeId=6451248:objectType=comment" href="https://freezepeach.xyz/notice/6451248"></thr:in-reply-to>
- <link rel="related" href="https://freezepeach.xyz/notice/6451248"/>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4389271"/>
- <ostatus:conversation href="https://shitposter.club/conversation/4389271" local_id="4389271" ref="https://freezepeach.xyz/conversation/4181784">https://freezepeach.xyz/conversation/4181784</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://freezepeach.xyz/user/3458"/>
- <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://shitposter.club/api/statuses/show/7387459.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387459.atom"/>
- <statusnet:notice_info local_id="7387459" source="Pleroma FE"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:shitposter.club,2018-02-23:noticeId=7387432:objectType=comment</id>
- <title>New comment by shpuld</title>
- <content type="html">@&lt;a href=&quot;https://freezepeach.xyz/user/3458&quot; class=&quot;h-card mention&quot; title=&quot;&amp;#x5FA1;&amp;#x5712;&amp;#x306F;&amp;#x304F;&amp;#x3044;&quot;&gt;hakui&lt;/a&gt; ndnd</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387432"/>
- <status_net notice_id="7387432"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2018-02-23T13:02:05+00:00</published>
- <updated>2018-02-23T13:02:05+00:00</updated>
- <thr:in-reply-to ref="tag:freezepeach.xyz,2018-02-23:noticeId=6451204:objectType=comment" href="https://freezepeach.xyz/notice/6451204"></thr:in-reply-to>
- <link rel="related" href="https://freezepeach.xyz/notice/6451204"/>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4389271"/>
- <ostatus:conversation href="https://shitposter.club/conversation/4389271" local_id="4389271" ref="https://freezepeach.xyz/conversation/4181784">https://freezepeach.xyz/conversation/4181784</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://freezepeach.xyz/user/3458"/>
- <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://shitposter.club/api/statuses/show/7387432.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387432.atom"/>
- <statusnet:notice_info local_id="7387432" source="Pleroma FE"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:shitposter.club,2018-02-23:noticeId=7387367:objectType=note</id>
- <title>New note by shpuld</title>
- <content type="html">dear diary: I'm trying to do work but I can only think of tenshi eating a corndog</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387367"/>
- <status_net notice_id="7387367"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2018-02-23T12:56:03+00:00</published>
- <updated>2018-02-23T12:56:03+00:00</updated>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4390142"/>
- <ostatus:conversation href="https://shitposter.club/conversation/4390142" local_id="4390142" ref="tag:shitposter.club,2018-02-23:objectType=thread:nonce=57f316da416743fc">tag:shitposter.club,2018-02-23:objectType=thread:nonce=57f316da416743fc</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://shitposter.club/api/statuses/show/7387367.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387367.atom"/>
- <statusnet:notice_info local_id="7387367" source="Pleroma FE"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
- <id>tag:shitposter.club,2018-02-23:noticeId=7387354:objectType=note</id>
- <title>New note by shpuld</title>
- <content type="html">jesus christ it's such a fridey at work</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387354"/>
- <status_net notice_id="7387354"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2018-02-23T12:53:50+00:00</published>
- <updated>2018-02-23T12:53:50+00:00</updated>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4390131"/>
- <ostatus:conversation href="https://shitposter.club/conversation/4390131" local_id="4390131" ref="tag:shitposter.club,2018-02-23:objectType=thread:nonce=c05eb5e91bdcbdb7">tag:shitposter.club,2018-02-23:objectType=thread:nonce=c05eb5e91bdcbdb7</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://shitposter.club/api/statuses/show/7387354.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387354.atom"/>
- <statusnet:notice_info local_id="7387354" source="Pleroma FE"></statusnet:notice_info>
-</entry>
-<entry>
- <activity:object-type>http://activitystrea.ms/schema/1.0/comment</activity:object-type>
- <id>tag:shitposter.club,2018-02-23:noticeId=7387343:objectType=comment</id>
- <title>New comment by shpuld</title>
- <content type="html">@&lt;a href=&quot;https://gs.smuglo.li/user/589&quot; class=&quot;h-card mention&quot; title=&quot;&amp;#x16DE;&amp;#x16A9;&amp;#x16B3;&amp;#x16C1;&amp;#x16DE;&amp;#x16A9;&amp;#x16B3;&amp;#x16C1;&quot;&gt;dokidoki&lt;/a&gt; give them free upgrades to krokodil</content>
- <link rel="alternate" type="text/html" href="https://shitposter.club/notice/7387343"/>
- <status_net notice_id="7387343"></status_net>
- <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
- <published>2018-02-23T12:53:15+00:00</published>
- <updated>2018-02-23T12:53:15+00:00</updated>
- <thr:in-reply-to ref="tag:gs.smuglo.li,2018-02-23:noticeId=6201061:objectType=note" href="https://gs.smuglo.li/notice/6201061"></thr:in-reply-to>
- <link rel="related" href="https://gs.smuglo.li/notice/6201061"/>
- <link rel="ostatus:conversation" href="https://shitposter.club/conversation/4390117"/>
- <ostatus:conversation href="https://shitposter.club/conversation/4390117" local_id="4390117" ref="https://gs.smuglo.li/conversation/3934774">https://gs.smuglo.li/conversation/3934774</ostatus:conversation>
- <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person" href="https://gs.smuglo.li/user/589"/>
- <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://shitposter.club/api/statuses/show/7387343.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://shitposter.club/api/statuses/show/7387343.atom"/>
- <statusnet:notice_info local_id="7387343" source="Pleroma FE"></statusnet:notice_info>
-</entry>
-</feed>
diff --git a/test/fixtures/tesla_mock/wedistribute-create-article.json b/test/fixtures/tesla_mock/wedistribute-create-article.json
new file mode 100644
index 000000000..3cfef8b99
--- /dev/null
+++ b/test/fixtures/tesla_mock/wedistribute-create-article.json
@@ -0,0 +1 @@
+{"@context":["https:\/\/www.w3.org\/ns\/activitystreams"],"type":"Create","actor":"https:\/\/wedistribute.org\/wp-json\/pterotype\/v1\/actor\/-blog","object":{"@context":["https:\/\/www.w3.org\/ns\/activitystreams"],"type":"Article","name":"The end is near: Mastodon plans to drop OStatus support","content":"<!-- wp:paragraph {\"dropCap\":true} -->\n<p class=\"has-drop-cap\">The days of OStatus are numbered. The venerable protocol has served as a glue between many different types of servers since the early days of the Fediverse, connecting StatusNet (now GNU Social) to Friendica, Hubzilla, Mastodon, and Pleroma.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>Now that many fediverse platforms support ActivityPub as a successor protocol, Mastodon appears to be drawing a line in the sand. In <a href=\"https:\/\/www.patreon.com\/posts\/mastodon-2-9-and-28121681\">a Patreon update<\/a>, Eugen Rochko writes:<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:quote -->\n<blockquote class=\"wp-block-quote\"><p>...OStatus...has overstayed its welcome in the code...and now that most of the network uses ActivityPub, it's time for it to go. <\/p><cite>Eugen Rochko, Mastodon creator<\/cite><\/blockquote>\n<!-- \/wp:quote -->\n\n<!-- wp:paragraph -->\n<p>The <a href=\"https:\/\/github.com\/tootsuite\/mastodon\/pull\/11205\">pull request<\/a> to remove Pubsubhubbub and Salmon, two of the main components of OStatus, has already been merged into Mastodon's master branch.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>Some projects will be left in the dark as a side effect of this. GNU Social and PostActiv, for example, both only communicate using OStatus. While <a href=\"https:\/\/mastodon.social\/@dansup\/102076573310057902\">some discussion<\/a> exists regarding adopting ActivityPub for GNU Social, and <a href=\"https:\/\/notabug.org\/diogo\/gnu-social\/src\/activitypub\/plugins\/ActivityPub\">a plugin is in development<\/a>, it hasn't been formally adopted yet. We just hope that the <a href=\"https:\/\/status.fsf.org\/main\/public\">Free Software Foundation's instance<\/a> gets updated in time!<\/p>\n<!-- \/wp:paragraph -->","summary":"One of the largest platforms in the federated social web is dropping the protocol that it started with.","attributedTo":"https:\/\/wedistribute.org\/wp-json\/pterotype\/v1\/actor\/-blog","url":"https:\/\/wedistribute.org\/2019\/07\/mastodon-drops-ostatus\/","to":["https:\/\/www.w3.org\/ns\/activitystreams#Public","https:\/\/wedistribute.org\/wp-json\/pterotype\/v1\/actor\/-blog\/followers"],"id":"https:\/\/wedistribute.org\/wp-json\/pterotype\/v1\/object\/85810","likes":"https:\/\/wedistribute.org\/wp-json\/pterotype\/v1\/object\/85810\/likes","shares":"https:\/\/wedistribute.org\/wp-json\/pterotype\/v1\/object\/85810\/shares"},"to":["https:\/\/www.w3.org\/ns\/activitystreams#Public","https:\/\/wedistribute.org\/wp-json\/pterotype\/v1\/actor\/-blog\/followers"],"id":"https:\/\/wedistribute.org\/wp-json\/pterotype\/v1\/object\/85809"} \ No newline at end of file
diff --git a/test/fixtures/tesla_mock/xn--q9jyb4c_host_meta b/test/fixtures/tesla_mock/xn--q9jyb4c_host_meta
deleted file mode 100644
index 45d260e55..000000000
--- a/test/fixtures/tesla_mock/xn--q9jyb4c_host_meta
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
- <Link rel="lrdd" template="https://zetsubou.xn--q9jyb4c/.well-known/webfinger?resource={uri}" type="application/xrd+xml" />
-</XRD>
diff --git a/test/fixtures/unfollow.xml b/test/fixtures/unfollow.xml
deleted file mode 100644
index 7a8f8fd2e..000000000
--- a/test/fixtures/unfollow.xml
+++ /dev/null
@@ -1,68 +0,0 @@
-<?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-07T09:54:49+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>undo:tag:social.heldscal.la,2017-05-07:subscription:23211:person:44803:2017-05-07T09:54:48+00:00</id>
- <title>Constance Variable (lambadalambda@social.heldscal.la)'s status on Sunday, 07-May-2017 09:54:49 UTC</title>
- <content type="html">&lt;a href=&quot;https://social.heldscal.la/lambadalambda&quot;&gt;Constance Variable&lt;/a&gt; stopped following &lt;a href=&quot;https://pawoo.net/@pekorino&quot;&gt;mono&lt;/a&gt;.</content>
- <link rel="alternate" type="text/html" href="https://social.heldscal.la/notice/2092981"/>
- <activity:verb>http://activitystrea.ms/schema/1.0/unfollow</activity:verb>
- <published>2017-05-07T09:54:49+00:00</published>
- <updated>2017-05-07T09:54:49+00:00</updated>
- <activity:object>
- <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
- <id>https://pawoo.net/users/pekorino</id>
- <title>mono</title>
- <summary>http://shitposter.club/mono 孤独のグルメ</summary>
- <link rel="alternate" type="text/html" href="https://pawoo.net/@pekorino"/>
- <link rel="avatar" type="image/png" media:width="96" media:height="96" href="http://social.heldscal.la/theme/neo-gnu/default-avatar-profile.png"/>
- <link rel="avatar" type="image/png" media:width="48" media:height="48" href="http://social.heldscal.la/theme/neo-gnu/default-avatar-stream.png"/>
- <link rel="avatar" type="image/png" media:width="24" media:height="24" href="http://social.heldscal.la/theme/neo-gnu/default-avatar-mini.png"/>
- <poco:preferredUsername>pekorino</poco:preferredUsername>
- <poco:displayName>mono</poco:displayName>
- <poco:note>http://shitposter.club/mono 孤独のグルメ</poco:note>
- </activity:object>
- <link rel="ostatus:conversation" href="https://social.heldscal.la/conversation/1079786"/>
- <ostatus:conversation href="https://social.heldscal.la/conversation/1079786" local_id="1079786" ref="tag:social.heldscal.la,2017-05-07:objectType=thread:nonce=6e80caf94e03029f">tag:social.heldscal.la,2017-05-07:objectType=thread:nonce=6e80caf94e03029f</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/2092981.atom"/>
- <link rel="edit" type="application/atom+xml" href="https://social.heldscal.la/api/statuses/show/2092981.atom"/>
- <statusnet:notice_info local_id="2092981" source="activity"></statusnet:notice_info>
-</entry>
-</feed>
diff --git a/test/fixtures/users_mock/localhost.json b/test/fixtures/users_mock/localhost.json
deleted file mode 100644
index a49935db1..000000000
--- a/test/fixtures/users_mock/localhost.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
- "@context": [
- "https://www.w3.org/ns/activitystreams",
- "http://localhost:4001/schemas/litepub-0.1.jsonld",
- {
- "@language": "und"
- }
- ],
- "attachment": [],
- "endpoints": {
- "oauthAuthorizationEndpoint": "http://localhost:4001/oauth/authorize",
- "oauthRegistrationEndpoint": "http://localhost:4001/api/v1/apps",
- "oauthTokenEndpoint": "http://localhost:4001/oauth/token",
- "sharedInbox": "http://localhost:4001/inbox"
- },
- "followers": "http://localhost:4001/users/{{nickname}}/followers",
- "following": "http://localhost:4001/users/{{nickname}}/following",
- "icon": {
- "type": "Image",
- "url": "http://localhost:4001/media/4e914f5b84e4a259a3f6c2d2edc9ab642f2ab05f3e3d9c52c81fc2d984b3d51e.jpg"
- },
- "id": "http://localhost:4001/users/{{nickname}}",
- "image": {
- "type": "Image",
- "url": "http://localhost:4001/media/f739efddefeee49c6e67e947c4811fdc911785c16ae43da4c3684051fbf8da6a.jpg?name=f739efddefeee49c6e67e947c4811fdc911785c16ae43da4c3684051fbf8da6a.jpg"
- },
- "inbox": "http://localhost:4001/users/{{nickname}}/inbox",
- "manuallyApprovesFollowers": false,
- "name": "{{nickname}}",
- "outbox": "http://localhost:4001/users/{{nickname}}/outbox",
- "preferredUsername": "{{nickname}}",
- "publicKey": {
- "id": "http://localhost:4001/users/{{nickname}}#main-key",
- "owner": "http://localhost:4001/users/{{nickname}}",
- "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5DLtwGXNZElJyxFGfcVc\nXANhaMadj/iYYQwZjOJTV9QsbtiNBeIK54PJrYuU0/0YIdrvS1iqheX5IwXRhcwa\nhm3ZyLz7XeN9st7FBni4BmZMBtMpxAuYuu5p/jbWy13qAiYOhPreCx0wrWgm/lBD\n9mkgaxIxPooBE0S4ZWEJIDIV1Vft3AWcRUyWW1vIBK0uZzs6GYshbQZB952S0yo4\nFzI1hABGHncH8UvuFauh4EZ8tY7/X5I0pGRnDOcRN1dAht5w5yTA+6r5kebiFQjP\nIzN/eCO/a9Flrj9YGW7HDNtjSOH0A31PLRGlJtJO3yK57dnf5ppyCZGfL4emShQo\ncQIDAQAB\n-----END PUBLIC KEY-----\n\n"
- },
- "summary": "your friendly neighborhood pleroma developer<br>I like cute things and distributed systems, and really hate delete and redrafts",
- "tag": [],
- "type": "Person",
- "url": "http://localhost:4001/users/{{nickname}}"
-} \ No newline at end of file
diff --git a/test/fixtures/users_mock/masto_featured.json b/test/fixtures/users_mock/masto_featured.json
new file mode 100644
index 000000000..646a343ad
--- /dev/null
+++ b/test/fixtures/users_mock/masto_featured.json
@@ -0,0 +1,18 @@
+{
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ {
+ "ostatus": "http://ostatus.org#",
+ "atomUri": "ostatus:atomUri",
+ "inReplyToAtomUri": "ostatus:inReplyToAtomUri",
+ "conversation": "ostatus:conversation",
+ "sensitive": "as:sensitive",
+ "toot": "http://joinmastodon.org/ns#",
+ "votersCount": "toot:votersCount"
+ }
+ ],
+ "id": "https://{{domain}}/users/{{nickname}}/collections/featured",
+ "type": "OrderedCollection",
+ "totalItems": 0,
+ "orderedItems": []
+}
diff --git a/test/fixtures/users_mock/user.json b/test/fixtures/users_mock/user.json
new file mode 100644
index 000000000..c722a1145
--- /dev/null
+++ b/test/fixtures/users_mock/user.json
@@ -0,0 +1,42 @@
+{
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://example.com/schemas/litepub-0.1.jsonld",
+ {
+ "@language": "und"
+ }
+ ],
+ "attachment": [],
+ "endpoints": {
+ "oauthAuthorizationEndpoint": "https://example.com/oauth/authorize",
+ "oauthRegistrationEndpoint": "https://example.com/api/v1/apps",
+ "oauthTokenEndpoint": "https://example.com/oauth/token",
+ "sharedInbox": "https://example.com/inbox"
+ },
+ "followers": "https://example.com/users/{{nickname}}/followers",
+ "following": "https://example.com/users/{{nickname}}/following",
+ "icon": {
+ "type": "Image",
+ "url": "https://example.com/media/4e914f5b84e4a259a3f6c2d2edc9ab642f2ab05f3e3d9c52c81fc2d984b3d51e.jpg"
+ },
+ "id": "https://example.com/users/{{nickname}}",
+ "image": {
+ "type": "Image",
+ "url": "https://example.com/media/f739efddefeee49c6e67e947c4811fdc911785c16ae43da4c3684051fbf8da6a.jpg?name=f739efddefeee49c6e67e947c4811fdc911785c16ae43da4c3684051fbf8da6a.jpg"
+ },
+ "inbox": "https://example.com/users/{{nickname}}/inbox",
+ "manuallyApprovesFollowers": false,
+ "name": "{{nickname}}",
+ "outbox": "https://example.com/users/{{nickname}}/outbox",
+ "preferredUsername": "{{nickname}}",
+ "publicKey": {
+ "id": "https://example.com/users/{{nickname}}#main-key",
+ "owner": "https://example.com/users/{{nickname}}",
+ "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5DLtwGXNZElJyxFGfcVc\nXANhaMadj/iYYQwZjOJTV9QsbtiNBeIK54PJrYuU0/0YIdrvS1iqheX5IwXRhcwa\nhm3ZyLz7XeN9st7FBni4BmZMBtMpxAuYuu5p/jbWy13qAiYOhPreCx0wrWgm/lBD\n9mkgaxIxPooBE0S4ZWEJIDIV1Vft3AWcRUyWW1vIBK0uZzs6GYshbQZB952S0yo4\nFzI1hABGHncH8UvuFauh4EZ8tY7/X5I0pGRnDOcRN1dAht5w5yTA+6r5kebiFQjP\nIzN/eCO/a9Flrj9YGW7HDNtjSOH0A31PLRGlJtJO3yK57dnf5ppyCZGfL4emShQo\ncQIDAQAB\n-----END PUBLIC KEY-----\n\n"
+ },
+ "featured": "https://example.com/users/{{nickname}}/collections/featured",
+ "summary": "your friendly neighborhood pleroma developer<br>I like cute things and distributed systems, and really hate delete and redrafts",
+ "tag": [],
+ "type": "Person",
+ "url": "https://example.com/users/{{nickname}}"
+}
diff --git a/test/fixtures/video.mp4 b/test/fixtures/video.mp4
new file mode 100644
index 000000000..2021e3a5b
--- /dev/null
+++ b/test/fixtures/video.mp4
Binary files differ
diff --git a/test/instance_static/emoji/blobs.gg/blank.png b/test/instance_static/emoji/blobs.gg/blank.png
new file mode 100644
index 000000000..8f50fa023
--- /dev/null
+++ b/test/instance_static/emoji/blobs.gg/blank.png
Binary files differ
diff --git a/test/instance_static/emoji/blobs.gg/pack.json b/test/instance_static/emoji/blobs.gg/pack.json
new file mode 100644
index 000000000..481891b08
--- /dev/null
+++ b/test/instance_static/emoji/blobs.gg/pack.json
@@ -0,0 +1,11 @@
+{
+ "files": {
+ "blank": "blank.png"
+ },
+ "pack": {
+ "description": "Test description",
+ "homepage": "https://pleroma.social",
+ "license": "Test license",
+ "share-files": true
+ }
+} \ No newline at end of file
diff --git a/test/tasks/pleroma_test.exs b/test/mix/pleroma_test.exs
index c3e47b285..af62cc1d9 100644
--- a/test/tasks/pleroma_test.exs
+++ b/test/mix/pleroma_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.PleromaTest do
diff --git a/test/tasks/app_test.exs b/test/mix/tasks/pleroma/app_test.exs
index 71a84ac8e..9eabd32af 100644
--- a/test/tasks/app_test.exs
+++ b/test/mix/tasks/pleroma/app_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.Tasks.Pleroma.AppTest do
diff --git a/test/mix/tasks/pleroma/config_test.exs b/test/mix/tasks/pleroma/config_test.exs
new file mode 100644
index 000000000..2b8252db7
--- /dev/null
+++ b/test/mix/tasks/pleroma/config_test.exs
@@ -0,0 +1,343 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Mix.Tasks.Pleroma.ConfigTest do
+ use Pleroma.DataCase
+
+ import Pleroma.Factory
+
+ alias Mix.Tasks.Pleroma.Config, as: MixTask
+ alias Pleroma.ConfigDB
+ alias Pleroma.Repo
+
+ setup_all do
+ Mix.shell(Mix.Shell.Process)
+
+ on_exit(fn ->
+ Mix.shell(Mix.Shell.IO)
+ Application.delete_env(:pleroma, :first_setting)
+ Application.delete_env(:pleroma, :second_setting)
+ end)
+
+ :ok
+ end
+
+ defp config_records do
+ ConfigDB
+ |> Repo.all()
+ |> Enum.sort()
+ end
+
+ defp insert_config_record(group, key, value) do
+ insert(:config,
+ group: group,
+ key: key,
+ value: value
+ )
+ end
+
+ test "error if file with custom settings doesn't exist" do
+ MixTask.migrate_to_db("config/non_existent_config_file.exs")
+
+ msg =
+ "To migrate settings, you must define custom settings in config/non_existent_config_file.exs."
+
+ assert_receive {:mix_shell, :info, [^msg]}, 15
+ end
+
+ describe "migrate_to_db/1" do
+ setup do
+ clear_config(:configurable_from_database, true)
+ clear_config([:quack, :level])
+ end
+
+ @tag capture_log: true
+ test "config migration refused when deprecated settings are found" do
+ clear_config([:media_proxy, :whitelist], ["domain_without_scheme.com"])
+ assert config_records() == []
+
+ MixTask.migrate_to_db("test/fixtures/config/temp.secret.exs")
+
+ assert_received {:mix_shell, :error, [message]}
+
+ assert message =~
+ "Migration is not allowed until all deprecation warnings have been resolved."
+ end
+
+ test "filtered settings are migrated to db" do
+ assert config_records() == []
+
+ MixTask.migrate_to_db("test/fixtures/config/temp.secret.exs")
+
+ config1 = ConfigDB.get_by_params(%{group: ":pleroma", key: ":first_setting"})
+ config2 = ConfigDB.get_by_params(%{group: ":pleroma", key: ":second_setting"})
+ config3 = ConfigDB.get_by_params(%{group: ":quack", key: ":level"})
+ refute ConfigDB.get_by_params(%{group: ":pleroma", key: "Pleroma.Repo"})
+ refute ConfigDB.get_by_params(%{group: ":postgrex", key: ":json_library"})
+ refute ConfigDB.get_by_params(%{group: ":pleroma", key: ":database"})
+
+ assert config1.value == [key: "value", key2: [Repo]]
+ assert config2.value == [key: "value2", key2: ["Activity"]]
+ assert config3.value == :info
+ end
+
+ test "config table is truncated before migration" do
+ insert_config_record(:pleroma, :first_setting, key: "value", key2: ["Activity"])
+ assert length(config_records()) == 1
+
+ MixTask.migrate_to_db("test/fixtures/config/temp.secret.exs")
+
+ config = ConfigDB.get_by_params(%{group: ":pleroma", key: ":first_setting"})
+ assert config.value == [key: "value", key2: [Repo]]
+ end
+ end
+
+ describe "with deletion of temp file" do
+ setup do
+ clear_config(:configurable_from_database, true)
+ temp_file = "config/temp.exported_from_db.secret.exs"
+
+ on_exit(fn ->
+ :ok = File.rm(temp_file)
+ end)
+
+ {:ok, temp_file: temp_file}
+ end
+
+ test "settings are migrated to file and deleted from db", %{temp_file: temp_file} do
+ insert_config_record(:pleroma, :setting_first, key: "value", key2: ["Activity"])
+ insert_config_record(:pleroma, :setting_second, key: "value2", key2: [Repo])
+ insert_config_record(:quack, :level, :info)
+
+ MixTask.run(["migrate_from_db", "--env", "temp", "-d"])
+
+ assert config_records() == []
+
+ file = File.read!(temp_file)
+ assert file =~ "config :pleroma, :setting_first,"
+ assert file =~ "config :pleroma, :setting_second,"
+ assert file =~ "config :quack, :level, :info"
+ end
+
+ test "load a settings with large values and pass to file", %{temp_file: temp_file} do
+ insert(:config,
+ key: :instance,
+ value: [
+ name: "Pleroma",
+ email: "example@example.com",
+ notify_email: "noreply@example.com",
+ description: "A Pleroma instance, an alternative fediverse server",
+ limit: 5_000,
+ chat_limit: 5_000,
+ remote_limit: 100_000,
+ upload_limit: 16_000_000,
+ avatar_upload_limit: 2_000_000,
+ background_upload_limit: 4_000_000,
+ banner_upload_limit: 4_000_000,
+ poll_limits: %{
+ max_options: 20,
+ max_option_chars: 200,
+ min_expiration: 0,
+ max_expiration: 365 * 24 * 60 * 60
+ },
+ registrations_open: true,
+ federating: true,
+ federation_incoming_replies_max_depth: 100,
+ federation_reachability_timeout_days: 7,
+ federation_publisher_modules: [Pleroma.Web.ActivityPub.Publisher],
+ allow_relay: true,
+ public: true,
+ quarantined_instances: [],
+ managed_config: true,
+ static_dir: "instance/static/",
+ allowed_post_formats: ["text/plain", "text/html", "text/markdown", "text/bbcode"],
+ autofollowed_nicknames: [],
+ max_pinned_statuses: 1,
+ attachment_links: false,
+ max_report_comment_size: 1000,
+ safe_dm_mentions: false,
+ healthcheck: false,
+ remote_post_retention_days: 90,
+ skip_thread_containment: true,
+ limit_to_local_content: :unauthenticated,
+ user_bio_length: 5000,
+ user_name_length: 100,
+ max_account_fields: 10,
+ max_remote_account_fields: 20,
+ account_field_name_length: 512,
+ account_field_value_length: 2048,
+ external_user_synchronization: true,
+ extended_nickname_format: true,
+ multi_factor_authentication: [
+ totp: [
+ digits: 6,
+ period: 30
+ ],
+ backup_codes: [
+ number: 2,
+ length: 6
+ ]
+ ]
+ ]
+ )
+
+ MixTask.run(["migrate_from_db", "--env", "temp", "-d"])
+
+ assert config_records() == []
+ assert File.exists?(temp_file)
+ {:ok, file} = File.read(temp_file)
+
+ assert file ==
+ "import Config\n\nconfig :pleroma, :instance,\n name: \"Pleroma\",\n email: \"example@example.com\",\n notify_email: \"noreply@example.com\",\n description: \"A Pleroma instance, an alternative fediverse server\",\n limit: 5000,\n chat_limit: 5000,\n remote_limit: 100_000,\n upload_limit: 16_000_000,\n avatar_upload_limit: 2_000_000,\n background_upload_limit: 4_000_000,\n banner_upload_limit: 4_000_000,\n poll_limits: %{\n max_expiration: 31_536_000,\n max_option_chars: 200,\n max_options: 20,\n min_expiration: 0\n },\n registrations_open: true,\n federating: true,\n federation_incoming_replies_max_depth: 100,\n federation_reachability_timeout_days: 7,\n federation_publisher_modules: [Pleroma.Web.ActivityPub.Publisher],\n allow_relay: true,\n public: true,\n quarantined_instances: [],\n managed_config: true,\n static_dir: \"instance/static/\",\n allowed_post_formats: [\"text/plain\", \"text/html\", \"text/markdown\", \"text/bbcode\"],\n autofollowed_nicknames: [],\n max_pinned_statuses: 1,\n attachment_links: false,\n max_report_comment_size: 1000,\n safe_dm_mentions: false,\n healthcheck: false,\n remote_post_retention_days: 90,\n skip_thread_containment: true,\n limit_to_local_content: :unauthenticated,\n user_bio_length: 5000,\n user_name_length: 100,\n max_account_fields: 10,\n max_remote_account_fields: 20,\n account_field_name_length: 512,\n account_field_value_length: 2048,\n external_user_synchronization: true,\n extended_nickname_format: true,\n multi_factor_authentication: [\n totp: [digits: 6, period: 30],\n backup_codes: [number: 2, length: 6]\n ]\n"
+ end
+ end
+
+ describe "migrate_from_db/1" do
+ setup do: clear_config(:configurable_from_database, true)
+
+ setup do
+ insert_config_record(:pleroma, :setting_first, key: "value", key2: ["Activity"])
+ insert_config_record(:pleroma, :setting_second, key: "value2", key2: [Repo])
+ insert_config_record(:quack, :level, :info)
+
+ path = "test/instance_static"
+ file_path = Path.join(path, "temp.exported_from_db.secret.exs")
+
+ on_exit(fn -> File.rm!(file_path) end)
+
+ [file_path: file_path]
+ end
+
+ test "with path parameter", %{file_path: file_path} do
+ MixTask.run(["migrate_from_db", "--env", "temp", "--path", Path.dirname(file_path)])
+
+ file = File.read!(file_path)
+ assert file =~ "config :pleroma, :setting_first,"
+ assert file =~ "config :pleroma, :setting_second,"
+ assert file =~ "config :quack, :level, :info"
+ end
+
+ test "release", %{file_path: file_path} do
+ clear_config(:release, true)
+ clear_config(:config_path, file_path)
+
+ MixTask.run(["migrate_from_db", "--env", "temp"])
+
+ file = File.read!(file_path)
+ assert file =~ "config :pleroma, :setting_first,"
+ assert file =~ "config :pleroma, :setting_second,"
+ assert file =~ "config :quack, :level, :info"
+ end
+ end
+
+ describe "operations on database config" do
+ setup do: clear_config(:configurable_from_database, true)
+
+ test "dumping a specific group" do
+ insert_config_record(:pleroma, :instance, name: "Pleroma Test")
+
+ insert_config_record(:web_push_encryption, :vapid_details,
+ subject: "mailto:administrator@example.com",
+ public_key:
+ "BOsPL-_KjNnjj_RMvLeR3dTOrcndi4TbMR0cu56gLGfGaT5m1gXxSfRHOcC4Dd78ycQL1gdhtx13qgKHmTM5xAI",
+ private_key: "Ism6FNdS31nLCA94EfVbJbDdJXCxAZ8cZiB1JQPN_t4"
+ )
+
+ MixTask.run(["dump", "pleroma"])
+
+ assert_receive {:mix_shell, :info,
+ ["config :pleroma, :instance, [name: \"Pleroma Test\"]\r\n\r\n"]}
+
+ refute_receive {
+ :mix_shell,
+ :info,
+ [
+ "config :web_push_encryption, :vapid_details, [subject: \"mailto:administrator@example.com\", public_key: \"BOsPL-_KjNnjj_RMvLeR3dTOrcndi4TbMR0cu56gLGfGaT5m1gXxSfRHOcC4Dd78ycQL1gdhtx13qgKHmTM5xAI\", private_key: \"Ism6FNdS31nLCA94EfVbJbDdJXCxAZ8cZiB1JQPN_t4\"]\r\n\r\n"
+ ]
+ }
+
+ # Ensure operations work when using atom syntax
+ MixTask.run(["dump", ":pleroma"])
+
+ assert_receive {:mix_shell, :info,
+ ["config :pleroma, :instance, [name: \"Pleroma Test\"]\r\n\r\n"]}
+ end
+
+ test "dumping a specific key in a group" do
+ insert_config_record(:pleroma, :instance, name: "Pleroma Test")
+ insert_config_record(:pleroma, Pleroma.Captcha, enabled: false)
+
+ MixTask.run(["dump", "pleroma", "Pleroma.Captcha"])
+
+ refute_receive {:mix_shell, :info,
+ ["config :pleroma, :instance, [name: \"Pleroma Test\"]\r\n\r\n"]}
+
+ assert_receive {:mix_shell, :info,
+ ["config :pleroma, Pleroma.Captcha, [enabled: false]\r\n\r\n"]}
+ end
+
+ test "dumps all configuration successfully" do
+ insert_config_record(:pleroma, :instance, name: "Pleroma Test")
+ insert_config_record(:pleroma, Pleroma.Captcha, enabled: false)
+
+ MixTask.run(["dump"])
+
+ assert_receive {:mix_shell, :info,
+ ["config :pleroma, :instance, [name: \"Pleroma Test\"]\r\n\r\n"]}
+
+ assert_receive {:mix_shell, :info,
+ ["config :pleroma, Pleroma.Captcha, [enabled: false]\r\n\r\n"]}
+ end
+ end
+
+ describe "when configdb disabled" do
+ test "refuses to dump" do
+ clear_config(:configurable_from_database, false)
+
+ insert_config_record(:pleroma, :instance, name: "Pleroma Test")
+
+ MixTask.run(["dump"])
+
+ msg =
+ "ConfigDB not enabled. Please check the value of :configurable_from_database in your configuration."
+
+ assert_receive {:mix_shell, :error, [^msg]}
+ end
+ end
+
+ describe "destructive operations" do
+ setup do: clear_config(:configurable_from_database, true)
+
+ setup do
+ insert_config_record(:pleroma, :instance, name: "Pleroma Test")
+ insert_config_record(:pleroma, Pleroma.Captcha, enabled: false)
+ insert_config_record(:pleroma2, :key2, z: 1)
+
+ assert length(config_records()) == 3
+
+ :ok
+ end
+
+ test "deletes group of settings" do
+ MixTask.run(["delete", "--force", "pleroma"])
+
+ assert [%ConfigDB{group: :pleroma2, key: :key2}] = config_records()
+ end
+
+ test "deletes specified key" do
+ MixTask.run(["delete", "--force", "pleroma", "Pleroma.Captcha"])
+
+ assert [
+ %ConfigDB{group: :pleroma, key: :instance},
+ %ConfigDB{group: :pleroma2, key: :key2}
+ ] = config_records()
+ end
+
+ test "resets entire config" do
+ MixTask.run(["reset", "--force"])
+
+ assert config_records() == []
+ end
+ end
+end
diff --git a/test/tasks/count_statuses_test.exs b/test/mix/tasks/pleroma/count_statuses_test.exs
index c5cd16960..80ec206b8 100644
--- a/test/tasks/count_statuses_test.exs
+++ b/test/mix/tasks/pleroma/count_statuses_test.exs
@@ -1,8 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.Tasks.Pleroma.CountStatusesTest do
+ # Uses log capture, has to stay synchronous
use Pleroma.DataCase
alias Pleroma.User
diff --git a/test/tasks/database_test.exs b/test/mix/tasks/pleroma/database_test.exs
index 3a28aa133..7a1a759da 100644
--- a/test/tasks/database_test.exs
+++ b/test/mix/tasks/pleroma/database_test.exs
@@ -1,16 +1,17 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.Tasks.Pleroma.DatabaseTest do
+ use Pleroma.DataCase, async: true
+ use Oban.Testing, repo: Pleroma.Repo
+
alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.CommonAPI
- use Pleroma.DataCase
-
import Pleroma.Factory
setup_all do
@@ -72,7 +73,7 @@ defmodule Mix.Tasks.Pleroma.DatabaseTest do
describe "running update_users_following_followers_counts" do
test "following and followers count are updated" do
[user, user2] = insert_pair(:user)
- {:ok, %User{} = user} = User.follow(user, user2)
+ {:ok, %User{} = user, _user2} = User.follow(user, user2)
following = User.following(user)
@@ -86,7 +87,8 @@ defmodule Mix.Tasks.Pleroma.DatabaseTest do
assert user.follower_count == 3
- assert :ok == Mix.Tasks.Pleroma.Database.run(["update_users_following_followers_counts"])
+ assert {:ok, :ok} ==
+ Mix.Tasks.Pleroma.Database.run(["update_users_following_followers_counts"])
user = User.get_by_id(user.id)
@@ -130,40 +132,45 @@ defmodule Mix.Tasks.Pleroma.DatabaseTest do
describe "ensure_expiration" do
test "it adds to expiration old statuses" do
- %{id: activity_id1} = insert(:note_activity)
+ activity1 = insert(:note_activity)
- %{id: activity_id2} =
- insert(:note_activity, %{inserted_at: NaiveDateTime.from_iso8601!("2015-01-23 23:50:07")})
+ {:ok, inserted_at, 0} = DateTime.from_iso8601("2015-01-23T23:50:07Z")
+ activity2 = insert(:note_activity, %{inserted_at: inserted_at})
- %{id: activity_id3} = activity3 = insert(:note_activity)
+ %{id: activity_id3} = insert(:note_activity)
- expires_at =
- NaiveDateTime.utc_now()
- |> NaiveDateTime.add(60 * 61, :second)
- |> NaiveDateTime.truncate(:second)
+ expires_at = DateTime.add(DateTime.utc_now(), 60 * 61)
- Pleroma.ActivityExpiration.create(activity3, expires_at)
+ Pleroma.Workers.PurgeExpiredActivity.enqueue(%{
+ activity_id: activity_id3,
+ expires_at: expires_at
+ })
Mix.Tasks.Pleroma.Database.run(["ensure_expiration"])
- expirations =
- Pleroma.ActivityExpiration
- |> order_by(:activity_id)
- |> Repo.all()
-
- assert [
- %Pleroma.ActivityExpiration{
- activity_id: ^activity_id1
- },
- %Pleroma.ActivityExpiration{
- activity_id: ^activity_id2,
- scheduled_at: ~N[2016-01-23 23:50:07]
- },
- %Pleroma.ActivityExpiration{
- activity_id: ^activity_id3,
- scheduled_at: ^expires_at
- }
- ] = expirations
+ assert_enqueued(
+ worker: Pleroma.Workers.PurgeExpiredActivity,
+ args: %{activity_id: activity1.id},
+ scheduled_at:
+ activity1.inserted_at
+ |> DateTime.from_naive!("Etc/UTC")
+ |> Timex.shift(days: 365)
+ )
+
+ assert_enqueued(
+ worker: Pleroma.Workers.PurgeExpiredActivity,
+ args: %{activity_id: activity2.id},
+ scheduled_at:
+ activity2.inserted_at
+ |> DateTime.from_naive!("Etc/UTC")
+ |> Timex.shift(days: 365)
+ )
+
+ assert_enqueued(
+ worker: Pleroma.Workers.PurgeExpiredActivity,
+ args: %{activity_id: activity_id3},
+ scheduled_at: expires_at
+ )
end
end
end
diff --git a/test/tasks/digest_test.exs b/test/mix/tasks/pleroma/digest_test.exs
index 0b444c86d..4a9e461a9 100644
--- a/test/tasks/digest_test.exs
+++ b/test/mix/tasks/pleroma/digest_test.exs
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Mix.Tasks.Pleroma.DigestTest do
use Pleroma.DataCase
diff --git a/test/tasks/ecto/migrate_test.exs b/test/mix/tasks/pleroma/ecto/migrate_test.exs
index 43df176a1..3bfdde1c0 100644
--- a/test/tasks/ecto/migrate_test.exs
+++ b/test/mix/tasks/pleroma/ecto/migrate_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-onl
defmodule Mix.Tasks.Pleroma.Ecto.MigrateTest do
- use Pleroma.DataCase, async: true
+ use Pleroma.DataCase
import ExUnit.CaptureLog
require Logger
@@ -13,7 +13,7 @@ defmodule Mix.Tasks.Pleroma.Ecto.MigrateTest do
assert capture_log(fn ->
Mix.Tasks.Pleroma.Ecto.Migrate.run()
- end) =~ "[info] Already up"
+ end) =~ "[info] Migrations already up"
Logger.configure(level: level)
end
diff --git a/test/tasks/ecto/rollback_test.exs b/test/mix/tasks/pleroma/ecto/rollback_test.exs
index 0236e35d5..f8a37bd49 100644
--- a/test/tasks/ecto/rollback_test.exs
+++ b/test/mix/tasks/pleroma/ecto/rollback_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.Tasks.Pleroma.Ecto.RollbackTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
import ExUnit.CaptureLog
require Logger
@@ -12,7 +12,7 @@ defmodule Mix.Tasks.Pleroma.Ecto.RollbackTest do
Logger.configure(level: :warn)
assert capture_log(fn ->
- Mix.Tasks.Pleroma.Ecto.Rollback.run()
+ Mix.Tasks.Pleroma.Ecto.Rollback.run(["--env", "test"])
end) =~ "[info] Rollback succesfully"
Logger.configure(level: level)
diff --git a/test/tasks/ecto/ecto_test.exs b/test/mix/tasks/pleroma/ecto_test.exs
index 3a028df83..0164da5a8 100644
--- a/test/tasks/ecto/ecto_test.exs
+++ b/test/mix/tasks/pleroma/ecto_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.Tasks.Pleroma.EctoTest do
diff --git a/test/mix/tasks/pleroma/email_test.exs b/test/mix/tasks/pleroma/email_test.exs
new file mode 100644
index 000000000..ce68b88de
--- /dev/null
+++ b/test/mix/tasks/pleroma/email_test.exs
@@ -0,0 +1,127 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Mix.Tasks.Pleroma.EmailTest do
+ use Pleroma.DataCase
+
+ import Swoosh.TestAssertions
+
+ alias Pleroma.Config
+ alias Pleroma.Tests.ObanHelpers
+
+ import Pleroma.Factory
+
+ setup_all do
+ Mix.shell(Mix.Shell.Process)
+
+ on_exit(fn ->
+ Mix.shell(Mix.Shell.IO)
+ end)
+
+ :ok
+ end
+
+ setup do: clear_config([Pleroma.Emails.Mailer, :enabled], true)
+ setup do: clear_config([:instance, :account_activation_required], true)
+
+ describe "pleroma.email test" do
+ test "Sends test email with no given address" do
+ mail_to = Config.get([:instance, :email])
+
+ :ok = Mix.Tasks.Pleroma.Email.run(["test"])
+
+ ObanHelpers.perform_all()
+
+ assert_receive {:mix_shell, :info, [message]}
+ assert message =~ "Test email has been sent"
+
+ assert_email_sent(
+ to: mail_to,
+ html_body: ~r/a test email was requested./i
+ )
+ end
+
+ test "Sends test email with given address" do
+ mail_to = "hewwo@example.com"
+
+ :ok = Mix.Tasks.Pleroma.Email.run(["test", "--to", mail_to])
+
+ ObanHelpers.perform_all()
+
+ assert_receive {:mix_shell, :info, [message]}
+ assert message =~ "Test email has been sent"
+
+ assert_email_sent(
+ to: mail_to,
+ html_body: ~r/a test email was requested./i
+ )
+ end
+
+ test "Sends confirmation emails" do
+ local_user1 =
+ insert(:user, %{
+ is_confirmed: false,
+ confirmation_token: "mytoken",
+ is_active: true,
+ email: "local1@pleroma.com",
+ local: true
+ })
+
+ local_user2 =
+ insert(:user, %{
+ is_confirmed: false,
+ confirmation_token: "mytoken",
+ is_active: true,
+ email: "local2@pleroma.com",
+ local: true
+ })
+
+ :ok = Mix.Tasks.Pleroma.Email.run(["resend_confirmation_emails"])
+
+ ObanHelpers.perform_all()
+
+ assert_email_sent(to: {local_user1.name, local_user1.email})
+ assert_email_sent(to: {local_user2.name, local_user2.email})
+ end
+
+ test "Does not send confirmation email to inappropriate users" do
+ # confirmed user
+ insert(:user, %{
+ is_confirmed: true,
+ confirmation_token: "mytoken",
+ is_active: true,
+ email: "confirmed@pleroma.com",
+ local: true
+ })
+
+ # remote user
+ insert(:user, %{
+ is_active: true,
+ email: "remote@not-pleroma.com",
+ local: false
+ })
+
+ # deactivated user =
+ insert(:user, %{
+ is_active: false,
+ email: "deactivated@pleroma.com",
+ local: false
+ })
+
+ # invisible user
+ insert(:user, %{
+ is_active: true,
+ email: "invisible@pleroma.com",
+ local: true,
+ invisible: true
+ })
+
+ :ok = Mix.Tasks.Pleroma.Email.run(["resend_confirmation_emails"])
+
+ ObanHelpers.perform_all()
+
+ refute_email_sent()
+ end
+ end
+end
diff --git a/test/tasks/emoji_test.exs b/test/mix/tasks/pleroma/emoji_test.exs
index 499f098c2..bd20f285c 100644
--- a/test/tasks/emoji_test.exs
+++ b/test/mix/tasks/pleroma/emoji_test.exs
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Mix.Tasks.Pleroma.EmojiTest do
use ExUnit.Case, async: true
diff --git a/test/tasks/frontend_test.exs b/test/mix/tasks/pleroma/frontend_test.exs
index 022ae51be..aa4b25ebb 100644
--- a/test/tasks/frontend_test.exs
+++ b/test/mix/tasks/pleroma/frontend_test.exs
@@ -1,8 +1,8 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.FrontendTest do
+defmodule Mix.Tasks.Pleroma.FrontendTest do
use Pleroma.DataCase
alias Mix.Tasks.Pleroma.Frontend
diff --git a/test/tasks/instance_test.exs b/test/mix/tasks/pleroma/instance_test.exs
index 3b4c041d9..5a5a68053 100644
--- a/test/tasks/instance_test.exs
+++ b/test/mix/tasks/pleroma/instance_test.exs
@@ -1,9 +1,10 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.InstanceTest do
- use ExUnit.Case
+defmodule Mix.Tasks.Pleroma.InstanceTest do
+ # Modifies the Application Environment, has to stay synchronous.
+ use Pleroma.DataCase
setup do
File.mkdir_p!(tmp_path())
@@ -15,15 +16,17 @@ defmodule Pleroma.InstanceTest do
if File.exists?(static_dir) do
File.rm_rf(Path.join(static_dir, "robots.txt"))
end
-
- Pleroma.Config.put([:instance, :static_dir], static_dir)
end)
+ # Is being modified by the mix task.
+ clear_config([:instance, :static_dir])
+
:ok
end
+ @uuid Ecto.UUID.generate()
defp tmp_path do
- "/tmp/generated_files/"
+ "/tmp/generated_files/#{@uuid}/"
end
test "running gen" do
@@ -63,7 +66,13 @@ defmodule Pleroma.InstanceTest do
"--uploads-dir",
"test/uploads",
"--static-dir",
- "./test/../test/instance/static/"
+ "./test/../test/instance/static/",
+ "--strip-uploads",
+ "y",
+ "--dedupe-uploads",
+ "n",
+ "--anonymize-uploads",
+ "n"
])
end
@@ -82,6 +91,7 @@ defmodule Pleroma.InstanceTest do
assert generated_config =~ "password: \"dbpass\""
assert generated_config =~ "configurable_from_database: true"
assert generated_config =~ "http: [ip: {127, 0, 0, 1}, port: 4000]"
+ assert generated_config =~ "filters: [Pleroma.Upload.Filter.Exiftool]"
assert File.read!(tmp_path() <> "setup.psql") == generated_setup_psql()
assert File.exists?(Path.expand("./test/instance/static/robots.txt"))
end
diff --git a/test/tasks/refresh_counter_cache_test.exs b/test/mix/tasks/pleroma/refresh_counter_cache_test.exs
index 6a1a9ac17..fe9e5cfeb 100644
--- a/test/tasks/refresh_counter_cache_test.exs
+++ b/test/mix/tasks/pleroma/refresh_counter_cache_test.exs
@@ -1,8 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.Tasks.Pleroma.RefreshCounterCacheTest do
+ # Uses log capture, has to stay synchronous
use Pleroma.DataCase
alias Pleroma.Web.CommonAPI
import ExUnit.CaptureIO, only: [capture_io: 1]
diff --git a/test/tasks/relay_test.exs b/test/mix/tasks/pleroma/relay_test.exs
index e5225b64c..db75b3630 100644
--- a/test/tasks/relay_test.exs
+++ b/test/mix/tasks/pleroma/relay_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.Tasks.Pleroma.RelayTest do
@@ -81,6 +81,80 @@ defmodule Mix.Tasks.Pleroma.RelayTest do
assert undo_activity.data["object"]["id"] == cancelled_activity.data["id"]
refute "#{target_instance}/followers" in User.following(local_user)
end
+
+ test "unfollow when relay is dead" do
+ user = insert(:user)
+ target_instance = user.ap_id
+
+ Mix.Tasks.Pleroma.Relay.run(["follow", target_instance])
+
+ %User{ap_id: follower_id} = local_user = Relay.get_actor()
+ target_user = User.get_cached_by_ap_id(target_instance)
+ follow_activity = Utils.fetch_latest_follow(local_user, target_user)
+ User.follow(local_user, target_user)
+
+ assert "#{target_instance}/followers" in User.following(local_user)
+
+ Tesla.Mock.mock(fn %{method: :get, url: ^target_instance} ->
+ %Tesla.Env{status: 404}
+ end)
+
+ Pleroma.Repo.delete(user)
+ User.invalidate_cache(user)
+
+ Mix.Tasks.Pleroma.Relay.run(["unfollow", target_instance])
+
+ cancelled_activity = Activity.get_by_ap_id(follow_activity.data["id"])
+ assert cancelled_activity.data["state"] == "accept"
+
+ assert [] ==
+ ActivityPub.fetch_activities(
+ [],
+ %{
+ type: "Undo",
+ actor_id: follower_id,
+ skip_preload: true,
+ invisible_actors: true
+ }
+ )
+ end
+
+ test "force unfollow when relay is dead" do
+ user = insert(:user)
+ target_instance = user.ap_id
+
+ Mix.Tasks.Pleroma.Relay.run(["follow", target_instance])
+
+ %User{ap_id: follower_id} = local_user = Relay.get_actor()
+ target_user = User.get_cached_by_ap_id(target_instance)
+ follow_activity = Utils.fetch_latest_follow(local_user, target_user)
+ User.follow(local_user, target_user)
+
+ assert "#{target_instance}/followers" in User.following(local_user)
+
+ Tesla.Mock.mock(fn %{method: :get, url: ^target_instance} ->
+ %Tesla.Env{status: 404}
+ end)
+
+ Pleroma.Repo.delete(user)
+ User.invalidate_cache(user)
+
+ Mix.Tasks.Pleroma.Relay.run(["unfollow", target_instance, "--force"])
+
+ cancelled_activity = Activity.get_by_ap_id(follow_activity.data["id"])
+ assert cancelled_activity.data["state"] == "cancelled"
+
+ [undo_activity] =
+ ActivityPub.fetch_activities(
+ [],
+ %{type: "Undo", actor_id: follower_id, skip_preload: true, invisible_actors: true}
+ )
+
+ assert undo_activity.data["type"] == "Undo"
+ assert undo_activity.data["actor"] == local_user.ap_id
+ assert undo_activity.data["object"]["id"] == cancelled_activity.data["id"]
+ refute "#{target_instance}/followers" in User.following(local_user)
+ end
end
describe "mix pleroma.relay list" do
diff --git a/test/tasks/robots_txt_test.exs b/test/mix/tasks/pleroma/robots_txt_test.exs
index 7040a0e4e..028aa4ccc 100644
--- a/test/tasks/robots_txt_test.exs
+++ b/test/mix/tasks/pleroma/robots_txt_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.Tasks.Pleroma.RobotsTxtTest do
@@ -12,7 +12,7 @@ defmodule Mix.Tasks.Pleroma.RobotsTxtTest do
test "creates new dir" do
path = "test/fixtures/new_dir/"
file_path = path <> "robots.txt"
- Pleroma.Config.put([:instance, :static_dir], path)
+ clear_config([:instance, :static_dir], path)
on_exit(fn ->
{:ok, ["test/fixtures/new_dir/", "test/fixtures/new_dir/robots.txt"]} = File.rm_rf(path)
@@ -29,7 +29,7 @@ defmodule Mix.Tasks.Pleroma.RobotsTxtTest do
test "to existance folder" do
path = "test/fixtures/"
file_path = path <> "robots.txt"
- Pleroma.Config.put([:instance, :static_dir], path)
+ clear_config([:instance, :static_dir], path)
on_exit(fn ->
:ok = File.rm(file_path)
diff --git a/test/tasks/uploads_test.exs b/test/mix/tasks/pleroma/uploads_test.exs
index d69e149a8..a7d15e0fa 100644
--- a/test/tasks/uploads_test.exs
+++ b/test/mix/tasks/pleroma/uploads_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.Tasks.Pleroma.UploadsTest do
diff --git a/test/tasks/user_test.exs b/test/mix/tasks/pleroma/user_test.exs
index ce43a9cc7..a2178bbd1 100644
--- a/test/tasks/user_test.exs
+++ b/test/mix/tasks/pleroma/user_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.Tasks.Pleroma.UserTest do
@@ -36,7 +36,7 @@ defmodule Mix.Tasks.Pleroma.UserTest do
unsaved = build(:user)
# prepare to answer yes
- send(self(), {:mix_shell_input, :yes?, true})
+ send(self(), {:mix_shell_input, :prompt, "Y"})
Mix.Tasks.Pleroma.User.run([
"new",
@@ -55,7 +55,7 @@ defmodule Mix.Tasks.Pleroma.UserTest do
assert_received {:mix_shell, :info, [message]}
assert message =~ "user will be created"
- assert_received {:mix_shell, :yes?, [message]}
+ assert_received {:mix_shell, :prompt, [message]}
assert message =~ "Continue"
assert_received {:mix_shell, :info, [message]}
@@ -73,14 +73,14 @@ defmodule Mix.Tasks.Pleroma.UserTest do
unsaved = build(:user)
# prepare to answer no
- send(self(), {:mix_shell_input, :yes?, false})
+ send(self(), {:mix_shell_input, :prompt, "N"})
Mix.Tasks.Pleroma.User.run(["new", unsaved.nickname, unsaved.email])
assert_received {:mix_shell, :info, [message]}
assert message =~ "user will be created"
- assert_received {:mix_shell, :yes?, [message]}
+ assert_received {:mix_shell, :prompt, [message]}
assert message =~ "Continue"
assert_received {:mix_shell, :info, [message]}
@@ -102,7 +102,7 @@ defmodule Mix.Tasks.Pleroma.UserTest do
assert_received {:mix_shell, :info, [message]}
assert message =~ " deleted"
- assert %{deactivated: true} = User.get_by_nickname(user.nickname)
+ assert %{is_active: false} = User.get_by_nickname(user.nickname)
assert called(Pleroma.Web.Federator.publish(:_))
end
@@ -114,7 +114,7 @@ defmodule Mix.Tasks.Pleroma.UserTest do
{:ok, post} = CommonAPI.post(user, %{status: "uguu"})
{:ok, post2} = CommonAPI.post(user2, %{status: "test"})
- obj = Object.normalize(post2)
+ obj = Object.normalize(post2, fetch: false)
{:ok, like_object, meta} = Pleroma.Web.ActivityPub.Builder.like(user, obj)
@@ -130,7 +130,7 @@ defmodule Mix.Tasks.Pleroma.UserTest do
clear_config([:instance, :federating], true)
- object = Object.normalize(post)
+ object = Object.normalize(post, fetch: false)
Object.prune(object)
with_mock Pleroma.Web.Federator,
@@ -140,7 +140,7 @@ defmodule Mix.Tasks.Pleroma.UserTest do
assert_received {:mix_shell, :info, [message]}
assert message =~ " deleted"
- assert %{deactivated: true} = User.get_by_nickname(user.nickname)
+ assert %{is_active: false} = User.get_by_nickname(user.nickname)
assert called(Pleroma.Web.Federator.publish(:_))
refute Pleroma.Repo.get(Pleroma.Activity, like_activity.id)
@@ -157,41 +157,8 @@ defmodule Mix.Tasks.Pleroma.UserTest do
end
end
- describe "running toggle_activated" do
- test "user is deactivated" do
- user = insert(:user)
-
- Mix.Tasks.Pleroma.User.run(["toggle_activated", user.nickname])
-
- assert_received {:mix_shell, :info, [message]}
- assert message =~ " deactivated"
-
- user = User.get_cached_by_nickname(user.nickname)
- assert user.deactivated
- end
-
- test "user is activated" do
- user = insert(:user, deactivated: true)
-
- Mix.Tasks.Pleroma.User.run(["toggle_activated", user.nickname])
-
- assert_received {:mix_shell, :info, [message]}
- assert message =~ " activated"
-
- user = User.get_cached_by_nickname(user.nickname)
- refute user.deactivated
- end
-
- test "no user to toggle" do
- Mix.Tasks.Pleroma.User.run(["toggle_activated", "nonexistent"])
-
- assert_received {:mix_shell, :error, [message]}
- assert message =~ "No user"
- end
- end
-
describe "running deactivate" do
- test "user is unsubscribed" do
+ test "active user is deactivated and unsubscribed" do
followed = insert(:user)
remote_followed = insert(:user, local: false)
user = insert(:user)
@@ -201,16 +168,26 @@ defmodule Mix.Tasks.Pleroma.UserTest do
Mix.Tasks.Pleroma.User.run(["deactivate", user.nickname])
- assert_received {:mix_shell, :info, [message]}
- assert message =~ "Deactivating"
-
# Note that the task has delay :timer.sleep(500)
assert_received {:mix_shell, :info, [message]}
- assert message =~ "Successfully unsubscribed"
+
+ assert message ==
+ "Successfully deactivated #{user.nickname} and unsubscribed all local followers"
user = User.get_cached_by_nickname(user.nickname)
assert Enum.empty?(Enum.filter(User.get_friends(user), & &1.local))
- assert user.deactivated
+ refute user.is_active
+ end
+
+ test "user is deactivated" do
+ %{id: id, nickname: nickname} = insert(:user, is_active: false)
+
+ assert :ok = Mix.Tasks.Pleroma.User.run(["deactivate", nickname])
+ assert_received {:mix_shell, :info, [message]}
+ assert message == "User #{nickname} already deactivated"
+
+ user = Repo.get(User, id)
+ refute user.is_active
end
test "no user to deactivate" do
@@ -225,47 +202,69 @@ defmodule Mix.Tasks.Pleroma.UserTest do
test "All statuses set" do
user = insert(:user)
- Mix.Tasks.Pleroma.User.run(["set", user.nickname, "--moderator", "--admin", "--locked"])
+ Mix.Tasks.Pleroma.User.run([
+ "set",
+ user.nickname,
+ "--admin",
+ "--confirmed",
+ "--locked",
+ "--moderator"
+ ])
+
+ assert_received {:mix_shell, :info, [message]}
+ assert message =~ ~r/Admin status .* true/
assert_received {:mix_shell, :info, [message]}
- assert message =~ ~r/Moderator status .* true/
+ assert message =~ ~r/Confirmation status.* true/
assert_received {:mix_shell, :info, [message]}
assert message =~ ~r/Locked status .* true/
assert_received {:mix_shell, :info, [message]}
- assert message =~ ~r/Admin status .* true/
+ assert message =~ ~r/Moderator status .* true/
user = User.get_cached_by_nickname(user.nickname)
assert user.is_moderator
- assert user.locked
+ assert user.is_locked
assert user.is_admin
+ assert user.is_confirmed
end
test "All statuses unset" do
- user = insert(:user, locked: true, is_moderator: true, is_admin: true)
+ user =
+ insert(:user,
+ is_locked: true,
+ is_moderator: true,
+ is_admin: true,
+ is_confirmed: false
+ )
Mix.Tasks.Pleroma.User.run([
"set",
user.nickname,
- "--no-moderator",
"--no-admin",
- "--no-locked"
+ "--no-confirmed",
+ "--no-locked",
+ "--no-moderator"
])
assert_received {:mix_shell, :info, [message]}
- assert message =~ ~r/Moderator status .* false/
+ assert message =~ ~r/Admin status .* false/
+
+ assert_received {:mix_shell, :info, [message]}
+ assert message =~ ~r/Confirmation status.* false/
assert_received {:mix_shell, :info, [message]}
assert message =~ ~r/Locked status .* false/
assert_received {:mix_shell, :info, [message]}
- assert message =~ ~r/Admin status .* false/
+ assert message =~ ~r/Moderator status .* false/
user = User.get_cached_by_nickname(user.nickname)
refute user.is_moderator
- refute user.locked
+ refute user.is_locked
refute user.is_admin
+ refute user.is_confirmed
end
test "no user to set status" do
@@ -414,13 +413,6 @@ defmodule Mix.Tasks.Pleroma.UserTest do
assert_received {:mix_shell, :info, [message]}
assert message =~ "Invite for token #{invite.token} was revoked."
end
-
- test "it prints an error message when invite is not exist" do
- Mix.Tasks.Pleroma.User.run(["revoke_invite", "foo"])
-
- assert_received {:mix_shell, :error, [message]}
- assert message =~ "No invite found"
- end
end
describe "running delete_activities" do
@@ -440,40 +432,71 @@ defmodule Mix.Tasks.Pleroma.UserTest do
end
end
- describe "running toggle_confirmed" do
+ describe "running confirm" do
test "user is confirmed" do
- %{id: id, nickname: nickname} = insert(:user, confirmation_pending: false)
+ %{id: id, nickname: nickname} = insert(:user, is_confirmed: true)
- assert :ok = Mix.Tasks.Pleroma.User.run(["toggle_confirmed", nickname])
+ assert :ok = Mix.Tasks.Pleroma.User.run(["confirm", nickname])
assert_received {:mix_shell, :info, [message]}
- assert message == "#{nickname} needs confirmation."
+ assert message == "#{nickname} doesn't need confirmation."
user = Repo.get(User, id)
- assert user.confirmation_pending
- assert user.confirmation_token
+ assert user.is_confirmed
+ refute user.confirmation_token
end
test "user is not confirmed" do
%{id: id, nickname: nickname} =
- insert(:user, confirmation_pending: true, confirmation_token: "some token")
+ insert(:user, is_confirmed: false, confirmation_token: "some token")
- assert :ok = Mix.Tasks.Pleroma.User.run(["toggle_confirmed", nickname])
+ assert :ok = Mix.Tasks.Pleroma.User.run(["confirm", nickname])
assert_received {:mix_shell, :info, [message]}
assert message == "#{nickname} doesn't need confirmation."
user = Repo.get(User, id)
- refute user.confirmation_pending
+ assert user.is_confirmed
refute user.confirmation_token
end
test "it prints an error message when user is not exist" do
- Mix.Tasks.Pleroma.User.run(["toggle_confirmed", "foo"])
+ Mix.Tasks.Pleroma.User.run(["confirm", "foo"])
assert_received {:mix_shell, :error, [message]}
assert message =~ "No local user"
end
end
+ describe "running activate" do
+ test "user is activated" do
+ %{id: id, nickname: nickname} = insert(:user, is_active: true)
+
+ assert :ok = Mix.Tasks.Pleroma.User.run(["activate", nickname])
+ assert_received {:mix_shell, :info, [message]}
+ assert message == "User #{nickname} already activated"
+
+ user = Repo.get(User, id)
+ assert user.is_active
+ end
+
+ test "user is not activated" do
+ %{id: id, nickname: nickname} = insert(:user, is_active: false)
+
+ assert :ok = Mix.Tasks.Pleroma.User.run(["activate", nickname])
+ assert_received {:mix_shell, :info, [message]}
+ assert message == "Successfully activated #{nickname}"
+
+ user = Repo.get(User, id)
+ assert user.is_active
+ end
+
+ test "no user to activate" do
+ Mix.Tasks.Pleroma.User.run(["activate", "foo"])
+
+ assert_received {:mix_shell, :error, [message]}
+ assert message =~ "No user"
+ end
+ end
+
describe "search" do
test "it returns users matching" do
user = insert(:user)
@@ -481,7 +504,7 @@ defmodule Mix.Tasks.Pleroma.UserTest do
moot = insert(:user, nickname: "moot")
kawen = insert(:user, nickname: "kawen", name: "fediverse expert moon")
- {:ok, user} = User.follow(user, moon)
+ {:ok, user, moon} = User.follow(user, moon)
assert [moon.id, kawen.id] == User.Search.search("moon") |> Enum.map(& &1.id)
@@ -554,4 +577,44 @@ defmodule Mix.Tasks.Pleroma.UserTest do
assert message =~ "Could not change user tags"
end
end
+
+ describe "bulk confirm and unconfirm" do
+ test "confirm all" do
+ user1 = insert(:user, is_confirmed: false)
+ user2 = insert(:user, is_confirmed: false)
+
+ refute user1.is_confirmed
+ refute user2.is_confirmed
+
+ Mix.Tasks.Pleroma.User.run(["confirm_all"])
+
+ user1 = User.get_cached_by_nickname(user1.nickname)
+ user2 = User.get_cached_by_nickname(user2.nickname)
+
+ assert user1.is_confirmed
+ assert user2.is_confirmed
+ end
+
+ test "unconfirm all" do
+ user1 = insert(:user, is_confirmed: true)
+ user2 = insert(:user, is_confirmed: true)
+ admin = insert(:user, is_admin: true, is_confirmed: true)
+ mod = insert(:user, is_moderator: true, is_confirmed: true)
+
+ assert user1.is_confirmed
+ assert user2.is_confirmed
+
+ Mix.Tasks.Pleroma.User.run(["unconfirm_all"])
+
+ user1 = User.get_cached_by_nickname(user1.nickname)
+ user2 = User.get_cached_by_nickname(user2.nickname)
+ admin = User.get_cached_by_nickname(admin.nickname)
+ mod = User.get_cached_by_nickname(mod.nickname)
+
+ refute user1.is_confirmed
+ refute user2.is_confirmed
+ assert admin.is_confirmed
+ assert mod.is_confirmed
+ end
+ end
end
diff --git a/test/activity/ir/topics_test.exs b/test/pleroma/activity/ir/topics_test.exs
index 14a6e6b71..9c8e5d932 100644
--- a/test/activity/ir/topics_test.exs
+++ b/test/pleroma/activity/ir/topics_test.exs
@@ -1,5 +1,9 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Activity.Ir.TopicsTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Activity
alias Pleroma.Activity.Ir.Topics
@@ -7,6 +11,8 @@ defmodule Pleroma.Activity.Ir.TopicsTest do
require Pleroma.Constants
+ import Mock
+
describe "poll answer" do
test "produce no topics" do
activity = %Activity{object: %Object{data: %{"type" => "Answer"}}}
@@ -73,14 +79,13 @@ defmodule Pleroma.Activity.Ir.TopicsTest do
refute Enum.member?(topics, "public:local:media")
end
- test "converts tags to hash tags", %{activity: %{object: %{data: data} = object} = activity} do
- tagged_data = Map.put(data, "tag", ["foo", "bar"])
- activity = %{activity | object: %{object | data: tagged_data}}
-
- topics = Topics.get_activity_topics(activity)
+ test "converts tags to hash tags", %{activity: activity} do
+ with_mock(Object, [:passthrough], hashtags: fn _ -> ["foo", "bar"] end) do
+ topics = Topics.get_activity_topics(activity)
- assert Enum.member?(topics, "hashtag:foo")
- assert Enum.member?(topics, "hashtag:bar")
+ assert Enum.member?(topics, "hashtag:foo")
+ assert Enum.member?(topics, "hashtag:bar")
+ end
end
test "only converts strings to hash tags", %{
@@ -93,6 +98,20 @@ defmodule Pleroma.Activity.Ir.TopicsTest do
refute Enum.member?(topics, "hashtag:2")
end
+
+ test "non-local action produces public:remote topic", %{activity: activity} do
+ activity = %{activity | local: false, actor: "https://lain.com/users/lain"}
+ topics = Topics.get_activity_topics(activity)
+
+ assert Enum.member?(topics, "public:remote:lain.com")
+ end
+
+ test "local action doesn't produce public:remote topic", %{activity: activity} do
+ activity = %{activity | local: true, actor: "https://lain.com/users/lain"}
+ topics = Topics.get_activity_topics(activity)
+
+ refute Enum.member?(topics, "public:remote:lain.com")
+ end
end
describe "public visibility create events with attachments" do
@@ -124,6 +143,13 @@ defmodule Pleroma.Activity.Ir.TopicsTest do
refute Enum.member?(topics, "public:local:media")
end
+
+ test "non-local action produces public:remote:media topic", %{activity: activity} do
+ activity = %{activity | local: false, actor: "https://lain.com/users/lain"}
+ topics = Topics.get_activity_topics(activity)
+
+ assert Enum.member?(topics, "public:remote:media:lain.com")
+ end
end
describe "non-public visibility" do
diff --git a/test/pleroma/activity/search_test.exs b/test/pleroma/activity/search_test.exs
new file mode 100644
index 000000000..657fbc627
--- /dev/null
+++ b/test/pleroma/activity/search_test.exs
@@ -0,0 +1,45 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Activity.SearchTest do
+ alias Pleroma.Activity.Search
+ alias Pleroma.Web.CommonAPI
+ import Pleroma.Factory
+
+ use Pleroma.DataCase, async: true
+
+ test "it finds something" do
+ user = insert(:user)
+ {:ok, post} = CommonAPI.post(user, %{status: "it's wednesday my dudes"})
+
+ [result] = Search.search(nil, "wednesday")
+
+ assert result.id == post.id
+ end
+
+ test "using plainto_tsquery on postgres < 11" do
+ old_version = :persistent_term.get({Pleroma.Repo, :postgres_version})
+ :persistent_term.put({Pleroma.Repo, :postgres_version}, 10.0)
+ on_exit(fn -> :persistent_term.put({Pleroma.Repo, :postgres_version}, old_version) end)
+
+ user = insert(:user)
+ {:ok, post} = CommonAPI.post(user, %{status: "it's wednesday my dudes"})
+ {:ok, _post2} = CommonAPI.post(user, %{status: "it's wednesday my bros"})
+
+ # plainto doesn't understand complex queries
+ assert [result] = Search.search(nil, "wednesday -dudes")
+
+ assert result.id == post.id
+ end
+
+ test "using websearch_to_tsquery" do
+ user = insert(:user)
+ {:ok, _post} = CommonAPI.post(user, %{status: "it's wednesday my dudes"})
+ {:ok, other_post} = CommonAPI.post(user, %{status: "it's wednesday my bros"})
+
+ assert [result] = Search.search(nil, "wednesday -dudes")
+
+ assert result.id == other_post.id
+ end
+end
diff --git a/test/activity_test.exs b/test/pleroma/activity_test.exs
index 2a92327d1..4f9144f91 100644
--- a/test/activity_test.exs
+++ b/test/pleroma/activity_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.ActivityTest do
@@ -25,7 +25,7 @@ defmodule Pleroma.ActivityTest do
test "returns activities by it's objects AP ids" do
activity = insert(:note_activity)
- object_data = Object.normalize(activity).data
+ object_data = Object.normalize(activity, fetch: false).data
[found_activity] = Activity.get_all_create_by_object_ap_id(object_data["id"])
@@ -34,7 +34,7 @@ defmodule Pleroma.ActivityTest do
test "returns the activity that created an object" do
activity = insert(:note_activity)
- object_data = Object.normalize(activity).data
+ object_data = Object.normalize(activity, fetch: false).data
found_activity = Activity.get_create_by_object_ap_id(object_data["id"])
@@ -123,7 +123,8 @@ defmodule Pleroma.ActivityTest do
"type" => "Note",
"content" => "find me!",
"id" => "http://mastodon.example.org/users/admin/objects/1",
- "attributedTo" => "http://mastodon.example.org/users/admin"
+ "attributedTo" => "http://mastodon.example.org/users/admin",
+ "to" => ["https://www.w3.org/ns/activitystreams#Public"]
},
"to" => ["https://www.w3.org/ns/activitystreams#Public"]
}
@@ -132,6 +133,7 @@ defmodule Pleroma.ActivityTest do
{:ok, japanese_activity} = Pleroma.Web.CommonAPI.post(user, %{status: "更新情報"})
{:ok, job} = Pleroma.Web.Federator.incoming_ap_doc(params)
{:ok, remote_activity} = ObanHelpers.perform(job)
+ remote_activity = Activity.get_by_id_with_object(remote_activity.id)
%{
japanese_activity: japanese_activity,
@@ -168,7 +170,7 @@ defmodule Pleroma.ActivityTest do
test "find only local statuses for unauthenticated users when `limit_to_local_content` is `:all`",
%{local_activity: local_activity} do
- Pleroma.Config.put([:instance, :limit_to_local_content], :all)
+ clear_config([:instance, :limit_to_local_content], :all)
assert [^local_activity] = Activity.search(nil, "find me")
end
@@ -177,7 +179,7 @@ defmodule Pleroma.ActivityTest do
local_activity: local_activity,
remote_activity: remote_activity
} do
- Pleroma.Config.put([:instance, :limit_to_local_content], false)
+ clear_config([:instance, :limit_to_local_content], false)
activities = Enum.sort_by(Activity.search(nil, "find me"), & &1.id)
@@ -185,15 +187,6 @@ defmodule Pleroma.ActivityTest do
end
end
- test "add an activity with an expiration" do
- activity = insert(:note_activity)
- insert(:expiration_in_the_future, %{activity_id: activity.id})
-
- Pleroma.ActivityExpiration
- |> where([a], a.activity_id == ^activity.id)
- |> Repo.one!()
- end
-
test "all_by_ids_with_object/1" do
%{id: id1} = insert(:note_activity)
%{id: id2} = insert(:note_activity)
@@ -206,6 +199,13 @@ defmodule Pleroma.ActivityTest do
assert [%{id: ^id1, object: %Object{}}, %{id: ^id2, object: %Object{}}] = activities
end
+ test "get_by_id_with_user_actor/1" do
+ user = insert(:user)
+ activity = insert(:note_activity, note: insert(:note, user: user))
+
+ assert Activity.get_by_id_with_user_actor(activity.id).user_actor == user
+ end
+
test "get_by_id_with_object/1" do
%{id: id} = insert(:note_activity)
@@ -240,4 +240,42 @@ defmodule Pleroma.ActivityTest do
assert [%Activity{id: ^id1}, %Activity{id: ^id2}] = activities
end
+
+ test "get_by_object_ap_id_with_object/1" do
+ user = insert(:user)
+ another = insert(:user)
+
+ {:ok, %{id: id, object: %{data: %{"id" => obj_id}}}} =
+ Pleroma.Web.CommonAPI.post(user, %{status: "cofe"})
+
+ Pleroma.Web.CommonAPI.favorite(another, id)
+
+ assert obj_id
+ |> Pleroma.Activity.Queries.by_object_id()
+ |> Repo.aggregate(:count, :id) == 2
+
+ assert %{id: ^id} = Activity.get_by_object_ap_id_with_object(obj_id)
+ end
+
+ test "add_by_params_query/3" do
+ user = insert(:user)
+
+ note = insert(:note_activity, user: user)
+
+ insert(:add_activity, user: user, note: note)
+ insert(:add_activity, user: user, note: note)
+ insert(:add_activity, user: user)
+
+ assert Repo.aggregate(Activity, :count, :id) == 4
+
+ add_query =
+ Activity.add_by_params_query(note.data["object"], user.ap_id, user.featured_address)
+
+ assert Repo.aggregate(add_query, :count, :id) == 2
+
+ Repo.delete_all(add_query)
+ assert Repo.aggregate(add_query, :count, :id) == 0
+
+ assert Repo.aggregate(Activity, :count, :id) == 2
+ end
end
diff --git a/test/application_requirements_test.exs b/test/pleroma/application_requirements_test.exs
index 21d24ddd0..a54c37968 100644
--- a/test/application_requirements_test.exs
+++ b/test/pleroma/application_requirements_test.exs
@@ -1,25 +1,47 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.ApplicationRequirementsTest do
use Pleroma.DataCase
+
import ExUnit.CaptureLog
import Mock
+ alias Pleroma.ApplicationRequirements
alias Pleroma.Repo
+ describe "check_repo_pool_size!/1" do
+ test "raises if the pool size is unexpected" do
+ clear_config([Pleroma.Repo, :pool_size], 11)
+ clear_config([:dangerzone, :override_repo_pool_size], false)
+
+ assert_raise Pleroma.ApplicationRequirements.VerifyError,
+ "Repo.pool_size different than recommended value.",
+ fn ->
+ capture_log(&Pleroma.ApplicationRequirements.verify!/0)
+ end
+ end
+
+ test "doesn't raise if the pool size is unexpected but the respective flag is set" do
+ clear_config([Pleroma.Repo, :pool_size], 11)
+ clear_config([:dangerzone, :override_repo_pool_size], true)
+
+ assert Pleroma.ApplicationRequirements.verify!() == :ok
+ end
+ end
+
describe "check_welcome_message_config!/1" do
setup do: clear_config([:welcome])
setup do: clear_config([Pleroma.Emails.Mailer])
- test "raises if welcome email enabled but mail disabled" do
- Pleroma.Config.put([:welcome, :email, :enabled], true)
- Pleroma.Config.put([Pleroma.Emails.Mailer, :enabled], false)
+ test "warns if welcome email enabled but mail disabled" do
+ clear_config([:welcome, :email, :enabled], true)
+ clear_config([Pleroma.Emails.Mailer, :enabled], false)
- assert_raise Pleroma.ApplicationRequirements.VerifyError, "The mail disabled.", fn ->
- capture_log(&Pleroma.ApplicationRequirements.verify!/0)
- end
+ assert capture_log(fn ->
+ assert Pleroma.ApplicationRequirements.verify!() == :ok
+ end) =~ "Welcome emails will NOT be sent"
end
end
@@ -35,26 +57,24 @@ defmodule Pleroma.ApplicationRequirementsTest do
setup do: clear_config([:instance, :account_activation_required])
- test "raises if account confirmation is required but mailer isn't enable" do
- Pleroma.Config.put([:instance, :account_activation_required], true)
- Pleroma.Config.put([Pleroma.Emails.Mailer, :enabled], false)
+ test "warns if account confirmation is required but mailer isn't enabled" do
+ clear_config([:instance, :account_activation_required], true)
+ clear_config([Pleroma.Emails.Mailer, :enabled], false)
- assert_raise Pleroma.ApplicationRequirements.VerifyError,
- "Account activation enabled, but Mailer is disabled. Cannot send confirmation emails.",
- fn ->
- capture_log(&Pleroma.ApplicationRequirements.verify!/0)
- end
+ assert capture_log(fn ->
+ assert Pleroma.ApplicationRequirements.verify!() == :ok
+ end) =~ "Users will NOT be able to confirm their accounts"
end
test "doesn't do anything if account confirmation is disabled" do
- Pleroma.Config.put([:instance, :account_activation_required], false)
- Pleroma.Config.put([Pleroma.Emails.Mailer, :enabled], false)
+ clear_config([:instance, :account_activation_required], false)
+ clear_config([Pleroma.Emails.Mailer, :enabled], false)
assert Pleroma.ApplicationRequirements.verify!() == :ok
end
test "doesn't do anything if account confirmation is required and mailer is enabled" do
- Pleroma.Config.put([:instance, :account_activation_required], true)
- Pleroma.Config.put([Pleroma.Emails.Mailer, :enabled], true)
+ clear_config([:instance, :account_activation_required], true)
+ clear_config([Pleroma.Emails.Mailer, :enabled], true)
assert Pleroma.ApplicationRequirements.verify!() == :ok
end
end
@@ -70,42 +90,42 @@ defmodule Pleroma.ApplicationRequirementsTest do
setup do: clear_config([:database, :rum_enabled])
test "raises if rum is enabled and detects unapplied rum migrations" do
- Pleroma.Config.put([:database, :rum_enabled], true)
+ clear_config([:database, :rum_enabled], true)
with_mocks([{Repo, [:passthrough], [exists?: fn _, _ -> false end]}]) do
- assert_raise Pleroma.ApplicationRequirements.VerifyError,
+ assert_raise ApplicationRequirements.VerifyError,
"Unapplied RUM Migrations detected",
fn ->
- capture_log(&Pleroma.ApplicationRequirements.verify!/0)
+ capture_log(&ApplicationRequirements.verify!/0)
end
end
end
test "raises if rum is disabled and detects rum migrations" do
- Pleroma.Config.put([:database, :rum_enabled], false)
+ clear_config([:database, :rum_enabled], false)
with_mocks([{Repo, [:passthrough], [exists?: fn _, _ -> true end]}]) do
- assert_raise Pleroma.ApplicationRequirements.VerifyError,
+ assert_raise ApplicationRequirements.VerifyError,
"RUM Migrations detected",
fn ->
- capture_log(&Pleroma.ApplicationRequirements.verify!/0)
+ capture_log(&ApplicationRequirements.verify!/0)
end
end
end
test "doesn't do anything if rum enabled and applied migrations" do
- Pleroma.Config.put([:database, :rum_enabled], true)
+ clear_config([:database, :rum_enabled], true)
with_mocks([{Repo, [:passthrough], [exists?: fn _, _ -> true end]}]) do
- assert Pleroma.ApplicationRequirements.verify!() == :ok
+ assert ApplicationRequirements.verify!() == :ok
end
end
test "doesn't do anything if rum disabled" do
- Pleroma.Config.put([:database, :rum_enabled], false)
+ clear_config([:database, :rum_enabled], false)
with_mocks([{Repo, [:passthrough], [exists?: fn _, _ -> false end]}]) do
- assert Pleroma.ApplicationRequirements.verify!() == :ok
+ assert ApplicationRequirements.verify!() == :ok
end
end
end
@@ -130,17 +150,17 @@ defmodule Pleroma.ApplicationRequirementsTest do
setup do: clear_config([:i_am_aware_this_may_cause_data_loss, :disable_migration_check])
test "raises if it detects unapplied migrations" do
- assert_raise Pleroma.ApplicationRequirements.VerifyError,
+ assert_raise ApplicationRequirements.VerifyError,
"Unapplied Migrations detected",
fn ->
- capture_log(&Pleroma.ApplicationRequirements.verify!/0)
+ capture_log(&ApplicationRequirements.verify!/0)
end
end
test "doesn't do anything if disabled" do
- Pleroma.Config.put([:i_am_aware_this_may_cause_data_loss, :disable_migration_check], true)
+ clear_config([:i_am_aware_this_may_cause_data_loss, :disable_migration_check], true)
- assert :ok == Pleroma.ApplicationRequirements.verify!()
+ assert :ok == ApplicationRequirements.verify!()
end
end
end
diff --git a/test/bbs/handler_test.exs b/test/pleroma/bbs/handler_test.exs
index eb716486e..3990f8286 100644
--- a/test/bbs/handler_test.exs
+++ b/test/pleroma/bbs/handler_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.BBS.HandlerTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Activity
alias Pleroma.BBS.Handler
alias Pleroma.Object
@@ -19,7 +19,7 @@ defmodule Pleroma.BBS.HandlerTest do
user = insert(:user)
followed = insert(:user)
- {:ok, user} = User.follow(user, followed)
+ {:ok, user, followed} = User.follow(user, followed)
{:ok, _first} = CommonAPI.post(user, %{status: "hey"})
{:ok, _second} = CommonAPI.post(followed, %{status: "hello"})
@@ -54,7 +54,7 @@ defmodule Pleroma.BBS.HandlerTest do
)
assert activity.actor == user.ap_id
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
assert object.data["content"] == "this is a test post"
end
@@ -63,7 +63,7 @@ defmodule Pleroma.BBS.HandlerTest do
another_user = insert(:user)
{:ok, activity} = CommonAPI.post(another_user, %{status: "this is a test post"})
- activity_object = Object.normalize(activity)
+ activity_object = Object.normalize(activity, fetch: false)
output =
capture_io(fn ->
@@ -82,7 +82,7 @@ defmodule Pleroma.BBS.HandlerTest do
assert reply.actor == user.ap_id
- reply_object_data = Object.normalize(reply).data
+ reply_object_data = Object.normalize(reply, fetch: false).data
assert reply_object_data["content"] == "this is a reply"
assert reply_object_data["inReplyTo"] == activity_object.data["id"]
end
diff --git a/test/bookmark_test.exs b/test/pleroma/bookmark_test.exs
index 2726fe7cd..9f64a01c2 100644
--- a/test/bookmark_test.exs
+++ b/test/pleroma/bookmark_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.BookmarkTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
import Pleroma.Factory
alias Pleroma.Bookmark
alias Pleroma.Web.CommonAPI
diff --git a/test/captcha_test.exs b/test/pleroma/captcha_test.exs
index 1b9f4a12f..fcb585112 100644
--- a/test/captcha_test.exs
+++ b/test/pleroma/captcha_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.CaptchaTest do
@@ -69,7 +69,7 @@ defmodule Pleroma.CaptchaTest do
describe "Captcha Wrapper" do
test "validate" do
- Pleroma.Config.put([Pleroma.Captcha, :enabled], true)
+ clear_config([Pleroma.Captcha, :enabled], true)
new = Captcha.new()
@@ -80,11 +80,10 @@ defmodule Pleroma.CaptchaTest do
assert is_binary(answer)
assert :ok = Captcha.validate(token, "63615261b77f5354fb8c4e4986477555", answer)
- Cachex.del(:used_captcha_cache, token)
end
test "doesn't validate invalid answer" do
- Pleroma.Config.put([Pleroma.Captcha, :enabled], true)
+ clear_config([Pleroma.Captcha, :enabled], true)
new = Captcha.new()
@@ -100,7 +99,7 @@ defmodule Pleroma.CaptchaTest do
end
test "nil answer_data" do
- Pleroma.Config.put([Pleroma.Captcha, :enabled], true)
+ clear_config([Pleroma.Captcha, :enabled], true)
new = Captcha.new()
diff --git a/test/chat/message_reference_test.exs b/test/pleroma/chat/message_reference_test.exs
index aaa7c1ad4..c8db3b450 100644
--- a/test/chat/message_reference_test.exs
+++ b/test/pleroma/chat/message_reference_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Chat.MessageReferenceTest do
diff --git a/test/chat_test.exs b/test/pleroma/chat_test.exs
index 9e8a9ebf0..a5fd1e02e 100644
--- a/test/chat_test.exs
+++ b/test/pleroma/chat_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.ChatTest do
@@ -73,7 +73,8 @@ defmodule Pleroma.ChatTest do
other_user = insert(:user)
{:ok, chat} = Chat.bump_or_create(user.id, other_user.ap_id)
- :timer.sleep(1500)
+ {:ok, chat} = time_travel(chat, -2)
+
{:ok, chat_two} = Chat.bump_or_create(user.id, other_user.ap_id)
assert chat.id == chat_two.id
diff --git a/test/pleroma/config/deprecation_warnings_test.exs b/test/pleroma/config/deprecation_warnings_test.exs
new file mode 100644
index 000000000..c5e2b20f4
--- /dev/null
+++ b/test/pleroma/config/deprecation_warnings_test.exs
@@ -0,0 +1,336 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Config.DeprecationWarningsTest do
+ use ExUnit.Case
+ use Pleroma.Tests.Helpers
+
+ import ExUnit.CaptureLog
+
+ alias Pleroma.Config
+ alias Pleroma.Config.DeprecationWarnings
+
+ describe "simple policy tuples" do
+ test "gives warning when there are still strings" do
+ clear_config([:mrf_simple],
+ media_removal: ["some.removal"],
+ media_nsfw: ["some.nsfw"],
+ federated_timeline_removal: ["some.tl.removal"],
+ report_removal: ["some.report.removal"],
+ reject: ["some.reject"],
+ followers_only: ["some.followers.only"],
+ accept: ["some.accept"],
+ avatar_removal: ["some.avatar.removal"],
+ banner_removal: ["some.banner.removal"],
+ reject_deletes: ["some.reject.deletes"]
+ )
+
+ assert capture_log(fn -> DeprecationWarnings.check_simple_policy_tuples() end) =~
+ """
+ !!!DEPRECATION WARNING!!!
+ Your config is using strings in the SimplePolicy configuration instead of tuples. They should work for now, but you are advised to change to the new configuration to prevent possible issues later:
+
+ ```
+ config :pleroma, :mrf_simple,
+ media_removal: ["instance.tld"],
+ media_nsfw: ["instance.tld"],
+ federated_timeline_removal: ["instance.tld"],
+ report_removal: ["instance.tld"],
+ reject: ["instance.tld"],
+ followers_only: ["instance.tld"],
+ accept: ["instance.tld"],
+ avatar_removal: ["instance.tld"],
+ banner_removal: ["instance.tld"],
+ reject_deletes: ["instance.tld"]
+ ```
+
+ Is now
+
+
+ ```
+ config :pleroma, :mrf_simple,
+ media_removal: [{"instance.tld", "Reason for media removal"}],
+ media_nsfw: [{"instance.tld", "Reason for media nsfw"}],
+ federated_timeline_removal: [{"instance.tld", "Reason for federated timeline removal"}],
+ report_removal: [{"instance.tld", "Reason for report removal"}],
+ reject: [{"instance.tld", "Reason for reject"}],
+ followers_only: [{"instance.tld", "Reason for followers only"}],
+ accept: [{"instance.tld", "Reason for accept"}],
+ avatar_removal: [{"instance.tld", "Reason for avatar removal"}],
+ banner_removal: [{"instance.tld", "Reason for banner removal"}],
+ reject_deletes: [{"instance.tld", "Reason for reject deletes"}]
+ ```
+ """
+ end
+
+ test "transforms config to tuples" do
+ clear_config([:mrf_simple],
+ media_removal: ["some.removal", {"some.other.instance", "Some reason"}]
+ )
+
+ expected_config = [
+ {:media_removal, [{"some.removal", ""}, {"some.other.instance", "Some reason"}]}
+ ]
+
+ capture_log(fn -> DeprecationWarnings.warn() end)
+
+ assert Config.get([:mrf_simple]) == expected_config
+ end
+
+ test "doesn't give a warning with correct config" do
+ clear_config([:mrf_simple],
+ media_removal: [{"some.removal", ""}, {"some.other.instance", "Some reason"}]
+ )
+
+ assert capture_log(fn -> DeprecationWarnings.check_simple_policy_tuples() end) == ""
+ end
+ end
+
+ describe "quarantined_instances tuples" do
+ test "gives warning when there are still strings" do
+ clear_config([:instance, :quarantined_instances], [
+ {"domain.com", "some reason"},
+ "somedomain.tld"
+ ])
+
+ assert capture_log(fn -> DeprecationWarnings.check_quarantined_instances_tuples() end) =~
+ """
+ !!!DEPRECATION WARNING!!!
+ Your config is using strings in the quarantined_instances configuration instead of tuples. They should work for now, but you are advised to change to the new configuration to prevent possible issues later:
+
+ ```
+ config :pleroma, :instance,
+ quarantined_instances: ["instance.tld"]
+ ```
+
+ Is now
+
+
+ ```
+ config :pleroma, :instance,
+ quarantined_instances: [{"instance.tld", "Reason for quarantine"}]
+ ```
+ """
+ end
+
+ test "transforms config to tuples" do
+ clear_config([:instance, :quarantined_instances], [
+ {"domain.com", "some reason"},
+ "some.tld"
+ ])
+
+ expected_config = [{"domain.com", "some reason"}, {"some.tld", ""}]
+
+ capture_log(fn -> DeprecationWarnings.warn() end)
+
+ assert Config.get([:instance, :quarantined_instances]) == expected_config
+ end
+
+ test "doesn't give a warning with correct config" do
+ clear_config([:instance, :quarantined_instances], [
+ {"domain.com", "some reason"},
+ {"some.tld", ""}
+ ])
+
+ assert capture_log(fn -> DeprecationWarnings.check_quarantined_instances_tuples() end) == ""
+ end
+ end
+
+ describe "transparency_exclusions tuples" do
+ test "gives warning when there are still strings" do
+ clear_config([:mrf, :transparency_exclusions], [
+ {"domain.com", "some reason"},
+ "somedomain.tld"
+ ])
+
+ assert capture_log(fn -> DeprecationWarnings.check_transparency_exclusions_tuples() end) =~
+ """
+ !!!DEPRECATION WARNING!!!
+ Your config is using strings in the transparency_exclusions configuration instead of tuples. They should work for now, but you are advised to change to the new configuration to prevent possible issues later:
+
+ ```
+ config :pleroma, :mrf,
+ transparency_exclusions: ["instance.tld"]
+ ```
+
+ Is now
+
+
+ ```
+ config :pleroma, :mrf,
+ transparency_exclusions: [{"instance.tld", "Reason to exlude transparency"}]
+ ```
+ """
+ end
+
+ test "transforms config to tuples" do
+ clear_config([:mrf, :transparency_exclusions], [
+ {"domain.com", "some reason"},
+ "some.tld"
+ ])
+
+ expected_config = [{"domain.com", "some reason"}, {"some.tld", ""}]
+
+ capture_log(fn -> DeprecationWarnings.warn() end)
+
+ assert Config.get([:mrf, :transparency_exclusions]) == expected_config
+ end
+
+ test "doesn't give a warning with correct config" do
+ clear_config([:mrf, :transparency_exclusions], [
+ {"domain.com", "some reason"},
+ {"some.tld", ""}
+ ])
+
+ assert capture_log(fn -> DeprecationWarnings.check_transparency_exclusions_tuples() end) ==
+ ""
+ end
+ end
+
+ test "check_old_mrf_config/0" do
+ clear_config([:instance, :rewrite_policy], [])
+ clear_config([:instance, :mrf_transparency], true)
+ clear_config([:instance, :mrf_transparency_exclusions], [])
+
+ assert capture_log(fn -> DeprecationWarnings.check_old_mrf_config() end) =~
+ """
+ !!!DEPRECATION WARNING!!!
+ Your config is using old namespaces for MRF configuration. They should work for now, but you are advised to change to new namespaces to prevent possible issues later:
+
+ * `config :pleroma, :instance, rewrite_policy` is now `config :pleroma, :mrf, policies`
+ * `config :pleroma, :instance, mrf_transparency` is now `config :pleroma, :mrf, transparency`
+ * `config :pleroma, :instance, mrf_transparency_exclusions` is now `config :pleroma, :mrf, transparency_exclusions`
+ """
+ end
+
+ test "move_namespace_and_warn/2" do
+ old_group1 = [:group, :key]
+ old_group2 = [:group, :key2]
+ old_group3 = [:group, :key3]
+
+ new_group1 = [:another_group, :key4]
+ new_group2 = [:another_group, :key5]
+ new_group3 = [:another_group, :key6]
+
+ clear_config(old_group1, 1)
+ clear_config(old_group2, 2)
+ clear_config(old_group3, 3)
+
+ clear_config(new_group1)
+ clear_config(new_group2)
+ clear_config(new_group3)
+
+ config_map = [
+ {old_group1, new_group1, "\n error :key"},
+ {old_group2, new_group2, "\n error :key2"},
+ {old_group3, new_group3, "\n error :key3"}
+ ]
+
+ assert capture_log(fn ->
+ DeprecationWarnings.move_namespace_and_warn(
+ config_map,
+ "Warning preface"
+ )
+ end) =~ "Warning preface\n error :key\n error :key2\n error :key3"
+
+ assert Config.get(new_group1) == 1
+ assert Config.get(new_group2) == 2
+ assert Config.get(new_group3) == 3
+ end
+
+ test "check_media_proxy_whitelist_config/0" do
+ clear_config([:media_proxy, :whitelist], ["https://example.com", "example2.com"])
+
+ assert capture_log(fn ->
+ DeprecationWarnings.check_media_proxy_whitelist_config()
+ end) =~ "Your config is using old format (only domain) for MediaProxy whitelist option"
+ end
+
+ test "check_welcome_message_config/0" do
+ clear_config([:instance, :welcome_user_nickname], "LainChan")
+
+ assert capture_log(fn ->
+ DeprecationWarnings.check_welcome_message_config()
+ end) =~ "Your config is using the old namespace for Welcome messages configuration."
+ end
+
+ test "check_hellthread_threshold/0" do
+ clear_config([:mrf_hellthread, :threshold], 16)
+
+ assert capture_log(fn ->
+ DeprecationWarnings.check_hellthread_threshold()
+ end) =~ "You are using the old configuration mechanism for the hellthread filter."
+ end
+
+ test "check_activity_expiration_config/0" do
+ clear_config([Pleroma.ActivityExpiration], enabled: true)
+
+ assert capture_log(fn ->
+ DeprecationWarnings.check_activity_expiration_config()
+ end) =~ "Your config is using old namespace for activity expiration configuration."
+ end
+
+ test "check_uploders_s3_public_endpoint/0" do
+ clear_config([Pleroma.Uploaders.S3], public_endpoint: "https://fake.amazonaws.com/bucket/")
+
+ assert capture_log(fn ->
+ DeprecationWarnings.check_uploders_s3_public_endpoint()
+ end) =~
+ "Your config is using the old setting for controlling the URL of media uploaded to your S3 bucket."
+ end
+
+ describe "check_gun_pool_options/0" do
+ test "await_up_timeout" do
+ config = Config.get(:connections_pool)
+ clear_config(:connections_pool, Keyword.put(config, :await_up_timeout, 5_000))
+
+ assert capture_log(fn ->
+ DeprecationWarnings.check_gun_pool_options()
+ end) =~
+ "Your config is using old setting `config :pleroma, :connections_pool, await_up_timeout`."
+ end
+
+ test "pool timeout" do
+ old_config = [
+ federation: [
+ size: 50,
+ max_waiting: 10,
+ timeout: 10_000
+ ],
+ media: [
+ size: 50,
+ max_waiting: 10,
+ timeout: 10_000
+ ],
+ upload: [
+ size: 25,
+ max_waiting: 5,
+ timeout: 15_000
+ ],
+ default: [
+ size: 10,
+ max_waiting: 2,
+ timeout: 5_000
+ ]
+ ]
+
+ clear_config(:pools, old_config)
+
+ assert capture_log(fn ->
+ DeprecationWarnings.check_gun_pool_options()
+ end) =~
+ "Your config is using old setting name `timeout` instead of `recv_timeout` in pool settings"
+ end
+ end
+
+ test "check_old_chat_shoutbox/0" do
+ clear_config([:instance, :chat_limit], 1_000)
+ clear_config([:chat, :enabled], true)
+
+ assert capture_log(fn ->
+ DeprecationWarnings.check_old_chat_shoutbox()
+ end) =~
+ "Your config is using the old namespace for the Shoutbox configuration."
+ end
+end
diff --git a/test/config/holder_test.exs b/test/pleroma/config/holder_test.exs
index abcaa27dd..ca4c38995 100644
--- a/test/config/holder_test.exs
+++ b/test/pleroma/config/holder_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Config.HolderTest do
diff --git a/test/config/loader_test.exs b/test/pleroma/config/loader_test.exs
index 607572f4e..b34fd70da 100644
--- a/test/config/loader_test.exs
+++ b/test/pleroma/config/loader_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Config.LoaderTest do
diff --git a/test/pleroma/config/release_runtime_provider_test.exs b/test/pleroma/config/release_runtime_provider_test.exs
new file mode 100644
index 000000000..6578d3268
--- /dev/null
+++ b/test/pleroma/config/release_runtime_provider_test.exs
@@ -0,0 +1,45 @@
+defmodule Pleroma.Config.ReleaseRuntimeProviderTest do
+ use ExUnit.Case, async: true
+
+ alias Pleroma.Config.ReleaseRuntimeProvider
+
+ describe "load/2" do
+ test "loads release defaults config and warns about non-existent runtime config" do
+ ExUnit.CaptureIO.capture_io(fn ->
+ merged = ReleaseRuntimeProvider.load([], [])
+ assert merged == Pleroma.Config.Holder.release_defaults()
+ end) =~
+ "!!! Config path is not declared! Please ensure it exists and that PLEROMA_CONFIG_PATH is unset or points to an existing file"
+ end
+
+ test "merged runtime config" do
+ merged =
+ ReleaseRuntimeProvider.load([], config_path: "test/fixtures/config/temp.secret.exs")
+
+ assert merged[:pleroma][:first_setting] == [key: "value", key2: [Pleroma.Repo]]
+ assert merged[:pleroma][:second_setting] == [key: "value2", key2: ["Activity"]]
+ end
+
+ test "merged exported config" do
+ ExUnit.CaptureIO.capture_io(fn ->
+ merged =
+ ReleaseRuntimeProvider.load([],
+ exported_config_path: "test/fixtures/config/temp.exported_from_db.secret.exs"
+ )
+
+ assert merged[:pleroma][:exported_config_merged]
+ end) =~
+ "!!! Config path is not declared! Please ensure it exists and that PLEROMA_CONFIG_PATH is unset or points to an existing file"
+ end
+
+ test "runtime config is merged with exported config" do
+ merged =
+ ReleaseRuntimeProvider.load([],
+ config_path: "test/fixtures/config/temp.secret.exs",
+ exported_config_path: "test/fixtures/config/temp.exported_from_db.secret.exs"
+ )
+
+ assert merged[:pleroma][:first_setting] == [key2: [Pleroma.Repo], key: "new value"]
+ end
+ end
+end
diff --git a/test/config/transfer_task_test.exs b/test/pleroma/config/transfer_task_test.exs
index f53829e09..9e3f11f1a 100644
--- a/test/config/transfer_task_test.exs
+++ b/test/pleroma/config/transfer_task_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Config.TransferTaskTest do
@@ -82,6 +82,7 @@ defmodule Pleroma.Config.TransferTaskTest do
on_exit(fn -> Restarter.Pleroma.refresh() end)
end
+ @tag :erratic
test "don't restart if no reboot time settings were changed" do
clear_config(:emoji)
insert(:config, key: :emoji, value: [groups: [a: 1, b: 2]])
@@ -92,23 +93,26 @@ defmodule Pleroma.Config.TransferTaskTest do
)
end
+ @tag :erratic
test "on reboot time key" do
- clear_config(:chat)
- insert(:config, key: :chat, value: [enabled: false])
+ clear_config(:shout)
+ insert(:config, key: :shout, value: [enabled: false])
assert capture_log(fn -> TransferTask.start_link([]) end) =~ "pleroma restarted"
end
+ @tag :erratic
test "on reboot time subkey" do
clear_config(Pleroma.Captcha)
insert(:config, key: Pleroma.Captcha, value: [seconds_valid: 60])
assert capture_log(fn -> TransferTask.start_link([]) end) =~ "pleroma restarted"
end
+ @tag :erratic
test "don't restart pleroma on reboot time key and subkey if there is false flag" do
- clear_config(:chat)
+ clear_config(:shout)
clear_config(Pleroma.Captcha)
- insert(:config, key: :chat, value: [enabled: false])
+ insert(:config, key: :shout, value: [enabled: false])
insert(:config, key: Pleroma.Captcha, value: [seconds_valid: 60])
refute String.contains?(
diff --git a/test/config/config_db_test.exs b/test/pleroma/config_db_test.exs
index 3895e2cda..d42123fb4 100644
--- a/test/config/config_db_test.exs
+++ b/test/pleroma/config_db_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.ConfigDBTest do
diff --git a/test/config_test.exs b/test/pleroma/config_test.exs
index 1556e4237..3158a2ec8 100644
--- a/test/config_test.exs
+++ b/test/pleroma/config_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.ConfigTest do
- use ExUnit.Case
+ use Pleroma.DataCase
test "get/1 with an atom" do
assert Pleroma.Config.get(:instance) == Application.get_env(:pleroma, :instance)
@@ -30,9 +30,9 @@ defmodule Pleroma.ConfigTest do
describe "nil values" do
setup do
- Pleroma.Config.put(:lorem, nil)
- Pleroma.Config.put(:ipsum, %{dolor: [sit: nil]})
- Pleroma.Config.put(:dolor, sit: %{amet: nil})
+ clear_config(:lorem, nil)
+ clear_config(:ipsum, %{dolor: [sit: nil]})
+ clear_config(:dolor, sit: %{amet: nil})
on_exit(fn -> Enum.each(~w(lorem ipsum dolor)a, &Pleroma.Config.delete/1) end)
end
@@ -57,9 +57,9 @@ defmodule Pleroma.ConfigTest do
end
test "get/1 when value is false" do
- Pleroma.Config.put([:instance, :false_test], false)
- Pleroma.Config.put([:instance, :nested], [])
- Pleroma.Config.put([:instance, :nested, :false_test], false)
+ clear_config([:instance, :false_test], false)
+ clear_config([:instance, :nested], [])
+ clear_config([:instance, :nested, :false_test], false)
assert Pleroma.Config.get([:instance, :false_test]) == false
assert Pleroma.Config.get([:instance, :nested, :false_test]) == false
@@ -81,40 +81,40 @@ defmodule Pleroma.ConfigTest do
end
test "get!/1 when value is false" do
- Pleroma.Config.put([:instance, :false_test], false)
- Pleroma.Config.put([:instance, :nested], [])
- Pleroma.Config.put([:instance, :nested, :false_test], false)
+ clear_config([:instance, :false_test], false)
+ clear_config([:instance, :nested], [])
+ clear_config([:instance, :nested, :false_test], false)
assert Pleroma.Config.get!([:instance, :false_test]) == false
assert Pleroma.Config.get!([:instance, :nested, :false_test]) == false
end
test "put/2 with a key" do
- Pleroma.Config.put(:config_test, true)
+ clear_config(:config_test, true)
assert Pleroma.Config.get(:config_test) == true
end
test "put/2 with a list of keys" do
- Pleroma.Config.put([:instance, :config_test], true)
- Pleroma.Config.put([:instance, :config_nested_test], [])
- Pleroma.Config.put([:instance, :config_nested_test, :x], true)
+ clear_config([:instance, :config_test], true)
+ clear_config([:instance, :config_nested_test], [])
+ clear_config([:instance, :config_nested_test, :x], true)
assert Pleroma.Config.get([:instance, :config_test]) == true
assert Pleroma.Config.get([:instance, :config_nested_test, :x]) == true
end
test "delete/1 with a key" do
- Pleroma.Config.put([:delete_me], :delete_me)
+ clear_config([:delete_me], :delete_me)
Pleroma.Config.delete([:delete_me])
assert Pleroma.Config.get([:delete_me]) == nil
end
test "delete/2 with a list of keys" do
- Pleroma.Config.put([:delete_me], hello: "world", world: "Hello")
+ clear_config([:delete_me], hello: "world", world: "Hello")
Pleroma.Config.delete([:delete_me, :world])
assert Pleroma.Config.get([:delete_me]) == [hello: "world"]
- Pleroma.Config.put([:delete_me, :delete_me], hello: "world", world: "Hello")
+ clear_config([:delete_me, :delete_me], hello: "world", world: "Hello")
Pleroma.Config.delete([:delete_me, :delete_me, :world])
assert Pleroma.Config.get([:delete_me, :delete_me]) == [hello: "world"]
@@ -123,8 +123,8 @@ defmodule Pleroma.ConfigTest do
end
test "fetch/1" do
- Pleroma.Config.put([:lorem], :ipsum)
- Pleroma.Config.put([:ipsum], dolor: :sit)
+ clear_config([:lorem], :ipsum)
+ clear_config([:ipsum], dolor: :sit)
assert Pleroma.Config.fetch([:lorem]) == {:ok, :ipsum}
assert Pleroma.Config.fetch(:lorem) == {:ok, :ipsum}
diff --git a/test/conversation/participation_test.exs b/test/pleroma/conversation/participation_test.exs
index 59a1b6492..a25e17c95 100644
--- a/test/conversation/participation_test.exs
+++ b/test/pleroma/conversation/participation_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Conversation.ParticipationTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
import Pleroma.Factory
alias Pleroma.Conversation
alias Pleroma.Conversation.Participation
@@ -37,9 +37,8 @@ defmodule Pleroma.Conversation.ParticipationTest do
[%{read: true}] = Participation.for_user(user)
[%{read: false} = participation] = Participation.for_user(other_user)
-
- assert User.get_cached_by_id(user.id).unread_conversation_count == 0
- assert User.get_cached_by_id(other_user.id).unread_conversation_count == 1
+ assert Participation.unread_count(user) == 0
+ assert Participation.unread_count(other_user) == 1
{:ok, _} =
CommonAPI.post(other_user, %{
@@ -54,8 +53,8 @@ defmodule Pleroma.Conversation.ParticipationTest do
[%{read: false}] = Participation.for_user(user)
[%{read: true}] = Participation.for_user(other_user)
- assert User.get_cached_by_id(user.id).unread_conversation_count == 1
- assert User.get_cached_by_id(other_user.id).unread_conversation_count == 0
+ assert Participation.unread_count(user) == 1
+ assert Participation.unread_count(other_user) == 0
end
test "for a new conversation, it sets the recipents of the participation" do
@@ -97,12 +96,11 @@ defmodule Pleroma.Conversation.ParticipationTest do
{:ok, %Participation{} = participation} =
Participation.create_for_user_and_conversation(user, conversation)
+ {:ok, participation} = time_travel(participation, -2)
+
assert participation.user_id == user.id
assert participation.conversation_id == conversation.id
- # Needed because updated_at is accurate down to a second
- :timer.sleep(1000)
-
# Creating again returns the same participation
{:ok, %Participation{} = participation_two} =
Participation.create_for_user_and_conversation(user, conversation)
@@ -177,8 +175,8 @@ defmodule Pleroma.Conversation.ParticipationTest do
assert [participation_one, participation_two] = Participation.for_user(user)
- object2 = Pleroma.Object.normalize(activity_two)
- object3 = Pleroma.Object.normalize(activity_three)
+ object2 = Pleroma.Object.normalize(activity_two, fetch: false)
+ object3 = Pleroma.Object.normalize(activity_three, fetch: false)
user = Repo.get(Pleroma.User, user.id)
@@ -264,7 +262,7 @@ defmodule Pleroma.Conversation.ParticipationTest do
assert [%{read: false}, %{read: false}, %{read: false}, %{read: false}] =
Participation.for_user(blocker)
- assert User.get_cached_by_id(blocker.id).unread_conversation_count == 4
+ assert Participation.unread_count(blocker) == 4
{:ok, _user_relationship} = User.block(blocker, blocked)
@@ -272,15 +270,15 @@ defmodule Pleroma.Conversation.ParticipationTest do
assert [%{read: true}, %{read: true}, %{read: true}, %{read: false}] =
Participation.for_user(blocker)
- assert User.get_cached_by_id(blocker.id).unread_conversation_count == 1
+ assert Participation.unread_count(blocker) == 1
# The conversation is not marked as read for the blocked user
assert [_, _, %{read: false}] = Participation.for_user(blocked)
- assert User.get_cached_by_id(blocked.id).unread_conversation_count == 1
+ assert Participation.unread_count(blocker) == 1
# The conversation is not marked as read for the third user
assert [%{read: false}, _, _] = Participation.for_user(third_user)
- assert User.get_cached_by_id(third_user.id).unread_conversation_count == 1
+ assert Participation.unread_count(third_user) == 1
end
test "the new conversation with the blocked user is not marked as unread " do
@@ -298,7 +296,7 @@ defmodule Pleroma.Conversation.ParticipationTest do
})
assert [%{read: true}] = Participation.for_user(blocker)
- assert User.get_cached_by_id(blocker.id).unread_conversation_count == 0
+ assert Participation.unread_count(blocker) == 0
# When the blocked user is a recipient
{:ok, _direct2} =
@@ -308,10 +306,10 @@ defmodule Pleroma.Conversation.ParticipationTest do
})
assert [%{read: true}, %{read: true}] = Participation.for_user(blocker)
- assert User.get_cached_by_id(blocker.id).unread_conversation_count == 0
+ assert Participation.unread_count(blocker) == 0
assert [%{read: false}, _] = Participation.for_user(blocked)
- assert User.get_cached_by_id(blocked.id).unread_conversation_count == 1
+ assert Participation.unread_count(blocked) == 1
end
test "the conversation with the blocked user is not marked as unread on a reply" do
@@ -327,8 +325,8 @@ defmodule Pleroma.Conversation.ParticipationTest do
{:ok, _user_relationship} = User.block(blocker, blocked)
assert [%{read: true}] = Participation.for_user(blocker)
- assert User.get_cached_by_id(blocker.id).unread_conversation_count == 0
+ assert Participation.unread_count(blocker) == 0
assert [blocked_participation] = Participation.for_user(blocked)
# When it's a reply from the blocked user
@@ -340,8 +338,8 @@ defmodule Pleroma.Conversation.ParticipationTest do
})
assert [%{read: true}] = Participation.for_user(blocker)
- assert User.get_cached_by_id(blocker.id).unread_conversation_count == 0
+ assert Participation.unread_count(blocker) == 0
assert [third_user_participation] = Participation.for_user(third_user)
# When it's a reply from the third user
@@ -353,11 +351,24 @@ defmodule Pleroma.Conversation.ParticipationTest do
})
assert [%{read: true}] = Participation.for_user(blocker)
- assert User.get_cached_by_id(blocker.id).unread_conversation_count == 0
+ assert Participation.unread_count(blocker) == 0
# Marked as unread for the blocked user
assert [%{read: false}] = Participation.for_user(blocked)
- assert User.get_cached_by_id(blocked.id).unread_conversation_count == 1
+
+ assert Participation.unread_count(blocked) == 1
end
end
+
+ test "deletes a conversation" do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, _activity} =
+ CommonAPI.post(user, %{status: "Hey @#{other_user.nickname}.", visibility: "direct"})
+
+ assert [participation] = Participation.for_user(other_user)
+ assert {:ok, _} = Participation.delete(participation)
+ assert [] == Participation.for_user(other_user)
+ end
end
diff --git a/test/conversation_test.exs b/test/pleroma/conversation_test.exs
index 359aa6840..1a947606d 100644
--- a/test/conversation_test.exs
+++ b/test/pleroma/conversation_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.ConversationTest do
@@ -48,7 +48,7 @@ defmodule Pleroma.ConversationTest do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "Hey"})
- object = Pleroma.Object.normalize(activity)
+ object = Pleroma.Object.normalize(activity, fetch: false)
context = object.data["context"]
conversation = Conversation.get_for_ap_id(context)
@@ -64,7 +64,7 @@ defmodule Pleroma.ConversationTest do
{:ok, activity} =
CommonAPI.post(har, %{status: "Hey @#{jafnhar.nickname}", visibility: "direct"})
- object = Pleroma.Object.normalize(activity)
+ object = Pleroma.Object.normalize(activity, fetch: false)
context = object.data["context"]
conversation =
@@ -86,7 +86,7 @@ defmodule Pleroma.ConversationTest do
in_reply_to_status_id: activity.id
})
- object = Pleroma.Object.normalize(activity)
+ object = Pleroma.Object.normalize(activity, fetch: false)
context = object.data["context"]
conversation_two =
@@ -110,7 +110,7 @@ defmodule Pleroma.ConversationTest do
in_reply_to_status_id: activity.id
})
- object = Pleroma.Object.normalize(activity)
+ object = Pleroma.Object.normalize(activity, fetch: false)
context = object.data["context"]
conversation_three =
diff --git a/test/docs/generator_test.exs b/test/pleroma/docs/generator_test.exs
index b32918a69..8574c1d5e 100644
--- a/test/docs/generator_test.exs
+++ b/test/pleroma/docs/generator_test.exs
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Docs.GeneratorTest do
use ExUnit.Case, async: true
alias Pleroma.Docs.Generator
@@ -19,7 +23,7 @@ defmodule Pleroma.Docs.GeneratorTest do
key: :filters,
type: {:list, :module},
description: "",
- suggestions: {:list_behaviour_implementations, Pleroma.Web.ActivityPub.MRF}
+ suggestions: {:list_behaviour_implementations, Pleroma.Web.ActivityPub.MRF.Policy}
},
%{
key: Pleroma.Upload,
diff --git a/test/web/activity_pub/object_validators/types/date_time_test.exs b/test/pleroma/ecto_type/activity_pub/object_validators/date_time_test.exs
index 43be8e936..259fd6a5f 100644
--- a/test/web/activity_pub/object_validators/types/date_time_test.exs
+++ b/test/pleroma/ecto_type/activity_pub/object_validators/date_time_test.exs
@@ -1,6 +1,10 @@
-defmodule Pleroma.Web.ActivityPub.ObjectValidators.Types.DateTimeTest do
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.DateTimeTest do
alias Pleroma.EctoType.ActivityPub.ObjectValidators.DateTime
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
test "it validates an xsd:Datetime" do
valid_strings = [
diff --git a/test/web/activity_pub/object_validators/types/object_id_test.exs b/test/pleroma/ecto_type/activity_pub/object_validators/object_id_test.exs
index e0ab76379..1a4c2dfcb 100644
--- a/test/web/activity_pub/object_validators/types/object_id_test.exs
+++ b/test/pleroma/ecto_type/activity_pub/object_validators/object_id_test.exs
@@ -1,10 +1,10 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Web.ObjectValidators.Types.ObjectIDTest do
+defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.ObjectIDTest do
alias Pleroma.EctoType.ActivityPub.ObjectValidators.ObjectID
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
@uris [
"http://lain.com/users/lain",
diff --git a/test/web/activity_pub/object_validators/types/recipients_test.exs b/test/pleroma/ecto_type/activity_pub/object_validators/recipients_test.exs
index 053916bdd..4cdafa898 100644
--- a/test/web/activity_pub/object_validators/types/recipients_test.exs
+++ b/test/pleroma/ecto_type/activity_pub/object_validators/recipients_test.exs
@@ -1,11 +1,15 @@
-defmodule Pleroma.Web.ObjectValidators.Types.RecipientsTest do
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.RecipientsTest do
alias Pleroma.EctoType.ActivityPub.ObjectValidators.Recipients
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
- test "it asserts that all elements of the list are object ids" do
+ test "it only keeps elements that are valid object ids" do
list = ["https://lain.com/users/lain", "invalid"]
- assert :error == Recipients.cast(list)
+ assert {:ok, ["https://lain.com/users/lain"]} == Recipients.cast(list)
end
test "it works with a list" do
diff --git a/test/web/activity_pub/object_validators/types/safe_text_test.exs b/test/pleroma/ecto_type/activity_pub/object_validators/safe_text_test.exs
index 9c08606f6..7002eca30 100644
--- a/test/web/activity_pub/object_validators/types/safe_text_test.exs
+++ b/test/pleroma/ecto_type/activity_pub/object_validators/safe_text_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Web.ActivityPub.ObjectValidators.Types.SafeTextTest do
- use Pleroma.DataCase
+defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.SafeTextTest do
+ use Pleroma.DataCase, async: true
alias Pleroma.EctoType.ActivityPub.ObjectValidators.SafeText
diff --git a/test/emails/admin_email_test.exs b/test/pleroma/emails/admin_email_test.exs
index e24231e27..e65752c23 100644
--- a/test/emails/admin_email_test.exs
+++ b/test/pleroma/emails/admin_email_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Emails.AdminEmailTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
import Pleroma.Factory
alias Pleroma.Emails.AdminEmail
@@ -19,19 +19,15 @@ defmodule Pleroma.Emails.AdminEmailTest do
AdminEmail.report(to_user, reporter, account, [%{name: "Test", id: "12"}], "Test comment")
status_url = Helpers.o_status_url(Pleroma.Web.Endpoint, :notice, "12")
- reporter_url = Helpers.user_feed_url(Pleroma.Web.Endpoint, :feed_redirect, reporter.id)
- account_url = Helpers.user_feed_url(Pleroma.Web.Endpoint, :feed_redirect, account.id)
+ reporter_url = reporter.ap_id
+ account_url = account.ap_id
assert res.to == [{to_user.name, to_user.email}]
assert res.from == {config[:name], config[:notify_email]}
assert res.subject == "#{config[:name]} Report"
assert res.html_body ==
- "<p>Reported by: <a href=\"#{reporter_url}\">#{reporter.nickname}</a></p>\n<p>Reported Account: <a href=\"#{
- account_url
- }\">#{account.nickname}</a></p>\n<p>Comment: Test comment\n<p> Statuses:\n <ul>\n <li><a href=\"#{
- status_url
- }\">#{status_url}</li>\n </ul>\n</p>\n\n<p>\n<a href=\"http://localhost:4001/pleroma/admin/#/reports/index\">View Reports in AdminFE</a>\n"
+ "<p>Reported by: <a href=\"#{reporter_url}\">#{reporter.nickname}</a></p>\n<p>Reported Account: <a href=\"#{account_url}\">#{account.nickname}</a></p>\n<p>Comment: Test comment\n<p> Statuses:\n <ul>\n <li><a href=\"#{status_url}\">#{status_url}</li>\n </ul>\n</p>\n\n<p>\n<a href=\"http://localhost:4001/pleroma/admin/#/reports/index\">View Reports in AdminFE</a>\n"
end
test "it works when the reporter is a remote user without email" do
@@ -54,7 +50,7 @@ defmodule Pleroma.Emails.AdminEmailTest do
res = AdminEmail.new_unapproved_registration(to_user, account)
- account_url = Helpers.user_feed_url(Pleroma.Web.Endpoint, :feed_redirect, account.id)
+ account_url = account.ap_id
assert res.to == [{to_user.name, to_user.email}]
assert res.from == {config[:name], config[:notify_email]}
@@ -63,7 +59,7 @@ defmodule Pleroma.Emails.AdminEmailTest do
assert res.html_body == """
<p>New account for review: <a href="#{account_url}">@#{account.nickname}</a></p>
<blockquote>Plz let me in</blockquote>
- <a href="http://localhost:4001/pleroma/admin">Visit AdminFE</a>
+ <a href="http://localhost:4001/pleroma/admin/#/users/#{account.id}/">Visit AdminFE</a>
"""
end
end
diff --git a/test/emails/mailer_test.exs b/test/pleroma/emails/mailer_test.exs
index 9e232d2a0..a8e1553e5 100644
--- a/test/emails/mailer_test.exs
+++ b/test/pleroma/emails/mailer_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Emails.MailerTest do
diff --git a/test/emails/user_email_test.exs b/test/pleroma/emails/user_email_test.exs
index a75623bb4..21fd06ea6 100644
--- a/test/emails/user_email_test.exs
+++ b/test/pleroma/emails/user_email_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Emails.UserEmailTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Emails.UserEmail
alias Pleroma.Web.Endpoint
@@ -45,4 +45,15 @@ defmodule Pleroma.Emails.UserEmailTest do
assert email.html_body =~
Router.Helpers.confirm_email_url(Endpoint, :confirm_email, user.id, "conf-token")
end
+
+ test "build approval pending email" do
+ config = Pleroma.Config.get(:instance)
+ user = insert(:user)
+ email = UserEmail.approval_pending_email(user)
+
+ assert email.from == {config[:name], config[:notify_email]}
+ assert email.to == [{user.name, user.email}]
+ assert email.subject == "Your account is awaiting approval"
+ assert email.html_body =~ "Awaiting Approval"
+ end
end
diff --git a/test/emoji/formatter_test.exs b/test/pleroma/emoji/formatter_test.exs
index 12af6cd8b..3942f609f 100644
--- a/test/emoji/formatter_test.exs
+++ b/test/pleroma/emoji/formatter_test.exs
@@ -1,10 +1,10 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Emoji.FormatterTest do
alias Pleroma.Emoji.Formatter
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
describe "emojify" do
test "it adds cool emoji" do
diff --git a/test/emoji/loader_test.exs b/test/pleroma/emoji/loader_test.exs
index 804039e7e..de89e3bc4 100644
--- a/test/emoji/loader_test.exs
+++ b/test/pleroma/emoji/loader_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Emoji.LoaderTest do
diff --git a/test/pleroma/emoji/pack_test.exs b/test/pleroma/emoji/pack_test.exs
new file mode 100644
index 000000000..ac7535412
--- /dev/null
+++ b/test/pleroma/emoji/pack_test.exs
@@ -0,0 +1,93 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Emoji.PackTest do
+ use Pleroma.DataCase
+ alias Pleroma.Emoji.Pack
+
+ @emoji_path Path.join(
+ Pleroma.Config.get!([:instance, :static_dir]),
+ "emoji"
+ )
+
+ setup do
+ pack_path = Path.join(@emoji_path, "dump_pack")
+ File.mkdir(pack_path)
+
+ File.write!(Path.join(pack_path, "pack.json"), """
+ {
+ "files": { },
+ "pack": {
+ "description": "Dump pack", "homepage": "https://pleroma.social",
+ "license": "Test license", "share-files": true
+ }}
+ """)
+
+ {:ok, pack} = Pleroma.Emoji.Pack.load_pack("dump_pack")
+
+ on_exit(fn ->
+ File.rm_rf!(pack_path)
+ end)
+
+ {:ok, pack: pack}
+ end
+
+ describe "add_file/4" do
+ test "add emojies from zip file", %{pack: pack} do
+ file = %Plug.Upload{
+ content_type: "application/zip",
+ filename: "emojis.zip",
+ path: Path.absname("test/fixtures/emojis.zip")
+ }
+
+ {:ok, updated_pack} = Pack.add_file(pack, nil, nil, file)
+
+ assert updated_pack.files == %{
+ "a_trusted_friend-128" => "128px/a_trusted_friend-128.png",
+ "auroraborealis" => "auroraborealis.png",
+ "baby_in_a_box" => "1000px/baby_in_a_box.png",
+ "bear" => "1000px/bear.png",
+ "bear-128" => "128px/bear-128.png"
+ }
+
+ assert updated_pack.files_count == 5
+ end
+ end
+
+ test "returns error when zip file is bad", %{pack: pack} do
+ file = %Plug.Upload{
+ content_type: "application/zip",
+ filename: "emojis.zip",
+ path: Path.absname("test/instance_static/emoji/test_pack/blank.png")
+ }
+
+ assert Pack.add_file(pack, nil, nil, file) == {:error, :einval}
+ end
+
+ test "returns pack when zip file is empty", %{pack: pack} do
+ file = %Plug.Upload{
+ content_type: "application/zip",
+ filename: "emojis.zip",
+ path: Path.absname("test/fixtures/empty.zip")
+ }
+
+ {:ok, updated_pack} = Pack.add_file(pack, nil, nil, file)
+ assert updated_pack == pack
+ end
+
+ test "add emoji file", %{pack: pack} do
+ file = %Plug.Upload{
+ filename: "blank.png",
+ path: "#{@emoji_path}/test_pack/blank.png"
+ }
+
+ {:ok, updated_pack} = Pack.add_file(pack, "test_blank", "test_blank.png", file)
+
+ assert updated_pack.files == %{
+ "test_blank" => "test_blank.png"
+ }
+
+ assert updated_pack.files_count == 1
+ end
+end
diff --git a/test/emoji_test.exs b/test/pleroma/emoji_test.exs
index b36047578..027a8132f 100644
--- a/test/emoji_test.exs
+++ b/test/pleroma/emoji_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.EmojiTest do
@@ -9,8 +9,22 @@ defmodule Pleroma.EmojiTest do
describe "is_unicode_emoji?/1" do
test "tells if a string is an unicode emoji" do
refute Emoji.is_unicode_emoji?("X")
- assert Emoji.is_unicode_emoji?("☂")
+ refute Emoji.is_unicode_emoji?("ね")
+
+ # Only accept fully-qualified (RGI) emoji
+ # See http://www.unicode.org/reports/tr51/
+ refute Emoji.is_unicode_emoji?("❤")
+ refute Emoji.is_unicode_emoji?("☂")
+
assert Emoji.is_unicode_emoji?("🥺")
+ assert Emoji.is_unicode_emoji?("🤰")
+ assert Emoji.is_unicode_emoji?("❤️")
+ assert Emoji.is_unicode_emoji?("🏳️‍⚧️")
+
+ # Additionally, we accept regional indicators.
+ assert Emoji.is_unicode_emoji?("🇵")
+ assert Emoji.is_unicode_emoji?("🇴")
+ assert Emoji.is_unicode_emoji?("🇬")
end
end
diff --git a/test/pleroma/filter_test.exs b/test/pleroma/filter_test.exs
new file mode 100644
index 000000000..19ad6b8c0
--- /dev/null
+++ b/test/pleroma/filter_test.exs
@@ -0,0 +1,193 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.FilterTest do
+ use Pleroma.DataCase, async: true
+
+ import Pleroma.Factory
+
+ alias Oban.Job
+ alias Pleroma.Filter
+
+ setup do
+ [user: insert(:user)]
+ end
+
+ describe "creating filters" do
+ test "creation validation error", %{user: user} do
+ attrs = %{
+ user_id: user.id,
+ expires_in: 60
+ }
+
+ {:error, _} = Filter.create(attrs)
+
+ assert Repo.all(Job) == []
+ end
+
+ test "use passed expires_at instead expires_in", %{user: user} do
+ now = NaiveDateTime.utc_now()
+
+ attrs = %{
+ user_id: user.id,
+ expires_at: now,
+ phrase: "knights",
+ context: ["home"],
+ expires_in: 600
+ }
+
+ {:ok, %Filter{} = filter} = Filter.create(attrs)
+
+ result = Filter.get(filter.filter_id, user)
+ assert result.expires_at == NaiveDateTime.truncate(now, :second)
+
+ [job] = Repo.all(Job)
+
+ assert DateTime.truncate(job.scheduled_at, :second) ==
+ now |> NaiveDateTime.truncate(:second) |> DateTime.from_naive!("Etc/UTC")
+ end
+
+ test "creating one filter", %{user: user} do
+ attrs = %{
+ user_id: user.id,
+ filter_id: 42,
+ phrase: "knights",
+ context: ["home"]
+ }
+
+ {:ok, %Filter{} = filter} = Filter.create(attrs)
+ result = Filter.get(filter.filter_id, user)
+ assert attrs.phrase == result.phrase
+ end
+
+ test "creating with expired_at", %{user: user} do
+ attrs = %{
+ user_id: user.id,
+ filter_id: 42,
+ phrase: "knights",
+ context: ["home"],
+ expires_in: 60
+ }
+
+ {:ok, %Filter{} = filter} = Filter.create(attrs)
+ result = Filter.get(filter.filter_id, user)
+ assert attrs.phrase == result.phrase
+
+ assert [_] = Repo.all(Job)
+ end
+
+ test "creating one filter without a pre-defined filter_id", %{user: user} do
+ attrs = %{
+ user_id: user.id,
+ phrase: "knights",
+ context: ["home"]
+ }
+
+ {:ok, %Filter{} = filter} = Filter.create(attrs)
+ # Should start at 1
+ assert filter.filter_id == 1
+ end
+
+ test "creating additional filters uses previous highest filter_id + 1", %{user: user} do
+ filter1 = insert(:filter, user: user)
+
+ attrs = %{
+ user_id: user.id,
+ # No filter_id
+ phrase: "who",
+ context: ["home"]
+ }
+
+ {:ok, %Filter{} = filter2} = Filter.create(attrs)
+ assert filter2.filter_id == filter1.filter_id + 1
+ end
+
+ test "filter_id is unique per user", %{user: user_one} do
+ user_two = insert(:user)
+
+ attrs1 = %{
+ user_id: user_one.id,
+ phrase: "knights",
+ context: ["home"]
+ }
+
+ {:ok, %Filter{} = filter_one} = Filter.create(attrs1)
+
+ attrs2 = %{
+ user_id: user_two.id,
+ phrase: "who",
+ context: ["home"]
+ }
+
+ {:ok, %Filter{} = filter_two} = Filter.create(attrs2)
+
+ assert filter_one.filter_id == 1
+ assert filter_two.filter_id == 1
+
+ result_one = Filter.get(filter_one.filter_id, user_one)
+ assert result_one.phrase == filter_one.phrase
+
+ result_two = Filter.get(filter_two.filter_id, user_two)
+ assert result_two.phrase == filter_two.phrase
+ end
+ end
+
+ test "deleting a filter", %{user: user} do
+ filter = insert(:filter, user: user)
+
+ assert Repo.get(Filter, filter.id)
+ {:ok, filter} = Filter.delete(filter)
+ refute Repo.get(Filter, filter.id)
+ end
+
+ test "deleting a filter with expires_at is removing Oban job too", %{user: user} do
+ attrs = %{
+ user_id: user.id,
+ phrase: "cofe",
+ context: ["home"],
+ expires_in: 600
+ }
+
+ {:ok, filter} = Filter.create(attrs)
+ assert %Job{id: job_id} = Pleroma.Workers.PurgeExpiredFilter.get_expiration(filter.id)
+ {:ok, _} = Filter.delete(filter)
+
+ assert Repo.get(Job, job_id) == nil
+ end
+
+ test "getting all filters by an user", %{user: user} do
+ filter1 = insert(:filter, user: user)
+ filter2 = insert(:filter, user: user)
+
+ filter_ids = user |> Filter.get_filters() |> collect_ids()
+
+ assert filter1.id in filter_ids
+ assert filter2.id in filter_ids
+ end
+
+ test "updating a filter", %{user: user} do
+ filter = insert(:filter, user: user)
+
+ changes = %{
+ phrase: "who",
+ context: ["home", "timeline"]
+ }
+
+ {:ok, updated_filter} = Filter.update(filter, changes)
+
+ assert filter != updated_filter
+ assert updated_filter.phrase == changes.phrase
+ assert updated_filter.context == changes.context
+ end
+
+ test "updating with error", %{user: user} do
+ filter = insert(:filter, user: user)
+
+ changes = %{
+ phrase: nil
+ }
+
+ {:error, _} = Filter.update(filter, changes)
+ end
+end
diff --git a/test/following_relationship_test.exs b/test/pleroma/following_relationship_test.exs
index 17a468abb..37452996b 100644
--- a/test/following_relationship_test.exs
+++ b/test/pleroma/following_relationship_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.FollowingRelationshipTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.FollowingRelationship
alias Pleroma.Web.ActivityPub.InternalFetchActor
diff --git a/test/formatter_test.exs b/test/pleroma/formatter_test.exs
index f066bd50a..b0f9f41b1 100644
--- a/test/formatter_test.exs
+++ b/test/pleroma/formatter_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.FormatterTest do
@@ -151,13 +151,7 @@ defmodule Pleroma.FormatterTest do
assert length(mentions) == 3
expected_text =
- ~s(<span class="h-card"><a class="u-url mention" data-user="#{gsimg.id}" href="#{
- gsimg.ap_id
- }" rel="ugc">@<span>gsimg</span></a></span> According to <span class="h-card"><a class="u-url mention" data-user="#{
- archaeme.id
- }" href="#{"https://archeme/@archa_eme_"}" rel="ugc">@<span>archa_eme_</span></a></span>, that is @daggsy. Also hello <span class="h-card"><a class="u-url mention" data-user="#{
- archaeme_remote.id
- }" href="#{archaeme_remote.ap_id}" rel="ugc">@<span>archaeme</span></a></span>)
+ ~s(<span class="h-card"><a class="u-url mention" data-user="#{gsimg.id}" href="#{gsimg.ap_id}" rel="ugc">@<span>gsimg</span></a></span> According to <span class="h-card"><a class="u-url mention" data-user="#{archaeme.id}" href="#{"https://archeme/@archa_eme_"}" rel="ugc">@<span>archa_eme_</span></a></span>, that is @daggsy. Also hello <span class="h-card"><a class="u-url mention" data-user="#{archaeme_remote.id}" href="#{archaeme_remote.ap_id}" rel="ugc">@<span>archaeme</span></a></span>)
assert expected_text == text
end
@@ -172,9 +166,7 @@ defmodule Pleroma.FormatterTest do
assert length(mentions) == 1
expected_text =
- ~s(<span class="h-card"><a class="u-url mention" data-user="#{mike.id}" href="#{
- mike.ap_id
- }" rel="ugc">@<span>mike</span></a></span> test)
+ ~s(<span class="h-card"><a class="u-url mention" data-user="#{mike.id}" href="#{mike.ap_id}" rel="ugc">@<span>mike</span></a></span> test)
assert expected_text == text
end
@@ -210,13 +202,7 @@ defmodule Pleroma.FormatterTest do
assert mentions == [{"@#{user.nickname}", user}, {"@#{other_user.nickname}", other_user}]
assert expected_text ==
- ~s(<span class="h-card"><a class="u-url mention" data-user="#{user.id}" href="#{
- user.ap_id
- }" rel="ugc">@<span>#{user.nickname}</span></a></span> <span class="h-card"><a class="u-url mention" data-user="#{
- other_user.id
- }" href="#{other_user.ap_id}" rel="ugc">@<span>#{other_user.nickname}</span></a></span> hey dudes i hate <span class="h-card"><a class="u-url mention" data-user="#{
- third_user.id
- }" href="#{third_user.ap_id}" rel="ugc">@<span>#{third_user.nickname}</span></a></span>)
+ ~s(<span class="h-card"><a class="u-url mention" data-user="#{user.id}" href="#{user.ap_id}" rel="ugc">@<span>#{user.nickname}</span></a></span> <span class="h-card"><a class="u-url mention" data-user="#{other_user.id}" href="#{other_user.ap_id}" rel="ugc">@<span>#{other_user.nickname}</span></a></span> hey dudes i hate <span class="h-card"><a class="u-url mention" data-user="#{third_user.id}" href="#{third_user.ap_id}" rel="ugc">@<span>#{third_user.nickname}</span></a></span>)
end
test "given the 'safe_mention' option, it will still work without any mention" do
@@ -241,16 +227,14 @@ defmodule Pleroma.FormatterTest do
"@@gsimg According to @archaeme, that is @daggsy. Also hello @archaeme@archae.me and @o and @@@jimm"
o = insert(:user, %{nickname: "o"})
- jimm = insert(:user, %{nickname: "jimm"})
- gsimg = insert(:user, %{nickname: "gsimg"})
+ _jimm = insert(:user, %{nickname: "jimm"})
+ _gsimg = insert(:user, %{nickname: "gsimg"})
archaeme = insert(:user, %{nickname: "archaeme"})
archaeme_remote = insert(:user, %{nickname: "archaeme@archae.me"})
expected_mentions = [
{"@archaeme", archaeme},
{"@archaeme@archae.me", archaeme_remote},
- {"@gsimg", gsimg},
- {"@jimm", jimm},
{"@o", o}
]
diff --git a/test/pleroma/frontend_test.exs b/test/pleroma/frontend_test.exs
new file mode 100644
index 000000000..1b50a031d
--- /dev/null
+++ b/test/pleroma/frontend_test.exs
@@ -0,0 +1,72 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.FrontendTest do
+ use Pleroma.DataCase
+ alias Pleroma.Frontend
+
+ @dir "test/frontend_static_test"
+
+ setup do
+ File.mkdir_p!(@dir)
+ clear_config([:instance, :static_dir], @dir)
+
+ on_exit(fn ->
+ File.rm_rf(@dir)
+ end)
+ end
+
+ test "it downloads and unzips a known frontend" do
+ clear_config([:frontends, :available], %{
+ "pleroma" => %{
+ "ref" => "fantasy",
+ "name" => "pleroma",
+ "build_url" => "http://gensokyo.2hu/builds/${ref}"
+ }
+ })
+
+ Tesla.Mock.mock(fn %{url: "http://gensokyo.2hu/builds/fantasy"} ->
+ %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/frontend_dist.zip")}
+ end)
+
+ Frontend.install("pleroma")
+
+ assert File.exists?(Path.join([@dir, "frontends", "pleroma", "fantasy", "test.txt"]))
+ end
+
+ test "it also works given a file" do
+ clear_config([:frontends, :available], %{
+ "pleroma" => %{
+ "ref" => "fantasy",
+ "name" => "pleroma",
+ "build_dir" => ""
+ }
+ })
+
+ folder = Path.join([@dir, "frontends", "pleroma", "fantasy"])
+ previously_existing = Path.join([folder, "temp"])
+ File.mkdir_p!(folder)
+ File.write!(previously_existing, "yey")
+ assert File.exists?(previously_existing)
+
+ Frontend.install("pleroma", file: "test/fixtures/tesla_mock/frontend.zip")
+
+ assert File.exists?(Path.join([folder, "test.txt"]))
+ refute File.exists?(previously_existing)
+ end
+
+ test "it downloads and unzips unknown frontends" do
+ Tesla.Mock.mock(fn %{url: "http://gensokyo.2hu/madeup.zip"} ->
+ %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/frontend.zip")}
+ end)
+
+ Frontend.install("unknown",
+ ref: "baka",
+ build_url: "http://gensokyo.2hu/madeup.zip",
+ build_dir: ""
+ )
+
+ assert File.exists?(Path.join([@dir, "frontends", "unknown", "baka", "test.txt"]))
+ end
+end
diff --git a/test/gun/conneciton_pool_test.exs b/test/pleroma/gun/connection_pool_test.exs
index aea908fac..51637f541 100644
--- a/test/gun/conneciton_pool_test.exs
+++ b/test/pleroma/gun/connection_pool_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Gun.ConnectionPoolTest do
@@ -7,7 +7,6 @@ defmodule Pleroma.Gun.ConnectionPoolTest do
import Mox
import ExUnit.CaptureLog
- alias Pleroma.Config
alias Pleroma.Gun.ConnectionPool
defp gun_mock(_) do
@@ -19,7 +18,6 @@ defmodule Pleroma.Gun.ConnectionPoolTest do
:ok
end
- setup :set_mox_from_context
setup :gun_mock
test "gives the same connection to 2 concurrent requests" do
@@ -48,9 +46,10 @@ defmodule Pleroma.Gun.ConnectionPoolTest do
end
end
+ @tag :erratic
test "connection limit is respected with concurrent requests" do
clear_config([:connections_pool, :max_connections]) do
- Config.put([:connections_pool, :max_connections], 1)
+ clear_config([:connections_pool, :max_connections], 1)
# The supervisor needs a reboot to apply the new config setting
Process.exit(Process.whereis(Pleroma.Gun.ConnectionPool.WorkerSupervisor), :kill)
diff --git a/test/pleroma/hashtag_test.exs b/test/pleroma/hashtag_test.exs
new file mode 100644
index 000000000..0264dea0b
--- /dev/null
+++ b/test/pleroma/hashtag_test.exs
@@ -0,0 +1,17 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.HashtagTest do
+ use Pleroma.DataCase
+
+ alias Pleroma.Hashtag
+
+ describe "changeset validations" do
+ test "ensure non-blank :name" do
+ changeset = Hashtag.changeset(%Hashtag{}, %{name: ""})
+
+ assert {:name, {"can't be blank", [validation: :required]}} in changeset.errors
+ end
+ end
+end
diff --git a/test/healthcheck_test.exs b/test/pleroma/healthcheck_test.exs
index e341e6983..469e5b397 100644
--- a/test/healthcheck_test.exs
+++ b/test/pleroma/healthcheck_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.HealthcheckTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Healthcheck
test "system_info/0" do
diff --git a/test/html_test.exs b/test/pleroma/html_test.exs
index 7d3756884..fe1a1ed57 100644
--- a/test/html_test.exs
+++ b/test/pleroma/html_test.exs
@@ -1,12 +1,12 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.HTMLTest do
alias Pleroma.HTML
alias Pleroma.Object
alias Pleroma.Web.CommonAPI
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
import Pleroma.Factory
@@ -175,7 +175,7 @@ defmodule Pleroma.HTMLTest do
"I think I just found the best github repo https://github.com/komeiji-satori/Dress"
})
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
{:ok, url} = HTML.extract_first_external_url_from_object(object)
assert url == "https://github.com/komeiji-satori/Dress"
end
@@ -190,7 +190,7 @@ defmodule Pleroma.HTMLTest do
"@#{other_user.nickname} install misskey! https://github.com/syuilo/misskey/blob/develop/docs/setup.en.md"
})
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
{:ok, url} = HTML.extract_first_external_url_from_object(object)
assert url == "https://github.com/syuilo/misskey/blob/develop/docs/setup.en.md"
@@ -206,7 +206,7 @@ defmodule Pleroma.HTMLTest do
status: "#cofe https://www.pixiv.net/member_illust.php?mode=medium&illust_id=72255140"
})
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
{:ok, url} = HTML.extract_first_external_url_from_object(object)
assert url == "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=72255140"
@@ -222,7 +222,7 @@ defmodule Pleroma.HTMLTest do
content_type: "text/html"
})
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
{:ok, url} = HTML.extract_first_external_url_from_object(object)
assert url == "https://www.pixiv.net/member_illust.php?mode=medium&illust_id=72255140"
@@ -233,7 +233,7 @@ defmodule Pleroma.HTMLTest do
{:ok, activity} = CommonAPI.post(user, %{status: "\"http://cofe.com/?boomer=ok&foo=bar\""})
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
assert {:ok, nil} = HTML.extract_first_external_url_from_object(object)
end
@@ -247,7 +247,7 @@ defmodule Pleroma.HTMLTest do
"<a href=\"https://pleroma.gov/media/d24caa3a498e21e0298377a9ca0149a4f4f8b767178aacf837542282e2d94fb1.png?name=image.png\" class=\"attachment\">image.png</a>"
})
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
assert {:ok, nil} = HTML.extract_first_external_url_from_object(object)
end
diff --git a/test/http/adapter_helper/gun_test.exs b/test/pleroma/http/adapter_helper/gun_test.exs
index 80589c73d..cfb68557d 100644
--- a/test/http/adapter_helper/gun_test.exs
+++ b/test/pleroma/http/adapter_helper/gun_test.exs
@@ -1,14 +1,13 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.HTTP.AdapterHelper.GunTest do
- use ExUnit.Case, async: true
+ use ExUnit.Case
use Pleroma.Tests.Helpers
import Mox
- alias Pleroma.Config
alias Pleroma.HTTP.AdapterHelper.Gun
setup :verify_on_exit!
@@ -52,9 +51,7 @@ defmodule Pleroma.HTTP.AdapterHelper.GunTest do
end
test "parses string proxy host & port" do
- proxy = Config.get([:http, :proxy_url])
- Config.put([:http, :proxy_url], "localhost:8123")
- on_exit(fn -> Config.put([:http, :proxy_url], proxy) end)
+ clear_config([:http, :proxy_url], "localhost:8123")
uri = URI.parse("https://some-domain.com")
opts = Gun.options([receive_conn: false], uri)
@@ -62,9 +59,7 @@ defmodule Pleroma.HTTP.AdapterHelper.GunTest do
end
test "parses tuple proxy scheme host and port" do
- proxy = Config.get([:http, :proxy_url])
- Config.put([:http, :proxy_url], {:socks, 'localhost', 1234})
- on_exit(fn -> Config.put([:http, :proxy_url], proxy) end)
+ clear_config([:http, :proxy_url], {:socks, 'localhost', 1234})
uri = URI.parse("https://some-domain.com")
opts = Gun.options([receive_conn: false], uri)
@@ -72,9 +67,7 @@ defmodule Pleroma.HTTP.AdapterHelper.GunTest do
end
test "passed opts have more weight than defaults" do
- proxy = Config.get([:http, :proxy_url])
- Config.put([:http, :proxy_url], {:socks5, 'localhost', 1234})
- on_exit(fn -> Config.put([:http, :proxy_url], proxy) end)
+ clear_config([:http, :proxy_url], {:socks5, 'localhost', 1234})
uri = URI.parse("https://some-domain.com")
opts = Gun.options([receive_conn: false, proxy: {'example.com', 4321}], uri)
diff --git a/test/http/adapter_helper/hackney_test.exs b/test/pleroma/http/adapter_helper/hackney_test.exs
index f2361ff0b..85150a65c 100644
--- a/test/http/adapter_helper/hackney_test.exs
+++ b/test/pleroma/http/adapter_helper/hackney_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.HTTP.AdapterHelper.HackneyTest do
diff --git a/test/http/adapter_helper_test.exs b/test/pleroma/http/adapter_helper_test.exs
index 24d501ad5..3c8c89164 100644
--- a/test/http/adapter_helper_test.exs
+++ b/test/pleroma/http/adapter_helper_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.HTTP.AdapterHelperTest do
diff --git a/test/http/ex_aws_test.exs b/test/pleroma/http/ex_aws_test.exs
index d0b00ca26..4cbc440bd 100644
--- a/test/http/ex_aws_test.exs
+++ b/test/pleroma/http/ex_aws_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.HTTP.ExAwsTest do
diff --git a/test/http/request_builder_test.exs b/test/pleroma/http/request_builder_test.exs
index fab909905..433beaac1 100644
--- a/test/http/request_builder_test.exs
+++ b/test/pleroma/http/request_builder_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.HTTP.RequestBuilderTest do
@@ -34,24 +34,32 @@ defmodule Pleroma.HTTP.RequestBuilderTest do
describe "add_param/4" do
test "add file parameter" do
- %Request{
- body: %Tesla.Multipart{
- boundary: _,
- content_type_params: [],
- parts: [
- %Tesla.Multipart.Part{
- body: %File.Stream{
- line_or_bytes: 2048,
- modes: [:raw, :read_ahead, :read, :binary],
- path: "some-path/filename.png",
- raw: true
- },
- dispositions: [name: "filename.png", filename: "filename.png"],
- headers: []
- }
- ]
- }
- } = RequestBuilder.add_param(%Request{}, :file, "filename.png", "some-path/filename.png")
+ assert match?(
+ %Request{
+ body: %Tesla.Multipart{
+ boundary: _,
+ content_type_params: [],
+ parts: [
+ %Tesla.Multipart.Part{
+ body: %File.Stream{
+ line_or_bytes: 2048,
+ modes: [:raw, :read_ahead, :binary],
+ path: "some-path/filename.png",
+ raw: true
+ },
+ dispositions: [name: "filename.png", filename: "filename.png"],
+ headers: []
+ }
+ ]
+ }
+ },
+ RequestBuilder.add_param(
+ %Request{},
+ :file,
+ "filename.png",
+ "some-path/filename.png"
+ )
+ )
end
test "add key to body" do
diff --git a/test/http/tzdata_test.exs b/test/pleroma/http/tzdata_test.exs
index 3e605d33b..1161bfaef 100644
--- a/test/http/tzdata_test.exs
+++ b/test/pleroma/http/tzdata_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.HTTP.TzdataTest do
diff --git a/test/http_test.exs b/test/pleroma/http_test.exs
index d394bb942..e6a6d31b3 100644
--- a/test/http_test.exs
+++ b/test/pleroma/http_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.HTTPTest do
diff --git a/test/web/instances/instance_test.exs b/test/pleroma/instances/instance_test.exs
index dc6ace843..e49922724 100644
--- a/test/web/instances/instance_test.exs
+++ b/test/pleroma/instances/instance_test.exs
@@ -1,10 +1,13 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Instances.InstanceTest do
+ alias Pleroma.Instances
alias Pleroma.Instances.Instance
alias Pleroma.Repo
+ alias Pleroma.Tests.ObanHelpers
+ alias Pleroma.Web.CommonAPI
use Pleroma.DataCase
@@ -99,35 +102,91 @@ defmodule Pleroma.Instances.InstanceTest do
end
end
- test "Scrapes favicon URLs" do
- Tesla.Mock.mock(fn %{url: "https://favicon.example.org/"} ->
- %Tesla.Env{
- status: 200,
- body: ~s[<html><head><link rel="icon" href="/favicon.png"></head></html>]
- }
- end)
+ describe "get_or_update_favicon/1" do
+ test "Scrapes favicon URLs" do
+ Tesla.Mock.mock(fn %{url: "https://favicon.example.org/"} ->
+ %Tesla.Env{
+ status: 200,
+ body: ~s[<html><head><link rel="icon" href="/favicon.png"></head></html>]
+ }
+ end)
+
+ assert "https://favicon.example.org/favicon.png" ==
+ Instance.get_or_update_favicon(URI.parse("https://favicon.example.org/"))
+ end
+
+ test "Returns nil on too long favicon URLs" do
+ long_favicon_url =
+ "https://Lorem.ipsum.dolor.sit.amet/consecteturadipiscingelit/Praesentpharetrapurusutaliquamtempus/Mauriseulaoreetarcu/atfacilisisorci/Nullamporttitor/nequesedfeugiatmollis/dolormagnaefficiturlorem/nonpretiumsapienorcieurisus/Nullamveleratsem/Maecenassedaccumsanexnam/favicon.png"
+
+ Tesla.Mock.mock(fn %{url: "https://long-favicon.example.org/"} ->
+ %Tesla.Env{
+ status: 200,
+ body:
+ ~s[<html><head><link rel="icon" href="] <> long_favicon_url <> ~s["></head></html>]
+ }
+ end)
+
+ assert capture_log(fn ->
+ assert nil ==
+ Instance.get_or_update_favicon(
+ URI.parse("https://long-favicon.example.org/")
+ )
+ end) =~
+ "Instance.get_or_update_favicon(\"long-favicon.example.org\") error: %Postgrex.Error{"
+ end
- assert "https://favicon.example.org/favicon.png" ==
- Instance.get_or_update_favicon(URI.parse("https://favicon.example.org/"))
+ test "Handles not getting a favicon URL properly" do
+ Tesla.Mock.mock(fn %{url: "https://no-favicon.example.org/"} ->
+ %Tesla.Env{
+ status: 200,
+ body: ~s[<html><head><h1>I wil look down and whisper "GNO.."</h1></head></html>]
+ }
+ end)
+
+ refute capture_log(fn ->
+ assert nil ==
+ Instance.get_or_update_favicon(
+ URI.parse("https://no-favicon.example.org/")
+ )
+ end) =~ "Instance.scrape_favicon(\"https://no-favicon.example.org/\") error: "
+ end
+
+ test "Doesn't scrapes unreachable instances" do
+ instance = insert(:instance, unreachable_since: Instances.reachability_datetime_threshold())
+ url = "https://" <> instance.host
+
+ assert capture_log(fn -> assert nil == Instance.get_or_update_favicon(URI.parse(url)) end) =~
+ "Instance.scrape_favicon(\"#{url}\") ignored unreachable host"
+ end
end
- test "Returns nil on too long favicon URLs" do
- long_favicon_url =
- "https://Lorem.ipsum.dolor.sit.amet/consecteturadipiscingelit/Praesentpharetrapurusutaliquamtempus/Mauriseulaoreetarcu/atfacilisisorci/Nullamporttitor/nequesedfeugiatmollis/dolormagnaefficiturlorem/nonpretiumsapienorcieurisus/Nullamveleratsem/Maecenassedaccumsanexnam/favicon.png"
-
- Tesla.Mock.mock(fn %{url: "https://long-favicon.example.org/"} ->
- %Tesla.Env{
- status: 200,
- body: ~s[<html><head><link rel="icon" href="] <> long_favicon_url <> ~s["></head></html>]
- }
- end)
-
- assert capture_log(fn ->
- assert nil ==
- Instance.get_or_update_favicon(
- URI.parse("https://long-favicon.example.org/")
- )
- end) =~
- "Instance.get_or_update_favicon(\"long-favicon.example.org\") error: %Postgrex.Error{"
+ test "delete_users_and_activities/1 deletes remote instance users and activities" do
+ [mario, luigi, _peach, wario] =
+ users = [
+ insert(:user, nickname: "mario@mushroom.kingdom", name: "Mario"),
+ insert(:user, nickname: "luigi@mushroom.kingdom", name: "Luigi"),
+ insert(:user, nickname: "peach@mushroom.kingdom", name: "Peach"),
+ insert(:user, nickname: "wario@greedville.biz", name: "Wario")
+ ]
+
+ {:ok, post1} = CommonAPI.post(mario, %{status: "letsa go!"})
+ {:ok, post2} = CommonAPI.post(luigi, %{status: "itsa me... luigi"})
+ {:ok, post3} = CommonAPI.post(wario, %{status: "WHA-HA-HA!"})
+
+ {:ok, job} = Instance.delete_users_and_activities("mushroom.kingdom")
+ :ok = ObanHelpers.perform(job)
+
+ [mario, luigi, peach, wario] = Repo.reload(users)
+
+ refute mario.is_active
+ refute luigi.is_active
+ refute peach.is_active
+ refute peach.name == "Peach"
+
+ assert wario.is_active
+ assert wario.name == "Wario"
+
+ assert [nil, nil, %{}] = Repo.reload([post1, post2, post3])
end
end
diff --git a/test/web/instances/instances_test.exs b/test/pleroma/instances_test.exs
index d2618025c..03f9e4e97 100644
--- a/test/web/instances/instances_test.exs
+++ b/test/pleroma/instances_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.InstancesTest do
@@ -32,9 +32,9 @@ defmodule Pleroma.InstancesTest do
assert Instances.reachable?(URI.parse(url).host)
end
- test "returns true on non-binary input" do
- assert Instances.reachable?(nil)
- assert Instances.reachable?(1)
+ test "raises FunctionClauseError exception on non-binary input" do
+ assert_raise FunctionClauseError, fn -> Instances.reachable?(nil) end
+ assert_raise FunctionClauseError, fn -> Instances.reachable?(1) end
end
end
diff --git a/test/federation/federation_test.exs b/test/pleroma/integration/federation_test.exs
index 10d71fb88..da433e2c0 100644
--- a/test/federation/federation_test.exs
+++ b/test/pleroma/integration/federation_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Integration.FederationTest do
diff --git a/test/integration/mastodon_websocket_test.exs b/test/pleroma/integration/mastodon_websocket_test.exs
index ea17e9feb..43ec57893 100644
--- a/test/integration/mastodon_websocket_test.exs
+++ b/test/pleroma/integration/mastodon_websocket_test.exs
@@ -1,8 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Integration.MastodonWebsocketTest do
+ # Needs a streamer, needs to stay synchronous
use Pleroma.DataCase
import ExUnit.CaptureLog
@@ -49,6 +50,7 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do
test "allows public streams without authentication" do
assert {:ok, _} = start_socket("?stream=public")
assert {:ok, _} = start_socket("?stream=public:local")
+ assert {:ok, _} = start_socket("?stream=public:remote&instance=lain.com")
assert {:ok, _} = start_socket("?stream=hashtag&tag=lain")
end
@@ -78,7 +80,7 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do
Pleroma.Repo.insert(
OAuth.App.register_changeset(%OAuth.App{}, %{
client_name: "client",
- scopes: ["scope"],
+ scopes: ["read"],
redirect_uris: "url"
})
)
@@ -99,30 +101,30 @@ defmodule Pleroma.Integration.MastodonWebsocketTest do
test "accepts the 'user' stream", %{token: token} = _state do
assert {:ok, _} = start_socket("?stream=user&access_token=#{token.token}")
- assert capture_log(fn ->
- assert {:error, {401, _}} = start_socket("?stream=user")
- Process.sleep(30)
- end) =~ ":badarg"
+ capture_log(fn ->
+ assert {:error, {401, _}} = start_socket("?stream=user")
+ Process.sleep(30)
+ end)
end
test "accepts the 'user:notification' stream", %{token: token} = _state do
assert {:ok, _} = start_socket("?stream=user:notification&access_token=#{token.token}")
- assert capture_log(fn ->
- assert {:error, {401, _}} = start_socket("?stream=user:notification")
- Process.sleep(30)
- end) =~ ":badarg"
+ capture_log(fn ->
+ assert {:error, {401, _}} = start_socket("?stream=user:notification")
+ Process.sleep(30)
+ end)
end
test "accepts valid token on Sec-WebSocket-Protocol header", %{token: token} do
assert {:ok, _} = start_socket("?stream=user", [{"Sec-WebSocket-Protocol", token.token}])
- assert capture_log(fn ->
- assert {:error, {401, _}} =
- start_socket("?stream=user", [{"Sec-WebSocket-Protocol", "I am a friend"}])
+ capture_log(fn ->
+ assert {:error, {401, _}} =
+ start_socket("?stream=user", [{"Sec-WebSocket-Protocol", "I am a friend"}])
- Process.sleep(30)
- end) =~ ":badarg"
+ Process.sleep(30)
+ end)
end
end
end
diff --git a/test/job_queue_monitor_test.exs b/test/pleroma/job_queue_monitor_test.exs
index 65c1e9f29..eebf602c5 100644
--- a/test/job_queue_monitor_test.exs
+++ b/test/pleroma/job_queue_monitor_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.JobQueueMonitorTest do
diff --git a/test/keys_test.exs b/test/pleroma/keys_test.exs
index 9e8528cba..9a15bf06e 100644
--- a/test/keys_test.exs
+++ b/test/pleroma/keys_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.KeysTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Keys
diff --git a/test/list_test.exs b/test/pleroma/list_test.exs
index b5572cbae..7e66ad385 100644
--- a/test/list_test.exs
+++ b/test/pleroma/list_test.exs
@@ -1,10 +1,10 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.ListTest do
alias Pleroma.Repo
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
import Pleroma.Factory
diff --git a/test/marker_test.exs b/test/pleroma/marker_test.exs
index 5b6d0b4a4..5f87a1c38 100644
--- a/test/marker_test.exs
+++ b/test/pleroma/marker_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.MarkerTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Marker
import Pleroma.Factory
@@ -33,8 +33,8 @@ defmodule Pleroma.MarkerTest do
test "returns user markers" do
user = insert(:user)
marker = insert(:marker, user: user)
- insert(:notification, user: user)
- insert(:notification, user: user)
+ insert(:notification, user: user, activity: insert(:note_activity))
+ insert(:notification, user: user, activity: insert(:note_activity))
insert(:marker, timeline: "home", user: user)
assert Marker.get_markers(
diff --git a/test/mfa/backup_codes_test.exs b/test/pleroma/mfa/backup_codes_test.exs
index 7bc01b36b..59f984e32 100644
--- a/test/mfa/backup_codes_test.exs
+++ b/test/pleroma/mfa/backup_codes_test.exs
@@ -1,5 +1,9 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.MFA.BackupCodesTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.MFA.BackupCodes
diff --git a/test/mfa/totp_test.exs b/test/pleroma/mfa/totp_test.exs
index 50153d208..828993866 100644
--- a/test/mfa/totp_test.exs
+++ b/test/pleroma/mfa/totp_test.exs
@@ -1,5 +1,9 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.MFA.TOTPTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.MFA.TOTP
diff --git a/test/mfa_test.exs b/test/pleroma/mfa_test.exs
index 8875cefd9..76ba1a99d 100644
--- a/test/mfa_test.exs
+++ b/test/pleroma/mfa_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.MFATest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
import Pleroma.Factory
alias Pleroma.MFA
@@ -30,8 +30,8 @@ defmodule Pleroma.MFATest do
{:ok, [code1, code2]} = MFA.generate_backup_codes(user)
updated_user = refresh_record(user)
[hash1, hash2] = updated_user.multi_factor_authentication_settings.backup_codes
- assert Pbkdf2.verify_pass(code1, hash1)
- assert Pbkdf2.verify_pass(code2, hash2)
+ assert Pleroma.Password.Pbkdf2.verify_pass(code1, hash1)
+ assert Pleroma.Password.Pbkdf2.verify_pass(code2, hash2)
end
end
diff --git a/test/migration_helper/notification_backfill_test.exs b/test/pleroma/migration_helper/notification_backfill_test.exs
index 2a62a2b00..fd253b530 100644
--- a/test/migration_helper/notification_backfill_test.exs
+++ b/test/pleroma/migration_helper/notification_backfill_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.MigrationHelper.NotificationBackfillTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Activity
alias Pleroma.MigrationHelper.NotificationBackfill
diff --git a/test/moderation_log_test.exs b/test/pleroma/moderation_log_test.exs
index 59f4d67f8..607301815 100644
--- a/test/moderation_log_test.exs
+++ b/test/pleroma/moderation_log_test.exs
@@ -1,12 +1,12 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.ModerationLogTest do
alias Pleroma.Activity
alias Pleroma.ModerationLog
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
import Pleroma.Factory
@@ -182,11 +182,14 @@ defmodule Pleroma.ModerationLogTest do
end
test "logging report update", %{moderator: moderator} do
+ user = insert(:user)
+
report = %Activity{
id: "9m9I1F4p8ftrTP6QTI",
data: %{
"type" => "Flag",
- "state" => "resolved"
+ "state" => "resolved",
+ "actor" => user.ap_id
}
}
@@ -194,35 +197,46 @@ defmodule Pleroma.ModerationLogTest do
ModerationLog.insert_log(%{
actor: moderator,
action: "report_update",
- subject: report
+ subject: report,
+ subject_actor: user
})
log = Repo.one(ModerationLog)
assert log.data["message"] ==
- "@#{moderator.nickname} updated report ##{report.id} with 'resolved' state"
+ "@#{moderator.nickname} updated report ##{report.id} (on user @#{user.nickname}) with 'resolved' state"
end
test "logging report response", %{moderator: moderator} do
+ user = insert(:user)
+
report = %Activity{
id: "9m9I1F4p8ftrTP6QTI",
data: %{
- "type" => "Note"
+ "type" => "Note",
+ "actor" => user.ap_id
}
}
- {:ok, _} =
- ModerationLog.insert_log(%{
- actor: moderator,
- action: "report_note",
- subject: report,
- text: "look at this"
- })
+ attrs = %{
+ actor: moderator,
+ action: "report_note",
+ subject: report,
+ text: "look at this"
+ }
- log = Repo.one(ModerationLog)
+ {:ok, log1} = ModerationLog.insert_log(attrs)
+ log = Repo.get(ModerationLog, log1.id)
assert log.data["message"] ==
"@#{moderator.nickname} added note 'look at this' to report ##{report.id}"
+
+ {:ok, log2} = ModerationLog.insert_log(Map.merge(attrs, %{subject_actor: user}))
+
+ log = Repo.get(ModerationLog, log2.id)
+
+ assert log.data["message"] ==
+ "@#{moderator.nickname} added note 'look at this' to report ##{report.id} on user @#{user.nickname}"
end
test "logging status sensitivity update", %{moderator: moderator} do
diff --git a/test/notification_test.exs b/test/pleroma/notification_test.exs
index a09b08675..716af496d 100644
--- a/test/notification_test.exs
+++ b/test/pleroma/notification_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.NotificationTest do
@@ -32,6 +32,33 @@ defmodule Pleroma.NotificationTest do
refute {:ok, [nil]} == Notification.create_notifications(activity)
end
+ test "creates a notification for a report" do
+ reporting_user = insert(:user)
+ reported_user = insert(:user)
+ {:ok, moderator_user} = insert(:user) |> User.admin_api_update(%{is_moderator: true})
+
+ {:ok, activity} = CommonAPI.report(reporting_user, %{account_id: reported_user.id})
+
+ {:ok, [notification]} = Notification.create_notifications(activity)
+
+ assert notification.user_id == moderator_user.id
+ assert notification.type == "pleroma:report"
+ end
+
+ test "suppresses notification to reporter if reporter is an admin" do
+ reporting_admin = insert(:user, is_admin: true)
+ reported_user = insert(:user)
+ other_admin = insert(:user, is_admin: true)
+
+ {:ok, activity} = CommonAPI.report(reporting_admin, %{account_id: reported_user.id})
+
+ {:ok, [notification]} = Notification.create_notifications(activity)
+
+ refute notification.user_id == reporting_admin.id
+ assert notification.user_id == other_admin.id
+ assert notification.type == "pleroma:report"
+ end
+
test "creates a notification for an emoji reaction" do
user = insert(:user)
other_user = insert(:user)
@@ -102,6 +129,19 @@ defmodule Pleroma.NotificationTest do
end
end
+ test "create_poll_notifications/1" do
+ [user1, user2, user3, _, _] = insert_list(5, :user)
+ question = insert(:question, user: user1)
+ activity = insert(:question_activity, question: question)
+
+ {:ok, _, _} = CommonAPI.vote(user2, question, [0])
+ {:ok, _, _} = CommonAPI.vote(user3, question, [1])
+
+ {:ok, notifications} = Notification.create_poll_notifications(activity)
+
+ assert [user2.id, user3.id, user1.id] == Enum.map(notifications, & &1.user_id)
+ end
+
describe "CommonApi.post/2 notification-related functionality" do
test_with_mock "creates but does NOT send notification to blocker user",
Push,
@@ -179,17 +219,19 @@ defmodule Pleroma.NotificationTest do
describe "create_notification" do
@tag needs_streamer: true
test "it creates a notification for user and send to the 'user' and the 'user:notification' stream" do
- user = insert(:user)
+ %{user: user, token: oauth_token} = oauth_access(["read"])
task =
Task.async(fn ->
- Streamer.get_topic_and_add_socket("user", user)
+ {:ok, _topic} = Streamer.get_topic_and_add_socket("user", user, oauth_token)
assert_receive {:render_with_user, _, _, _}, 4_000
end)
task_user_notification =
Task.async(fn ->
- Streamer.get_topic_and_add_socket("user:notification", user)
+ {:ok, _topic} =
+ Streamer.get_topic_and_add_socket("user:notification", user, oauth_token)
+
assert_receive {:render_with_user, _, _, _}, 4_000
end)
@@ -227,7 +269,7 @@ defmodule Pleroma.NotificationTest do
muter = insert(:user)
muted = insert(:user)
- {:ok, _user_relationships} = User.mute(muter, muted, false)
+ {:ok, _user_relationships} = User.mute(muter, muted, %{notifications: false})
{:ok, activity} = CommonAPI.post(muted, %{status: "Hi @#{muter.nickname}"})
@@ -344,7 +386,7 @@ defmodule Pleroma.NotificationTest do
describe "follow / follow_request notifications" do
test "it creates `follow` notification for approved Follow activity" do
user = insert(:user)
- followed_user = insert(:user, locked: false)
+ followed_user = insert(:user, is_locked: false)
{:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
assert FollowingRelationship.following?(user, followed_user)
@@ -359,7 +401,7 @@ defmodule Pleroma.NotificationTest do
test "it creates `follow_request` notification for pending Follow activity" do
user = insert(:user)
- followed_user = insert(:user, locked: true)
+ followed_user = insert(:user, is_locked: true)
{:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
refute FollowingRelationship.following?(user, followed_user)
@@ -381,7 +423,7 @@ defmodule Pleroma.NotificationTest do
test "it doesn't create a notification for follow-unfollow-follow chains" do
user = insert(:user)
- followed_user = insert(:user, locked: false)
+ followed_user = insert(:user, is_locked: false)
{:ok, _, _, _activity} = CommonAPI.follow(user, followed_user)
assert FollowingRelationship.following?(user, followed_user)
@@ -395,10 +437,10 @@ defmodule Pleroma.NotificationTest do
end
test "dismisses the notification on follow request rejection" do
- user = insert(:user, locked: true)
+ user = insert(:user, is_locked: true)
follower = insert(:user)
{:ok, _, _, _follow_activity} = CommonAPI.follow(follower, user)
- assert [notification] = Notification.for_user(user)
+ assert [_notification] = Notification.for_user(user)
{:ok, _follower} = CommonAPI.reject_follow_request(follower, user)
assert [] = Notification.for_user(user)
end
@@ -595,6 +637,8 @@ defmodule Pleroma.NotificationTest do
"actor" => user.ap_id,
"object" => %{
"type" => "Note",
+ "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
+ "to" => ["https://www.w3.org/ns/activitystreams#Public"],
"content" => "message with a Mention tag, but no explicit tagging",
"tag" => [
%{
@@ -626,6 +670,9 @@ defmodule Pleroma.NotificationTest do
"actor" => user.ap_id,
"object" => %{
"type" => "Note",
+ "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
+ "to" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "cc" => [other_user.ap_id],
"content" => "hi everyone",
"attributedTo" => user.ap_id
}
@@ -764,7 +811,7 @@ defmodule Pleroma.NotificationTest do
other_user = insert(:user)
{:ok, other_user} = User.block_domain(other_user, blocked_domain)
- {:ok, other_user} = User.follow(other_user, user)
+ {:ok, other_user, user} = User.follow(other_user, user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{other_user.nickname}!"})
@@ -922,6 +969,7 @@ defmodule Pleroma.NotificationTest do
"cc" => [],
"object" => %{
"type" => "Note",
+ "id" => remote_user.ap_id <> "/objects/test",
"content" => "Hello!",
"tag" => [
%{
@@ -961,7 +1009,6 @@ defmodule Pleroma.NotificationTest do
assert Enum.empty?(Notification.for_user(local_user))
end
- @tag capture_log: true
test "move activity generates a notification" do
%{ap_id: old_ap_id} = old_user = insert(:user)
%{ap_id: new_ap_id} = new_user = insert(:user, also_known_as: [old_ap_id])
@@ -971,18 +1018,6 @@ defmodule Pleroma.NotificationTest do
User.follow(follower, old_user)
User.follow(other_follower, old_user)
- old_user_url = old_user.ap_id
-
- body =
- File.read!("test/fixtures/users_mock/localhost.json")
- |> String.replace("{{nickname}}", old_user.nickname)
- |> Jason.encode!()
-
- Tesla.Mock.mock(fn
- %{method: :get, url: ^old_user_url} ->
- %Tesla.Env{status: 200, body: body}
- end)
-
Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user)
ObanHelpers.perform_all()
@@ -1013,7 +1048,7 @@ defmodule Pleroma.NotificationTest do
test "it returns notifications for muted user without notifications", %{user: user} do
muted = insert(:user)
- {:ok, _user_relationships} = User.mute(user, muted, false)
+ {:ok, _user_relationships} = User.mute(user, muted, %{notifications: false})
{:ok, _activity} = CommonAPI.post(muted, %{status: "hey @#{user.nickname}"})
@@ -1055,7 +1090,7 @@ defmodule Pleroma.NotificationTest do
blocked = insert(:user, ap_id: "http://some-domain.com")
{:ok, user} = User.block_domain(user, "some-domain.com")
- {:ok, _} = User.follow(user, blocked)
+ {:ok, _, _} = User.follow(user, blocked)
{:ok, _activity} = CommonAPI.post(blocked, %{status: "hey @#{user.nickname}"})
diff --git a/test/object/containment_test.exs b/test/pleroma/object/containment_test.exs
index 90b6dccf2..fb2fb7d49 100644
--- a/test/object/containment_test.exs
+++ b/test/pleroma/object/containment_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Object.ContainmentTest do
diff --git a/test/object/fetcher_test.exs b/test/pleroma/object/fetcher_test.exs
index 16cfa7f5c..bd0a6e497 100644
--- a/test/object/fetcher_test.exs
+++ b/test/pleroma/object/fetcher_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Object.FetcherTest do
@@ -8,8 +8,9 @@ defmodule Pleroma.Object.FetcherTest do
alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.Object.Fetcher
- import Tesla.Mock
+
import Mock
+ import Tesla.Mock
setup do
mock(fn
@@ -19,6 +20,17 @@ defmodule Pleroma.Object.FetcherTest do
%{method: :get, url: "https://mastodon.example.org/users/userisgone404"} ->
%Tesla.Env{status: 404}
+ %{
+ method: :get,
+ url:
+ "https://patch.cx/media/03ca3c8b4ac3ddd08bf0f84be7885f2f88de0f709112131a22d83650819e36c2.json"
+ } ->
+ %Tesla.Env{
+ status: 200,
+ headers: [{"content-type", "application/json"}],
+ body: File.read!("test/fixtures/spoofed-object.json")
+ }
+
env ->
apply(HttpRequestMock, :request, [env])
end)
@@ -32,25 +44,36 @@ defmodule Pleroma.Object.FetcherTest do
%{method: :get, url: "https://social.sakamoto.gq/notice/9wTkLEnuq47B25EehM"} ->
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/fetch_mocks/9wTkLEnuq47B25EehM.json")
+ body: File.read!("test/fixtures/fetch_mocks/9wTkLEnuq47B25EehM.json"),
+ headers: HttpRequestMock.activitypub_object_headers()
}
%{method: :get, url: "https://social.sakamoto.gq/users/eal"} ->
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/fetch_mocks/eal.json")
+ body: File.read!("test/fixtures/fetch_mocks/eal.json"),
+ headers: HttpRequestMock.activitypub_object_headers()
}
%{method: :get, url: "https://busshi.moe/users/tuxcrafting/statuses/104410921027210069"} ->
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/fetch_mocks/104410921027210069.json")
+ body: File.read!("test/fixtures/fetch_mocks/104410921027210069.json"),
+ headers: HttpRequestMock.activitypub_object_headers()
}
%{method: :get, url: "https://busshi.moe/users/tuxcrafting"} ->
%Tesla.Env{
status: 500
}
+
+ %{
+ method: :get,
+ url: "https://stereophonic.space/objects/02997b83-3ea7-4b63-94af-ef3aa2d4ed17"
+ } ->
+ %Tesla.Env{
+ status: 500
+ }
end)
:ok
@@ -71,20 +94,20 @@ defmodule Pleroma.Object.FetcherTest do
setup do: clear_config([:instance, :federation_incoming_replies_max_depth])
test "it returns thread depth exceeded error if thread depth is exceeded" do
- Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 0)
+ clear_config([:instance, :federation_incoming_replies_max_depth], 0)
assert {:error, "Max thread distance exceeded."} =
Fetcher.fetch_object_from_id(@ap_id, depth: 1)
end
test "it fetches object if max thread depth is restricted to 0 and depth is not specified" do
- Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 0)
+ clear_config([:instance, :federation_incoming_replies_max_depth], 0)
assert {:ok, _} = Fetcher.fetch_object_from_id(@ap_id)
end
test "it fetches object if requested depth does not exceed max thread depth" do
- Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 10)
+ clear_config([:instance, :federation_incoming_replies_max_depth], 10)
assert {:ok, _} = Fetcher.fetch_object_from_id(@ap_id, depth: 10)
end
@@ -109,8 +132,7 @@ defmodule Pleroma.Object.FetcherTest do
{:ok, object} =
Fetcher.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367")
- assert activity = Activity.get_create_by_object_ap_id(object.data["id"])
- assert activity.data["id"]
+ assert _activity = Activity.get_create_by_object_ap_id(object.data["id"])
{:ok, object_again} =
Fetcher.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367")
@@ -120,6 +142,23 @@ defmodule Pleroma.Object.FetcherTest do
assert object == object_again
end
+
+ test "Return MRF reason when fetched status is rejected by one" do
+ clear_config([:mrf_keyword, :reject], ["yeah"])
+ clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.KeywordPolicy])
+
+ assert {:reject, "[KeywordPolicy] Matches with rejected keyword"} ==
+ Fetcher.fetch_object_from_id(
+ "http://mastodon.example.org/@admin/99541947525187367"
+ )
+ end
+
+ test "it does not fetch a spoofed object uploaded on an instance as an attachment" do
+ assert {:error, _} =
+ Fetcher.fetch_object_from_id(
+ "https://patch.cx/media/03ca3c8b4ac3ddd08bf0f84be7885f2f88de0f709112131a22d83650819e36c2.json"
+ )
+ end
end
describe "implementation quirks" do
@@ -212,7 +251,7 @@ defmodule Pleroma.Object.FetcherTest do
Pleroma.Signature,
[:passthrough],
[] do
- Pleroma.Config.put([:activitypub, :sign_object_fetches], true)
+ clear_config([:activitypub, :sign_object_fetches], true)
Fetcher.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367")
@@ -223,7 +262,7 @@ defmodule Pleroma.Object.FetcherTest do
Pleroma.Signature,
[:passthrough],
[] do
- Pleroma.Config.put([:activitypub, :sign_object_fetches], false)
+ clear_config([:activitypub, :sign_object_fetches], false)
Fetcher.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367")
diff --git a/test/object_test.exs b/test/pleroma/object_test.exs
index 198d3b1cf..8320660a5 100644
--- a/test/object_test.exs
+++ b/test/pleroma/object_test.exs
@@ -1,14 +1,17 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.ObjectTest do
use Pleroma.DataCase
use Oban.Testing, repo: Pleroma.Repo
+
import ExUnit.CaptureLog
import Pleroma.Factory
import Tesla.Mock
+
alias Pleroma.Activity
+ alias Pleroma.Hashtag
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.Tests.ObanHelpers
@@ -78,11 +81,11 @@ defmodule Pleroma.ObjectTest do
setup do: clear_config([:instance, :cleanup_attachments])
test "Disabled via config" do
- Pleroma.Config.put([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
- Pleroma.Config.put([:instance, :cleanup_attachments], false)
+ clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
+ clear_config([:instance, :cleanup_attachments], false)
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}
@@ -112,11 +115,11 @@ defmodule Pleroma.ObjectTest do
end
test "in subdirectories" do
- Pleroma.Config.put([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
- Pleroma.Config.put([:instance, :cleanup_attachments], true)
+ clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
+ clear_config([:instance, :cleanup_attachments], true)
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}
@@ -146,16 +149,16 @@ defmodule Pleroma.ObjectTest do
end
test "with dedupe enabled" do
- Pleroma.Config.put([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
- Pleroma.Config.put([Pleroma.Upload, :filters], [Pleroma.Upload.Filter.Dedupe])
- Pleroma.Config.put([:instance, :cleanup_attachments], true)
+ clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
+ clear_config([Pleroma.Upload, :filters], [Pleroma.Upload.Filter.Dedupe])
+ clear_config([:instance, :cleanup_attachments], true)
uploads_dir = Pleroma.Config.get!([Pleroma.Uploaders.Local, :uploads])
File.mkdir_p!(uploads_dir)
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}
@@ -184,11 +187,11 @@ defmodule Pleroma.ObjectTest do
end
test "with objects that have legacy data.url attribute" do
- Pleroma.Config.put([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
- Pleroma.Config.put([:instance, :cleanup_attachments], true)
+ clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
+ clear_config([:instance, :cleanup_attachments], true)
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}
@@ -220,12 +223,12 @@ defmodule Pleroma.ObjectTest do
end
test "With custom base_url" do
- Pleroma.Config.put([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
- Pleroma.Config.put([Pleroma.Upload, :base_url], "https://sub.domain.tld/dir/")
- Pleroma.Config.put([:instance, :cleanup_attachments], true)
+ clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
+ clear_config([Pleroma.Upload, :base_url], "https://sub.domain.tld/dir/")
+ clear_config([:instance, :cleanup_attachments], true)
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}
@@ -256,23 +259,22 @@ defmodule Pleroma.ObjectTest do
end
describe "normalizer" do
- test "fetches unknown objects by default" do
- %Object{} =
- object = Object.normalize("http://mastodon.example.org/@admin/99541947525187367")
-
- assert object.data["url"] == "http://mastodon.example.org/@admin/99541947525187367"
+ @url "http://mastodon.example.org/@admin/99541947525187367"
+ test "does not fetch unknown objects by default" do
+ assert nil == Object.normalize(@url)
end
- test "fetches unknown objects when fetch_remote is explicitly true" do
- %Object{} =
- object = Object.normalize("http://mastodon.example.org/@admin/99541947525187367", true)
+ test "fetches unknown objects when fetch is explicitly true" do
+ %Object{} = object = Object.normalize(@url, fetch: true)
- assert object.data["url"] == "http://mastodon.example.org/@admin/99541947525187367"
+ assert object.data["url"] == @url
end
- test "does not fetch unknown objects when fetch_remote is false" do
+ test "does not fetch unknown objects when fetch is false" do
assert is_nil(
- Object.normalize("http://mastodon.example.org/@admin/99541947525187367", false)
+ Object.normalize(@url,
+ fetch: false
+ )
)
end
end
@@ -281,7 +283,11 @@ defmodule Pleroma.ObjectTest do
setup do
mock(fn
%{method: :get, url: "https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d"} ->
- %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/poll_original.json")}
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/tesla_mock/poll_original.json"),
+ headers: HttpRequestMock.activitypub_object_headers()
+ }
env ->
apply(HttpRequestMock, :request, [env])
@@ -306,7 +312,10 @@ defmodule Pleroma.ObjectTest do
mock_modified: mock_modified
} do
%Object{} =
- object = Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d")
+ object =
+ Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d",
+ fetch: true
+ )
Object.set_cache(object)
@@ -315,7 +324,8 @@ defmodule Pleroma.ObjectTest do
mock_modified.(%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/poll_modified.json")
+ body: File.read!("test/fixtures/tesla_mock/poll_modified.json"),
+ headers: HttpRequestMock.activitypub_object_headers()
})
updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: -1)
@@ -327,7 +337,10 @@ defmodule Pleroma.ObjectTest do
test "returns the old object if refetch fails", %{mock_modified: mock_modified} do
%Object{} =
- object = Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d")
+ object =
+ Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d",
+ fetch: true
+ )
Object.set_cache(object)
@@ -350,7 +363,10 @@ defmodule Pleroma.ObjectTest do
mock_modified: mock_modified
} do
%Object{} =
- object = Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d")
+ object =
+ Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d",
+ fetch: true
+ )
Object.set_cache(object)
@@ -359,7 +375,8 @@ defmodule Pleroma.ObjectTest do
mock_modified.(%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/poll_modified.json")
+ body: File.read!("test/fixtures/tesla_mock/poll_modified.json"),
+ headers: HttpRequestMock.activitypub_object_headers()
})
updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: 100)
@@ -371,7 +388,10 @@ defmodule Pleroma.ObjectTest do
test "preserves internal fields on refetch", %{mock_modified: mock_modified} do
%Object{} =
- object = Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d")
+ object =
+ Object.normalize("https://patch.cx/objects/9a172665-2bc5-452d-8428-2361d4c33b1d",
+ fetch: true
+ )
Object.set_cache(object)
@@ -387,7 +407,8 @@ defmodule Pleroma.ObjectTest do
mock_modified.(%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/poll_modified.json")
+ body: File.read!("test/fixtures/tesla_mock/poll_modified.json"),
+ headers: HttpRequestMock.activitypub_object_headers()
})
updated_object = Object.get_by_id_and_maybe_refetch(object.id, interval: -1)
@@ -399,4 +420,28 @@ defmodule Pleroma.ObjectTest do
assert updated_object.data["like_count"] == 1
end
end
+
+ describe ":hashtags association" do
+ test "Hashtag records are created with Object record and updated on its change" do
+ user = insert(:user)
+
+ {:ok, %{object: object}} =
+ CommonAPI.post(user, %{status: "some text #hashtag1 #hashtag2 ..."})
+
+ assert [%Hashtag{name: "hashtag1"}, %Hashtag{name: "hashtag2"}] =
+ Enum.sort_by(object.hashtags, & &1.name)
+
+ {:ok, object} = Object.update_data(object, %{"tag" => []})
+
+ assert [] = object.hashtags
+
+ object = Object.get_by_id(object.id) |> Repo.preload(:hashtags)
+ assert [] = object.hashtags
+
+ {:ok, object} = Object.update_data(object, %{"tag" => ["abc", "def"]})
+
+ assert [%Hashtag{name: "abc"}, %Hashtag{name: "def"}] =
+ Enum.sort_by(object.hashtags, & &1.name)
+ end
+ end
end
diff --git a/test/otp_version_test.exs b/test/pleroma/otp_version_test.exs
index 7d2538ec8..736d440af 100644
--- a/test/otp_version_test.exs
+++ b/test/pleroma/otp_version_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.OTPVersionTest do
diff --git a/test/pagination_test.exs b/test/pleroma/pagination_test.exs
index e526f23e8..bc26c8b46 100644
--- a/test/pagination_test.exs
+++ b/test/pleroma/pagination_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.PaginationTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
import Pleroma.Factory
diff --git a/test/pleroma/password/pbkdf2_test.exs b/test/pleroma/password/pbkdf2_test.exs
new file mode 100644
index 000000000..e55348f9a
--- /dev/null
+++ b/test/pleroma/password/pbkdf2_test.exs
@@ -0,0 +1,35 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Password.Pbkdf2Test do
+ use Pleroma.DataCase, async: true
+
+ alias Pleroma.Password.Pbkdf2, as: Password
+
+ test "it generates the same hash as pbkd2_elixir" do
+ # hash = Pbkdf2.hash_pwd_salt("password")
+ hash =
+ "$pbkdf2-sha512$1$QJpEYw8iBKcnY.4Rm0eCVw$UBPeWQ91RxSv3snxsb/ZzMeG/2aa03c541bbo8vQudREGNta5t8jBQrd00fyJp8RjaqfvgdZxy2rhSwljyu21g"
+
+ # Use the same randomly generated salt
+ salt = Password.decode64("QJpEYw8iBKcnY.4Rm0eCVw")
+
+ assert hash == Password.hash_pwd_salt("password", salt: salt)
+ end
+
+ @tag skip: "Works when Pbkd2 is present. Source: trust me bro"
+ test "Pbkdf2 can verify passwords generated with it" do
+ # Commented to prevent warnings.
+ # hash = Password.hash_pwd_salt("password")
+ # assert Pbkdf2.verify_pass("password", hash)
+ end
+
+ test "it verifies pbkdf2_elixir hashes" do
+ # hash = Pbkdf2.hash_pwd_salt("password")
+ hash =
+ "$pbkdf2-sha512$1$QJpEYw8iBKcnY.4Rm0eCVw$UBPeWQ91RxSv3snxsb/ZzMeG/2aa03c541bbo8vQudREGNta5t8jBQrd00fyJp8RjaqfvgdZxy2rhSwljyu21g"
+
+ assert Password.verify_pass("password", hash)
+ end
+end
diff --git a/test/registration_test.exs b/test/pleroma/registration_test.exs
index 7db8e3664..6e4ad9487 100644
--- a/test/registration_test.exs
+++ b/test/pleroma/registration_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.RegistrationTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
import Pleroma.Factory
diff --git a/test/migrations/20200716195806_autolinker_to_linkify_test.exs b/test/pleroma/repo/migrations/autolinker_to_linkify_test.exs
index 250d11c61..a7d4d493c 100644
--- a/test/migrations/20200716195806_autolinker_to_linkify_test.exs
+++ b/test/pleroma/repo/migrations/autolinker_to_linkify_test.exs
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Repo.Migrations.AutolinkerToLinkifyTest do
use Pleroma.DataCase
import Pleroma.Factory
@@ -33,7 +37,7 @@ defmodule Pleroma.Repo.Migrations.AutolinkerToLinkifyTest do
strip_prefix: false
]
- Pleroma.Config.put(Pleroma.Formatter, new_opts)
+ clear_config(Pleroma.Formatter, new_opts)
assert new_opts == Pleroma.Config.get(Pleroma.Formatter)
{text, _mentions, []} =
diff --git a/test/pleroma/repo/migrations/confirm_logged_in_users_test.exs b/test/pleroma/repo/migrations/confirm_logged_in_users_test.exs
new file mode 100644
index 000000000..99d17f62a
--- /dev/null
+++ b/test/pleroma/repo/migrations/confirm_logged_in_users_test.exs
@@ -0,0 +1,40 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Repo.Migrations.ConfirmLoggedInUsersTest do
+ alias Pleroma.Repo
+ alias Pleroma.User
+ use Pleroma.DataCase, async: true
+ import Ecto.Query
+ import Pleroma.Factory
+ import Pleroma.Tests.Helpers
+
+ setup_all do: require_migration("20201231185546_confirm_logged_in_users")
+
+ test "up/0 confirms unconfirmed but previously-logged-in users", %{migration: migration} do
+ insert_list(25, :oauth_token)
+ Repo.update_all(User, set: [is_confirmed: false])
+ insert_list(5, :user, is_confirmed: false)
+
+ count =
+ User
+ |> where(is_confirmed: false)
+ |> Repo.aggregate(:count)
+
+ assert count == 30
+
+ assert {25, nil} == migration.up()
+
+ count =
+ User
+ |> where(is_confirmed: false)
+ |> Repo.aggregate(:count)
+
+ assert count == 5
+ end
+
+ test "down/0 does nothing", %{migration: migration} do
+ assert :noop == migration.down()
+ end
+end
diff --git a/test/pleroma/repo/migrations/deprecate_public_endpoint_test.exs b/test/pleroma/repo/migrations/deprecate_public_endpoint_test.exs
new file mode 100644
index 000000000..2ffc1b145
--- /dev/null
+++ b/test/pleroma/repo/migrations/deprecate_public_endpoint_test.exs
@@ -0,0 +1,60 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Repo.Migrations.DeprecatePublicEndpointTest do
+ use Pleroma.DataCase
+ import Pleroma.Factory
+ import Pleroma.Tests.Helpers
+ alias Pleroma.ConfigDB
+
+ setup do: clear_config(Pleroma.Upload)
+ setup do: clear_config(Pleroma.Uploaders.S3)
+ setup_all do: require_migration("20210113225652_deprecate_public_endpoint")
+
+ test "up/0 migrates public_endpoint to base_url", %{migration: migration} do
+ s3_values = [
+ public_endpoint: "https://coolhost.com/",
+ bucket: "secret_bucket"
+ ]
+
+ insert(:config, group: :pleroma, key: Pleroma.Uploaders.S3, value: s3_values)
+
+ upload_values = [
+ uploader: Pleroma.Uploaders.S3
+ ]
+
+ insert(:config, group: :pleroma, key: Pleroma.Upload, value: upload_values)
+
+ migration.up()
+
+ assert [bucket: "secret_bucket"] ==
+ ConfigDB.get_by_params(%{group: :pleroma, key: Pleroma.Uploaders.S3}).value
+
+ assert [uploader: Pleroma.Uploaders.S3, base_url: "https://coolhost.com/"] ==
+ ConfigDB.get_by_params(%{group: :pleroma, key: Pleroma.Upload}).value
+ end
+
+ test "down/0 reverts base_url to public_endpoint", %{migration: migration} do
+ s3_values = [
+ bucket: "secret_bucket"
+ ]
+
+ insert(:config, group: :pleroma, key: Pleroma.Uploaders.S3, value: s3_values)
+
+ upload_values = [
+ uploader: Pleroma.Uploaders.S3,
+ base_url: "https://coolhost.com/"
+ ]
+
+ insert(:config, group: :pleroma, key: Pleroma.Upload, value: upload_values)
+
+ migration.down()
+
+ assert [bucket: "secret_bucket", public_endpoint: "https://coolhost.com/"] ==
+ ConfigDB.get_by_params(%{group: :pleroma, key: Pleroma.Uploaders.S3}).value
+
+ assert [uploader: Pleroma.Uploaders.S3] ==
+ ConfigDB.get_by_params(%{group: :pleroma, key: Pleroma.Upload}).value
+ end
+end
diff --git a/test/migrations/20200802170532_fix_legacy_tags_test.exs b/test/pleroma/repo/migrations/fix_legacy_tags_test.exs
index 3b4dee407..0a1d1d0bb 100644
--- a/test/migrations/20200802170532_fix_legacy_tags_test.exs
+++ b/test/pleroma/repo/migrations/fix_legacy_tags_test.exs
@@ -1,6 +1,10 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Repo.Migrations.FixLegacyTagsTest do
alias Pleroma.User
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
import Pleroma.Factory
import Pleroma.Tests.Helpers
diff --git a/test/migrations/20200722185515_fix_malformed_formatter_config_test.exs b/test/pleroma/repo/migrations/fix_malformed_formatter_config_test.exs
index d3490478e..65c9961b0 100644
--- a/test/migrations/20200722185515_fix_malformed_formatter_config_test.exs
+++ b/test/pleroma/repo/migrations/fix_malformed_formatter_config_test.exs
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Repo.Migrations.FixMalformedFormatterConfigTest do
use Pleroma.DataCase
import Pleroma.Factory
@@ -30,7 +34,7 @@ defmodule Pleroma.Repo.Migrations.FixMalformedFormatterConfigTest do
strip_prefix: false
]
- Pleroma.Config.put(Pleroma.Formatter, new_opts)
+ clear_config(Pleroma.Formatter, new_opts)
assert new_opts == Pleroma.Config.get(Pleroma.Formatter)
{text, _mentions, []} =
diff --git a/test/migrations/20200724133313_move_welcome_settings_test.exs b/test/pleroma/repo/migrations/move_welcome_settings_test.exs
index 739f24547..1da6b8a04 100644
--- a/test/migrations/20200724133313_move_welcome_settings_test.exs
+++ b/test/pleroma/repo/migrations/move_welcome_settings_test.exs
@@ -1,5 +1,9 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Repo.Migrations.MoveWelcomeSettingsTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
import Pleroma.Factory
import Pleroma.Tests.Helpers
alias Pleroma.ConfigDB
diff --git a/test/pleroma/repo/migrations/rename_instance_chat_test.exs b/test/pleroma/repo/migrations/rename_instance_chat_test.exs
new file mode 100644
index 000000000..acd45600c
--- /dev/null
+++ b/test/pleroma/repo/migrations/rename_instance_chat_test.exs
@@ -0,0 +1,52 @@
+defmodule Pleroma.Repo.Migrations.RenameInstanceChatTest do
+ use Pleroma.DataCase
+ import Pleroma.Factory
+ import Pleroma.Tests.Helpers
+ alias Pleroma.ConfigDB
+
+ setup do: clear_config([:instance])
+ setup do: clear_config([:chat])
+ setup_all do: require_migration("20200806175913_rename_instance_chat")
+
+ describe "up/0" do
+ test "migrates chat settings to shout", %{migration: migration} do
+ insert(:config, group: :pleroma, key: :instance, value: [chat_limit: 6000])
+ insert(:config, group: :pleroma, key: :chat, value: [enabled: true])
+
+ assert migration.up() == :ok
+
+ assert ConfigDB.get_by_params(%{group: :pleroma, key: :chat}) == nil
+ assert ConfigDB.get_by_params(%{group: :pleroma, key: :instance}) == nil
+
+ assert ConfigDB.get_by_params(%{group: :pleroma, key: :shout}).value == [
+ limit: 6000,
+ enabled: true
+ ]
+ end
+
+ test "does nothing when chat settings are not set", %{migration: migration} do
+ assert migration.up() == :noop
+ assert ConfigDB.get_by_params(%{group: :pleroma, key: :chat}) == nil
+ assert ConfigDB.get_by_params(%{group: :pleroma, key: :shout}) == nil
+ end
+ end
+
+ describe "down/0" do
+ test "migrates shout settings back to instance and chat", %{migration: migration} do
+ insert(:config, group: :pleroma, key: :shout, value: [limit: 42, enabled: true])
+
+ assert migration.down() == :ok
+
+ assert ConfigDB.get_by_params(%{group: :pleroma, key: :chat}).value == [enabled: true]
+ assert ConfigDB.get_by_params(%{group: :pleroma, key: :instance}).value == [chat_limit: 42]
+ assert ConfigDB.get_by_params(%{group: :pleroma, key: :shout}) == nil
+ end
+
+ test "does nothing when shout settings are not set", %{migration: migration} do
+ assert migration.down() == :noop
+ assert ConfigDB.get_by_params(%{group: :pleroma, key: :chat}) == nil
+ assert ConfigDB.get_by_params(%{group: :pleroma, key: :instance}) == nil
+ assert ConfigDB.get_by_params(%{group: :pleroma, key: :shout}) == nil
+ end
+ end
+end
diff --git a/test/repo_test.exs b/test/pleroma/repo_test.exs
index 92e827c95..9e14bdbd1 100644
--- a/test/repo_test.exs
+++ b/test/pleroma/repo_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.RepoTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
import Pleroma.Factory
alias Pleroma.User
@@ -37,7 +37,9 @@ defmodule Pleroma.RepoTest do
test "get one-to-many assoc from repo" do
user = insert(:user)
- notification = refresh_record(insert(:notification, user: user))
+
+ notification =
+ refresh_record(insert(:notification, user: user, activity: insert(:note_activity)))
assert Repo.get_assoc(user, :notifications) == {:ok, [notification]}
end
@@ -47,4 +49,32 @@ defmodule Pleroma.RepoTest do
assert Repo.get_assoc(token, :user) == {:error, :not_found}
end
end
+
+ describe "chunk_stream/3" do
+ test "fetch records one-by-one" do
+ users = insert_list(50, :user)
+
+ {fetch_users, 50} =
+ from(t in User)
+ |> Repo.chunk_stream(5)
+ |> Enum.reduce({[], 0}, fn %User{} = user, {acc, count} ->
+ {acc ++ [user], count + 1}
+ end)
+
+ assert users == fetch_users
+ end
+
+ test "fetch records in bulk" do
+ users = insert_list(50, :user)
+
+ {fetch_users, 10} =
+ from(t in User)
+ |> Repo.chunk_stream(5, :batches)
+ |> Enum.reduce({[], 0}, fn users, {acc, count} ->
+ {acc ++ users, count + 1}
+ end)
+
+ assert users == fetch_users
+ end
+ end
end
diff --git a/test/report_note_test.exs b/test/pleroma/report_note_test.exs
index 25c1d6a61..2620560a0 100644
--- a/test/report_note_test.exs
+++ b/test/pleroma/report_note_test.exs
@@ -1,10 +1,10 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.ReportNoteTest do
alias Pleroma.ReportNote
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
import Pleroma.Factory
test "create/3" do
diff --git a/test/reverse_proxy/reverse_proxy_test.exs b/test/pleroma/reverse_proxy_test.exs
index 8df63de65..a4dd8e99a 100644
--- a/test/reverse_proxy/reverse_proxy_test.exs
+++ b/test/pleroma/reverse_proxy_test.exs
@@ -1,10 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.ReverseProxyTest do
- use Pleroma.Web.ConnCase, async: true
-
+ use Pleroma.Web.ConnCase
import ExUnit.CaptureLog
import Mox
@@ -19,24 +18,23 @@ defmodule Pleroma.ReverseProxyTest do
setup :verify_on_exit!
- defp user_agent_mock(user_agent, invokes) do
- json = Jason.encode!(%{"user-agent": user_agent})
-
+ defp request_mock(invokes) do
ClientMock
- |> expect(:request, fn :get, url, _, _, _ ->
+ |> expect(:request, fn :get, url, headers, _body, _opts ->
Registry.register(ClientMock, url, 0)
+ body = headers |> Enum.into(%{}) |> Jason.encode!()
{:ok, 200,
[
{"content-type", "application/json"},
- {"content-length", byte_size(json) |> to_string()}
- ], %{url: url}}
+ {"content-length", byte_size(body) |> to_string()}
+ ], %{url: url, body: body}}
end)
- |> expect(:stream_body, invokes, fn %{url: url} = client ->
+ |> expect(:stream_body, invokes, fn %{url: url, body: body} = client ->
case Registry.lookup(ClientMock, url) do
[{_, 0}] ->
Registry.update_value(ClientMock, url, &(&1 + 1))
- {:ok, json, client}
+ {:ok, body, client}
[{_, 1}] ->
Registry.unregister(ClientMock, url)
@@ -47,7 +45,7 @@ defmodule Pleroma.ReverseProxyTest do
describe "reverse proxy" do
test "do not track successful request", %{conn: conn} do
- user_agent_mock("hackney/1.15.1", 2)
+ request_mock(2)
url = "/success"
conn = ReverseProxy.call(conn, url)
@@ -57,18 +55,15 @@ defmodule Pleroma.ReverseProxyTest do
end
end
- describe "user-agent" do
- test "don't keep", %{conn: conn} do
- user_agent_mock("hackney/1.15.1", 2)
- conn = ReverseProxy.call(conn, "/user-agent")
- assert json_response(conn, 200) == %{"user-agent" => "hackney/1.15.1"}
- end
+ test "use Pleroma's user agent in the request; don't pass the client's", %{conn: conn} do
+ request_mock(2)
- test "keep", %{conn: conn} do
- user_agent_mock(Pleroma.Application.user_agent(), 2)
- conn = ReverseProxy.call(conn, "/user-agent-keep", keep_user_agent: true)
- assert json_response(conn, 200) == %{"user-agent" => Pleroma.Application.user_agent()}
- end
+ conn =
+ conn
+ |> Plug.Conn.put_req_header("user-agent", "fake/1.0")
+ |> ReverseProxy.call("/user-agent")
+
+ assert json_response(conn, 200) == %{"user-agent" => Pleroma.Application.user_agent()}
end
test "closed connection", %{conn: conn} do
@@ -115,7 +110,7 @@ defmodule Pleroma.ReverseProxyTest do
describe "max_body" do
test "length returns error if content-length more than option", %{conn: conn} do
- user_agent_mock("hackney/1.15.1", 0)
+ request_mock(0)
assert capture_log(fn ->
ReverseProxy.call(conn, "/huge-file", max_body_length: 4)
diff --git a/test/runtime_test.exs b/test/pleroma/runtime_test.exs
index a1a6c57cd..b9e769602 100644
--- a/test/runtime_test.exs
+++ b/test/pleroma/runtime_test.exs
@@ -1,11 +1,12 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.RuntimeTest do
use ExUnit.Case, async: true
test "it loads custom runtime modules" do
- assert {:module, RuntimeModule} == Code.ensure_compiled(RuntimeModule)
+ assert {:module, Fixtures.Modules.RuntimeModule} ==
+ Code.ensure_compiled(Fixtures.Modules.RuntimeModule)
end
end
diff --git a/test/safe_jsonb_set_test.exs b/test/pleroma/safe_jsonb_set_test.exs
index 748540570..69d696c1b 100644
--- a/test/safe_jsonb_set_test.exs
+++ b/test/pleroma/safe_jsonb_set_test.exs
@@ -1,5 +1,9 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.SafeJsonbSetTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
test "it doesn't wipe the object when asked to set the value to NULL" do
assert %{rows: [[%{"key" => "value", "test" => nil}]]} =
diff --git a/test/scheduled_activity_test.exs b/test/pleroma/scheduled_activity_test.exs
index 7faa5660d..ef91e9bce 100644
--- a/test/scheduled_activity_test.exs
+++ b/test/pleroma/scheduled_activity_test.exs
@@ -1,22 +1,21 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.ScheduledActivityTest do
use Pleroma.DataCase
- alias Pleroma.DataCase
+
alias Pleroma.ScheduledActivity
+
import Pleroma.Factory
setup do: clear_config([ScheduledActivity, :enabled])
- setup context do
- DataCase.ensure_local_uploader(context)
- end
+ setup [:ensure_local_uploader]
describe "creation" do
test "scheduled activities with jobs when ScheduledActivity enabled" do
- Pleroma.Config.put([ScheduledActivity, :enabled], true)
+ clear_config([ScheduledActivity, :enabled], true)
user = insert(:user)
today =
@@ -35,7 +34,7 @@ defmodule Pleroma.ScheduledActivityTest do
end
test "scheduled activities without jobs when ScheduledActivity disabled" do
- Pleroma.Config.put([ScheduledActivity, :enabled], false)
+ clear_config([ScheduledActivity, :enabled], false)
user = insert(:user)
today =
diff --git a/test/signature_test.exs b/test/pleroma/signature_test.exs
index a7a75aa4d..047c537e0 100644
--- a/test/signature_test.exs
+++ b/test/pleroma/signature_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.SignatureTest do
diff --git a/test/stats_test.exs b/test/pleroma/stats_test.exs
index f09d8d31a..fd3195969 100644
--- a/test/stats_test.exs
+++ b/test/pleroma/stats_test.exs
@@ -1,10 +1,13 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.StatsTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
+
import Pleroma.Factory
+
+ alias Pleroma.Stats
alias Pleroma.Web.CommonAPI
describe "user count" do
@@ -13,7 +16,7 @@ defmodule Pleroma.StatsTest do
_internal = insert(:user, local: true, nickname: nil)
_internal = Pleroma.Web.ActivityPub.Relay.get_actor()
- assert match?(%{stats: %{user_count: 1}}, Pleroma.Stats.calculate_stat_data())
+ assert match?(%{stats: %{user_count: 1}}, Stats.calculate_stat_data())
end
end
@@ -47,23 +50,23 @@ defmodule Pleroma.StatsTest do
end)
assert %{"direct" => 3, "private" => 4, "public" => 1, "unlisted" => 2} =
- Pleroma.Stats.get_status_visibility_count()
+ Stats.get_status_visibility_count()
end
test "on status delete" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{visibility: "public", status: "hey"})
- assert %{"public" => 1} = Pleroma.Stats.get_status_visibility_count()
+ assert %{"public" => 1} = Stats.get_status_visibility_count()
CommonAPI.delete(activity.id, user)
- assert %{"public" => 0} = Pleroma.Stats.get_status_visibility_count()
+ assert %{"public" => 0} = Stats.get_status_visibility_count()
end
test "on status visibility update" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{visibility: "public", status: "hey"})
- assert %{"public" => 1, "private" => 0} = Pleroma.Stats.get_status_visibility_count()
+ assert %{"public" => 1, "private" => 0} = Stats.get_status_visibility_count()
{:ok, _} = CommonAPI.update_activity_scope(activity.id, %{visibility: "private"})
- assert %{"public" => 0, "private" => 1} = Pleroma.Stats.get_status_visibility_count()
+ assert %{"public" => 0, "private" => 1} = Stats.get_status_visibility_count()
end
test "doesn't count unrelated activities" do
@@ -75,7 +78,7 @@ defmodule Pleroma.StatsTest do
CommonAPI.repeat(activity.id, other_user)
assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 0} =
- Pleroma.Stats.get_status_visibility_count()
+ Stats.get_status_visibility_count()
end
end
@@ -110,10 +113,10 @@ defmodule Pleroma.StatsTest do
end)
assert %{"direct" => 10, "private" => 0, "public" => 1, "unlisted" => 5} =
- Pleroma.Stats.get_status_visibility_count(local_instance)
+ Stats.get_status_visibility_count(local_instance)
assert %{"direct" => 0, "private" => 20, "public" => 0, "unlisted" => 0} =
- Pleroma.Stats.get_status_visibility_count(instance2)
+ Stats.get_status_visibility_count(instance2)
end
end
end
diff --git a/test/pleroma/upload/filter/analyze_metadata_test.exs b/test/pleroma/upload/filter/analyze_metadata_test.exs
new file mode 100644
index 000000000..4b636a684
--- /dev/null
+++ b/test/pleroma/upload/filter/analyze_metadata_test.exs
@@ -0,0 +1,33 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Upload.Filter.AnalyzeMetadataTest do
+ use Pleroma.DataCase, async: true
+ alias Pleroma.Upload.Filter.AnalyzeMetadata
+
+ test "adds the dimensions and blurhash for images" do
+ upload = %Pleroma.Upload{
+ name: "an… image.jpg",
+ content_type: "image/jpeg",
+ path: Path.absname("test/fixtures/image.jpg"),
+ tempfile: Path.absname("test/fixtures/image.jpg")
+ }
+
+ {:ok, :filtered, meta} = AnalyzeMetadata.filter(upload)
+
+ assert %{width: 1024, height: 768} = meta
+ assert meta.blurhash
+ end
+
+ test "adds the dimensions for videos" do
+ upload = %Pleroma.Upload{
+ name: "coolvideo.mp4",
+ content_type: "video/mp4",
+ path: Path.absname("test/fixtures/video.mp4"),
+ tempfile: Path.absname("test/fixtures/video.mp4")
+ }
+
+ assert {:ok, :filtered, %{width: 480, height: 480}} = AnalyzeMetadata.filter(upload)
+ end
+end
diff --git a/test/upload/filter/anonymize_filename_test.exs b/test/pleroma/upload/filter/anonymize_filename_test.exs
index adff70f57..9387c1abc 100644
--- a/test/upload/filter/anonymize_filename_test.exs
+++ b/test/pleroma/upload/filter/anonymize_filename_test.exs
@@ -1,11 +1,10 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Upload.Filter.AnonymizeFilenameTest do
use Pleroma.DataCase
- alias Pleroma.Config
alias Pleroma.Upload
setup do
@@ -13,7 +12,7 @@ defmodule Pleroma.Upload.Filter.AnonymizeFilenameTest do
upload_file = %Upload{
name: "an… image.jpg",
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg")
}
@@ -23,19 +22,19 @@ defmodule Pleroma.Upload.Filter.AnonymizeFilenameTest do
setup do: clear_config([Pleroma.Upload.Filter.AnonymizeFilename, :text])
test "it replaces filename on pre-defined text", %{upload_file: upload_file} do
- Config.put([Upload.Filter.AnonymizeFilename, :text], "custom-file.png")
- {:ok, %Upload{name: name}} = Upload.Filter.AnonymizeFilename.filter(upload_file)
+ clear_config([Upload.Filter.AnonymizeFilename, :text], "custom-file.png")
+ {:ok, :filtered, %Upload{name: name}} = Upload.Filter.AnonymizeFilename.filter(upload_file)
assert name == "custom-file.png"
end
test "it replaces filename on pre-defined text expression", %{upload_file: upload_file} do
- Config.put([Upload.Filter.AnonymizeFilename, :text], "custom-file.{extension}")
- {:ok, %Upload{name: name}} = Upload.Filter.AnonymizeFilename.filter(upload_file)
+ clear_config([Upload.Filter.AnonymizeFilename, :text], "custom-file.{extension}")
+ {:ok, :filtered, %Upload{name: name}} = Upload.Filter.AnonymizeFilename.filter(upload_file)
assert name == "custom-file.jpg"
end
test "it replaces filename on random text", %{upload_file: upload_file} do
- {:ok, %Upload{name: name}} = Upload.Filter.AnonymizeFilename.filter(upload_file)
+ {:ok, :filtered, %Upload{name: name}} = Upload.Filter.AnonymizeFilename.filter(upload_file)
assert <<_::bytes-size(14)>> <> ".jpg" = name
refute name == "an… image.jpg"
end
diff --git a/test/upload/filter/dedupe_test.exs b/test/pleroma/upload/filter/dedupe_test.exs
index 966c353f7..f00ba12f9 100644
--- a/test/upload/filter/dedupe_test.exs
+++ b/test/pleroma/upload/filter/dedupe_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Upload.Filter.DedupeTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Upload
alias Pleroma.Upload.Filter.Dedupe
@@ -18,13 +18,14 @@ defmodule Pleroma.Upload.Filter.DedupeTest do
upload = %Upload{
name: "an… image.jpg",
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"),
tempfile: Path.absname("test/fixtures/image_tmp.jpg")
}
assert {
:ok,
+ :filtered,
%Pleroma.Upload{id: @shasum, path: @shasum <> ".jpg"}
} = Dedupe.filter(upload)
end
diff --git a/test/upload/filter/exiftool_test.exs b/test/pleroma/upload/filter/exiftool_test.exs
index 8ed7d650b..cfbe34be8 100644
--- a/test/upload/filter/exiftool_test.exs
+++ b/test/pleroma/upload/filter/exiftool_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Upload.Filter.ExiftoolTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Upload.Filter
test "apply exiftool filter" do
@@ -16,12 +16,12 @@ defmodule Pleroma.Upload.Filter.ExiftoolTest do
upload = %Pleroma.Upload{
name: "image_with_GPS_data.jpg",
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/DSCN0010.jpg"),
tempfile: Path.absname("test/fixtures/DSCN0010_tmp.jpg")
}
- assert Filter.Exiftool.filter(upload) == :ok
+ assert Filter.Exiftool.filter(upload) == {:ok, :filtered}
{exif_original, 0} = System.cmd("exiftool", ["test/fixtures/DSCN0010.jpg"])
{exif_filtered, 0} = System.cmd("exiftool", ["test/fixtures/DSCN0010_tmp.jpg"])
@@ -30,4 +30,13 @@ defmodule Pleroma.Upload.Filter.ExiftoolTest do
assert String.match?(exif_original, ~r/GPS/)
refute String.match?(exif_filtered, ~r/GPS/)
end
+
+ test "verify webp files are skipped" do
+ upload = %Pleroma.Upload{
+ name: "sample.webp",
+ content_type: "image/webp"
+ }
+
+ assert Filter.Exiftool.filter(upload) == {:ok, :noop}
+ end
end
diff --git a/test/upload/filter/mogrifun_test.exs b/test/pleroma/upload/filter/mogrifun_test.exs
index 2426a8496..d2b183e90 100644
--- a/test/upload/filter/mogrifun_test.exs
+++ b/test/pleroma/upload/filter/mogrifun_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Upload.Filter.MogrifunTest do
@@ -17,7 +17,7 @@ defmodule Pleroma.Upload.Filter.MogrifunTest do
upload = %Upload{
name: "an… image.jpg",
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"),
tempfile: Path.absname("test/fixtures/image_tmp.jpg")
}
@@ -36,7 +36,7 @@ defmodule Pleroma.Upload.Filter.MogrifunTest do
save: fn _f, _o -> :ok end
]}
]) do
- assert Filter.Mogrifun.filter(upload) == :ok
+ assert Filter.Mogrifun.filter(upload) == {:ok, :filtered}
end
Task.await(task)
diff --git a/test/upload/filter/mogrify_test.exs b/test/pleroma/upload/filter/mogrify_test.exs
index 62ca30487..d62cd83b4 100644
--- a/test/upload/filter/mogrify_test.exs
+++ b/test/pleroma/upload/filter/mogrify_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Upload.Filter.MogrifyTest do
@@ -18,7 +18,7 @@ defmodule Pleroma.Upload.Filter.MogrifyTest do
upload = %Pleroma.Upload{
name: "an… image.jpg",
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"),
tempfile: Path.absname("test/fixtures/image_tmp.jpg")
}
@@ -33,7 +33,7 @@ defmodule Pleroma.Upload.Filter.MogrifyTest do
custom: fn _m, _a -> :ok end,
custom: fn m, a, o -> send(task.pid, {:apply_filter, {m, a, o}}) end,
save: fn _f, _o -> :ok end do
- assert Filter.Mogrify.filter(upload) == :ok
+ assert Filter.Mogrify.filter(upload) == {:ok, :filtered}
end
Task.await(task)
diff --git a/test/upload/filter_test.exs b/test/pleroma/upload/filter_test.exs
index 352b66402..f0053ed9b 100644
--- a/test/upload/filter_test.exs
+++ b/test/pleroma/upload/filter_test.exs
@@ -1,17 +1,16 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Upload.FilterTest do
use Pleroma.DataCase
- alias Pleroma.Config
alias Pleroma.Upload.Filter
setup do: clear_config([Pleroma.Upload.Filter.AnonymizeFilename, :text])
test "applies filters" do
- Config.put([Pleroma.Upload.Filter.AnonymizeFilename, :text], "custom-file.png")
+ clear_config([Pleroma.Upload.Filter.AnonymizeFilename, :text], "custom-file.png")
File.cp!(
"test/fixtures/image.jpg",
@@ -20,7 +19,7 @@ defmodule Pleroma.Upload.FilterTest do
upload = %Pleroma.Upload{
name: "an… image.jpg",
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"),
tempfile: Path.absname("test/fixtures/image_tmp.jpg")
}
diff --git a/test/upload_test.exs b/test/pleroma/upload_test.exs
index b06b54487..f1ab82a57 100644
--- a/test/upload_test.exs
+++ b/test/pleroma/upload_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.UploadTest do
@@ -11,7 +11,7 @@ defmodule Pleroma.UploadTest do
alias Pleroma.Uploaders.Uploader
@upload_file %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"),
filename: "image.jpg"
}
@@ -112,7 +112,7 @@ defmodule Pleroma.UploadTest do
File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"),
filename: "image.jpg"
}
@@ -124,7 +124,7 @@ defmodule Pleroma.UploadTest do
File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"),
filename: "image.jpg"
}
@@ -133,14 +133,14 @@ defmodule Pleroma.UploadTest do
assert %{"url" => [%{"href" => url}]} = data
- assert String.starts_with?(url, Pleroma.Web.base_url() <> "/media/")
+ assert String.starts_with?(url, Pleroma.Upload.base_url())
end
test "copies the file to the configured folder with deduping" do
File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"),
filename: "an [image.jpg"
}
@@ -148,15 +148,15 @@ defmodule Pleroma.UploadTest do
{:ok, data} = Upload.store(file, filters: [Pleroma.Upload.Filter.Dedupe])
assert List.first(data["url"])["href"] ==
- Pleroma.Web.base_url() <>
- "/media/e30397b58d226d6583ab5b8b3c5defb0c682bda5c31ef07a9f57c1c4986e3781.jpg"
+ Pleroma.Upload.base_url() <>
+ "e30397b58d226d6583ab5b8b3c5defb0c682bda5c31ef07a9f57c1c4986e3781.jpg"
end
test "copies the file to the configured folder without deduping" do
File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"),
filename: "an [image.jpg"
}
@@ -165,63 +165,31 @@ defmodule Pleroma.UploadTest do
assert data["name"] == "an [image.jpg"
end
- test "fixes incorrect content type" do
- File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
-
- file = %Plug.Upload{
- content_type: "application/octet-stream",
- path: Path.absname("test/fixtures/image_tmp.jpg"),
- filename: "an [image.jpg"
+ test "fixes incorrect content type when base64 is given" do
+ params = %{
+ img: "data:image/png;base64,#{Base.encode64(File.read!("test/fixtures/image.jpg"))}"
}
- {:ok, data} = Upload.store(file, filters: [Pleroma.Upload.Filter.Dedupe])
+ {:ok, data} = Upload.store(params)
assert hd(data["url"])["mediaType"] == "image/jpeg"
end
- test "adds missing extension" do
+ test "adds extension when base64 is given" do
File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
- file = %Plug.Upload{
- content_type: "image/jpg",
- path: Path.absname("test/fixtures/image_tmp.jpg"),
- filename: "an [image"
+ params = %{
+ img: "data:image/png;base64,#{Base.encode64(File.read!("test/fixtures/image.jpg"))}"
}
- {:ok, data} = Upload.store(file)
- assert data["name"] == "an [image.jpg"
- end
-
- test "fixes incorrect file extension" do
- File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
-
- file = %Plug.Upload{
- content_type: "image/jpg",
- path: Path.absname("test/fixtures/image_tmp.jpg"),
- filename: "an [image.blah"
- }
-
- {:ok, data} = Upload.store(file)
- assert data["name"] == "an [image.jpg"
- end
-
- test "don't modify filename of an unknown type" do
- File.cp("test/fixtures/test.txt", "test/fixtures/test_tmp.txt")
-
- file = %Plug.Upload{
- content_type: "text/plain",
- path: Path.absname("test/fixtures/test_tmp.txt"),
- filename: "test.txt"
- }
-
- {:ok, data} = Upload.store(file)
- assert data["name"] == "test.txt"
+ {:ok, data} = Upload.store(params)
+ assert String.ends_with?(data["name"], ".jpg")
end
test "copies the file to the configured folder with anonymizing filename" do
File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"),
filename: "an [image.jpg"
}
@@ -235,7 +203,7 @@ defmodule Pleroma.UploadTest do
File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"),
filename: "an… image.jpg"
}
@@ -250,7 +218,7 @@ defmodule Pleroma.UploadTest do
File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"),
filename: ":?#[]@!$&\\'()*+,;=.jpg"
}
@@ -272,7 +240,7 @@ defmodule Pleroma.UploadTest do
File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"),
filename: "image.jpg"
}
diff --git a/test/uploaders/local_test.exs b/test/pleroma/uploaders/local_test.exs
index 18122ff6c..0a5952f50 100644
--- a/test/uploaders/local_test.exs
+++ b/test/pleroma/uploaders/local_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Uploaders.LocalTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Uploaders.Local
describe "get_file/1" do
@@ -19,7 +19,7 @@ defmodule Pleroma.Uploaders.LocalTest do
file = %Pleroma.Upload{
name: "image.jpg",
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: file_path,
tempfile: Path.absname("test/fixtures/image_tmp.jpg")
}
@@ -38,7 +38,7 @@ defmodule Pleroma.Uploaders.LocalTest do
file = %Pleroma.Upload{
name: "image.jpg",
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: file_path,
tempfile: Path.absname("test/fixtures/image_tmp.jpg")
}
diff --git a/test/uploaders/s3_test.exs b/test/pleroma/uploaders/s3_test.exs
index d949c90a5..2711e2c8d 100644
--- a/test/uploaders/s3_test.exs
+++ b/test/pleroma/uploaders/s3_test.exs
@@ -1,21 +1,21 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Uploaders.S3Test do
use Pleroma.DataCase
- alias Pleroma.Config
alias Pleroma.Uploaders.S3
import Mock
import ExUnit.CaptureLog
- setup do:
- clear_config(Pleroma.Uploaders.S3,
- bucket: "test_bucket",
- public_endpoint: "https://s3.amazonaws.com"
- )
+ setup do
+ clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.S3)
+ clear_config([Pleroma.Upload, :base_url], "https://s3.amazonaws.com")
+ clear_config([Pleroma.Uploaders.S3])
+ clear_config([Pleroma.Uploaders.S3, :bucket], "test_bucket")
+ end
describe "get_file/1" do
test "it returns path to local folder for files" do
@@ -26,12 +26,14 @@ defmodule Pleroma.Uploaders.S3Test do
end
test "it returns path without bucket when truncated_namespace set to ''" do
- Config.put([Pleroma.Uploaders.S3],
+ clear_config([Pleroma.Uploaders.S3],
bucket: "test_bucket",
- public_endpoint: "https://s3.amazonaws.com",
+ bucket_namespace: "myaccount",
truncated_namespace: ""
)
+ clear_config([Pleroma.Upload, :base_url], "https://s3.amazonaws.com")
+
assert S3.get_file("test_image.jpg") == {
:ok,
{:url, "https://s3.amazonaws.com/test_image.jpg"}
@@ -39,9 +41,8 @@ defmodule Pleroma.Uploaders.S3Test do
end
test "it returns path with bucket namespace when namespace is set" do
- Config.put([Pleroma.Uploaders.S3],
+ clear_config([Pleroma.Uploaders.S3],
bucket: "test_bucket",
- public_endpoint: "https://s3.amazonaws.com",
bucket_namespace: "family"
)
@@ -56,7 +57,7 @@ defmodule Pleroma.Uploaders.S3Test do
setup do
file_upload = %Pleroma.Upload{
name: "image-tet.jpg",
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: "test_folder/image-tet.jpg",
tempfile: Path.absname("test/instance_static/add/shortcode.png")
}
diff --git a/test/pleroma/user/backup_test.exs b/test/pleroma/user/backup_test.exs
new file mode 100644
index 000000000..b16152876
--- /dev/null
+++ b/test/pleroma/user/backup_test.exs
@@ -0,0 +1,238 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.User.BackupTest do
+ use Oban.Testing, repo: Pleroma.Repo
+ use Pleroma.DataCase
+
+ import Mock
+ import Pleroma.Factory
+ import Swoosh.TestAssertions
+
+ alias Pleroma.Bookmark
+ alias Pleroma.Tests.ObanHelpers
+ alias Pleroma.User.Backup
+ alias Pleroma.Web.CommonAPI
+ alias Pleroma.Workers.BackupWorker
+
+ setup do
+ clear_config([Pleroma.Upload, :uploader])
+ clear_config([Backup, :limit_days])
+ clear_config([Pleroma.Emails.Mailer, :enabled], true)
+ end
+
+ test "it requries enabled email" do
+ clear_config([Pleroma.Emails.Mailer, :enabled], false)
+ user = insert(:user)
+ assert {:error, "Backups require enabled email"} == Backup.create(user)
+ end
+
+ test "it requries user's email" do
+ user = insert(:user, %{email: nil})
+ assert {:error, "Email is required"} == Backup.create(user)
+ end
+
+ test "it creates a backup record and an Oban job" do
+ %{id: user_id} = user = insert(:user)
+ assert {:ok, %Oban.Job{args: args}} = Backup.create(user)
+ assert_enqueued(worker: BackupWorker, args: args)
+
+ backup = Backup.get(args["backup_id"])
+ assert %Backup{user_id: ^user_id, processed: false, file_size: 0} = backup
+ end
+
+ test "it return an error if the export limit is over" do
+ %{id: user_id} = user = insert(:user)
+ limit_days = Pleroma.Config.get([Backup, :limit_days])
+ assert {:ok, %Oban.Job{args: args}} = Backup.create(user)
+ backup = Backup.get(args["backup_id"])
+ assert %Backup{user_id: ^user_id, processed: false, file_size: 0} = backup
+
+ assert Backup.create(user) == {:error, "Last export was less than #{limit_days} days ago"}
+ end
+
+ test "it process a backup record" do
+ clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
+ %{id: user_id} = user = insert(:user)
+
+ assert {:ok, %Oban.Job{args: %{"backup_id" => backup_id} = args}} = Backup.create(user)
+ assert {:ok, backup} = perform_job(BackupWorker, args)
+ assert backup.file_size > 0
+ assert %Backup{id: ^backup_id, processed: true, user_id: ^user_id} = backup
+
+ delete_job_args = %{"op" => "delete", "backup_id" => backup_id}
+
+ assert_enqueued(worker: BackupWorker, args: delete_job_args)
+ assert {:ok, backup} = perform_job(BackupWorker, delete_job_args)
+ refute Backup.get(backup_id)
+
+ email = Pleroma.Emails.UserEmail.backup_is_ready_email(backup)
+
+ assert_email_sent(
+ to: {user.name, user.email},
+ html_body: email.html_body
+ )
+ end
+
+ test "it removes outdated backups after creating a fresh one" do
+ clear_config([Backup, :limit_days], -1)
+ clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
+ user = insert(:user)
+
+ assert {:ok, job1} = Backup.create(user)
+
+ assert {:ok, %Backup{}} = ObanHelpers.perform(job1)
+ assert {:ok, job2} = Backup.create(user)
+ assert Pleroma.Repo.aggregate(Backup, :count) == 2
+ assert {:ok, backup2} = ObanHelpers.perform(job2)
+
+ ObanHelpers.perform_all()
+
+ assert [^backup2] = Pleroma.Repo.all(Backup)
+ end
+
+ test "it creates a zip archive with user data" do
+ user = insert(:user, %{nickname: "cofe", name: "Cofe", ap_id: "http://cofe.io/users/cofe"})
+
+ {:ok, %{object: %{data: %{"id" => id1}}} = status1} =
+ CommonAPI.post(user, %{status: "status1"})
+
+ {:ok, %{object: %{data: %{"id" => id2}}} = status2} =
+ CommonAPI.post(user, %{status: "status2"})
+
+ {:ok, %{object: %{data: %{"id" => id3}}} = status3} =
+ CommonAPI.post(user, %{status: "status3"})
+
+ CommonAPI.favorite(user, status1.id)
+ CommonAPI.favorite(user, status2.id)
+
+ Bookmark.create(user.id, status2.id)
+ Bookmark.create(user.id, status3.id)
+
+ assert {:ok, backup} = user |> Backup.new() |> Repo.insert()
+ assert {:ok, path} = Backup.export(backup)
+ assert {:ok, zipfile} = :zip.zip_open(String.to_charlist(path), [:memory])
+ assert {:ok, {'actor.json', json}} = :zip.zip_get('actor.json', zipfile)
+
+ assert %{
+ "@context" => [
+ "https://www.w3.org/ns/activitystreams",
+ "http://localhost:4001/schemas/litepub-0.1.jsonld",
+ %{"@language" => "und"}
+ ],
+ "bookmarks" => "bookmarks.json",
+ "followers" => "http://cofe.io/users/cofe/followers",
+ "following" => "http://cofe.io/users/cofe/following",
+ "id" => "http://cofe.io/users/cofe",
+ "inbox" => "http://cofe.io/users/cofe/inbox",
+ "likes" => "likes.json",
+ "name" => "Cofe",
+ "outbox" => "http://cofe.io/users/cofe/outbox",
+ "preferredUsername" => "cofe",
+ "publicKey" => %{
+ "id" => "http://cofe.io/users/cofe#main-key",
+ "owner" => "http://cofe.io/users/cofe"
+ },
+ "type" => "Person",
+ "url" => "http://cofe.io/users/cofe"
+ } = Jason.decode!(json)
+
+ assert {:ok, {'outbox.json', json}} = :zip.zip_get('outbox.json', zipfile)
+
+ assert %{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "id" => "outbox.json",
+ "orderedItems" => [
+ %{
+ "object" => %{
+ "actor" => "http://cofe.io/users/cofe",
+ "content" => "status1",
+ "type" => "Note"
+ },
+ "type" => "Create"
+ },
+ %{
+ "object" => %{
+ "actor" => "http://cofe.io/users/cofe",
+ "content" => "status2"
+ }
+ },
+ %{
+ "actor" => "http://cofe.io/users/cofe",
+ "object" => %{
+ "content" => "status3"
+ }
+ }
+ ],
+ "totalItems" => 3,
+ "type" => "OrderedCollection"
+ } = Jason.decode!(json)
+
+ assert {:ok, {'likes.json', json}} = :zip.zip_get('likes.json', zipfile)
+
+ assert %{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "id" => "likes.json",
+ "orderedItems" => [^id1, ^id2],
+ "totalItems" => 2,
+ "type" => "OrderedCollection"
+ } = Jason.decode!(json)
+
+ assert {:ok, {'bookmarks.json', json}} = :zip.zip_get('bookmarks.json', zipfile)
+
+ assert %{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "id" => "bookmarks.json",
+ "orderedItems" => [^id2, ^id3],
+ "totalItems" => 2,
+ "type" => "OrderedCollection"
+ } = Jason.decode!(json)
+
+ :zip.zip_close(zipfile)
+ File.rm!(path)
+ end
+
+ describe "it uploads and deletes a backup archive" do
+ setup do
+ clear_config([Pleroma.Upload, :base_url], "https://s3.amazonaws.com")
+ clear_config([Pleroma.Uploaders.S3, :bucket], "test_bucket")
+
+ user = insert(:user, %{nickname: "cofe", name: "Cofe", ap_id: "http://cofe.io/users/cofe"})
+
+ {:ok, status1} = CommonAPI.post(user, %{status: "status1"})
+ {:ok, status2} = CommonAPI.post(user, %{status: "status2"})
+ {:ok, status3} = CommonAPI.post(user, %{status: "status3"})
+ CommonAPI.favorite(user, status1.id)
+ CommonAPI.favorite(user, status2.id)
+ Bookmark.create(user.id, status2.id)
+ Bookmark.create(user.id, status3.id)
+
+ assert {:ok, backup} = user |> Backup.new() |> Repo.insert()
+ assert {:ok, path} = Backup.export(backup)
+
+ [path: path, backup: backup]
+ end
+
+ test "S3", %{path: path, backup: backup} do
+ clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.S3)
+ clear_config([Pleroma.Uploaders.S3, :streaming_enabled], false)
+
+ with_mock ExAws,
+ request: fn
+ %{http_method: :put} -> {:ok, :ok}
+ %{http_method: :delete} -> {:ok, %{status_code: 204}}
+ end do
+ assert {:ok, %Pleroma.Upload{}} = Backup.upload(backup, path)
+ assert {:ok, _backup} = Backup.delete(backup)
+ end
+ end
+
+ test "Local", %{path: path, backup: backup} do
+ clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
+
+ assert {:ok, %Pleroma.Upload{}} = Backup.upload(backup, path)
+ assert {:ok, _backup} = Backup.delete(backup)
+ end
+ end
+end
diff --git a/test/pleroma/user/import_test.exs b/test/pleroma/user/import_test.exs
new file mode 100644
index 000000000..a84fce337
--- /dev/null
+++ b/test/pleroma/user/import_test.exs
@@ -0,0 +1,76 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.User.ImportTest do
+ alias Pleroma.Repo
+ alias Pleroma.Tests.ObanHelpers
+ alias Pleroma.User
+
+ use Pleroma.DataCase
+ use Oban.Testing, repo: Pleroma.Repo
+
+ import Pleroma.Factory
+
+ setup_all do
+ Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
+ :ok
+ end
+
+ describe "follow_import" do
+ test "it imports user followings from list" do
+ [user1, user2, user3] = insert_list(3, :user)
+
+ identifiers = [
+ user2.ap_id,
+ user3.nickname
+ ]
+
+ {:ok, job} = User.Import.follow_import(user1, identifiers)
+
+ assert {:ok, result} = ObanHelpers.perform(job)
+ assert is_list(result)
+ assert result == [refresh_record(user2), refresh_record(user3)]
+ assert User.following?(user1, user2)
+ assert User.following?(user1, user3)
+ end
+ end
+
+ describe "blocks_import" do
+ test "it imports user blocks from list" do
+ [user1, user2, user3] = insert_list(3, :user)
+
+ identifiers = [
+ user2.ap_id,
+ user3.nickname
+ ]
+
+ {:ok, job} = User.Import.blocks_import(user1, identifiers)
+
+ assert {:ok, result} = ObanHelpers.perform(job)
+ assert is_list(result)
+ assert result == [user2, user3]
+ assert User.blocks?(user1, user2)
+ assert User.blocks?(user1, user3)
+ end
+ end
+
+ describe "mutes_import" do
+ test "it imports user mutes from list" do
+ [user1, user2, user3] = insert_list(3, :user)
+
+ identifiers = [
+ user2.ap_id,
+ user3.nickname
+ ]
+
+ {:ok, job} = User.Import.mutes_import(user1, identifiers)
+
+ assert {:ok, result} = ObanHelpers.perform(job)
+ assert is_list(result)
+ assert result == [user2, user3]
+ assert User.mutes?(user1, user2)
+ assert User.mutes?(user1, user3)
+ end
+ end
+end
diff --git a/test/user/notification_setting_test.exs b/test/pleroma/user/notification_setting_test.exs
index 308da216a..6cb8803d9 100644
--- a/test/user/notification_setting_test.exs
+++ b/test/pleroma/user/notification_setting_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.User.NotificationSettingTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.User.NotificationSetting
diff --git a/test/pleroma/user/query_test.exs b/test/pleroma/user/query_test.exs
new file mode 100644
index 000000000..363da7665
--- /dev/null
+++ b/test/pleroma/user/query_test.exs
@@ -0,0 +1,47 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.User.QueryTest do
+ use Pleroma.DataCase, async: true
+
+ alias Pleroma.Repo
+ alias Pleroma.User
+ alias Pleroma.User.Query
+ alias Pleroma.Web.ActivityPub.InternalFetchActor
+
+ import Pleroma.Factory
+
+ describe "internal users" do
+ test "it filters out internal users by default" do
+ %User{nickname: "internal.fetch"} = InternalFetchActor.get_actor()
+
+ assert [_user] = User |> Repo.all()
+ assert [] == %{} |> Query.build() |> Repo.all()
+ end
+
+ test "it filters out users without nickname by default" do
+ insert(:user, %{nickname: nil})
+
+ assert [_user] = User |> Repo.all()
+ assert [] == %{} |> Query.build() |> Repo.all()
+ end
+
+ test "it returns internal users when enabled" do
+ %User{nickname: "internal.fetch"} = InternalFetchActor.get_actor()
+ insert(:user, %{nickname: nil})
+
+ assert %{internal: true} |> Query.build() |> Repo.aggregate(:count) == 2
+ end
+ end
+
+ test "is_suggested param" do
+ _user1 = insert(:user, is_suggested: false)
+ user2 = insert(:user, is_suggested: true)
+
+ assert [^user2] =
+ %{is_suggested: true}
+ |> User.Query.build()
+ |> Repo.all()
+ end
+end
diff --git a/test/user/welcome_chat_massage_test.exs b/test/pleroma/user/welcome_chat_message_test.exs
index fe26d6e4d..42a45fa19 100644
--- a/test/user/welcome_chat_massage_test.exs
+++ b/test/pleroma/user/welcome_chat_message_test.exs
@@ -1,11 +1,10 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.User.WelcomeChatMessageTest do
use Pleroma.DataCase
- alias Pleroma.Config
alias Pleroma.User.WelcomeChatMessage
import Pleroma.Factory
@@ -17,10 +16,10 @@ defmodule Pleroma.User.WelcomeChatMessageTest do
welcome_user = insert(:user, name: "mewmew")
user = insert(:user)
- Config.put([:welcome, :chat_message, :enabled], true)
- Config.put([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
+ clear_config([:welcome, :chat_message, :enabled], true)
+ clear_config([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
- Config.put(
+ clear_config(
[:welcome, :chat_message, :message],
"Hello, welcome to Blob/Cat!"
)
@@ -28,8 +27,10 @@ defmodule Pleroma.User.WelcomeChatMessageTest do
{:ok, %Pleroma.Activity{} = activity} = WelcomeChatMessage.post_message(user)
assert user.ap_id in activity.recipients
- assert Pleroma.Object.normalize(activity).data["type"] == "ChatMessage"
- assert Pleroma.Object.normalize(activity).data["content"] == "Hello, welcome to Blob/Cat!"
+ assert Pleroma.Object.normalize(activity, fetch: false).data["type"] == "ChatMessage"
+
+ assert Pleroma.Object.normalize(activity, fetch: false).data["content"] ==
+ "Hello, welcome to Blob/Cat!"
end
end
end
diff --git a/test/user/welcome_email_test.exs b/test/pleroma/user/welcome_email_test.exs
index d005d11b2..c3d383a7f 100644
--- a/test/user/welcome_email_test.exs
+++ b/test/pleroma/user/welcome_email_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.User.WelcomeEmailTest do
@@ -18,15 +18,15 @@ defmodule Pleroma.User.WelcomeEmailTest do
test "send a welcome email" do
user = insert(:user, name: "Jimm")
- Config.put([:welcome, :email, :enabled], true)
- Config.put([:welcome, :email, :sender], "welcome@pleroma.app")
+ clear_config([:welcome, :email, :enabled], true)
+ clear_config([:welcome, :email, :sender], "welcome@pleroma.app")
- Config.put(
+ clear_config(
[:welcome, :email, :subject],
"Hello, welcome to pleroma: <%= instance_name %>"
)
- Config.put(
+ clear_config(
[:welcome, :email, :html],
"<h1>Hello <%= user.name %>.</h1> <p>Welcome to <%= instance_name %></p>"
)
@@ -44,7 +44,7 @@ defmodule Pleroma.User.WelcomeEmailTest do
html_body: "<h1>Hello #{user.name}.</h1> <p>Welcome to #{instance_name}</p>"
)
- Config.put([:welcome, :email, :sender], {"Pleroma App", "welcome@pleroma.app"})
+ clear_config([:welcome, :email, :sender], {"Pleroma App", "welcome@pleroma.app"})
{:ok, _job} = WelcomeEmail.send_email(user)
diff --git a/test/user/welcome_message_test.exs b/test/pleroma/user/welcome_message_test.exs
index 3cd6f5cb7..28afde943 100644
--- a/test/user/welcome_message_test.exs
+++ b/test/pleroma/user/welcome_message_test.exs
@@ -1,11 +1,10 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.User.WelcomeMessageTest do
use Pleroma.DataCase
- alias Pleroma.Config
alias Pleroma.User.WelcomeMessage
import Pleroma.Factory
@@ -17,10 +16,10 @@ defmodule Pleroma.User.WelcomeMessageTest do
welcome_user = insert(:user)
user = insert(:user, name: "Jimm")
- Config.put([:welcome, :direct_message, :enabled], true)
- Config.put([:welcome, :direct_message, :sender_nickname], welcome_user.nickname)
+ clear_config([:welcome, :direct_message, :enabled], true)
+ clear_config([:welcome, :direct_message, :sender_nickname], welcome_user.nickname)
- Config.put(
+ clear_config(
[:welcome, :direct_message, :message],
"Hello. Welcome to Pleroma"
)
@@ -28,7 +27,9 @@ defmodule Pleroma.User.WelcomeMessageTest do
{:ok, %Pleroma.Activity{} = activity} = WelcomeMessage.post_message(user)
assert user.ap_id in activity.recipients
assert activity.data["directMessage"] == true
- assert Pleroma.Object.normalize(activity).data["content"] =~ "Hello. Welcome to Pleroma"
+
+ assert Pleroma.Object.normalize(activity, fetch: false).data["content"] =~
+ "Hello. Welcome to Pleroma"
end
end
end
diff --git a/test/user_invite_token_test.exs b/test/pleroma/user_invite_token_test.exs
index 63f18f13c..233d4e864 100644
--- a/test/user_invite_token_test.exs
+++ b/test/pleroma/user_invite_token_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.UserInviteTokenTest do
diff --git a/test/user_relationship_test.exs b/test/pleroma/user_relationship_test.exs
index f12406097..b2b074607 100644
--- a/test/user_relationship_test.exs
+++ b/test/pleroma/user_relationship_test.exs
@@ -1,11 +1,11 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.UserRelationshipTest do
alias Pleroma.UserRelationship
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
import Pleroma.Factory
diff --git a/test/user_search_test.exs b/test/pleroma/user_search_test.exs
index 01976bf58..69167bb0c 100644
--- a/test/user_search_test.exs
+++ b/test/pleroma/user_search_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.UserSearchTest do
@@ -17,6 +17,46 @@ defmodule Pleroma.UserSearchTest do
describe "User.search" do
setup do: clear_config([:instance, :limit_to_local_content])
+ test "returns a resolved user as the first result" do
+ clear_config([:instance, :limit_to_local_content], false)
+ user = insert(:user, %{nickname: "no_relation", ap_id: "https://lain.com/users/lain"})
+ _user = insert(:user, %{nickname: "com_user"})
+
+ [first_user, _second_user] = User.search("https://lain.com/users/lain", resolve: true)
+
+ assert first_user.id == user.id
+ end
+
+ test "returns a user with matching ap_id as the first result" do
+ user = insert(:user, %{nickname: "no_relation", ap_id: "https://lain.com/users/lain"})
+ _user = insert(:user, %{nickname: "com_user"})
+
+ [first_user, _second_user] = User.search("https://lain.com/users/lain")
+
+ assert first_user.id == user.id
+ end
+
+ test "doesn't die if two users have the same uri" do
+ insert(:user, %{uri: "https://gensokyo.2hu/@raymoo"})
+ insert(:user, %{uri: "https://gensokyo.2hu/@raymoo"})
+ assert [_first_user, _second_user] = User.search("https://gensokyo.2hu/@raymoo")
+ end
+
+ test "returns a user with matching uri as the first result" do
+ user =
+ insert(:user, %{
+ nickname: "no_relation",
+ ap_id: "https://lain.com/users/lain",
+ uri: "https://lain.com/@lain"
+ })
+
+ _user = insert(:user, %{nickname: "com_user"})
+
+ [first_user, _second_user] = User.search("https://lain.com/@lain")
+
+ assert first_user.id == user.id
+ end
+
test "excludes invisible users from results" do
user = insert(:user, %{nickname: "john t1000"})
insert(:user, %{invisible: true, nickname: "john t800"})
@@ -25,6 +65,15 @@ defmodule Pleroma.UserSearchTest do
assert found_user.id == user.id
end
+ # Note: as in Mastodon, `is_discoverable` doesn't anyhow relate to user searchability
+ test "includes non-discoverable users in results" do
+ insert(:user, %{nickname: "john 3000", is_discoverable: false})
+ insert(:user, %{nickname: "john 3001"})
+
+ users = User.search("john")
+ assert Enum.count(users) == 2
+ end
+
test "excludes service actors from results" do
insert(:user, actor_type: "Application", nickname: "user1")
service = insert(:user, actor_type: "Service", nickname: "user2")
@@ -102,8 +151,8 @@ defmodule Pleroma.UserSearchTest do
follower = insert(:user, %{name: "Doe"})
friend = insert(:user, %{name: "Doe"})
- {:ok, follower} = User.follow(follower, u1)
- {:ok, u1} = User.follow(u1, friend)
+ {:ok, follower, u1} = User.follow(follower, u1)
+ {:ok, u1, friend} = User.follow(u1, friend)
assert [friend.id, follower.id, u2.id] --
Enum.map(User.search("doe", resolve: false, for_user: u1), & &1.id) == []
@@ -116,9 +165,9 @@ defmodule Pleroma.UserSearchTest do
following_jimi = insert(:user, %{name: "Lizz Wright"})
follower_lizz = insert(:user, %{name: "Jimi"})
- {:ok, lizz} = User.follow(lizz, following_lizz)
- {:ok, _jimi} = User.follow(jimi, following_jimi)
- {:ok, _follower_lizz} = User.follow(follower_lizz, lizz)
+ {:ok, lizz, following_lizz} = User.follow(lizz, following_lizz)
+ {:ok, _jimi, _following_jimi} = User.follow(jimi, following_jimi)
+ {:ok, _follower_lizz, _lizz} = User.follow(follower_lizz, lizz)
assert Enum.map(User.search("jimi", following: true, for_user: lizz), & &1.id) == [
following_lizz.id
@@ -150,7 +199,7 @@ defmodule Pleroma.UserSearchTest do
end
test "find only local users for authenticated users when `limit_to_local_content` is `:all`" do
- Pleroma.Config.put([:instance, :limit_to_local_content], :all)
+ clear_config([:instance, :limit_to_local_content], :all)
%{id: id} = insert(:user, %{name: "lain"})
insert(:user, %{name: "ebn", nickname: "lain@mastodon.social", local: false})
@@ -160,7 +209,7 @@ defmodule Pleroma.UserSearchTest do
end
test "find all users for unauthenticated users when `limit_to_local_content` is `false`" do
- Pleroma.Config.put([:instance, :limit_to_local_content], false)
+ clear_config([:instance, :limit_to_local_content], false)
u1 = insert(:user, %{name: "lain"})
u2 = insert(:user, %{name: "ebn", nickname: "lain@mastodon.social", local: false})
diff --git a/test/user_test.exs b/test/pleroma/user_test.exs
index 50f72549e..6cd93c34c 100644
--- a/test/user_test.exs
+++ b/test/pleroma/user_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.UserTest do
@@ -151,7 +151,7 @@ defmodule Pleroma.UserTest do
test "ap_id returns the activity pub id for the user" do
user = UserBuilder.build()
- expected_ap_id = "#{Pleroma.Web.base_url()}/users/#{user.nickname}"
+ expected_ap_id = "#{Pleroma.Web.Endpoint.url()}/users/#{user.nickname}"
assert expected_ap_id == User.ap_id(user)
end
@@ -174,7 +174,7 @@ defmodule Pleroma.UserTest do
test "returns all pending follow requests" do
unlocked = insert(:user)
- locked = insert(:user, locked: true)
+ locked = insert(:user, is_locked: true)
follower = insert(:user)
CommonAPI.follow(follower, unlocked)
@@ -187,7 +187,7 @@ defmodule Pleroma.UserTest do
end
test "doesn't return already accepted or duplicate follow requests" do
- locked = insert(:user, locked: true)
+ locked = insert(:user, is_locked: true)
pending_follower = insert(:user)
accepted_follower = insert(:user)
@@ -201,17 +201,17 @@ defmodule Pleroma.UserTest do
end
test "doesn't return follow requests for deactivated accounts" do
- locked = insert(:user, locked: true)
- pending_follower = insert(:user, %{deactivated: true})
+ locked = insert(:user, is_locked: true)
+ pending_follower = insert(:user, %{is_active: false})
CommonAPI.follow(pending_follower, locked)
- assert true == pending_follower.deactivated
+ refute pending_follower.is_active
assert [] = User.get_follow_requests(locked)
end
test "clears follow requests when requester is blocked" do
- followed = insert(:user, locked: true)
+ followed = insert(:user, is_locked: true)
follower = insert(:user)
CommonAPI.follow(follower, followed)
@@ -233,7 +233,7 @@ defmodule Pleroma.UserTest do
{:ok, _user_relationship} = User.block(user, blocked)
{:ok, _user_relationship} = User.block(reverse_blocked, user)
- {:ok, user} = User.follow(user, followed_zero)
+ {:ok, user, followed_zero} = User.follow(user, followed_zero)
{:ok, user} = User.follow_all(user, [followed_one, followed_two, blocked, reverse_blocked])
@@ -262,7 +262,7 @@ defmodule Pleroma.UserTest do
user = insert(:user)
followed = insert(:user)
- {:ok, user} = User.follow(user, followed)
+ {:ok, user, followed} = User.follow(user, followed)
user = User.get_cached_by_id(user.id)
followed = User.get_cached_by_ap_id(followed.ap_id)
@@ -275,7 +275,7 @@ defmodule Pleroma.UserTest do
test "can't follow a deactivated users" do
user = insert(:user)
- followed = insert(:user, %{deactivated: true})
+ followed = insert(:user, %{is_active: false})
{:error, _} = User.follow(user, followed)
end
@@ -299,10 +299,10 @@ defmodule Pleroma.UserTest do
end
test "local users do not automatically follow local locked accounts" do
- follower = insert(:user, locked: true)
- followed = insert(:user, locked: true)
+ follower = insert(:user, is_locked: true)
+ followed = insert(:user, is_locked: true)
- {:ok, follower} = User.maybe_direct_follow(follower, followed)
+ {:ok, follower, followed} = User.maybe_direct_follow(follower, followed)
refute User.following?(follower, followed)
end
@@ -311,7 +311,7 @@ defmodule Pleroma.UserTest do
setup do: clear_config([:instance, :external_user_synchronization])
test "unfollow with syncronizes external user" do
- Pleroma.Config.put([:instance, :external_user_synchronization], true)
+ clear_config([:instance, :external_user_synchronization], true)
followed =
insert(:user,
@@ -330,7 +330,7 @@ defmodule Pleroma.UserTest do
following_address: "http://localhost:4001/users/fuser2/following"
})
- {:ok, user} = User.follow(user, followed, :follow_accept)
+ {:ok, user, followed} = User.follow(user, followed, :follow_accept)
{:ok, user, _activity} = User.unfollow(user, followed)
@@ -343,7 +343,7 @@ defmodule Pleroma.UserTest do
followed = insert(:user)
user = insert(:user)
- {:ok, user} = User.follow(user, followed, :follow_accept)
+ {:ok, user, followed} = User.follow(user, followed, :follow_accept)
assert User.following(user) == [user.follower_address, followed.follower_address]
@@ -388,6 +388,7 @@ defmodule Pleroma.UserTest do
}
setup do: clear_config([:instance, :autofollowed_nicknames])
+ setup do: clear_config([:instance, :autofollowing_nicknames])
setup do: clear_config([:welcome])
setup do: clear_config([:instance, :account_activation_required])
@@ -395,7 +396,7 @@ defmodule Pleroma.UserTest do
user = insert(:user)
remote_user = insert(:user, %{local: false})
- Pleroma.Config.put([:instance, :autofollowed_nicknames], [
+ clear_config([:instance, :autofollowed_nicknames], [
user.nickname,
remote_user.nickname
])
@@ -408,11 +409,28 @@ defmodule Pleroma.UserTest do
refute User.following?(registered_user, remote_user)
end
+ test "it adds automatic followers for new registered accounts" do
+ user1 = insert(:user)
+ user2 = insert(:user)
+
+ clear_config([:instance, :autofollowing_nicknames], [
+ user1.nickname,
+ user2.nickname
+ ])
+
+ cng = User.register_changeset(%User{}, @full_user_data)
+
+ {:ok, registered_user} = User.register(cng)
+
+ assert User.following?(user1, registered_user)
+ assert User.following?(user2, registered_user)
+ end
+
test "it sends a welcome message if it is set" do
welcome_user = insert(:user)
- Pleroma.Config.put([:welcome, :direct_message, :enabled], true)
- Pleroma.Config.put([:welcome, :direct_message, :sender_nickname], welcome_user.nickname)
- Pleroma.Config.put([:welcome, :direct_message, :message], "Hello, this is a direct message")
+ clear_config([:welcome, :direct_message, :enabled], true)
+ clear_config([:welcome, :direct_message, :sender_nickname], welcome_user.nickname)
+ clear_config([:welcome, :direct_message, :message], "Hello, this is a direct message")
cng = User.register_changeset(%User{}, @full_user_data)
{:ok, registered_user} = User.register(cng)
@@ -420,15 +438,54 @@ defmodule Pleroma.UserTest do
activity = Repo.one(Pleroma.Activity)
assert registered_user.ap_id in activity.recipients
- assert Object.normalize(activity).data["content"] =~ "direct message"
+ assert Object.normalize(activity, fetch: false).data["content"] =~ "direct message"
assert activity.actor == welcome_user.ap_id
end
test "it sends a welcome chat message if it is set" do
welcome_user = insert(:user)
- Pleroma.Config.put([:welcome, :chat_message, :enabled], true)
- Pleroma.Config.put([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
- Pleroma.Config.put([:welcome, :chat_message, :message], "Hello, this is a chat message")
+ clear_config([:welcome, :chat_message, :enabled], true)
+ clear_config([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
+ clear_config([:welcome, :chat_message, :message], "Hello, this is a chat message")
+
+ cng = User.register_changeset(%User{}, @full_user_data)
+ {:ok, registered_user} = User.register(cng)
+ ObanHelpers.perform_all()
+
+ activity = Repo.one(Pleroma.Activity)
+ assert registered_user.ap_id in activity.recipients
+ assert Object.normalize(activity, fetch: false).data["content"] =~ "chat message"
+ assert activity.actor == welcome_user.ap_id
+ end
+
+ setup do:
+ clear_config(:mrf_simple,
+ media_removal: [],
+ media_nsfw: [],
+ federated_timeline_removal: [],
+ report_removal: [],
+ reject: [],
+ followers_only: [],
+ accept: [],
+ avatar_removal: [],
+ banner_removal: [],
+ reject_deletes: []
+ )
+
+ setup do:
+ clear_config(:mrf,
+ policies: [
+ Pleroma.Web.ActivityPub.MRF.SimplePolicy
+ ]
+ )
+
+ test "it sends a welcome chat message when Simple policy applied to local instance" do
+ clear_config([:mrf_simple, :media_nsfw], [{"localhost", ""}])
+
+ welcome_user = insert(:user)
+ clear_config([:welcome, :chat_message, :enabled], true)
+ clear_config([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
+ clear_config([:welcome, :chat_message, :message], "Hello, this is a chat message")
cng = User.register_changeset(%User{}, @full_user_data)
{:ok, registered_user} = User.register(cng)
@@ -436,16 +493,16 @@ defmodule Pleroma.UserTest do
activity = Repo.one(Pleroma.Activity)
assert registered_user.ap_id in activity.recipients
- assert Object.normalize(activity).data["content"] =~ "chat message"
+ assert Object.normalize(activity, fetch: false).data["content"] =~ "chat message"
assert activity.actor == welcome_user.ap_id
end
test "it sends a welcome email message if it is set" do
welcome_user = insert(:user)
- Pleroma.Config.put([:welcome, :email, :enabled], true)
- Pleroma.Config.put([:welcome, :email, :sender], welcome_user.email)
+ clear_config([:welcome, :email, :enabled], true)
+ clear_config([:welcome, :email, :sender], welcome_user.email)
- Pleroma.Config.put(
+ clear_config(
[:welcome, :email, :subject],
"Hello, welcome to cool site: <%= instance_name %>"
)
@@ -465,16 +522,76 @@ defmodule Pleroma.UserTest do
end
test "it sends a confirm email" do
- Pleroma.Config.put([:instance, :account_activation_required], true)
+ clear_config([:instance, :account_activation_required], true)
cng = User.register_changeset(%User{}, @full_user_data)
{:ok, registered_user} = User.register(cng)
ObanHelpers.perform_all()
- assert_email_sent(Pleroma.Emails.UserEmail.account_confirmation_email(registered_user))
+
+ Pleroma.Emails.UserEmail.account_confirmation_email(registered_user)
+ # temporary hackney fix until hackney max_connections bug is fixed
+ # https://git.pleroma.social/pleroma/pleroma/-/issues/2101
+ |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]])
+ |> assert_email_sent()
+ end
+
+ test "sends a pending approval email" do
+ clear_config([:instance, :account_approval_required], true)
+
+ {:ok, user} =
+ User.register_changeset(%User{}, @full_user_data)
+ |> User.register()
+
+ ObanHelpers.perform_all()
+
+ assert_email_sent(
+ from: Pleroma.Config.Helpers.sender(),
+ to: {user.name, user.email},
+ subject: "Your account is awaiting approval"
+ )
+ end
+
+ test "it sends a registration confirmed email if no others will be sent" do
+ clear_config([:welcome, :email, :enabled], false)
+ clear_config([:instance, :account_activation_required], false)
+ clear_config([:instance, :account_approval_required], false)
+
+ {:ok, user} =
+ User.register_changeset(%User{}, @full_user_data)
+ |> User.register()
+
+ ObanHelpers.perform_all()
+
+ instance_name = Pleroma.Config.get([:instance, :name])
+ sender = Pleroma.Config.get([:instance, :notify_email])
+
+ assert_email_sent(
+ from: {instance_name, sender},
+ to: {user.name, user.email},
+ subject: "Account registered on #{instance_name}"
+ )
+ end
+
+ test "it fails gracefully with invalid email config" do
+ cng = User.register_changeset(%User{}, @full_user_data)
+
+ # Disable the mailer but enable all the things that want to send emails
+ clear_config([Pleroma.Emails.Mailer, :enabled], false)
+ clear_config([:instance, :account_activation_required], true)
+ clear_config([:instance, :account_approval_required], true)
+ clear_config([:welcome, :email, :enabled], true)
+ clear_config([:welcome, :email, :sender], "lain@lain.com")
+
+ # The user is still created
+ assert {:ok, %User{nickname: "nick"}} = User.register(cng)
+
+ # No emails are sent
+ ObanHelpers.perform_all()
+ refute_email_sent()
end
test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
- Pleroma.Config.put([:instance, :account_activation_required], true)
+ clear_config([:instance, :account_activation_required], true)
@full_user_data
|> Map.keys()
@@ -487,7 +604,7 @@ defmodule Pleroma.UserTest do
end
test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do
- Pleroma.Config.put([:instance, :account_activation_required], false)
+ clear_config([:instance, :account_activation_required], false)
@full_user_data
|> Map.keys()
@@ -562,7 +679,7 @@ defmodule Pleroma.UserTest do
{:ok, user} = Repo.insert(changeset)
- refute user.confirmation_pending
+ assert user.is_confirmed
end
end
@@ -583,17 +700,17 @@ defmodule Pleroma.UserTest do
{:ok, user} = Repo.insert(changeset)
- assert user.confirmation_pending
+ refute user.is_confirmed
assert user.confirmation_token
end
test "it creates confirmed user if :confirmed option is given" do
- changeset = User.register_changeset(%User{}, @full_user_data, need_confirmation: false)
+ changeset = User.register_changeset(%User{}, @full_user_data, confirmed: true)
assert changeset.valid?
{:ok, user} = Repo.insert(changeset)
- refute user.confirmation_pending
+ assert user.is_confirmed
refute user.confirmation_token
end
end
@@ -616,7 +733,7 @@ defmodule Pleroma.UserTest do
{:ok, user} = Repo.insert(changeset)
- assert user.approval_pending
+ refute user.is_approved
assert user.registration_reason == "I'm a cool guy :)"
end
@@ -833,6 +950,13 @@ defmodule Pleroma.UserTest do
refute cs.valid?
end)
end
+
+ test "it is invalid given a local user" do
+ user = insert(:user)
+ cs = User.remote_user_changeset(user, %{name: "tom from myspace"})
+
+ refute cs.valid?
+ end
end
describe "followers and friends" do
@@ -842,8 +966,8 @@ defmodule Pleroma.UserTest do
follower_two = insert(:user)
not_follower = insert(:user)
- {:ok, follower_one} = User.follow(follower_one, user)
- {:ok, follower_two} = User.follow(follower_two, user)
+ {:ok, follower_one, user} = User.follow(follower_one, user)
+ {:ok, follower_two, user} = User.follow(follower_two, user)
res = User.get_followers(user)
@@ -858,8 +982,8 @@ defmodule Pleroma.UserTest do
followed_two = insert(:user)
not_followed = insert(:user)
- {:ok, user} = User.follow(user, followed_one)
- {:ok, user} = User.follow(user, followed_two)
+ {:ok, user, followed_one} = User.follow(user, followed_one)
+ {:ok, user, followed_two} = User.follow(user, followed_two)
res = User.get_friends(user)
@@ -932,23 +1056,6 @@ defmodule Pleroma.UserTest do
end
end
- describe "follow_import" do
- test "it imports user followings from list" do
- [user1, user2, user3] = insert_list(3, :user)
-
- identifiers = [
- user2.ap_id,
- user3.nickname
- ]
-
- {:ok, job} = User.follow_import(user1, identifiers)
-
- assert {:ok, result} = ObanHelpers.perform(job)
- assert is_list(result)
- assert result == [user2, user3]
- end
- end
-
describe "mutes" do
test "it mutes people" do
user = insert(:user)
@@ -963,6 +1070,27 @@ defmodule Pleroma.UserTest do
assert User.muted_notifications?(user, muted_user)
end
+ test "expiring" do
+ user = insert(:user)
+ muted_user = insert(:user)
+
+ {:ok, _user_relationships} = User.mute(user, muted_user, %{expires_in: 60})
+ assert User.mutes?(user, muted_user)
+
+ worker = Pleroma.Workers.MuteExpireWorker
+ args = %{"op" => "unmute_user", "muter_id" => user.id, "mutee_id" => muted_user.id}
+
+ assert_enqueued(
+ worker: worker,
+ args: args
+ )
+
+ assert :ok = perform_job(worker, args)
+
+ refute User.mutes?(user, muted_user)
+ refute User.muted_notifications?(user, muted_user)
+ end
+
test "it unmutes users" do
user = insert(:user)
muted_user = insert(:user)
@@ -974,6 +1102,17 @@ defmodule Pleroma.UserTest do
refute User.muted_notifications?(user, muted_user)
end
+ test "it unmutes users by id" do
+ user = insert(:user)
+ muted_user = insert(:user)
+
+ {:ok, _user_relationships} = User.mute(user, muted_user)
+ {:ok, _user_mute} = User.unmute(user.id, muted_user.id)
+
+ refute User.mutes?(user, muted_user)
+ refute User.muted_notifications?(user, muted_user)
+ end
+
test "it mutes user without notifications" do
user = insert(:user)
muted_user = insert(:user)
@@ -981,7 +1120,7 @@ defmodule Pleroma.UserTest do
refute User.mutes?(user, muted_user)
refute User.muted_notifications?(user, muted_user)
- {:ok, _user_relationships} = User.mute(user, muted_user, false)
+ {:ok, _user_relationships} = User.mute(user, muted_user, %{notifications: false})
assert User.mutes?(user, muted_user)
refute User.muted_notifications?(user, muted_user)
@@ -1014,8 +1153,8 @@ defmodule Pleroma.UserTest do
blocker = insert(:user)
blocked = insert(:user)
- {:ok, blocker} = User.follow(blocker, blocked)
- {:ok, blocked} = User.follow(blocked, blocker)
+ {:ok, blocker, blocked} = User.follow(blocker, blocked)
+ {:ok, blocked, blocker} = User.follow(blocked, blocker)
assert User.following?(blocker, blocked)
assert User.following?(blocked, blocker)
@@ -1033,7 +1172,7 @@ defmodule Pleroma.UserTest do
blocker = insert(:user)
blocked = insert(:user)
- {:ok, blocker} = User.follow(blocker, blocked)
+ {:ok, blocker, blocked} = User.follow(blocker, blocked)
assert User.following?(blocker, blocked)
refute User.following?(blocked, blocker)
@@ -1051,7 +1190,7 @@ defmodule Pleroma.UserTest do
blocker = insert(:user)
blocked = insert(:user)
- {:ok, blocked} = User.follow(blocked, blocker)
+ {:ok, blocked, blocker} = User.follow(blocked, blocker)
refute User.following?(blocker, blocked)
assert User.following?(blocked, blocker)
@@ -1149,29 +1288,12 @@ defmodule Pleroma.UserTest do
good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
{:ok, user} = User.block_domain(user, "meanies.social")
- {:ok, user} = User.follow(user, good_eggo)
+ {:ok, user, good_eggo} = User.follow(user, good_eggo)
refute User.blocks?(user, good_eggo)
end
end
- describe "blocks_import" do
- test "it imports user blocks from list" do
- [user1, user2, user3] = insert_list(3, :user)
-
- identifiers = [
- user2.ap_id,
- user3.nickname
- ]
-
- {:ok, job} = User.blocks_import(user1, identifiers)
-
- assert {:ok, result} = ObanHelpers.perform(job)
- assert is_list(result)
- assert result == [user2, user3]
- end
- end
-
describe "get_recipients_from_activity" do
test "works for announces" do
actor = insert(:user)
@@ -1200,8 +1322,8 @@ defmodule Pleroma.UserTest do
assert Enum.map([actor, addressed], & &1.ap_id) --
Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
- {:ok, user} = User.follow(user, actor)
- {:ok, _user_two} = User.follow(user_two, actor)
+ {:ok, user, actor} = User.follow(user, actor)
+ {:ok, _user_two, _actor} = User.follow(user_two, actor)
recipients = User.get_recipients_from_activity(activity)
assert length(recipients) == 3
assert user in recipients
@@ -1222,30 +1344,30 @@ defmodule Pleroma.UserTest do
assert Enum.map([actor, addressed], & &1.ap_id) --
Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
- {:ok, _actor} = User.follow(actor, user)
- {:ok, _actor} = User.follow(actor, user_two)
+ {:ok, _actor, _user} = User.follow(actor, user)
+ {:ok, _actor, _user_two} = User.follow(actor, user_two)
recipients = User.get_recipients_from_activity(activity)
assert length(recipients) == 2
assert addressed in recipients
end
end
- describe ".deactivate" do
+ describe ".set_activation" do
test "can de-activate then re-activate a user" do
user = insert(:user)
- assert false == user.deactivated
- {:ok, user} = User.deactivate(user)
- assert true == user.deactivated
- {:ok, user} = User.deactivate(user, false)
- assert false == user.deactivated
+ assert user.is_active
+ {:ok, user} = User.set_activation(user, false)
+ refute user.is_active
+ {:ok, user} = User.set_activation(user, true)
+ assert user.is_active
end
test "hide a user from followers" do
user = insert(:user)
user2 = insert(:user)
- {:ok, user} = User.follow(user, user2)
- {:ok, _user} = User.deactivate(user)
+ {:ok, user, user2} = User.follow(user, user2)
+ {:ok, _user} = User.set_activation(user, false)
user2 = User.get_cached_by_id(user2.id)
@@ -1257,11 +1379,11 @@ defmodule Pleroma.UserTest do
user = insert(:user)
user2 = insert(:user)
- {:ok, user2} = User.follow(user2, user)
+ {:ok, user2, user} = User.follow(user2, user)
assert user2.following_count == 1
assert User.following_count(user2) == 1
- {:ok, _user} = User.deactivate(user)
+ {:ok, _user} = User.set_activation(user, false)
user2 = User.get_cached_by_id(user2.id)
@@ -1275,7 +1397,7 @@ defmodule Pleroma.UserTest do
user = insert(:user)
user2 = insert(:user)
- {:ok, user2} = User.follow(user2, user)
+ {:ok, user2, user} = User.follow(user2, user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
@@ -1291,7 +1413,7 @@ defmodule Pleroma.UserTest do
user: user2
})
- {:ok, _user} = User.deactivate(user)
+ {:ok, _user} = User.set_activation(user, false)
assert [] == ActivityPub.fetch_public_activities(%{})
assert [] == Pleroma.Notification.for_user(user2)
@@ -1305,17 +1427,17 @@ defmodule Pleroma.UserTest do
describe "approve" do
test "approves a user" do
- user = insert(:user, approval_pending: true)
- assert true == user.approval_pending
+ user = insert(:user, is_approved: false)
+ refute user.is_approved
{:ok, user} = User.approve(user)
- assert false == user.approval_pending
+ assert user.is_approved
end
test "approves a list of users" do
unapproved_users = [
- insert(:user, approval_pending: true),
- insert(:user, approval_pending: true),
- insert(:user, approval_pending: true)
+ insert(:user, is_approved: false),
+ insert(:user, is_approved: false),
+ insert(:user, is_approved: false)
]
{:ok, users} = User.approve(unapproved_users)
@@ -1323,9 +1445,101 @@ defmodule Pleroma.UserTest do
assert Enum.count(users) == 3
Enum.each(users, fn user ->
- assert false == user.approval_pending
+ assert user.is_approved
end)
end
+
+ test "it sends welcome email if it is set" do
+ clear_config([:welcome, :email, :enabled], true)
+ clear_config([:welcome, :email, :sender], "tester@test.me")
+
+ user = insert(:user, is_approved: false)
+ welcome_user = insert(:user, email: "tester@test.me")
+ instance_name = Pleroma.Config.get([:instance, :name])
+
+ User.approve(user)
+
+ ObanHelpers.perform_all()
+
+ assert_email_sent(
+ from: {instance_name, welcome_user.email},
+ to: {user.name, user.email},
+ html_body: "Welcome to #{instance_name}"
+ )
+ end
+
+ test "approving an approved user does not trigger post-register actions" do
+ clear_config([:welcome, :email, :enabled], true)
+
+ user = insert(:user, is_approved: true)
+ User.approve(user)
+
+ ObanHelpers.perform_all()
+
+ assert_no_email_sent()
+ end
+ end
+
+ describe "confirm" do
+ test "confirms a user" do
+ user = insert(:user, is_confirmed: false)
+ refute user.is_confirmed
+ {:ok, user} = User.confirm(user)
+ assert user.is_confirmed
+ end
+
+ test "confirms a list of users" do
+ unconfirmed_users = [
+ insert(:user, is_confirmed: false),
+ insert(:user, is_confirmed: false),
+ insert(:user, is_confirmed: false)
+ ]
+
+ {:ok, users} = User.confirm(unconfirmed_users)
+
+ assert Enum.count(users) == 3
+
+ Enum.each(users, fn user ->
+ assert user.is_confirmed
+ end)
+ end
+
+ test "sends approval emails when `is_approved: false`" do
+ admin = insert(:user, is_admin: true)
+ user = insert(:user, is_confirmed: false, is_approved: false)
+ User.confirm(user)
+
+ ObanHelpers.perform_all()
+
+ user_email = Pleroma.Emails.UserEmail.approval_pending_email(user)
+ admin_email = Pleroma.Emails.AdminEmail.new_unapproved_registration(admin, user)
+
+ notify_email = Pleroma.Config.get([:instance, :notify_email])
+ instance_name = Pleroma.Config.get([:instance, :name])
+
+ # User approval email
+ assert_email_sent(
+ from: {instance_name, notify_email},
+ to: {user.name, user.email},
+ html_body: user_email.html_body
+ )
+
+ # Admin email
+ assert_email_sent(
+ from: {instance_name, notify_email},
+ to: {admin.name, admin.email},
+ html_body: admin_email.html_body
+ )
+ end
+
+ test "confirming a confirmed user does not trigger post-register actions" do
+ user = insert(:user, is_confirmed: true, is_approved: false)
+ User.confirm(user)
+
+ ObanHelpers.perform_all()
+
+ assert_no_email_sent()
+ end
end
describe "delete" do
@@ -1348,10 +1562,10 @@ defmodule Pleroma.UserTest do
test "it deactivates a user, all follow relationships and all activities", %{user: user} do
follower = insert(:user)
- {:ok, follower} = User.follow(follower, user)
+ {:ok, follower, user} = User.follow(follower, user)
- locked_user = insert(:user, name: "locked", locked: true)
- {:ok, _} = User.follow(user, locked_user, :follow_pending)
+ locked_user = insert(:user, name: "locked", is_locked: true)
+ {:ok, _, _} = User.follow(user, locked_user, :follow_pending)
object = insert(:note, user: user)
activity = insert(:note_activity, user: user, note: object)
@@ -1369,7 +1583,7 @@ defmodule Pleroma.UserTest do
follower = User.get_cached_by_id(follower.id)
refute User.following?(follower, user)
- assert %{deactivated: true} = User.get_by_id(user.id)
+ assert %{is_active: false} = User.get_by_id(user.id)
assert [] == User.get_follow_requests(locked_user)
@@ -1388,35 +1602,19 @@ defmodule Pleroma.UserTest do
end
end
- describe "delete/1 when confirmation is pending" do
- setup do
- user = insert(:user, confirmation_pending: true)
- {:ok, user: user}
- end
-
- test "deletes user from database when activation required", %{user: user} do
- clear_config([:instance, :account_activation_required], true)
-
- {:ok, job} = User.delete(user)
- {:ok, _} = ObanHelpers.perform(job)
-
- refute User.get_cached_by_id(user.id)
- refute User.get_by_id(user.id)
- end
+ test "delete/1 when confirmation is pending deletes the user" do
+ clear_config([:instance, :account_activation_required], true)
+ user = insert(:user, is_confirmed: false)
- test "deactivates user when activation is not required", %{user: user} do
- clear_config([:instance, :account_activation_required], false)
-
- {:ok, job} = User.delete(user)
- {:ok, _} = ObanHelpers.perform(job)
+ {:ok, job} = User.delete(user)
+ {:ok, _} = ObanHelpers.perform(job)
- assert %{deactivated: true} = User.get_cached_by_id(user.id)
- assert %{deactivated: true} = User.get_by_id(user.id)
- end
+ refute User.get_cached_by_id(user.id)
+ refute User.get_by_id(user.id)
end
test "delete/1 when approval is pending deletes the user" do
- user = insert(:user, approval_pending: true)
+ user = insert(:user, is_approved: false)
{:ok, job} = User.delete(user)
{:ok, _} = ObanHelpers.perform(job)
@@ -1440,24 +1638,23 @@ defmodule Pleroma.UserTest do
note_count: 9,
follower_count: 9,
following_count: 9001,
- locked: true,
- confirmation_pending: true,
+ is_locked: true,
+ is_confirmed: true,
password_reset_pending: true,
- approval_pending: true,
+ is_approved: true,
registration_reason: "ahhhhh",
confirmation_token: "qqqq",
domain_blocks: ["lain.com"],
- deactivated: true,
+ is_active: false,
ap_enabled: true,
is_moderator: true,
is_admin: true,
- mastofe_settings: %{"a" => "b"},
mascot: %{"a" => "b"},
emoji: %{"a" => "b"},
pleroma_settings_store: %{"q" => "x"},
fields: [%{"gg" => "qq"}],
raw_fields: [%{"gg" => "qq"}],
- discoverable: true,
+ is_discoverable: true,
also_known_as: ["https://lol.olo/users/loll"]
})
@@ -1471,8 +1668,8 @@ defmodule Pleroma.UserTest do
email: nil,
name: nil,
password_hash: nil,
- keys: nil,
- public_key: nil,
+ keys: "RSA begin buplic key",
+ public_key: "--PRIVATE KEYE--",
avatar: %{},
tags: [],
last_refreshed_at: nil,
@@ -1482,28 +1679,77 @@ defmodule Pleroma.UserTest do
note_count: 0,
follower_count: 0,
following_count: 0,
- locked: false,
- confirmation_pending: false,
+ is_locked: false,
+ is_confirmed: true,
password_reset_pending: false,
- approval_pending: false,
+ is_approved: true,
registration_reason: nil,
confirmation_token: nil,
domain_blocks: [],
- deactivated: true,
+ is_active: false,
ap_enabled: false,
is_moderator: false,
is_admin: false,
- mastofe_settings: nil,
mascot: nil,
emoji: %{},
pleroma_settings_store: %{},
fields: [],
raw_fields: [],
- discoverable: false,
+ is_discoverable: false,
also_known_as: []
} = user
end
+ test "delete/1 purges a remote user" do
+ user =
+ insert(:user, %{
+ name: "qqqqqqq",
+ avatar: %{"a" => "b"},
+ banner: %{"a" => "b"},
+ local: false
+ })
+
+ {:ok, job} = User.delete(user)
+ {:ok, _} = ObanHelpers.perform(job)
+ user = User.get_by_id(user.id)
+
+ assert user.name == nil
+ assert user.avatar == %{}
+ assert user.banner == %{}
+ end
+
+ describe "set_suggestion" do
+ test "suggests a user" do
+ user = insert(:user, is_suggested: false)
+ refute user.is_suggested
+ {:ok, user} = User.set_suggestion(user, true)
+ assert user.is_suggested
+ end
+
+ test "suggests a list of users" do
+ unsuggested_users = [
+ insert(:user, is_suggested: false),
+ insert(:user, is_suggested: false),
+ insert(:user, is_suggested: false)
+ ]
+
+ {:ok, users} = User.set_suggestion(unsuggested_users, true)
+
+ assert Enum.count(users) == 3
+
+ Enum.each(users, fn user ->
+ assert user.is_suggested
+ end)
+ end
+
+ test "unsuggests a user" do
+ user = insert(:user, is_suggested: true)
+ assert user.is_suggested
+ {:ok, user} = User.set_suggestion(user, false)
+ refute user.is_suggested
+ end
+ end
+
test "get_public_key_for_ap_id fetches a user that's not in the db" do
assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
end
@@ -1553,14 +1799,14 @@ defmodule Pleroma.UserTest do
setup do: clear_config([:instance, :account_activation_required])
test "return confirmation_pending for unconfirm user" do
- Pleroma.Config.put([:instance, :account_activation_required], true)
- user = insert(:user, confirmation_pending: true)
+ clear_config([:instance, :account_activation_required], true)
+ user = insert(:user, is_confirmed: false)
assert User.account_status(user) == :confirmation_pending
end
test "return active for confirmed user" do
- Pleroma.Config.put([:instance, :account_activation_required], true)
- user = insert(:user, confirmation_pending: false)
+ clear_config([:instance, :account_activation_required], true)
+ user = insert(:user, is_confirmed: true)
assert User.account_status(user) == :active
end
@@ -1575,15 +1821,15 @@ defmodule Pleroma.UserTest do
end
test "returns :deactivated for deactivated user" do
- user = insert(:user, local: true, confirmation_pending: false, deactivated: true)
+ user = insert(:user, local: true, is_confirmed: true, is_active: false)
assert User.account_status(user) == :deactivated
end
test "returns :approval_pending for unapproved user" do
- user = insert(:user, local: true, approval_pending: true)
+ user = insert(:user, local: true, is_approved: false)
assert User.account_status(user) == :approval_pending
- user = insert(:user, local: true, confirmation_pending: true, approval_pending: true)
+ user = insert(:user, local: true, is_confirmed: false, is_approved: false)
assert User.account_status(user) == :approval_pending
end
end
@@ -1637,26 +1883,28 @@ defmodule Pleroma.UserTest do
assert User.visible_for(user, user) == :visible
end
- test "returns false when the account is unauthenticated and auth is required" do
- Pleroma.Config.put([:instance, :account_activation_required], true)
+ test "returns false when the account is unconfirmed and confirmation is required" do
+ clear_config([:instance, :account_activation_required], true)
- user = insert(:user, local: true, confirmation_pending: true)
+ user = insert(:user, local: true, is_confirmed: false)
other_user = insert(:user, local: true)
refute User.visible_for(user, other_user) == :visible
end
- test "returns true when the account is unauthenticated and auth is not required" do
- user = insert(:user, local: true, confirmation_pending: true)
+ test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do
+ clear_config([:instance, :account_activation_required], true)
+
+ user = insert(:user, local: false, is_confirmed: false)
other_user = insert(:user, local: true)
assert User.visible_for(user, other_user) == :visible
end
- test "returns true when the account is unauthenticated and being viewed by a privileged account (auth required)" do
- Pleroma.Config.put([:instance, :account_activation_required], true)
+ test "returns true when the account is unconfirmed and being viewed by a privileged account (confirmation required)" do
+ clear_config([:instance, :account_activation_required], true)
- user = insert(:user, local: true, confirmation_pending: true)
+ user = insert(:user, local: true, is_confirmed: false)
other_user = insert(:user, local: true, is_admin: true)
assert User.visible_for(user, other_user) == :visible
@@ -1670,9 +1918,7 @@ defmodule Pleroma.UserTest do
bio = "A.k.a. @nick@domain.com"
expected_text =
- ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{
- remote_user.ap_id
- }" rel="ugc">@<span>nick@domain.com</span></a></span>)
+ ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{remote_user.ap_id}" rel="ugc">@<span>nick@domain.com</span></a></span>)
assert expected_text == User.parse_bio(bio, user)
end
@@ -1700,9 +1946,9 @@ defmodule Pleroma.UserTest do
follower2 = insert(:user)
follower3 = insert(:user)
- {:ok, follower} = User.follow(follower, user)
- {:ok, _follower2} = User.follow(follower2, user)
- {:ok, _follower3} = User.follow(follower3, user)
+ {:ok, follower, user} = User.follow(follower, user)
+ {:ok, _follower2, _user} = User.follow(follower2, user)
+ {:ok, _follower3, _user} = User.follow(follower3, user)
{:ok, _user_relationship} = User.block(user, follower)
user = refresh_record(user)
@@ -1724,7 +1970,7 @@ defmodule Pleroma.UserTest do
users =
Enum.map(1..total, fn _ ->
- insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
+ insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
end)
inactive_users_ids =
@@ -1742,7 +1988,7 @@ defmodule Pleroma.UserTest do
users =
Enum.map(1..total, fn _ ->
- insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
+ insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
end)
{inactive, active} = Enum.split(users, trunc(total / 2))
@@ -1775,7 +2021,7 @@ defmodule Pleroma.UserTest do
users =
Enum.map(1..total, fn _ ->
- insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
+ insert(:user, last_digest_emailed_at: days_ago(20), is_active: true)
end)
[sender | recipients] = users
@@ -1813,24 +2059,6 @@ defmodule Pleroma.UserTest do
end
end
- describe "toggle_confirmation/1" do
- test "if user is confirmed" do
- user = insert(:user, confirmation_pending: false)
- {:ok, user} = User.toggle_confirmation(user)
-
- assert user.confirmation_pending
- assert user.confirmation_token
- end
-
- test "if user is unconfirmed" do
- user = insert(:user, confirmation_pending: true, confirmation_token: "some token")
- {:ok, user} = User.toggle_confirmation(user)
-
- refute user.confirmation_pending
- refute user.confirmation_token
- end
- end
-
describe "ensure_keys_present" do
test "it creates keys for a user and stores them in info" do
user = insert(:user)
@@ -1863,7 +2091,7 @@ defmodule Pleroma.UserTest do
user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
insert(:user, local: true)
- insert(:user, local: false, deactivated: true)
+ insert(:user, local: false, is_active: false)
{:ok, user1: user1, user2: user2}
end
@@ -1929,7 +2157,7 @@ defmodule Pleroma.UserTest do
setup do: clear_config([:instance, :external_user_synchronization])
test "updates the counters normally on following/getting a follow when disabled" do
- Pleroma.Config.put([:instance, :external_user_synchronization], false)
+ clear_config([:instance, :external_user_synchronization], false)
user = insert(:user)
other_user =
@@ -1943,15 +2171,14 @@ defmodule Pleroma.UserTest do
assert other_user.following_count == 0
assert other_user.follower_count == 0
- {:ok, user} = Pleroma.User.follow(user, other_user)
- other_user = Pleroma.User.get_by_id(other_user.id)
+ {:ok, user, other_user} = Pleroma.User.follow(user, other_user)
assert user.following_count == 1
assert other_user.follower_count == 1
end
test "syncronizes the counters with the remote instance for the followed when enabled" do
- Pleroma.Config.put([:instance, :external_user_synchronization], false)
+ clear_config([:instance, :external_user_synchronization], false)
user = insert(:user)
@@ -1966,15 +2193,14 @@ defmodule Pleroma.UserTest do
assert other_user.following_count == 0
assert other_user.follower_count == 0
- Pleroma.Config.put([:instance, :external_user_synchronization], true)
- {:ok, _user} = User.follow(user, other_user)
- other_user = User.get_by_id(other_user.id)
+ clear_config([:instance, :external_user_synchronization], true)
+ {:ok, _user, other_user} = User.follow(user, other_user)
assert other_user.follower_count == 437
end
test "syncronizes the counters with the remote instance for the follower when enabled" do
- Pleroma.Config.put([:instance, :external_user_synchronization], false)
+ clear_config([:instance, :external_user_synchronization], false)
user = insert(:user)
@@ -1989,8 +2215,8 @@ defmodule Pleroma.UserTest do
assert other_user.following_count == 0
assert other_user.follower_count == 0
- Pleroma.Config.put([:instance, :external_user_synchronization], true)
- {:ok, other_user} = User.follow(other_user, user)
+ clear_config([:instance, :external_user_synchronization], true)
+ {:ok, other_user, _user} = User.follow(other_user, user)
assert other_user.following_count == 152
end
@@ -2001,11 +2227,40 @@ defmodule Pleroma.UserTest do
[user: insert(:user)]
end
- test "blank email returns error", %{user: user} do
+ test "blank email returns error if we require an email on registration", %{user: user} do
+ orig_account_activation_required =
+ Pleroma.Config.get([:instance, :account_activation_required])
+
+ Pleroma.Config.put([:instance, :account_activation_required], true)
+
+ on_exit(fn ->
+ Pleroma.Config.put(
+ [:instance, :account_activation_required],
+ orig_account_activation_required
+ )
+ end)
+
assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
end
+ test "blank email should be fine if we do not require an email on registration", %{user: user} do
+ orig_account_activation_required =
+ Pleroma.Config.get([:instance, :account_activation_required])
+
+ Pleroma.Config.put([:instance, :account_activation_required], false)
+
+ on_exit(fn ->
+ Pleroma.Config.put(
+ [:instance, :account_activation_required],
+ orig_account_activation_required
+ )
+ end)
+
+ assert {:ok, %User{email: nil}} = User.change_email(user, "")
+ assert {:ok, %User{email: nil}} = User.change_email(user, nil)
+ end
+
test "non unique email returns error", %{user: user} do
%{email: email} = insert(:user)
@@ -2021,6 +2276,25 @@ defmodule Pleroma.UserTest do
test "changes email", %{user: user} do
assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
end
+
+ test "adds email", %{user: user} do
+ orig_account_activation_required =
+ Pleroma.Config.get([:instance, :account_activation_required])
+
+ Pleroma.Config.put([:instance, :account_activation_required], false)
+
+ on_exit(fn ->
+ Pleroma.Config.put(
+ [:instance, :account_activation_required],
+ orig_account_activation_required
+ )
+ end)
+
+ assert {:ok, _} = User.change_email(user, "")
+ Pleroma.Config.put([:instance, :account_activation_required], true)
+
+ assert {:ok, %User{email: "cofe2@cofe.party"}} = User.change_email(user, "cofe2@cofe.party")
+ end
end
describe "get_cached_by_nickname_or_id" do
@@ -2036,43 +2310,43 @@ defmodule Pleroma.UserTest do
test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
remote_user: remote_user
} do
- Pleroma.Config.put([:instance, :limit_to_local_content], false)
+ clear_config([:instance, :limit_to_local_content], false)
assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
- Pleroma.Config.put([:instance, :limit_to_local_content], true)
+ clear_config([:instance, :limit_to_local_content], true)
assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
- Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
+ clear_config([:instance, :limit_to_local_content], :unauthenticated)
assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
end
test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
%{remote_user: remote_user} do
- Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
+ clear_config([:instance, :limit_to_local_content], :unauthenticated)
assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
end
test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
%{remote_user: remote_user, local_user: local_user} do
- Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
+ clear_config([:instance, :limit_to_local_content], :unauthenticated)
assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
end
test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
%{remote_user: remote_user} do
- Pleroma.Config.put([:instance, :limit_to_local_content], true)
+ clear_config([:instance, :limit_to_local_content], true)
assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
end
test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
%{local_user: local_user} do
- Pleroma.Config.put([:instance, :limit_to_local_content], false)
+ clear_config([:instance, :limit_to_local_content], false)
assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
- Pleroma.Config.put([:instance, :limit_to_local_content], true)
+ clear_config([:instance, :limit_to_local_content], true)
assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
- Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
+ clear_config([:instance, :limit_to_local_content], :unauthenticated)
assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
end
end
@@ -2091,6 +2365,36 @@ defmodule Pleroma.UserTest do
end
end
+ describe "local_nickname/1" do
+ test "returns nickname without host" do
+ assert User.local_nickname("@mentioned") == "mentioned"
+ assert User.local_nickname("a_local_nickname") == "a_local_nickname"
+ assert User.local_nickname("nickname@host.com") == "nickname"
+ end
+ end
+
+ describe "full_nickname/1" do
+ test "returns fully qualified nickname for local and remote users" do
+ local_user =
+ insert(:user, nickname: "local_user", ap_id: "https://somehost.com/users/local_user")
+
+ remote_user = insert(:user, nickname: "remote@host.com", local: false)
+
+ assert User.full_nickname(local_user) == "local_user@somehost.com"
+ assert User.full_nickname(remote_user) == "remote@host.com"
+ end
+
+ test "strips leading @ from mentions" do
+ assert User.full_nickname("@mentioned") == "mentioned"
+ assert User.full_nickname("@nickname@host.com") == "nickname@host.com"
+ end
+
+ test "does not modify nicknames" do
+ assert User.full_nickname("nickname") == "nickname"
+ assert User.full_nickname("nickname@host.com") == "nickname@host.com"
+ end
+ end
+
test "avatar fallback" do
user = insert(:user)
assert User.avatar_url(user) =~ "/images/avi.png"
@@ -2102,4 +2406,96 @@ defmodule Pleroma.UserTest do
assert User.avatar_url(user, no_default: true) == nil
end
+
+ test "get_host/1" do
+ user = insert(:user, ap_id: "https://lain.com/users/lain", nickname: "lain")
+ assert User.get_host(user) == "lain.com"
+ end
+
+ test "update_last_active_at/1" do
+ user = insert(:user)
+ assert is_nil(user.last_active_at)
+
+ test_started_at = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
+
+ assert {:ok, user} = User.update_last_active_at(user)
+
+ assert user.last_active_at >= test_started_at
+ assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
+
+ last_active_at =
+ NaiveDateTime.utc_now()
+ |> NaiveDateTime.add(-:timer.hours(24), :millisecond)
+ |> NaiveDateTime.truncate(:second)
+
+ assert {:ok, user} =
+ user
+ |> cast(%{last_active_at: last_active_at}, [:last_active_at])
+ |> User.update_and_set_cache()
+
+ assert user.last_active_at == last_active_at
+ assert {:ok, user} = User.update_last_active_at(user)
+ assert user.last_active_at >= test_started_at
+ assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
+ end
+
+ test "active_user_count/1" do
+ insert(:user)
+ insert(:user, %{local: false})
+ insert(:user, %{last_active_at: NaiveDateTime.utc_now()})
+ insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), days: -15)})
+ insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), weeks: -6)})
+ insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), months: -7)})
+ insert(:user, %{last_active_at: Timex.shift(NaiveDateTime.utc_now(), years: -2)})
+
+ assert User.active_user_count() == 2
+ assert User.active_user_count(180) == 3
+ assert User.active_user_count(365) == 4
+ assert User.active_user_count(1000) == 5
+ end
+
+ describe "pins" do
+ setup do
+ user = insert(:user)
+
+ [user: user, object_id: object_id_from_created_activity(user)]
+ end
+
+ test "unique pins", %{user: user, object_id: object_id} do
+ assert {:ok, %{pinned_objects: %{^object_id => pinned_at1} = pins} = updated_user} =
+ User.add_pinned_object_id(user, object_id)
+
+ assert Enum.count(pins) == 1
+
+ assert {:ok, %{pinned_objects: %{^object_id => pinned_at2} = pins}} =
+ User.add_pinned_object_id(updated_user, object_id)
+
+ assert pinned_at1 == pinned_at2
+
+ assert Enum.count(pins) == 1
+ end
+
+ test "respects max_pinned_statuses limit", %{user: user, object_id: object_id} do
+ clear_config([:instance, :max_pinned_statuses], 1)
+ {:ok, updated} = User.add_pinned_object_id(user, object_id)
+
+ object_id2 = object_id_from_created_activity(user)
+
+ {:error, %{errors: errors}} = User.add_pinned_object_id(updated, object_id2)
+ assert Keyword.has_key?(errors, :pinned_objects)
+ end
+
+ test "remove_pinned_object_id/2", %{user: user, object_id: object_id} do
+ assert {:ok, updated} = User.add_pinned_object_id(user, object_id)
+
+ {:ok, after_remove} = User.remove_pinned_object_id(updated, object_id)
+ assert after_remove.pinned_objects == %{}
+ end
+ end
+
+ defp object_id_from_created_activity(user) do
+ %{id: id} = insert(:note_activity, user: user)
+ %{object: %{data: %{"id" => object_id}}} = Activity.get_by_id_with_object(id)
+ object_id
+ end
end
diff --git a/test/pleroma/utils_test.exs b/test/pleroma/utils_test.exs
new file mode 100644
index 000000000..c593a9490
--- /dev/null
+++ b/test/pleroma/utils_test.exs
@@ -0,0 +1,15 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.UtilsTest do
+ use ExUnit.Case, async: true
+
+ describe "tmp_dir/1" do
+ test "returns unique temporary directory" do
+ {:ok, path} = Pleroma.Utils.tmp_dir("emoji")
+ assert path =~ ~r/\/emoji-(.*)-#{:os.getpid()}-(.*)/
+ File.rm_rf(path)
+ end
+ end
+end
diff --git a/test/web/activity_pub/activity_pub_controller_test.exs b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs
index 57988dc1e..50315e21f 100644
--- a/test/web/activity_pub/activity_pub_controller_test.exs
+++ b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
@@ -7,7 +7,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
use Oban.Testing, repo: Pleroma.Repo
alias Pleroma.Activity
- alias Pleroma.Config
alias Pleroma.Delivery
alias Pleroma.Instances
alias Pleroma.Object
@@ -46,7 +45,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
end
test "with the relay disabled, it returns 404", %{conn: conn} do
- Config.put([:instance, :allow_relay], false)
+ clear_config([:instance, :allow_relay], false)
conn
|> get(activity_pub_path(conn, :relay))
@@ -54,7 +53,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
end
test "on non-federating instance, it returns 404", %{conn: conn} do
- Config.put([:instance, :federating], false)
+ clear_config([:instance, :federating], false)
user = insert(:user)
conn
@@ -75,7 +74,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
end
test "on non-federating instance, it returns 404", %{conn: conn} do
- Config.put([:instance, :federating], false)
+ clear_config([:instance, :federating], false)
user = insert(:user)
conn
@@ -156,21 +155,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
assert response == "Not found"
end
-
- test "it requires authentication if instance is NOT federating", %{
- conn: conn
- } do
- user = insert(:user)
-
- conn =
- put_req_header(
- conn,
- "accept",
- "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
- )
-
- ensure_federating_or_authenticated(conn, "/users/#{user.nickname}.json", user)
- end
end
describe "mastodon compatibility routes" do
@@ -228,6 +212,41 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
end
describe "/objects/:uuid" do
+ test "it doesn't return a local-only object", %{conn: conn} do
+ user = insert(:user)
+ {:ok, post} = CommonAPI.post(user, %{status: "test", visibility: "local"})
+
+ assert Pleroma.Web.ActivityPub.Visibility.is_local_public?(post)
+
+ object = Object.normalize(post, fetch: false)
+ uuid = String.split(object.data["id"], "/") |> List.last()
+
+ conn =
+ conn
+ |> put_req_header("accept", "application/json")
+ |> get("/objects/#{uuid}")
+
+ assert json_response(conn, 404)
+ end
+
+ test "returns local-only objects when authenticated", %{conn: conn} do
+ user = insert(:user)
+ {:ok, post} = CommonAPI.post(user, %{status: "test", visibility: "local"})
+
+ assert Pleroma.Web.ActivityPub.Visibility.is_local_public?(post)
+
+ object = Object.normalize(post, fetch: false)
+ uuid = String.split(object.data["id"], "/") |> List.last()
+
+ assert response =
+ conn
+ |> assign(:user, user)
+ |> put_req_header("accept", "application/activity+json")
+ |> get("/objects/#{uuid}")
+
+ assert json_response(response, 200) == ObjectView.render("object.json", %{object: object})
+ end
+
test "it returns a json representation of the object with accept application/json", %{
conn: conn
} do
@@ -284,6 +303,28 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
assert json_response(conn, 404)
end
+ test "returns visible non-public messages when authenticated", %{conn: conn} do
+ note = insert(:direct_note)
+ uuid = String.split(note.data["id"], "/") |> List.last()
+ user = User.get_by_ap_id(note.data["actor"])
+ marisa = insert(:user)
+
+ assert conn
+ |> assign(:user, marisa)
+ |> put_req_header("accept", "application/activity+json")
+ |> get("/objects/#{uuid}")
+ |> json_response(404)
+
+ assert response =
+ conn
+ |> assign(:user, user)
+ |> put_req_header("accept", "application/activity+json")
+ |> get("/objects/#{uuid}")
+ |> json_response(200)
+
+ assert response == ObjectView.render("object.json", %{object: note})
+ end
+
test "it returns 404 for tombstone objects", %{conn: conn} do
tombstone = insert(:tombstone)
uuid = String.split(tombstone.data["id"], "/") |> List.last()
@@ -338,21 +379,42 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
assert "Not found" == json_response(conn2, :not_found)
end
+ end
- test "it requires authentication if instance is NOT federating", %{
- conn: conn
- } do
+ describe "/activities/:uuid" do
+ test "it doesn't return a local-only activity", %{conn: conn} do
user = insert(:user)
- note = insert(:note)
- uuid = String.split(note.data["id"], "/") |> List.last()
+ {:ok, post} = CommonAPI.post(user, %{status: "test", visibility: "local"})
- conn = put_req_header(conn, "accept", "application/activity+json")
+ assert Pleroma.Web.ActivityPub.Visibility.is_local_public?(post)
+
+ uuid = String.split(post.data["id"], "/") |> List.last()
- ensure_federating_or_authenticated(conn, "/objects/#{uuid}", user)
+ conn =
+ conn
+ |> put_req_header("accept", "application/json")
+ |> get("/activities/#{uuid}")
+
+ assert json_response(conn, 404)
+ end
+
+ test "returns local-only activities when authenticated", %{conn: conn} do
+ user = insert(:user)
+ {:ok, post} = CommonAPI.post(user, %{status: "test", visibility: "local"})
+
+ assert Pleroma.Web.ActivityPub.Visibility.is_local_public?(post)
+
+ uuid = String.split(post.data["id"], "/") |> List.last()
+
+ assert response =
+ conn
+ |> assign(:user, user)
+ |> put_req_header("accept", "application/activity+json")
+ |> get("/activities/#{uuid}")
+
+ assert json_response(response, 200) == ObjectView.render("object.json", %{object: post})
end
- end
- describe "/activities/:uuid" do
test "it returns a json representation of the activity", %{conn: conn} do
activity = insert(:note_activity)
uuid = String.split(activity.data["id"], "/") |> List.last()
@@ -377,6 +439,28 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
assert json_response(conn, 404)
end
+ test "returns visible non-public messages when authenticated", %{conn: conn} do
+ note = insert(:direct_note_activity)
+ uuid = String.split(note.data["id"], "/") |> List.last()
+ user = User.get_by_ap_id(note.data["actor"])
+ marisa = insert(:user)
+
+ assert conn
+ |> assign(:user, marisa)
+ |> put_req_header("accept", "application/activity+json")
+ |> get("/activities/#{uuid}")
+ |> json_response(404)
+
+ assert response =
+ conn
+ |> assign(:user, user)
+ |> put_req_header("accept", "application/activity+json")
+ |> get("/activities/#{uuid}")
+ |> json_response(200)
+
+ assert response == ObjectView.render("object.json", %{object: note})
+ end
+
test "it caches a response", %{conn: conn} do
activity = insert(:note_activity)
uuid = String.split(activity.data["id"], "/") |> List.last()
@@ -421,23 +505,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
assert "Not found" == json_response(conn2, :not_found)
end
-
- test "it requires authentication if instance is NOT federating", %{
- conn: conn
- } do
- user = insert(:user)
- activity = insert(:note_activity)
- uuid = String.split(activity.data["id"], "/") |> List.last()
-
- conn = put_req_header(conn, "accept", "application/activity+json")
-
- ensure_federating_or_authenticated(conn, "/activities/#{uuid}", user)
- end
end
describe "/inbox" do
test "it inserts an incoming activity into the database", %{conn: conn} do
- data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
+ data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!()
conn =
conn
@@ -465,9 +537,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
data =
File.read!("test/fixtures/mastodon-post-activity.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("actor", user.ap_id)
- |> put_in(["object", "attridbutedTo"], user.ap_id)
+ |> put_in(["object", "attributedTo"], user.ap_id)
conn =
conn
@@ -482,7 +554,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
end
test "it clears `unreachable` federation status of the sender", %{conn: conn} do
- data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
+ data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!()
sender_url = data["actor"]
Instances.set_consistently_unreachable(sender_url)
@@ -499,7 +571,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
end
test "accept follow activity", %{conn: conn} do
- Pleroma.Config.put([:instance, :federating], true)
+ clear_config([:instance, :federating], true)
relay = Relay.get_actor()
assert {:ok, %Activity{} = activity} = Relay.follow("https://relay.mastodon.host/actor")
@@ -540,12 +612,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
test "without valid signature, " <>
"it only accepts Create activities and requires enabled federation",
%{conn: conn} do
- data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
- non_create_data = File.read!("test/fixtures/mastodon-announce.json") |> Poison.decode!()
+ data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!()
+ non_create_data = File.read!("test/fixtures/mastodon-announce.json") |> Jason.decode!()
conn = put_req_header(conn, "content-type", "application/activity+json")
- Config.put([:instance, :federating], false)
+ clear_config([:instance, :federating], false)
conn
|> post("/inbox", data)
@@ -555,7 +627,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|> post("/inbox", non_create_data)
|> json_response(403)
- Config.put([:instance, :federating], true)
+ clear_config([:instance, :federating], true)
ret_conn = post(conn, "/inbox", data)
assert "ok" == json_response(ret_conn, 200)
@@ -564,20 +636,204 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|> post("/inbox", non_create_data)
|> json_response(400)
end
+
+ test "accepts Add/Remove activities", %{conn: conn} do
+ object_id = "c61d6733-e256-4fe1-ab13-1e369789423f"
+
+ status =
+ File.read!("test/fixtures/statuses/note.json")
+ |> String.replace("{{nickname}}", "lain")
+ |> String.replace("{{object_id}}", object_id)
+
+ object_url = "https://example.com/objects/#{object_id}"
+
+ user =
+ File.read!("test/fixtures/users_mock/user.json")
+ |> String.replace("{{nickname}}", "lain")
+
+ actor = "https://example.com/users/lain"
+
+ Tesla.Mock.mock(fn
+ %{
+ method: :get,
+ url: ^object_url
+ } ->
+ %Tesla.Env{
+ status: 200,
+ body: status,
+ headers: [{"content-type", "application/activity+json"}]
+ }
+
+ %{
+ method: :get,
+ url: ^actor
+ } ->
+ %Tesla.Env{
+ status: 200,
+ body: user,
+ headers: [{"content-type", "application/activity+json"}]
+ }
+
+ %{method: :get, url: "https://example.com/users/lain/collections/featured"} ->
+ %Tesla.Env{
+ status: 200,
+ body:
+ "test/fixtures/users_mock/masto_featured.json"
+ |> File.read!()
+ |> String.replace("{{domain}}", "example.com")
+ |> String.replace("{{nickname}}", "lain"),
+ headers: [{"content-type", "application/activity+json"}]
+ }
+ end)
+
+ data = %{
+ "id" => "https://example.com/objects/d61d6733-e256-4fe1-ab13-1e369789423f",
+ "actor" => actor,
+ "object" => object_url,
+ "target" => "https://example.com/users/lain/collections/featured",
+ "type" => "Add",
+ "to" => [Pleroma.Constants.as_public()]
+ }
+
+ assert "ok" ==
+ conn
+ |> assign(:valid_signature, true)
+ |> put_req_header("content-type", "application/activity+json")
+ |> post("/inbox", data)
+ |> json_response(200)
+
+ ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
+ assert Activity.get_by_ap_id(data["id"])
+ user = User.get_cached_by_ap_id(data["actor"])
+ assert user.pinned_objects[data["object"]]
+
+ data = %{
+ "id" => "https://example.com/objects/d61d6733-e256-4fe1-ab13-1e369789423d",
+ "actor" => actor,
+ "object" => object_url,
+ "target" => "https://example.com/users/lain/collections/featured",
+ "type" => "Remove",
+ "to" => [Pleroma.Constants.as_public()]
+ }
+
+ assert "ok" ==
+ conn
+ |> assign(:valid_signature, true)
+ |> put_req_header("content-type", "application/activity+json")
+ |> post("/inbox", data)
+ |> json_response(200)
+
+ ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
+ user = refresh_record(user)
+ refute user.pinned_objects[data["object"]]
+ end
+
+ test "mastodon pin/unpin", %{conn: conn} do
+ status_id = "105786274556060421"
+
+ status =
+ File.read!("test/fixtures/statuses/masto-note.json")
+ |> String.replace("{{nickname}}", "lain")
+ |> String.replace("{{status_id}}", status_id)
+
+ status_url = "https://example.com/users/lain/statuses/#{status_id}"
+
+ user =
+ File.read!("test/fixtures/users_mock/user.json")
+ |> String.replace("{{nickname}}", "lain")
+
+ actor = "https://example.com/users/lain"
+
+ Tesla.Mock.mock(fn
+ %{
+ method: :get,
+ url: ^status_url
+ } ->
+ %Tesla.Env{
+ status: 200,
+ body: status,
+ headers: [{"content-type", "application/activity+json"}]
+ }
+
+ %{
+ method: :get,
+ url: ^actor
+ } ->
+ %Tesla.Env{
+ status: 200,
+ body: user,
+ headers: [{"content-type", "application/activity+json"}]
+ }
+
+ %{method: :get, url: "https://example.com/users/lain/collections/featured"} ->
+ %Tesla.Env{
+ status: 200,
+ body:
+ "test/fixtures/users_mock/masto_featured.json"
+ |> File.read!()
+ |> String.replace("{{domain}}", "example.com")
+ |> String.replace("{{nickname}}", "lain"),
+ headers: [{"content-type", "application/activity+json"}]
+ }
+ end)
+
+ data = %{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "actor" => actor,
+ "object" => status_url,
+ "target" => "https://example.com/users/lain/collections/featured",
+ "type" => "Add"
+ }
+
+ assert "ok" ==
+ conn
+ |> assign(:valid_signature, true)
+ |> put_req_header("content-type", "application/activity+json")
+ |> post("/inbox", data)
+ |> json_response(200)
+
+ ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
+ assert Activity.get_by_object_ap_id_with_object(data["object"])
+ user = User.get_cached_by_ap_id(data["actor"])
+ assert user.pinned_objects[data["object"]]
+
+ data = %{
+ "actor" => actor,
+ "object" => status_url,
+ "target" => "https://example.com/users/lain/collections/featured",
+ "type" => "Remove"
+ }
+
+ assert "ok" ==
+ conn
+ |> assign(:valid_signature, true)
+ |> put_req_header("content-type", "application/activity+json")
+ |> post("/inbox", data)
+ |> json_response(200)
+
+ ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
+ assert Activity.get_by_object_ap_id_with_object(data["object"])
+ user = refresh_record(user)
+ refute user.pinned_objects[data["object"]]
+ end
end
describe "/users/:nickname/inbox" do
setup do
data =
File.read!("test/fixtures/mastodon-post-activity.json")
- |> Poison.decode!()
+ |> Jason.decode!()
[data: data]
end
test "it inserts an incoming activity into the database", %{conn: conn, data: data} do
user = insert(:user)
- data = Map.put(data, "bcc", [user.ap_id])
+
+ data =
+ data
+ |> Map.put("bcc", [user.ap_id])
+ |> Kernel.put_in(["object", "bcc"], [user.ap_id])
conn =
conn
@@ -594,8 +850,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
user = insert(:user)
data =
- Map.put(data, "to", user.ap_id)
- |> Map.delete("cc")
+ data
+ |> Map.put("to", user.ap_id)
+ |> Map.put("cc", [])
+ |> Kernel.put_in(["object", "to"], user.ap_id)
+ |> Kernel.put_in(["object", "cc"], [])
conn =
conn
@@ -612,8 +871,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
user = insert(:user)
data =
- Map.put(data, "cc", user.ap_id)
- |> Map.delete("to")
+ data
+ |> Map.put("to", [])
+ |> Map.put("cc", user.ap_id)
+ |> Kernel.put_in(["object", "to"], [])
+ |> Kernel.put_in(["object", "cc"], user.ap_id)
conn =
conn
@@ -631,9 +893,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
user = insert(:user)
data =
- Map.put(data, "bcc", user.ap_id)
- |> Map.delete("to")
- |> Map.delete("cc")
+ data
+ |> Map.put("to", [])
+ |> Map.put("cc", [])
+ |> Map.put("bcc", user.ap_id)
+ |> Kernel.put_in(["object", "to"], [])
+ |> Kernel.put_in(["object", "cc"], [])
+ |> Kernel.put_in(["object", "bcc"], user.ap_id)
conn =
conn
@@ -681,7 +947,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
recipient = insert(:user)
actor = insert(:user, %{ap_id: "http://mastodon.example.org/users/actor"})
- {:ok, recipient} = User.follow(recipient, actor)
+ {:ok, recipient, actor} = User.follow(recipient, actor)
object =
data["object"]
@@ -718,7 +984,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
test "it returns a note activity in a collection", %{conn: conn} do
note_activity = insert(:direct_note_activity)
- note_object = Object.normalize(note_activity)
+ note_object = Object.normalize(note_activity, fetch: false)
user = User.get_cached_by_ap_id(hd(note_activity.data["to"]))
conn =
@@ -748,29 +1014,34 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
assert Instances.reachable?(sender_host)
end
+ @tag capture_log: true
test "it removes all follower collections but actor's", %{conn: conn} do
[actor, recipient] = insert_pair(:user)
- data =
- File.read!("test/fixtures/activitypub-client-post-activity.json")
- |> Poison.decode!()
+ to = [
+ recipient.ap_id,
+ recipient.follower_address,
+ "https://www.w3.org/ns/activitystreams#Public"
+ ]
- object = Map.put(data["object"], "attributedTo", actor.ap_id)
+ cc = [recipient.follower_address, actor.follower_address]
- data =
- data
- |> Map.put("id", Utils.generate_object_id())
- |> Map.put("actor", actor.ap_id)
- |> Map.put("object", object)
- |> Map.put("cc", [
- recipient.follower_address,
- actor.follower_address
- ])
- |> Map.put("to", [
- recipient.ap_id,
- recipient.follower_address,
- "https://www.w3.org/ns/activitystreams#Public"
- ])
+ data = %{
+ "@context" => ["https://www.w3.org/ns/activitystreams"],
+ "type" => "Create",
+ "id" => Utils.generate_activity_id(),
+ "to" => to,
+ "cc" => cc,
+ "actor" => actor.ap_id,
+ "object" => %{
+ "type" => "Note",
+ "to" => to,
+ "cc" => cc,
+ "content" => "It's a note",
+ "attributedTo" => actor.ap_id,
+ "id" => Utils.generate_object_id()
+ }
+ }
conn
|> assign(:valid_signature, true)
@@ -780,7 +1051,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
- activity = Activity.get_by_ap_id(data["id"])
+ assert activity = Activity.get_by_ap_id(data["id"])
assert activity.id
assert actor.follower_address in activity.recipients
@@ -805,6 +1076,141 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
assert json_response(ret_conn, 200)
end
+
+ @tag capture_log: true
+ test "forwarded report", %{conn: conn} do
+ admin = insert(:user, is_admin: true)
+ actor = insert(:user, local: false)
+ remote_domain = URI.parse(actor.ap_id).host
+ reported_user = insert(:user)
+
+ note = insert(:note_activity, user: reported_user)
+
+ data = %{
+ "@context" => [
+ "https://www.w3.org/ns/activitystreams",
+ "https://#{remote_domain}/schemas/litepub-0.1.jsonld",
+ %{
+ "@language" => "und"
+ }
+ ],
+ "actor" => actor.ap_id,
+ "cc" => [
+ reported_user.ap_id
+ ],
+ "content" => "test",
+ "context" => "context",
+ "id" => "http://#{remote_domain}/activities/02be56cf-35e3-46b4-b2c6-47ae08dfee9e",
+ "nickname" => reported_user.nickname,
+ "object" => [
+ reported_user.ap_id,
+ %{
+ "actor" => %{
+ "actor_type" => "Person",
+ "approval_pending" => false,
+ "avatar" => "",
+ "confirmation_pending" => false,
+ "deactivated" => false,
+ "display_name" => "test user",
+ "id" => reported_user.id,
+ "local" => false,
+ "nickname" => reported_user.nickname,
+ "registration_reason" => nil,
+ "roles" => %{
+ "admin" => false,
+ "moderator" => false
+ },
+ "tags" => [],
+ "url" => reported_user.ap_id
+ },
+ "content" => "",
+ "id" => note.data["id"],
+ "published" => note.data["published"],
+ "type" => "Note"
+ }
+ ],
+ "published" => note.data["published"],
+ "state" => "open",
+ "to" => [],
+ "type" => "Flag"
+ }
+
+ conn
+ |> assign(:valid_signature, true)
+ |> put_req_header("content-type", "application/activity+json")
+ |> post("/users/#{reported_user.nickname}/inbox", data)
+ |> json_response(200)
+
+ ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
+
+ assert Pleroma.Repo.aggregate(Activity, :count, :id) == 2
+
+ ObanHelpers.perform_all()
+
+ Swoosh.TestAssertions.assert_email_sent(
+ to: {admin.name, admin.email},
+ html_body: ~r/Reported Account:/i
+ )
+ end
+
+ @tag capture_log: true
+ test "forwarded report from mastodon", %{conn: conn} do
+ admin = insert(:user, is_admin: true)
+ actor = insert(:user, local: false)
+ remote_domain = URI.parse(actor.ap_id).host
+ remote_actor = "https://#{remote_domain}/actor"
+ [reported_user, another] = insert_list(2, :user)
+
+ note = insert(:note_activity, user: reported_user)
+
+ Pleroma.Web.CommonAPI.favorite(another, note.id)
+
+ mock_json_body =
+ "test/fixtures/mastodon/application_actor.json"
+ |> File.read!()
+ |> String.replace("{{DOMAIN}}", remote_domain)
+
+ Tesla.Mock.mock(fn %{url: ^remote_actor} ->
+ %Tesla.Env{
+ status: 200,
+ body: mock_json_body,
+ headers: [{"content-type", "application/activity+json"}]
+ }
+ end)
+
+ data = %{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "actor" => remote_actor,
+ "content" => "test report",
+ "id" => "https://#{remote_domain}/e3b12fd1-948c-446e-b93b-a5e67edbe1d8",
+ "object" => [
+ reported_user.ap_id,
+ note.data["object"]
+ ],
+ "type" => "Flag"
+ }
+
+ conn
+ |> assign(:valid_signature, true)
+ |> put_req_header("content-type", "application/activity+json")
+ |> post("/users/#{reported_user.nickname}/inbox", data)
+ |> json_response(200)
+
+ ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
+
+ flag_activity = "Flag" |> Pleroma.Activity.Queries.by_type() |> Pleroma.Repo.one()
+ reported_user_ap_id = reported_user.ap_id
+
+ [^reported_user_ap_id, flag_data] = flag_activity.data["object"]
+
+ Enum.each(~w(actor content id published type), &Map.has_key?(flag_data, &1))
+ ObanHelpers.perform_all()
+
+ Swoosh.TestAssertions.assert_email_sent(
+ to: {admin.name, admin.email},
+ html_body: ~r/#{note.data["object"]}/i
+ )
+ end
end
describe "GET /users/:nickname/outbox" do
@@ -869,7 +1275,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
test "it returns a note activity in a collection", %{conn: conn} do
note_activity = insert(:note_activity)
- note_object = Object.normalize(note_activity)
+ note_object = Object.normalize(note_activity, fetch: false)
user = User.get_cached_by_ap_id(note_activity.data["actor"])
conn =
@@ -894,25 +1300,46 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
assert response(conn, 200) =~ announce_activity.data["object"]
end
- test "it requires authentication if instance is NOT federating", %{
- conn: conn
- } do
- user = insert(:user)
- conn = put_req_header(conn, "accept", "application/activity+json")
+ test "It returns poll Answers when authenticated", %{conn: conn} do
+ poller = insert(:user)
+ voter = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(poller, %{
+ status: "suya...",
+ poll: %{options: ["suya", "suya.", "suya.."], expires_in: 10}
+ })
+
+ assert question = Object.normalize(activity, fetch: false)
+
+ {:ok, [activity], _object} = CommonAPI.vote(voter, question, [1])
- ensure_federating_or_authenticated(conn, "/users/#{user.nickname}/outbox", user)
+ assert outbox_get =
+ conn
+ |> assign(:user, voter)
+ |> put_req_header("accept", "application/activity+json")
+ |> get(voter.ap_id <> "/outbox?page=true")
+ |> json_response(200)
+
+ assert [answer_outbox] = outbox_get["orderedItems"]
+ assert answer_outbox["id"] == activity.data["id"]
end
end
describe "POST /users/:nickname/outbox (C2S)" do
+ setup do: clear_config([:instance, :limit])
+
setup do
[
activity: %{
"@context" => "https://www.w3.org/ns/activitystreams",
"type" => "Create",
- "object" => %{"type" => "Note", "content" => "AP C2S test"},
- "to" => "https://www.w3.org/ns/activitystreams#Public",
- "cc" => []
+ "object" => %{
+ "type" => "Note",
+ "content" => "AP C2S test",
+ "to" => "https://www.w3.org/ns/activitystreams#Public",
+ "cc" => []
+ }
}
]
end
@@ -950,7 +1377,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
assert Activity.get_by_ap_id(result["id"])
assert result["object"]
- assert %Object{data: object} = Object.normalize(result["object"])
+ assert %Object{data: object} = Object.normalize(result["object"], fetch: false)
assert object["content"] == activity["object"]["content"]
end
@@ -986,7 +1413,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
assert Activity.get_by_ap_id(response["id"])
assert response["object"]
- assert %Object{data: response_object} = Object.normalize(response["object"])
+ assert %Object{data: response_object} = Object.normalize(response["object"], fetch: false)
assert response_object["sensitive"] == true
assert response_object["content"] == activity["object"]["content"]
@@ -1014,23 +1441,23 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
test "it erects a tombstone when receiving a delete activity", %{conn: conn} do
note_activity = insert(:note_activity)
- note_object = Object.normalize(note_activity)
+ note_object = Object.normalize(note_activity, fetch: false)
user = User.get_cached_by_ap_id(note_activity.data["actor"])
data = %{
- type: "Delete",
- object: %{
- id: note_object.data["id"]
+ "type" => "Delete",
+ "object" => %{
+ "id" => note_object.data["id"]
}
}
- conn =
+ result =
conn
|> assign(:user, user)
|> put_req_header("content-type", "application/activity+json")
|> post("/users/#{user.nickname}/outbox", data)
+ |> json_response(201)
- result = json_response(conn, 201)
assert Activity.get_by_ap_id(result["id"])
assert object = Object.get_by_ap_id(note_object.data["id"])
@@ -1039,7 +1466,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
test "it rejects delete activity of object from other actor", %{conn: conn} do
note_activity = insert(:note_activity)
- note_object = Object.normalize(note_activity)
+ note_object = Object.normalize(note_activity, fetch: false)
user = insert(:user)
data = %{
@@ -1055,12 +1482,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|> put_req_header("content-type", "application/activity+json")
|> post("/users/#{user.nickname}/outbox", data)
- assert json_response(conn, 400)
+ assert json_response(conn, 403)
end
test "it increases like count when receiving a like action", %{conn: conn} do
note_activity = insert(:note_activity)
- note_object = Object.normalize(note_activity)
+ note_object = Object.normalize(note_activity, fetch: false)
user = User.get_cached_by_ap_id(note_activity.data["actor"])
data = %{
@@ -1117,10 +1544,24 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
assert cirno_outbox["attributedTo"] == nil
assert cirno_outbox["actor"] == cirno.ap_id
- assert cirno_object = Object.normalize(cirno_outbox["object"])
+ assert cirno_object = Object.normalize(cirno_outbox["object"], fetch: false)
assert cirno_object.data["actor"] == cirno.ap_id
assert cirno_object.data["attributedTo"] == cirno.ap_id
end
+
+ test "Character limitation", %{conn: conn, activity: activity} do
+ clear_config([:instance, :limit], 5)
+ user = insert(:user)
+
+ result =
+ conn
+ |> assign(:user, user)
+ |> put_req_header("content-type", "application/activity+json")
+ |> post("/users/#{user.nickname}/outbox", activity)
+ |> json_response(400)
+
+ assert result == "Character limit (5 characters) exceeded, contains 11 characters"
+ end
end
describe "/relay/followers" do
@@ -1138,7 +1579,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
end
test "on non-federating instance, it returns 404", %{conn: conn} do
- Config.put([:instance, :federating], false)
+ clear_config([:instance, :federating], false)
user = insert(:user)
conn
@@ -1159,7 +1600,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
end
test "on non-federating instance, it returns 404", %{conn: conn} do
- Config.put([:instance, :federating], false)
+ clear_config([:instance, :federating], false)
user = insert(:user)
conn
@@ -1366,7 +1807,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
test "it tracks a signed object fetch", %{conn: conn} do
user = insert(:user, local: false)
activity = insert(:note_activity)
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
object_path = String.trim_leading(object.data["id"], Pleroma.Web.Endpoint.url())
@@ -1382,7 +1823,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
test "it tracks a signed activity fetch", %{conn: conn} do
user = insert(:user, local: false)
activity = insert(:note_activity)
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
activity_path = String.trim_leading(activity.data["id"], Pleroma.Web.Endpoint.url())
@@ -1399,7 +1840,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
user = insert(:user, local: false)
other_user = insert(:user, local: false)
activity = insert(:note_activity)
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
object_path = String.trim_leading(object.data["id"], Pleroma.Web.Endpoint.url())
@@ -1423,7 +1864,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
user = insert(:user, local: false)
other_user = insert(:user, local: false)
activity = insert(:note_activity)
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
activity_path = String.trim_leading(activity.data["id"], Pleroma.Web.Endpoint.url())
@@ -1471,7 +1912,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
desc = "Description of the image"
image = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}
@@ -1488,6 +1929,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
assert [%{"href" => object_href, "mediaType" => object_mediatype}] = object["url"]
assert is_binary(object_href)
assert object_mediatype == "image/jpeg"
+ assert String.ends_with?(object_href, ".jpg")
activity_request = %{
"@context" => "https://www.w3.org/ns/activitystreams",
@@ -1495,10 +1937,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
"object" => %{
"type" => "Note",
"content" => "AP C2S test, attachment",
- "attachment" => [object]
- },
- "to" => "https://www.w3.org/ns/activitystreams#Public",
- "cc" => []
+ "attachment" => [object],
+ "to" => "https://www.w3.org/ns/activitystreams#Public",
+ "cc" => []
+ }
}
activity_response =
@@ -1512,7 +1954,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
assert activity_response["actor"] == user.ap_id
assert %Object{data: %{"attachment" => [attachment]}} =
- Object.normalize(activity_response["object"])
+ Object.normalize(activity_response["object"], fetch: false)
assert attachment["type"] == "Document"
assert attachment["name"] == desc
@@ -1531,4 +1973,29 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|> json_response(403)
end
end
+
+ test "pinned collection", %{conn: conn} do
+ clear_config([:instance, :max_pinned_statuses], 2)
+ user = insert(:user)
+ objects = insert_list(2, :note, user: user)
+
+ Enum.reduce(objects, user, fn %{data: %{"id" => object_id}}, user ->
+ {:ok, updated} = User.add_pinned_object_id(user, object_id)
+ updated
+ end)
+
+ %{nickname: nickname, featured_address: featured_address, pinned_objects: pinned_objects} =
+ refresh_record(user)
+
+ %{"id" => ^featured_address, "orderedItems" => items, "totalItems" => 2} =
+ conn
+ |> get("/users/#{nickname}/collections/featured")
+ |> json_response(200)
+
+ object_ids = Enum.map(items, & &1["id"])
+
+ assert Enum.all?(pinned_objects, fn {obj_id, _} ->
+ obj_id in object_ids
+ end)
+ end
end
diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/pleroma/web/activity_pub/activity_pub_test.exs
index 03f968aaf..574ef0d71 100644
--- a/test/web/activity_pub/activity_pub_test.exs
+++ b/test/pleroma/web/activity_pub/activity_pub_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
@@ -190,37 +190,191 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert user.accepts_chat_messages
end
+
+ test "works for guppe actors" do
+ user_id = "https://gup.pe/u/bernie2020"
+
+ Tesla.Mock.mock(fn
+ %{method: :get, url: ^user_id} ->
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/guppe-actor.json"),
+ headers: [{"content-type", "application/activity+json"}]
+ }
+ end)
+
+ {:ok, user} = ActivityPub.make_user_from_ap_id(user_id)
+
+ assert user.name == "Bernie2020 group"
+ assert user.actor_type == "Group"
+ end
+
+ test "works for bridgy actors" do
+ user_id = "https://fed.brid.gy/jk.nipponalba.scot"
+
+ Tesla.Mock.mock(fn
+ %{method: :get, url: ^user_id} ->
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/bridgy/actor.json"),
+ headers: [{"content-type", "application/activity+json"}]
+ }
+ end)
+
+ {:ok, user} = ActivityPub.make_user_from_ap_id(user_id)
+
+ assert user.actor_type == "Person"
+
+ assert user.avatar == %{
+ "type" => "Image",
+ "url" => [%{"href" => "https://jk.nipponalba.scot/images/profile.jpg"}]
+ }
+
+ assert user.banner == %{
+ "type" => "Image",
+ "url" => [%{"href" => "https://jk.nipponalba.scot/images/profile.jpg"}]
+ }
+ end
+
+ test "fetches user featured collection" do
+ ap_id = "https://example.com/users/lain"
+
+ featured_url = "https://example.com/users/lain/collections/featured"
+
+ user_data =
+ "test/fixtures/users_mock/user.json"
+ |> File.read!()
+ |> String.replace("{{nickname}}", "lain")
+ |> Jason.decode!()
+ |> Map.put("featured", featured_url)
+ |> Jason.encode!()
+
+ object_id = Ecto.UUID.generate()
+
+ featured_data =
+ "test/fixtures/mastodon/collections/featured.json"
+ |> File.read!()
+ |> String.replace("{{domain}}", "example.com")
+ |> String.replace("{{nickname}}", "lain")
+ |> String.replace("{{object_id}}", object_id)
+
+ object_url = "https://example.com/objects/#{object_id}"
+
+ object_data =
+ "test/fixtures/statuses/note.json"
+ |> File.read!()
+ |> String.replace("{{object_id}}", object_id)
+ |> String.replace("{{nickname}}", "lain")
+
+ Tesla.Mock.mock(fn
+ %{
+ method: :get,
+ url: ^ap_id
+ } ->
+ %Tesla.Env{
+ status: 200,
+ body: user_data,
+ headers: [{"content-type", "application/activity+json"}]
+ }
+
+ %{
+ method: :get,
+ url: ^featured_url
+ } ->
+ %Tesla.Env{
+ status: 200,
+ body: featured_data,
+ headers: [{"content-type", "application/activity+json"}]
+ }
+ end)
+
+ Tesla.Mock.mock_global(fn
+ %{
+ method: :get,
+ url: ^object_url
+ } ->
+ %Tesla.Env{
+ status: 200,
+ body: object_data,
+ headers: [{"content-type", "application/activity+json"}]
+ }
+ end)
+
+ {:ok, user} = ActivityPub.make_user_from_ap_id(ap_id)
+ Process.sleep(50)
+
+ assert user.featured_address == featured_url
+ assert Map.has_key?(user.pinned_objects, object_url)
+
+ in_db = Pleroma.User.get_by_ap_id(ap_id)
+ assert in_db.featured_address == featured_url
+ assert Map.has_key?(user.pinned_objects, object_url)
+
+ assert %{data: %{"id" => ^object_url}} = Object.get_by_ap_id(object_url)
+ end
end
test "it fetches the appropriate tag-restricted posts" do
user = insert(:user)
- {:ok, status_one} = CommonAPI.post(user, %{status: ". #test"})
+ {:ok, status_one} = CommonAPI.post(user, %{status: ". #TEST"})
{:ok, status_two} = CommonAPI.post(user, %{status: ". #essais"})
- {:ok, status_three} = CommonAPI.post(user, %{status: ". #test #reject"})
+ {:ok, status_three} = CommonAPI.post(user, %{status: ". #test #Reject"})
- fetch_one = ActivityPub.fetch_activities([], %{type: "Create", tag: "test"})
+ {:ok, status_four} = CommonAPI.post(user, %{status: ". #Any1 #any2"})
+ {:ok, status_five} = CommonAPI.post(user, %{status: ". #Any2 #any1"})
- fetch_two = ActivityPub.fetch_activities([], %{type: "Create", tag: ["test", "essais"]})
+ for hashtag_timeline_strategy <- [:enabled, :disabled] do
+ clear_config([:features, :improved_hashtag_timeline], hashtag_timeline_strategy)
- fetch_three =
- ActivityPub.fetch_activities([], %{
- type: "Create",
- tag: ["test", "essais"],
- tag_reject: ["reject"]
- })
+ fetch_one = ActivityPub.fetch_activities([], %{type: "Create", tag: "test"})
- fetch_four =
- ActivityPub.fetch_activities([], %{
- type: "Create",
- tag: ["test"],
- tag_all: ["test", "reject"]
- })
+ fetch_two = ActivityPub.fetch_activities([], %{type: "Create", tag: ["TEST", "essais"]})
+
+ fetch_three =
+ ActivityPub.fetch_activities([], %{
+ type: "Create",
+ tag: ["test", "Essais"],
+ tag_reject: ["reject"]
+ })
+
+ fetch_four =
+ ActivityPub.fetch_activities([], %{
+ type: "Create",
+ tag: ["test"],
+ tag_all: ["test", "REJECT"]
+ })
+
+ # Testing that deduplication (if needed) is done on DB (not Ecto) level; :limit is important
+ fetch_five =
+ ActivityPub.fetch_activities([], %{
+ type: "Create",
+ tag: ["ANY1", "any2"],
+ limit: 2
+ })
+
+ fetch_six =
+ ActivityPub.fetch_activities([], %{
+ type: "Create",
+ tag: ["any1", "Any2"],
+ tag_all: [],
+ tag_reject: []
+ })
+
+ # Regression test: passing empty lists as filter options shouldn't affect the results
+ assert fetch_five == fetch_six
+
+ [fetch_one, fetch_two, fetch_three, fetch_four, fetch_five] =
+ Enum.map([fetch_one, fetch_two, fetch_three, fetch_four, fetch_five], fn statuses ->
+ Enum.map(statuses, fn s -> Repo.preload(s, object: :hashtags) end)
+ end)
- assert fetch_one == [status_one, status_three]
- assert fetch_two == [status_one, status_two, status_three]
- assert fetch_three == [status_one, status_two]
- assert fetch_four == [status_three]
+ assert fetch_one == [status_one, status_three]
+ assert fetch_two == [status_one, status_two, status_three]
+ assert fetch_three == [status_one, status_two]
+ assert fetch_four == [status_three]
+ assert fetch_five == [status_four, status_five]
+ end
end
describe "insertion" do
@@ -239,7 +393,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
}
}
- assert {:error, {:remote_limit_error, _}} = ActivityPub.insert(data)
+ assert {:error, :remote_limit} = ActivityPub.insert(data)
end
test "doesn't drop activities with content being null" do
@@ -321,7 +475,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
}
{:ok, %Activity{} = activity} = ActivityPub.insert(data)
- object = Pleroma.Object.normalize(activity)
+ object = Pleroma.Object.normalize(activity, fetch: false)
assert is_binary(activity.data["context"])
assert is_binary(object.data["context"])
@@ -344,7 +498,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
}
{:ok, %Activity{} = activity} = ActivityPub.insert(data)
- assert object = Object.normalize(activity)
+ assert object = Object.normalize(activity, fetch: false)
assert is_binary(object.data["id"])
end
end
@@ -386,9 +540,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
end
describe "create activities" do
- test "it reverts create" do
- user = insert(:user)
+ setup do
+ [user: insert(:user)]
+ end
+ test "it reverts create", %{user: user} do
with_mock(Utils, [:passthrough], maybe_federate: fn _ -> {:error, :reverted} end) do
assert {:error, :reverted} =
ActivityPub.create(%{
@@ -407,9 +563,47 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert Repo.aggregate(Object, :count, :id) == 0
end
- test "removes doubled 'to' recipients" do
- user = insert(:user)
+ test "creates activity if expiration is not configured and expires_at is not passed", %{
+ user: user
+ } do
+ clear_config([Pleroma.Workers.PurgeExpiredActivity, :enabled], false)
+
+ assert {:ok, _} =
+ ActivityPub.create(%{
+ to: ["user1", "user2"],
+ actor: user,
+ context: "",
+ object: %{
+ "to" => ["user1", "user2"],
+ "type" => "Note",
+ "content" => "testing"
+ }
+ })
+ end
+
+ test "rejects activity if expires_at present but expiration is not configured", %{user: user} do
+ clear_config([Pleroma.Workers.PurgeExpiredActivity, :enabled], false)
+
+ assert {:error, :expired_activities_disabled} =
+ ActivityPub.create(%{
+ to: ["user1", "user2"],
+ actor: user,
+ context: "",
+ object: %{
+ "to" => ["user1", "user2"],
+ "type" => "Note",
+ "content" => "testing"
+ },
+ additional: %{
+ "expires_at" => DateTime.utc_now()
+ }
+ })
+ assert Repo.aggregate(Activity, :count, :id) == 0
+ assert Repo.aggregate(Object, :count, :id) == 0
+ end
+
+ test "removes doubled 'to' recipients", %{user: user} do
{:ok, activity} =
ActivityPub.create(%{
to: ["user1", "user1", "user2"],
@@ -427,9 +621,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert activity.recipients == ["user1", "user2", user.ap_id]
end
- test "increases user note count only for public activities" do
- user = insert(:user)
-
+ test "increases user note count only for public activities", %{user: user} do
{:ok, _} =
CommonAPI.post(User.get_cached_by_id(user.id), %{
status: "1",
@@ -458,8 +650,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert user.note_count == 2
end
- test "increases replies count" do
- user = insert(:user)
+ test "increases replies count", %{user: user} do
user2 = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "1", visibility: "public"})
@@ -468,22 +659,22 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
# public
{:ok, _} = CommonAPI.post(user2, Map.put(reply_data, :visibility, "public"))
- assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
+ assert %{data: _data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
assert object.data["repliesCount"] == 1
# unlisted
{:ok, _} = CommonAPI.post(user2, Map.put(reply_data, :visibility, "unlisted"))
- assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
+ assert %{data: _data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
assert object.data["repliesCount"] == 2
# private
{:ok, _} = CommonAPI.post(user2, Map.put(reply_data, :visibility, "private"))
- assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
+ assert %{data: _data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
assert object.data["repliesCount"] == 2
# direct
{:ok, _} = CommonAPI.post(user2, Map.put(reply_data, :visibility, "direct"))
- assert %{data: data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
+ assert %{data: _data, object: object} = Activity.get_by_ap_id_with_object(ap_id)
assert object.data["repliesCount"] == 2
end
end
@@ -585,6 +776,32 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert Enum.member?(activities, activity_one)
end
+ test "doesn't return activities from deactivated users" do
+ _user = insert(:user)
+ deactivated = insert(:user)
+ active = insert(:user)
+ {:ok, activity_one} = CommonAPI.post(deactivated, %{status: "hey!"})
+ {:ok, activity_two} = CommonAPI.post(active, %{status: "yay!"})
+ {:ok, _updated_user} = User.set_activation(deactivated, false)
+
+ activities = ActivityPub.fetch_activities([], %{})
+
+ refute Enum.member?(activities, activity_one)
+ assert Enum.member?(activities, activity_two)
+ end
+
+ test "always see your own posts even when they address people you block" do
+ user = insert(:user)
+ blockee = insert(:user)
+
+ {:ok, _} = User.block(user, blockee)
+ {:ok, activity} = CommonAPI.post(user, %{status: "hey! @#{blockee.nickname}"})
+
+ activities = ActivityPub.fetch_activities([], %{blocking_user: user})
+
+ assert Enum.member?(activities, activity)
+ end
+
test "doesn't return transitive interactions concerning blocked users" do
blocker = insert(:user)
blockee = insert(:user)
@@ -641,7 +858,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
{:ok, activity_two} = CommonAPI.post(blockee, %{status: "hey! @#{friend.nickname}"})
- assert object = Pleroma.Object.normalize(activity_two)
+ assert object = Pleroma.Object.normalize(activity_two, fetch: false)
data = %{
"actor" => friend.ap_id,
@@ -684,12 +901,27 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
refute repeat_activity in activities
end
+ test "see your own posts even when they adress actors from blocked domains" do
+ user = insert(:user)
+
+ domain = "dogwhistle.zone"
+ domain_user = insert(:user, %{ap_id: "https://#{domain}/@pundit"})
+
+ {:ok, user} = User.block_domain(user, domain)
+
+ {:ok, activity} = CommonAPI.post(user, %{status: "hey! @#{domain_user.nickname}"})
+
+ activities = ActivityPub.fetch_activities([], %{blocking_user: user})
+
+ assert Enum.member?(activities, activity)
+ end
+
test "does return activities from followed users on blocked domains" do
domain = "meanies.social"
domain_user = insert(:user, %{ap_id: "https://#{domain}/@pundit"})
blocker = insert(:user)
- {:ok, blocker} = User.follow(blocker, domain_user)
+ {:ok, blocker, domain_user} = User.follow(blocker, domain_user)
{:ok, blocker} = User.block_domain(blocker, domain)
assert User.following?(blocker, domain_user)
@@ -715,6 +947,22 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
refute repeat_activity in activities
end
+ test "returns your own posts regardless of mute" do
+ user = insert(:user)
+ muted = insert(:user)
+
+ {:ok, muted_post} = CommonAPI.post(muted, %{status: "Im stupid"})
+
+ {:ok, reply} =
+ CommonAPI.post(user, %{status: "I'm muting you", in_reply_to_status_id: muted_post.id})
+
+ {:ok, _} = User.mute(user, muted)
+
+ [activity] = ActivityPub.fetch_activities([], %{muting_user: user, skip_preload: true})
+
+ assert activity.id == reply.id
+ end
+
test "doesn't return muted activities" do
activity_one = insert(:note_activity)
activity_two = insert(:note_activity)
@@ -800,7 +1048,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
user = insert(:user)
booster = insert(:user)
- {:ok, user} = User.follow(user, booster)
+ {:ok, user, booster} = User.follow(user, booster)
{:ok, announce} = CommonAPI.repeat(activity_three.id, booster)
@@ -992,7 +1240,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
describe "uploading files" do
setup do
test_file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}
@@ -1008,15 +1256,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
test "it sets the default description depending on the configuration", %{test_file: file} do
clear_config([Pleroma.Upload, :default_description])
- Pleroma.Config.put([Pleroma.Upload, :default_description], nil)
+ clear_config([Pleroma.Upload, :default_description], nil)
{:ok, %Object{} = object} = ActivityPub.upload(file)
assert object.data["name"] == ""
- Pleroma.Config.put([Pleroma.Upload, :default_description], :filename)
+ clear_config([Pleroma.Upload, :default_description], :filename)
{:ok, %Object{} = object} = ActivityPub.upload(file)
assert object.data["name"] == "an_image.jpg"
- Pleroma.Config.put([Pleroma.Upload, :default_description], "unnamed attachment")
+ clear_config([Pleroma.Upload, :default_description], "unnamed attachment")
{:ok, %Object{} = object} = ActivityPub.upload(file)
assert object.data["name"] == "unnamed attachment"
end
@@ -1083,7 +1331,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
test "creates an undo activity for a pending follow request" do
follower = insert(:user)
- followed = insert(:user, %{locked: true})
+ followed = insert(:user, %{is_locked: true})
{:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed)
{:ok, activity} = ActivityPub.unfollow(follower, followed)
@@ -1105,13 +1353,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
user2 = insert(:user)
user3 = insert(:user)
- {:ok, user1} = User.follow(user1, user3)
+ {:ok, user1, user3} = User.follow(user1, user3)
assert User.following?(user1, user3)
- {:ok, user2} = User.follow(user2, user3)
+ {:ok, user2, user3} = User.follow(user2, user3)
assert User.following?(user2, user3)
- {:ok, user3} = User.follow(user3, user2)
+ {:ok, user3, user2} = User.follow(user3, user2)
assert User.following?(user3, user2)
{:ok, public_activity} = CommonAPI.post(user3, %{status: "hi 1"})
@@ -1245,6 +1493,31 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert_called(Utils.maybe_federate(%{activity | data: new_data}))
end
+
+ test_with_mock "reverts on error",
+ %{
+ reporter: reporter,
+ context: context,
+ target_account: target_account,
+ reported_activity: reported_activity,
+ content: content
+ },
+ Utils,
+ [:passthrough],
+ maybe_federate: fn _ -> {:error, :reverted} end do
+ assert {:error, :reverted} =
+ ActivityPub.flag(%{
+ actor: reporter,
+ context: context,
+ account: target_account,
+ statuses: [reported_activity],
+ content: content
+ })
+
+ assert Repo.aggregate(Activity, :count, :id) == 1
+ assert Repo.aggregate(Object, :count, :id) == 2
+ assert Repo.aggregate(Notification, :count, :id) == 0
+ end
end
test "fetch_activities/2 returns activities addressed to a list " do
@@ -1373,19 +1646,25 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
mock(fn env ->
case env.url do
"http://localhost:4001/users/masto_hidden_counters/following" ->
- json(%{
- "@context" => "https://www.w3.org/ns/activitystreams",
- "id" => "http://localhost:4001/users/masto_hidden_counters/followers"
- })
+ json(
+ %{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "id" => "http://localhost:4001/users/masto_hidden_counters/followers"
+ },
+ headers: HttpRequestMock.activitypub_object_headers()
+ )
"http://localhost:4001/users/masto_hidden_counters/following?page=1" ->
%Tesla.Env{status: 403, body: ""}
"http://localhost:4001/users/masto_hidden_counters/followers" ->
- json(%{
- "@context" => "https://www.w3.org/ns/activitystreams",
- "id" => "http://localhost:4001/users/masto_hidden_counters/following"
- })
+ json(
+ %{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "id" => "http://localhost:4001/users/masto_hidden_counters/following"
+ },
+ headers: HttpRequestMock.activitypub_object_headers()
+ )
"http://localhost:4001/users/masto_hidden_counters/followers?page=1" ->
%Tesla.Env{status: 403, body: ""}
@@ -1773,6 +2052,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
|> Enum.map(& &1.id)
assert activities_ids == []
+
+ activities_ids =
+ %{}
+ |> Map.put(:reply_visibility, "self")
+ |> Map.put(:reply_filtering_user, nil)
+ |> ActivityPub.fetch_public_activities()
+
+ assert activities_ids == []
end
test "home timeline", %{users: %{u1: user}} do
@@ -1839,13 +2126,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
defp public_messages(_) do
[u1, u2, u3, u4] = insert_list(4, :user)
- {:ok, u1} = User.follow(u1, u2)
- {:ok, u2} = User.follow(u2, u1)
- {:ok, u1} = User.follow(u1, u4)
- {:ok, u4} = User.follow(u4, u1)
+ {:ok, u1, u2} = User.follow(u1, u2)
+ {:ok, u2, u1} = User.follow(u2, u1)
+ {:ok, u1, u4} = User.follow(u1, u4)
+ {:ok, u4, u1} = User.follow(u4, u1)
- {:ok, u2} = User.follow(u2, u3)
- {:ok, u3} = User.follow(u3, u2)
+ {:ok, u2, u3} = User.follow(u2, u3)
+ {:ok, u3, u2} = User.follow(u3, u2)
{:ok, a1} = CommonAPI.post(u1, %{status: "Status"})
@@ -1938,15 +2225,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
defp private_messages(_) do
[u1, u2, u3, u4] = insert_list(4, :user)
- {:ok, u1} = User.follow(u1, u2)
- {:ok, u2} = User.follow(u2, u1)
- {:ok, u1} = User.follow(u1, u3)
- {:ok, u3} = User.follow(u3, u1)
- {:ok, u1} = User.follow(u1, u4)
- {:ok, u4} = User.follow(u4, u1)
+ {:ok, u1, u2} = User.follow(u1, u2)
+ {:ok, u2, u1} = User.follow(u2, u1)
+ {:ok, u1, u3} = User.follow(u1, u3)
+ {:ok, u3, u1} = User.follow(u3, u1)
+ {:ok, u1, u4} = User.follow(u1, u4)
+ {:ok, u4, u1} = User.follow(u4, u1)
- {:ok, u2} = User.follow(u2, u3)
- {:ok, u3} = User.follow(u3, u2)
+ {:ok, u2, u3} = User.follow(u2, u3)
+ {:ok, u3, u2} = User.follow(u3, u2)
{:ok, a1} = CommonAPI.post(u1, %{status: "Status", visibility: "private"})
@@ -2069,18 +2356,25 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
end
describe "global activity expiration" do
- setup do: clear_config([:mrf, :policies])
-
test "creates an activity expiration for local Create activities" do
- Pleroma.Config.put(
- [:mrf, :policies],
- Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy
+ clear_config([:mrf, :policies], Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy)
+
+ {:ok, activity} = ActivityBuilder.insert(%{"type" => "Create", "context" => "3hu"})
+ {:ok, follow} = ActivityBuilder.insert(%{"type" => "Follow", "context" => "3hu"})
+
+ assert_enqueued(
+ worker: Pleroma.Workers.PurgeExpiredActivity,
+ args: %{activity_id: activity.id},
+ scheduled_at:
+ activity.inserted_at
+ |> DateTime.from_naive!("Etc/UTC")
+ |> Timex.shift(days: 365)
)
- {:ok, %{id: id_create}} = ActivityBuilder.insert(%{"type" => "Create", "context" => "3hu"})
- {:ok, _follow} = ActivityBuilder.insert(%{"type" => "Follow", "context" => "3hu"})
-
- assert [%{activity_id: ^id_create}] = Pleroma.ActivityExpiration |> Repo.all()
+ refute_enqueued(
+ worker: Pleroma.Workers.PurgeExpiredActivity,
+ args: %{activity_id: follow.id}
+ )
end
end
@@ -2125,4 +2419,95 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do
assert user.nickname == orig_user.nickname
end
end
+
+ describe "reply filtering" do
+ test "`following` still contains announcements by friends" do
+ user = insert(:user)
+ followed = insert(:user)
+ not_followed = insert(:user)
+
+ User.follow(user, followed)
+
+ {:ok, followed_post} = CommonAPI.post(followed, %{status: "Hello"})
+
+ {:ok, not_followed_to_followed} =
+ CommonAPI.post(not_followed, %{
+ status: "Also hello",
+ in_reply_to_status_id: followed_post.id
+ })
+
+ {:ok, retoot} = CommonAPI.repeat(not_followed_to_followed.id, followed)
+
+ params =
+ %{}
+ |> Map.put(:type, ["Create", "Announce"])
+ |> Map.put(:blocking_user, user)
+ |> Map.put(:muting_user, user)
+ |> Map.put(:reply_filtering_user, user)
+ |> Map.put(:reply_visibility, "following")
+ |> Map.put(:announce_filtering_user, user)
+ |> Map.put(:user, user)
+
+ activities =
+ [user.ap_id | User.following(user)]
+ |> ActivityPub.fetch_activities(params)
+
+ followed_post_id = followed_post.id
+ retoot_id = retoot.id
+
+ assert [%{id: ^followed_post_id}, %{id: ^retoot_id}] = activities
+
+ assert length(activities) == 2
+ end
+
+ # This test is skipped because, while this is the desired behavior,
+ # there seems to be no good way to achieve it with the method that
+ # we currently use for detecting to who a reply is directed.
+ # This is a TODO and should be fixed by a later rewrite of the code
+ # in question.
+ @tag skip: true
+ test "`following` still contains self-replies by friends" do
+ user = insert(:user)
+ followed = insert(:user)
+ not_followed = insert(:user)
+
+ User.follow(user, followed)
+
+ {:ok, followed_post} = CommonAPI.post(followed, %{status: "Hello"})
+ {:ok, not_followed_post} = CommonAPI.post(not_followed, %{status: "Also hello"})
+
+ {:ok, _followed_to_not_followed} =
+ CommonAPI.post(followed, %{status: "sup", in_reply_to_status_id: not_followed_post.id})
+
+ {:ok, _followed_self_reply} =
+ CommonAPI.post(followed, %{status: "Also cofe", in_reply_to_status_id: followed_post.id})
+
+ params =
+ %{}
+ |> Map.put(:type, ["Create", "Announce"])
+ |> Map.put(:blocking_user, user)
+ |> Map.put(:muting_user, user)
+ |> Map.put(:reply_filtering_user, user)
+ |> Map.put(:reply_visibility, "following")
+ |> Map.put(:announce_filtering_user, user)
+ |> Map.put(:user, user)
+
+ activities =
+ [user.ap_id | User.following(user)]
+ |> ActivityPub.fetch_activities(params)
+
+ assert length(activities) == 2
+ end
+ end
+
+ test "allow fetching of accounts with an empty string name field" do
+ Tesla.Mock.mock(fn
+ %{method: :get, url: "https://princess.cat/users/mewmew"} ->
+ file = File.read!("test/fixtures/mewmew_no_name.json")
+ %Tesla.Env{status: 200, body: file, headers: HttpRequestMock.activitypub_object_headers()}
+ end)
+
+ {:ok, user} = ActivityPub.make_user_from_ap_id("https://princess.cat/users/mewmew")
+ assert user.name == " "
+ end
end
diff --git a/test/pleroma/web/activity_pub/builder_test.exs b/test/pleroma/web/activity_pub/builder_test.exs
new file mode 100644
index 000000000..3fe32bce5
--- /dev/null
+++ b/test/pleroma/web/activity_pub/builder_test.exs
@@ -0,0 +1,48 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.BuilderTest do
+ alias Pleroma.Web.ActivityPub.Builder
+ alias Pleroma.Web.CommonAPI.ActivityDraft
+ use Pleroma.DataCase
+
+ import Pleroma.Factory
+
+ describe "note/1" do
+ test "returns note data" do
+ user = insert(:user)
+ note = insert(:note)
+ user2 = insert(:user)
+ user3 = insert(:user)
+
+ draft = %ActivityDraft{
+ user: user,
+ to: [user2.ap_id],
+ context: "2hu",
+ content_html: "<h1>This is :moominmamma: note</h1>",
+ in_reply_to: note.id,
+ tags: [name: "jimm"],
+ summary: "test summary",
+ cc: [user3.ap_id],
+ extra: %{"custom_tag" => "test"}
+ }
+
+ expected = %{
+ "actor" => user.ap_id,
+ "attachment" => [],
+ "cc" => [user3.ap_id],
+ "content" => "<h1>This is :moominmamma: note</h1>",
+ "context" => "2hu",
+ "sensitive" => false,
+ "summary" => "test summary",
+ "tag" => ["jimm"],
+ "to" => [user2.ap_id],
+ "type" => "Note",
+ "custom_tag" => "test"
+ }
+
+ assert {:ok, ^expected, []} = Builder.note(draft)
+ end
+ end
+end
diff --git a/test/web/activity_pub/mrf/activity_expiration_policy_test.exs b/test/pleroma/web/activity_pub/mrf/activity_expiration_policy_test.exs
index f25cf8b12..47b07fdd9 100644
--- a/test/web/activity_pub/mrf/activity_expiration_policy_test.exs
+++ b/test/pleroma/web/activity_pub/mrf/activity_expiration_policy_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicyTest do
@@ -18,11 +18,11 @@ defmodule Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicyTest do
"object" => %{"type" => "Note"}
})
- assert Timex.diff(expires_at, NaiveDateTime.utc_now(), :days) == 364
+ assert Timex.diff(expires_at, DateTime.utc_now(), :days) == 364
end
test "keeps existing `expires_at` if it less than the config setting" do
- expires_at = NaiveDateTime.utc_now() |> Timex.shift(days: 1)
+ expires_at = DateTime.utc_now() |> Timex.shift(days: 1)
assert {:ok, %{"type" => "Create", "expires_at" => ^expires_at}} =
ActivityExpirationPolicy.filter(%{
@@ -35,7 +35,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicyTest do
end
test "overwrites existing `expires_at` if it greater than the config setting" do
- too_distant_future = NaiveDateTime.utc_now() |> Timex.shift(years: 2)
+ too_distant_future = DateTime.utc_now() |> Timex.shift(years: 2)
assert {:ok, %{"type" => "Create", "expires_at" => expires_at}} =
ActivityExpirationPolicy.filter(%{
@@ -46,7 +46,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicyTest do
"object" => %{"type" => "Note"}
})
- assert Timex.diff(expires_at, NaiveDateTime.utc_now(), :days) == 364
+ assert Timex.diff(expires_at, DateTime.utc_now(), :days) == 364
end
test "ignores remote activities" do
diff --git a/test/web/activity_pub/mrf/anti_followbot_policy_test.exs b/test/pleroma/web/activity_pub/mrf/anti_followbot_policy_test.exs
index 3c795f5ac..d5af3a9b6 100644
--- a/test/web/activity_pub/mrf/anti_followbot_policy_test.exs
+++ b/test/pleroma/web/activity_pub/mrf/anti_followbot_policy_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicyTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
import Pleroma.Factory
alias Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy
diff --git a/test/web/activity_pub/mrf/anti_link_spam_policy_test.exs b/test/pleroma/web/activity_pub/mrf/anti_link_spam_policy_test.exs
index 6867c9853..5b990451c 100644
--- a/test/web/activity_pub/mrf/anti_link_spam_policy_test.exs
+++ b/test/pleroma/web/activity_pub/mrf/anti_link_spam_policy_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do
diff --git a/test/web/activity_pub/mrf/ensure_re_prepended_test.exs b/test/pleroma/web/activity_pub/mrf/ensure_re_prepended_test.exs
index 9a283f27d..89439b65f 100644
--- a/test/web/activity_pub/mrf/ensure_re_prepended_test.exs
+++ b/test/pleroma/web/activity_pub/mrf/ensure_re_prepended_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.EnsureRePrependedTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Activity
alias Pleroma.Object
diff --git a/test/pleroma/web/activity_pub/mrf/follow_bot_policy_test.exs b/test/pleroma/web/activity_pub/mrf/follow_bot_policy_test.exs
new file mode 100644
index 000000000..a61562558
--- /dev/null
+++ b/test/pleroma/web/activity_pub/mrf/follow_bot_policy_test.exs
@@ -0,0 +1,126 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.MRF.FollowBotPolicyTest do
+ use Pleroma.DataCase, async: true
+
+ alias Pleroma.User
+ alias Pleroma.Web.ActivityPub.MRF.FollowBotPolicy
+
+ import Pleroma.Factory
+
+ describe "FollowBotPolicy" do
+ test "follows remote users" do
+ bot = insert(:user, actor_type: "Service")
+ remote_user = insert(:user, local: false)
+ clear_config([:mrf_follow_bot, :follower_nickname], bot.nickname)
+
+ message = %{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "to" => [remote_user.follower_address],
+ "cc" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "type" => "Create",
+ "object" => %{
+ "content" => "Test post",
+ "type" => "Note",
+ "attributedTo" => remote_user.ap_id,
+ "inReplyTo" => nil
+ },
+ "actor" => remote_user.ap_id
+ }
+
+ refute User.following?(bot, remote_user)
+
+ assert User.get_follow_requests(remote_user) |> length == 0
+
+ FollowBotPolicy.filter(message)
+
+ assert User.get_follow_requests(remote_user) |> length == 1
+ end
+
+ test "does not follow users with #nobot in bio" do
+ bot = insert(:user, actor_type: "Service")
+ remote_user = insert(:user, %{local: false, bio: "go away bots! #nobot"})
+ clear_config([:mrf_follow_bot, :follower_nickname], bot.nickname)
+
+ message = %{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "to" => [remote_user.follower_address],
+ "cc" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "type" => "Create",
+ "object" => %{
+ "content" => "I don't like follow bots",
+ "type" => "Note",
+ "attributedTo" => remote_user.ap_id,
+ "inReplyTo" => nil
+ },
+ "actor" => remote_user.ap_id
+ }
+
+ refute User.following?(bot, remote_user)
+
+ assert User.get_follow_requests(remote_user) |> length == 0
+
+ FollowBotPolicy.filter(message)
+
+ assert User.get_follow_requests(remote_user) |> length == 0
+ end
+
+ test "does not follow local users" do
+ bot = insert(:user, actor_type: "Service")
+ local_user = insert(:user, local: true)
+ clear_config([:mrf_follow_bot, :follower_nickname], bot.nickname)
+
+ message = %{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "to" => [local_user.follower_address],
+ "cc" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "type" => "Create",
+ "object" => %{
+ "content" => "Hi I'm a local user",
+ "type" => "Note",
+ "attributedTo" => local_user.ap_id,
+ "inReplyTo" => nil
+ },
+ "actor" => local_user.ap_id
+ }
+
+ refute User.following?(bot, local_user)
+
+ assert User.get_follow_requests(local_user) |> length == 0
+
+ FollowBotPolicy.filter(message)
+
+ assert User.get_follow_requests(local_user) |> length == 0
+ end
+
+ test "does not follow users requiring follower approval" do
+ bot = insert(:user, actor_type: "Service")
+ remote_user = insert(:user, %{local: false, is_locked: true})
+ clear_config([:mrf_follow_bot, :follower_nickname], bot.nickname)
+
+ message = %{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "to" => [remote_user.follower_address],
+ "cc" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "type" => "Create",
+ "object" => %{
+ "content" => "I don't like randos following me",
+ "type" => "Note",
+ "attributedTo" => remote_user.ap_id,
+ "inReplyTo" => nil
+ },
+ "actor" => remote_user.ap_id
+ }
+
+ refute User.following?(bot, remote_user)
+
+ assert User.get_follow_requests(remote_user) |> length == 0
+
+ FollowBotPolicy.filter(message)
+
+ assert User.get_follow_requests(remote_user) |> length == 0
+ end
+ end
+end
diff --git a/test/pleroma/web/activity_pub/mrf/force_bot_unlisted_policy_test.exs b/test/pleroma/web/activity_pub/mrf/force_bot_unlisted_policy_test.exs
new file mode 100644
index 000000000..e3325d144
--- /dev/null
+++ b/test/pleroma/web/activity_pub/mrf/force_bot_unlisted_policy_test.exs
@@ -0,0 +1,60 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.MRF.ForceBotUnlistedPolicyTest do
+ use Pleroma.DataCase, async: true
+ import Pleroma.Factory
+
+ alias Pleroma.Web.ActivityPub.MRF.ForceBotUnlistedPolicy
+ @public "https://www.w3.org/ns/activitystreams#Public"
+
+ defp generate_messages(actor) do
+ {%{
+ "actor" => actor.ap_id,
+ "type" => "Create",
+ "object" => %{},
+ "to" => [@public, "f"],
+ "cc" => [actor.follower_address, "d"]
+ },
+ %{
+ "actor" => actor.ap_id,
+ "type" => "Create",
+ "object" => %{"to" => ["f", actor.follower_address], "cc" => ["d", @public]},
+ "to" => ["f", actor.follower_address],
+ "cc" => ["d", @public]
+ }}
+ end
+
+ test "removes from the federated timeline by nickname heuristics 1" do
+ actor = insert(:user, %{nickname: "annoying_ebooks@example.com"})
+
+ {message, except_message} = generate_messages(actor)
+
+ assert ForceBotUnlistedPolicy.filter(message) == {:ok, except_message}
+ end
+
+ test "removes from the federated timeline by nickname heuristics 2" do
+ actor = insert(:user, %{nickname: "cirnonewsnetworkbot@meow.cat"})
+
+ {message, except_message} = generate_messages(actor)
+
+ assert ForceBotUnlistedPolicy.filter(message) == {:ok, except_message}
+ end
+
+ test "removes from the federated timeline by actor type Application" do
+ actor = insert(:user, %{actor_type: "Application"})
+
+ {message, except_message} = generate_messages(actor)
+
+ assert ForceBotUnlistedPolicy.filter(message) == {:ok, except_message}
+ end
+
+ test "removes from the federated timeline by actor type Service" do
+ actor = insert(:user, %{actor_type: "Service"})
+
+ {message, except_message} = generate_messages(actor)
+
+ assert ForceBotUnlistedPolicy.filter(message) == {:ok, except_message}
+ end
+end
diff --git a/test/pleroma/web/activity_pub/mrf/hashtag_policy_test.exs b/test/pleroma/web/activity_pub/mrf/hashtag_policy_test.exs
new file mode 100644
index 000000000..13415bb79
--- /dev/null
+++ b/test/pleroma/web/activity_pub/mrf/hashtag_policy_test.exs
@@ -0,0 +1,31 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.MRF.HashtagPolicyTest do
+ use Oban.Testing, repo: Pleroma.Repo
+ use Pleroma.DataCase
+
+ alias Pleroma.Web.ActivityPub.Transmogrifier
+ alias Pleroma.Web.CommonAPI
+
+ import Pleroma.Factory
+
+ test "it sets the sensitive property with relevant hashtags" do
+ user = insert(:user)
+
+ {:ok, activity} = CommonAPI.post(user, %{status: "#nsfw hey"})
+ {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
+
+ assert modified["object"]["sensitive"]
+ end
+
+ test "it doesn't sets the sensitive property with irrelevant hashtags" do
+ user = insert(:user)
+
+ {:ok, activity} = CommonAPI.post(user, %{status: "#cofe hey"})
+ {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
+
+ refute modified["object"]["sensitive"]
+ end
+end
diff --git a/test/web/activity_pub/mrf/hellthread_policy_test.exs b/test/pleroma/web/activity_pub/mrf/hellthread_policy_test.exs
index 26f5bcdaa..439672479 100644
--- a/test/web/activity_pub/mrf/hellthread_policy_test.exs
+++ b/test/pleroma/web/activity_pub/mrf/hellthread_policy_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicyTest do
@@ -34,7 +34,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicyTest do
setup do: clear_config(:mrf_hellthread)
test "doesn't die on chat messages" do
- Pleroma.Config.put([:mrf_hellthread], %{delist_threshold: 2, reject_threshold: 0})
+ clear_config([:mrf_hellthread], %{delist_threshold: 2, reject_threshold: 0})
user = insert(:user)
other_user = insert(:user)
@@ -48,7 +48,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicyTest do
test "rejects the message if the recipient count is above reject_threshold", %{
message: message
} do
- Pleroma.Config.put([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 2})
+ clear_config([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 2})
assert {:reject, "[HellthreadPolicy] 3 recipients is over the limit of 2"} ==
filter(message)
@@ -57,7 +57,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicyTest do
test "does not reject the message if the recipient count is below reject_threshold", %{
message: message
} do
- Pleroma.Config.put([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 3})
+ clear_config([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 3})
assert {:ok, ^message} = filter(message)
end
@@ -68,7 +68,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicyTest do
user: user,
message: message
} do
- Pleroma.Config.put([:mrf_hellthread], %{delist_threshold: 2, reject_threshold: 0})
+ clear_config([:mrf_hellthread], %{delist_threshold: 2, reject_threshold: 0})
{:ok, message} = filter(message)
assert user.follower_address in message["to"]
@@ -78,14 +78,14 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicyTest do
test "does not delist the message if the recipient count is below delist_threshold", %{
message: message
} do
- Pleroma.Config.put([:mrf_hellthread], %{delist_threshold: 4, reject_threshold: 0})
+ clear_config([:mrf_hellthread], %{delist_threshold: 4, reject_threshold: 0})
assert {:ok, ^message} = filter(message)
end
end
test "excludes follower collection and public URI from threshold count", %{message: message} do
- Pleroma.Config.put([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 3})
+ clear_config([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 3})
assert {:ok, ^message} = filter(message)
end
diff --git a/test/web/activity_pub/mrf/keyword_policy_test.exs b/test/pleroma/web/activity_pub/mrf/keyword_policy_test.exs
index b3d0f3d90..8af4c5efa 100644
--- a/test/web/activity_pub/mrf/keyword_policy_test.exs
+++ b/test/pleroma/web/activity_pub/mrf/keyword_policy_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do
@@ -10,12 +10,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do
setup do: clear_config(:mrf_keyword)
setup do
- Pleroma.Config.put([:mrf_keyword], %{reject: [], federated_timeline_removal: [], replace: []})
+ clear_config([:mrf_keyword], %{reject: [], federated_timeline_removal: [], replace: []})
end
describe "rejecting based on keywords" do
test "rejects if string matches in content" do
- Pleroma.Config.put([:mrf_keyword, :reject], ["pun"])
+ clear_config([:mrf_keyword, :reject], ["pun"])
message = %{
"type" => "Create",
@@ -30,7 +30,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do
end
test "rejects if string matches in summary" do
- Pleroma.Config.put([:mrf_keyword, :reject], ["pun"])
+ clear_config([:mrf_keyword, :reject], ["pun"])
message = %{
"type" => "Create",
@@ -45,7 +45,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do
end
test "rejects if regex matches in content" do
- Pleroma.Config.put([:mrf_keyword, :reject], [~r/comp[lL][aA][iI][nN]er/])
+ clear_config([:mrf_keyword, :reject], [~r/comp[lL][aA][iI][nN]er/])
assert true ==
Enum.all?(["complainer", "compLainer", "compLAiNer", "compLAINer"], fn content ->
@@ -63,7 +63,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do
end
test "rejects if regex matches in summary" do
- Pleroma.Config.put([:mrf_keyword, :reject], [~r/comp[lL][aA][iI][nN]er/])
+ clear_config([:mrf_keyword, :reject], [~r/comp[lL][aA][iI][nN]er/])
assert true ==
Enum.all?(["complainer", "compLainer", "compLAiNer", "compLAINer"], fn content ->
@@ -83,7 +83,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do
describe "delisting from ftl based on keywords" do
test "delists if string matches in content" do
- Pleroma.Config.put([:mrf_keyword, :federated_timeline_removal], ["pun"])
+ clear_config([:mrf_keyword, :federated_timeline_removal], ["pun"])
message = %{
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
@@ -100,7 +100,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do
end
test "delists if string matches in summary" do
- Pleroma.Config.put([:mrf_keyword, :federated_timeline_removal], ["pun"])
+ clear_config([:mrf_keyword, :federated_timeline_removal], ["pun"])
message = %{
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
@@ -117,7 +117,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do
end
test "delists if regex matches in content" do
- Pleroma.Config.put([:mrf_keyword, :federated_timeline_removal], [~r/comp[lL][aA][iI][nN]er/])
+ clear_config([:mrf_keyword, :federated_timeline_removal], [~r/comp[lL][aA][iI][nN]er/])
assert true ==
Enum.all?(["complainer", "compLainer", "compLAiNer", "compLAINer"], fn content ->
@@ -138,7 +138,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do
end
test "delists if regex matches in summary" do
- Pleroma.Config.put([:mrf_keyword, :federated_timeline_removal], [~r/comp[lL][aA][iI][nN]er/])
+ clear_config([:mrf_keyword, :federated_timeline_removal], [~r/comp[lL][aA][iI][nN]er/])
assert true ==
Enum.all?(["complainer", "compLainer", "compLAiNer", "compLAINer"], fn content ->
@@ -161,7 +161,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do
describe "replacing keywords" do
test "replaces keyword if string matches in content" do
- Pleroma.Config.put([:mrf_keyword, :replace], [{"opensource", "free software"}])
+ clear_config([:mrf_keyword, :replace], [{"opensource", "free software"}])
message = %{
"type" => "Create",
@@ -174,7 +174,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do
end
test "replaces keyword if string matches in summary" do
- Pleroma.Config.put([:mrf_keyword, :replace], [{"opensource", "free software"}])
+ clear_config([:mrf_keyword, :replace], [{"opensource", "free software"}])
message = %{
"type" => "Create",
@@ -187,7 +187,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do
end
test "replaces keyword if regex matches in content" do
- Pleroma.Config.put([:mrf_keyword, :replace], [
+ clear_config([:mrf_keyword, :replace], [
{~r/open(-|\s)?source\s?(software)?/, "free software"}
])
@@ -205,7 +205,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do
end
test "replaces keyword if regex matches in summary" do
- Pleroma.Config.put([:mrf_keyword, :replace], [
+ clear_config([:mrf_keyword, :replace], [
{~r/open(-|\s)?source\s?(software)?/, "free software"}
])
diff --git a/test/web/activity_pub/mrf/mediaproxy_warming_policy_test.exs b/test/pleroma/web/activity_pub/mrf/media_proxy_warming_policy_test.exs
index 313d59a66..96e715d0d 100644
--- a/test/web/activity_pub/mrf/mediaproxy_warming_policy_test.exs
+++ b/test/pleroma/web/activity_pub/mrf/media_proxy_warming_policy_test.exs
@@ -1,12 +1,12 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicyTest do
- use Pleroma.DataCase
+ use ExUnit.Case
+ use Pleroma.Tests.Helpers
alias Pleroma.HTTP
- alias Pleroma.Tests.ObanHelpers
alias Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy
import Mock
@@ -22,14 +22,16 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicyTest do
}
}
+ setup do: clear_config([:media_proxy, :enabled], true)
+
test "it prefetches media proxy URIs" do
+ Tesla.Mock.mock(fn %{method: :get, url: "http://example.com/image.jpg"} ->
+ {:ok, %Tesla.Env{status: 200, body: ""}}
+ end)
+
with_mock HTTP, get: fn _, _, _ -> {:ok, []} end do
MediaProxyWarmingPolicy.filter(@message)
- ObanHelpers.perform_all()
- # Performing jobs which has been just enqueued
- ObanHelpers.perform_all()
-
assert called(HTTP.get(:_, :_, :_))
end
end
diff --git a/test/web/activity_pub/mrf/mention_policy_test.exs b/test/pleroma/web/activity_pub/mrf/mention_policy_test.exs
index 220309cc9..80ddcacbe 100644
--- a/test/web/activity_pub/mrf/mention_policy_test.exs
+++ b/test/pleroma/web/activity_pub/mrf/mention_policy_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do
@@ -23,7 +23,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do
describe "allow" do
test "empty" do
- Pleroma.Config.put([:mrf_mention], %{actors: ["https://example.com/blocked"]})
+ clear_config([:mrf_mention], %{actors: ["https://example.com/blocked"]})
message = %{
"type" => "Create"
@@ -33,7 +33,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do
end
test "to" do
- Pleroma.Config.put([:mrf_mention], %{actors: ["https://example.com/blocked"]})
+ clear_config([:mrf_mention], %{actors: ["https://example.com/blocked"]})
message = %{
"type" => "Create",
@@ -44,7 +44,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do
end
test "cc" do
- Pleroma.Config.put([:mrf_mention], %{actors: ["https://example.com/blocked"]})
+ clear_config([:mrf_mention], %{actors: ["https://example.com/blocked"]})
message = %{
"type" => "Create",
@@ -55,7 +55,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do
end
test "both" do
- Pleroma.Config.put([:mrf_mention], %{actors: ["https://example.com/blocked"]})
+ clear_config([:mrf_mention], %{actors: ["https://example.com/blocked"]})
message = %{
"type" => "Create",
@@ -69,7 +69,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do
describe "deny" do
test "to" do
- Pleroma.Config.put([:mrf_mention], %{actors: ["https://example.com/blocked"]})
+ clear_config([:mrf_mention], %{actors: ["https://example.com/blocked"]})
message = %{
"type" => "Create",
@@ -81,7 +81,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do
end
test "cc" do
- Pleroma.Config.put([:mrf_mention], %{actors: ["https://example.com/blocked"]})
+ clear_config([:mrf_mention], %{actors: ["https://example.com/blocked"]})
message = %{
"type" => "Create",
diff --git a/test/pleroma/web/activity_pub/mrf/no_empty_policy_test.exs b/test/pleroma/web/activity_pub/mrf/no_empty_policy_test.exs
new file mode 100644
index 000000000..fbcf68414
--- /dev/null
+++ b/test/pleroma/web/activity_pub/mrf/no_empty_policy_test.exs
@@ -0,0 +1,154 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.MRF.NoEmptyPolicyTest do
+ use Pleroma.DataCase
+ alias Pleroma.Web.ActivityPub.MRF.NoEmptyPolicy
+
+ setup_all do: clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.NoEmptyPolicy])
+
+ test "Notes with content are exempt" do
+ message = %{
+ "actor" => "http://localhost:4001/users/testuser",
+ "cc" => ["http://localhost:4001/users/testuser/followers"],
+ "object" => %{
+ "actor" => "http://localhost:4001/users/testuser",
+ "attachment" => [],
+ "cc" => ["http://localhost:4001/users/testuser/followers"],
+ "source" => "this is a test post",
+ "to" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "type" => "Note"
+ },
+ "to" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "type" => "Create"
+ }
+
+ assert NoEmptyPolicy.filter(message) == {:ok, message}
+ end
+
+ test "Polls are exempt" do
+ message = %{
+ "actor" => "http://localhost:4001/users/testuser",
+ "cc" => ["http://localhost:4001/users/testuser/followers"],
+ "object" => %{
+ "actor" => "http://localhost:4001/users/testuser",
+ "attachment" => [],
+ "cc" => ["http://localhost:4001/users/testuser/followers"],
+ "oneOf" => [
+ %{
+ "name" => "chocolate",
+ "replies" => %{"totalItems" => 0, "type" => "Collection"},
+ "type" => "Note"
+ },
+ %{
+ "name" => "vanilla",
+ "replies" => %{"totalItems" => 0, "type" => "Collection"},
+ "type" => "Note"
+ }
+ ],
+ "source" => "@user2",
+ "to" => [
+ "https://www.w3.org/ns/activitystreams#Public",
+ "http://localhost:4001/users/user2"
+ ],
+ "type" => "Question"
+ },
+ "to" => [
+ "https://www.w3.org/ns/activitystreams#Public",
+ "http://localhost:4001/users/user2"
+ ],
+ "type" => "Create"
+ }
+
+ assert NoEmptyPolicy.filter(message) == {:ok, message}
+ end
+
+ test "Notes with attachments are exempt" do
+ message = %{
+ "actor" => "http://localhost:4001/users/testuser",
+ "cc" => ["http://localhost:4001/users/testuser/followers"],
+ "object" => %{
+ "actor" => "http://localhost:4001/users/testuser",
+ "attachment" => [
+ %{
+ "actor" => "http://localhost:4001/users/testuser",
+ "mediaType" => "image/png",
+ "name" => "",
+ "type" => "Document",
+ "url" => [
+ %{
+ "href" =>
+ "http://localhost:4001/media/68ba231cf12e1382ce458f1979969f8ed5cc07ba198a02e653464abaf39bdb90.png",
+ "mediaType" => "image/png",
+ "type" => "Link"
+ }
+ ]
+ }
+ ],
+ "cc" => ["http://localhost:4001/users/testuser/followers"],
+ "source" => "@user2",
+ "to" => [
+ "https://www.w3.org/ns/activitystreams#Public",
+ "http://localhost:4001/users/user2"
+ ],
+ "type" => "Note"
+ },
+ "to" => [
+ "https://www.w3.org/ns/activitystreams#Public",
+ "http://localhost:4001/users/user2"
+ ],
+ "type" => "Create"
+ }
+
+ assert NoEmptyPolicy.filter(message) == {:ok, message}
+ end
+
+ test "Notes with only mentions are denied" do
+ message = %{
+ "actor" => "http://localhost:4001/users/testuser",
+ "cc" => ["http://localhost:4001/users/testuser/followers"],
+ "object" => %{
+ "actor" => "http://localhost:4001/users/testuser",
+ "attachment" => [],
+ "cc" => ["http://localhost:4001/users/testuser/followers"],
+ "source" => "@user2",
+ "to" => [
+ "https://www.w3.org/ns/activitystreams#Public",
+ "http://localhost:4001/users/user2"
+ ],
+ "type" => "Note"
+ },
+ "to" => [
+ "https://www.w3.org/ns/activitystreams#Public",
+ "http://localhost:4001/users/user2"
+ ],
+ "type" => "Create"
+ }
+
+ assert NoEmptyPolicy.filter(message) == {:reject, "[NoEmptyPolicy]"}
+ end
+
+ test "Notes with no content are denied" do
+ message = %{
+ "actor" => "http://localhost:4001/users/testuser",
+ "cc" => ["http://localhost:4001/users/testuser/followers"],
+ "object" => %{
+ "actor" => "http://localhost:4001/users/testuser",
+ "attachment" => [],
+ "cc" => ["http://localhost:4001/users/testuser/followers"],
+ "source" => "",
+ "to" => [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "type" => "Note"
+ },
+ "to" => [
+ "https://www.w3.org/ns/activitystreams#Public"
+ ],
+ "type" => "Create"
+ }
+
+ assert NoEmptyPolicy.filter(message) == {:reject, "[NoEmptyPolicy]"}
+ end
+end
diff --git a/test/web/activity_pub/mrf/no_placeholder_text_policy_test.exs b/test/pleroma/web/activity_pub/mrf/no_placeholder_text_policy_test.exs
index 64ea61dd4..81a6e0f50 100644
--- a/test/web/activity_pub/mrf/no_placeholder_text_policy_test.exs
+++ b/test/pleroma/web/activity_pub/mrf/no_placeholder_text_policy_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.NoPlaceholderTextPolicyTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Web.ActivityPub.MRF.NoPlaceholderTextPolicy
test "it clears content object" do
diff --git a/test/web/activity_pub/mrf/normalize_markup_test.exs b/test/pleroma/web/activity_pub/mrf/normalize_markup_test.exs
index 9b39c45bd..edc330b6c 100644
--- a/test/web/activity_pub/mrf/normalize_markup_test.exs
+++ b/test/pleroma/web/activity_pub/mrf/normalize_markup_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.NormalizeMarkupTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Web.ActivityPub.MRF.NormalizeMarkup
@html_sample """
diff --git a/test/web/activity_pub/mrf/object_age_policy_test.exs b/test/pleroma/web/activity_pub/mrf/object_age_policy_test.exs
index cf6acc9a2..2f649a0a4 100644
--- a/test/web/activity_pub/mrf/object_age_policy_test.exs
+++ b/test/pleroma/web/activity_pub/mrf/object_age_policy_test.exs
@@ -1,10 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do
use Pleroma.DataCase
- alias Pleroma.Config
alias Pleroma.User
alias Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy
alias Pleroma.Web.ActivityPub.Visibility
@@ -22,7 +21,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do
defp get_old_message do
File.read!("test/fixtures/mastodon-post-activity.json")
- |> Poison.decode!()
+ |> Jason.decode!()
+ |> Map.drop(["published"])
end
defp get_new_message do
@@ -39,7 +39,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do
describe "with reject action" do
test "works with objects with empty to or cc fields" do
- Config.put([:mrf_object_age, :actions], [:reject])
+ clear_config([:mrf_object_age, :actions], [:reject])
data =
get_old_message()
@@ -50,7 +50,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do
end
test "it rejects an old post" do
- Config.put([:mrf_object_age, :actions], [:reject])
+ clear_config([:mrf_object_age, :actions], [:reject])
data = get_old_message()
@@ -58,7 +58,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do
end
test "it allows a new post" do
- Config.put([:mrf_object_age, :actions], [:reject])
+ clear_config([:mrf_object_age, :actions], [:reject])
data = get_new_message()
@@ -68,7 +68,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do
describe "with delist action" do
test "works with objects with empty to or cc fields" do
- Config.put([:mrf_object_age, :actions], [:delist])
+ clear_config([:mrf_object_age, :actions], [:delist])
data =
get_old_message()
@@ -83,7 +83,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do
end
test "it delists an old post" do
- Config.put([:mrf_object_age, :actions], [:delist])
+ clear_config([:mrf_object_age, :actions], [:delist])
data = get_old_message()
@@ -95,7 +95,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do
end
test "it allows a new post" do
- Config.put([:mrf_object_age, :actions], [:delist])
+ clear_config([:mrf_object_age, :actions], [:delist])
data = get_new_message()
@@ -107,7 +107,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do
describe "with strip_followers action" do
test "works with objects with empty to or cc fields" do
- Config.put([:mrf_object_age, :actions], [:strip_followers])
+ clear_config([:mrf_object_age, :actions], [:strip_followers])
data =
get_old_message()
@@ -123,7 +123,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do
end
test "it strips followers collections from an old post" do
- Config.put([:mrf_object_age, :actions], [:strip_followers])
+ clear_config([:mrf_object_age, :actions], [:strip_followers])
data = get_old_message()
@@ -136,7 +136,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicyTest do
end
test "it allows a new post" do
- Config.put([:mrf_object_age, :actions], [:strip_followers])
+ clear_config([:mrf_object_age, :actions], [:strip_followers])
data = get_new_message()
diff --git a/test/web/activity_pub/mrf/reject_non_public_test.exs b/test/pleroma/web/activity_pub/mrf/reject_non_public_test.exs
index 58b46b9a2..63c68d798 100644
--- a/test/web/activity_pub/mrf/reject_non_public_test.exs
+++ b/test/pleroma/web/activity_pub/mrf/reject_non_public_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublicTest do
@@ -21,7 +21,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublicTest do
"type" => "Create"
}
- assert {:ok, message} = RejectNonPublic.filter(message)
+ assert {:ok, _message} = RejectNonPublic.filter(message)
end
test "it's allowed when cc address contain public address" do
@@ -34,7 +34,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublicTest do
"type" => "Create"
}
- assert {:ok, message} = RejectNonPublic.filter(message)
+ assert {:ok, _message} = RejectNonPublic.filter(message)
end
end
@@ -49,8 +49,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublicTest do
"type" => "Create"
}
- Pleroma.Config.put([:mrf_rejectnonpublic, :allow_followersonly], true)
- assert {:ok, message} = RejectNonPublic.filter(message)
+ clear_config([:mrf_rejectnonpublic, :allow_followersonly], true)
+ assert {:ok, _message} = RejectNonPublic.filter(message)
end
test "it's rejected when addrer of message in the follower addresses of user and it disabled in config" do
@@ -63,7 +63,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublicTest do
"type" => "Create"
}
- Pleroma.Config.put([:mrf_rejectnonpublic, :allow_followersonly], false)
+ clear_config([:mrf_rejectnonpublic, :allow_followersonly], false)
assert {:reject, _} = RejectNonPublic.filter(message)
end
end
@@ -79,8 +79,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublicTest do
"type" => "Create"
}
- Pleroma.Config.put([:mrf_rejectnonpublic, :allow_direct], true)
- assert {:ok, message} = RejectNonPublic.filter(message)
+ clear_config([:mrf_rejectnonpublic, :allow_direct], true)
+ assert {:ok, _message} = RejectNonPublic.filter(message)
end
test "it's reject when direct messages aren't allow" do
@@ -93,7 +93,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublicTest do
"type" => "Create"
}
- Pleroma.Config.put([:mrf_rejectnonpublic, :allow_direct], false)
+ clear_config([:mrf_rejectnonpublic, :allow_direct], false)
assert {:reject, _} = RejectNonPublic.filter(message)
end
end
diff --git a/test/web/activity_pub/mrf/simple_policy_test.exs b/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs
index d7dde62c4..0a0f51bdb 100644
--- a/test/web/activity_pub/mrf/simple_policy_test.exs
+++ b/test/pleroma/web/activity_pub/mrf/simple_policy_test.exs
@@ -1,11 +1,10 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
use Pleroma.DataCase
import Pleroma.Factory
- alias Pleroma.Config
alias Pleroma.Web.ActivityPub.MRF.SimplePolicy
alias Pleroma.Web.CommonAPI
@@ -25,7 +24,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
describe "when :media_removal" do
test "is empty" do
- Config.put([:mrf_simple, :media_removal], [])
+ clear_config([:mrf_simple, :media_removal], [])
media_message = build_media_message()
local_message = build_local_message()
@@ -34,7 +33,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end
test "has a matching host" do
- Config.put([:mrf_simple, :media_removal], ["remote.instance"])
+ clear_config([:mrf_simple, :media_removal], [{"remote.instance", "Some reason"}])
media_message = build_media_message()
local_message = build_local_message()
@@ -47,7 +46,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end
test "match with wildcard domain" do
- Config.put([:mrf_simple, :media_removal], ["*.remote.instance"])
+ clear_config([:mrf_simple, :media_removal], [{"*.remote.instance", "Whatever reason"}])
media_message = build_media_message()
local_message = build_local_message()
@@ -62,7 +61,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
describe "when :media_nsfw" do
test "is empty" do
- Config.put([:mrf_simple, :media_nsfw], [])
+ clear_config([:mrf_simple, :media_nsfw], [])
media_message = build_media_message()
local_message = build_local_message()
@@ -71,29 +70,23 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end
test "has a matching host" do
- Config.put([:mrf_simple, :media_nsfw], ["remote.instance"])
+ clear_config([:mrf_simple, :media_nsfw], [{"remote.instance", "Whetever"}])
media_message = build_media_message()
local_message = build_local_message()
assert SimplePolicy.filter(media_message) ==
- {:ok,
- media_message
- |> put_in(["object", "tag"], ["foo", "nsfw"])
- |> put_in(["object", "sensitive"], true)}
+ {:ok, put_in(media_message, ["object", "sensitive"], true)}
assert SimplePolicy.filter(local_message) == {:ok, local_message}
end
test "match with wildcard domain" do
- Config.put([:mrf_simple, :media_nsfw], ["*.remote.instance"])
+ clear_config([:mrf_simple, :media_nsfw], [{"*.remote.instance", "yeah yeah"}])
media_message = build_media_message()
local_message = build_local_message()
assert SimplePolicy.filter(media_message) ==
- {:ok,
- media_message
- |> put_in(["object", "tag"], ["foo", "nsfw"])
- |> put_in(["object", "sensitive"], true)}
+ {:ok, put_in(media_message, ["object", "sensitive"], true)}
assert SimplePolicy.filter(local_message) == {:ok, local_message}
end
@@ -113,7 +106,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
describe "when :report_removal" do
test "is empty" do
- Config.put([:mrf_simple, :report_removal], [])
+ clear_config([:mrf_simple, :report_removal], [])
report_message = build_report_message()
local_message = build_local_message()
@@ -122,7 +115,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end
test "has a matching host" do
- Config.put([:mrf_simple, :report_removal], ["remote.instance"])
+ clear_config([:mrf_simple, :report_removal], [{"remote.instance", "muh"}])
report_message = build_report_message()
local_message = build_local_message()
@@ -131,7 +124,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end
test "match with wildcard domain" do
- Config.put([:mrf_simple, :report_removal], ["*.remote.instance"])
+ clear_config([:mrf_simple, :report_removal], [{"*.remote.instance", "suya"}])
report_message = build_report_message()
local_message = build_local_message()
@@ -149,7 +142,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
describe "when :federated_timeline_removal" do
test "is empty" do
- Config.put([:mrf_simple, :federated_timeline_removal], [])
+ clear_config([:mrf_simple, :federated_timeline_removal], [])
{_, ftl_message} = build_ftl_actor_and_message()
local_message = build_local_message()
@@ -166,7 +159,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|> URI.parse()
|> Map.fetch!(:host)
- Config.put([:mrf_simple, :federated_timeline_removal], [ftl_message_actor_host])
+ clear_config([:mrf_simple, :federated_timeline_removal], [{ftl_message_actor_host, "uwu"}])
local_message = build_local_message()
assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message)
@@ -187,7 +180,10 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|> URI.parse()
|> Map.fetch!(:host)
- Config.put([:mrf_simple, :federated_timeline_removal], ["*." <> ftl_message_actor_host])
+ clear_config([:mrf_simple, :federated_timeline_removal], [
+ {"*." <> ftl_message_actor_host, "owo"}
+ ])
+
local_message = build_local_message()
assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message)
@@ -210,7 +206,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
ftl_message = Map.put(ftl_message, "cc", [])
- Config.put([:mrf_simple, :federated_timeline_removal], [ftl_message_actor_host])
+ clear_config([:mrf_simple, :federated_timeline_removal], [
+ {ftl_message_actor_host, "spiderwaifu goes 88w88"}
+ ])
assert {:ok, ftl_message} = SimplePolicy.filter(ftl_message)
refute "https://www.w3.org/ns/activitystreams#Public" in ftl_message["to"]
@@ -231,7 +229,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
describe "when :reject" do
test "is empty" do
- Config.put([:mrf_simple, :reject], [])
+ clear_config([:mrf_simple, :reject], [])
remote_message = build_remote_message()
@@ -239,7 +237,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end
test "activity has a matching host" do
- Config.put([:mrf_simple, :reject], ["remote.instance"])
+ clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
remote_message = build_remote_message()
@@ -247,7 +245,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end
test "activity matches with wildcard domain" do
- Config.put([:mrf_simple, :reject], ["*.remote.instance"])
+ clear_config([:mrf_simple, :reject], [{"*.remote.instance", ""}])
remote_message = build_remote_message()
@@ -255,17 +253,41 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end
test "actor has a matching host" do
- Config.put([:mrf_simple, :reject], ["remote.instance"])
+ clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
remote_user = build_remote_user()
assert {:reject, _} = SimplePolicy.filter(remote_user)
end
+
+ test "reject Announce when object would be rejected" do
+ clear_config([:mrf_simple, :reject], [{"blocked.tld", ""}])
+
+ announce = %{
+ "type" => "Announce",
+ "actor" => "https://okay.tld/users/alice",
+ "object" => %{"type" => "Note", "actor" => "https://blocked.tld/users/bob"}
+ }
+
+ assert {:reject, _} = SimplePolicy.filter(announce)
+ end
+
+ test "reject by URI object" do
+ clear_config([:mrf_simple, :reject], [{"blocked.tld", ""}])
+
+ announce = %{
+ "type" => "Announce",
+ "actor" => "https://okay.tld/users/alice",
+ "object" => "https://blocked.tld/activities/1"
+ }
+
+ assert {:reject, _} = SimplePolicy.filter(announce)
+ end
end
describe "when :followers_only" do
test "is empty" do
- Config.put([:mrf_simple, :followers_only], [])
+ clear_config([:mrf_simple, :followers_only], [])
{_, ftl_message} = build_ftl_actor_and_message()
local_message = build_local_message()
@@ -305,7 +327,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
|> URI.parse()
|> Map.fetch!(:host)
- Config.put([:mrf_simple, :followers_only], [actor_domain])
+ clear_config([:mrf_simple, :followers_only], [{actor_domain, ""}])
assert {:ok, new_activity} = SimplePolicy.filter(activity)
assert actor.follower_address in new_activity["cc"]
@@ -323,7 +345,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
describe "when :accept" do
test "is empty" do
- Config.put([:mrf_simple, :accept], [])
+ clear_config([:mrf_simple, :accept], [])
local_message = build_local_message()
remote_message = build_remote_message()
@@ -333,7 +355,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end
test "is not empty but activity doesn't have a matching host" do
- Config.put([:mrf_simple, :accept], ["non.matching.remote"])
+ clear_config([:mrf_simple, :accept], [{"non.matching.remote", ""}])
local_message = build_local_message()
remote_message = build_remote_message()
@@ -343,7 +365,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end
test "activity has a matching host" do
- Config.put([:mrf_simple, :accept], ["remote.instance"])
+ clear_config([:mrf_simple, :accept], [{"remote.instance", ""}])
local_message = build_local_message()
remote_message = build_remote_message()
@@ -353,7 +375,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end
test "activity matches with wildcard domain" do
- Config.put([:mrf_simple, :accept], ["*.remote.instance"])
+ clear_config([:mrf_simple, :accept], [{"*.remote.instance", ""}])
local_message = build_local_message()
remote_message = build_remote_message()
@@ -363,7 +385,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end
test "actor has a matching host" do
- Config.put([:mrf_simple, :accept], ["remote.instance"])
+ clear_config([:mrf_simple, :accept], [{"remote.instance", ""}])
remote_user = build_remote_user()
@@ -373,7 +395,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
describe "when :avatar_removal" do
test "is empty" do
- Config.put([:mrf_simple, :avatar_removal], [])
+ clear_config([:mrf_simple, :avatar_removal], [])
remote_user = build_remote_user()
@@ -381,7 +403,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end
test "is not empty but it doesn't have a matching host" do
- Config.put([:mrf_simple, :avatar_removal], ["non.matching.remote"])
+ clear_config([:mrf_simple, :avatar_removal], [{"non.matching.remote", ""}])
remote_user = build_remote_user()
@@ -389,7 +411,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end
test "has a matching host" do
- Config.put([:mrf_simple, :avatar_removal], ["remote.instance"])
+ clear_config([:mrf_simple, :avatar_removal], [{"remote.instance", ""}])
remote_user = build_remote_user()
{:ok, filtered} = SimplePolicy.filter(remote_user)
@@ -398,7 +420,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end
test "match with wildcard domain" do
- Config.put([:mrf_simple, :avatar_removal], ["*.remote.instance"])
+ clear_config([:mrf_simple, :avatar_removal], [{"*.remote.instance", ""}])
remote_user = build_remote_user()
{:ok, filtered} = SimplePolicy.filter(remote_user)
@@ -409,7 +431,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
describe "when :banner_removal" do
test "is empty" do
- Config.put([:mrf_simple, :banner_removal], [])
+ clear_config([:mrf_simple, :banner_removal], [])
remote_user = build_remote_user()
@@ -417,7 +439,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end
test "is not empty but it doesn't have a matching host" do
- Config.put([:mrf_simple, :banner_removal], ["non.matching.remote"])
+ clear_config([:mrf_simple, :banner_removal], [{"non.matching.remote", ""}])
remote_user = build_remote_user()
@@ -425,7 +447,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end
test "has a matching host" do
- Config.put([:mrf_simple, :banner_removal], ["remote.instance"])
+ clear_config([:mrf_simple, :banner_removal], [{"remote.instance", ""}])
remote_user = build_remote_user()
{:ok, filtered} = SimplePolicy.filter(remote_user)
@@ -434,7 +456,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end
test "match with wildcard domain" do
- Config.put([:mrf_simple, :banner_removal], ["*.remote.instance"])
+ clear_config([:mrf_simple, :banner_removal], [{"*.remote.instance", ""}])
remote_user = build_remote_user()
{:ok, filtered} = SimplePolicy.filter(remote_user)
@@ -444,10 +466,10 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end
describe "when :reject_deletes is empty" do
- setup do: Config.put([:mrf_simple, :reject_deletes], [])
+ setup do: clear_config([:mrf_simple, :reject_deletes], [])
test "it accepts deletions even from rejected servers" do
- Config.put([:mrf_simple, :reject], ["remote.instance"])
+ clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
deletion_message = build_remote_deletion_message()
@@ -455,7 +477,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end
test "it accepts deletions even from non-whitelisted servers" do
- Config.put([:mrf_simple, :accept], ["non.matching.remote"])
+ clear_config([:mrf_simple, :accept], [{"non.matching.remote", ""}])
deletion_message = build_remote_deletion_message()
@@ -464,10 +486,10 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end
describe "when :reject_deletes is not empty but it doesn't have a matching host" do
- setup do: Config.put([:mrf_simple, :reject_deletes], ["non.matching.remote"])
+ setup do: clear_config([:mrf_simple, :reject_deletes], [{"non.matching.remote", ""}])
test "it accepts deletions even from rejected servers" do
- Config.put([:mrf_simple, :reject], ["remote.instance"])
+ clear_config([:mrf_simple, :reject], [{"remote.instance", ""}])
deletion_message = build_remote_deletion_message()
@@ -475,7 +497,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end
test "it accepts deletions even from non-whitelisted servers" do
- Config.put([:mrf_simple, :accept], ["non.matching.remote"])
+ clear_config([:mrf_simple, :accept], [{"non.matching.remote", ""}])
deletion_message = build_remote_deletion_message()
@@ -484,7 +506,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end
describe "when :reject_deletes has a matching host" do
- setup do: Config.put([:mrf_simple, :reject_deletes], ["remote.instance"])
+ setup do: clear_config([:mrf_simple, :reject_deletes], [{"remote.instance", ""}])
test "it rejects the deletion" do
deletion_message = build_remote_deletion_message()
@@ -494,7 +516,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
end
describe "when :reject_deletes match with wildcard domain" do
- setup do: Config.put([:mrf_simple, :reject_deletes], ["*.remote.instance"])
+ setup do: clear_config([:mrf_simple, :reject_deletes], [{"*.remote.instance", ""}])
test "it rejects the deletion" do
deletion_message = build_remote_deletion_message()
@@ -505,7 +527,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
defp build_local_message do
%{
- "actor" => "#{Pleroma.Web.base_url()}/users/alice",
+ "actor" => "#{Pleroma.Web.Endpoint.url()}/users/alice",
"to" => [],
"cc" => []
}
diff --git a/test/pleroma/web/activity_pub/mrf/steal_emoji_policy_test.exs b/test/pleroma/web/activity_pub/mrf/steal_emoji_policy_test.exs
new file mode 100644
index 000000000..1b37e4c26
--- /dev/null
+++ b/test/pleroma/web/activity_pub/mrf/steal_emoji_policy_test.exs
@@ -0,0 +1,108 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicyTest do
+ use Pleroma.DataCase
+
+ alias Pleroma.Config
+ alias Pleroma.Emoji
+ alias Pleroma.Web.ActivityPub.MRF.StealEmojiPolicy
+
+ setup do
+ emoji_path = [:instance, :static_dir] |> Config.get() |> Path.join("emoji/stolen")
+
+ Emoji.reload()
+
+ message = %{
+ "type" => "Create",
+ "object" => %{
+ "emoji" => [{"firedfox", "https://example.org/emoji/firedfox.png"}],
+ "actor" => "https://example.org/users/admin"
+ }
+ }
+
+ on_exit(fn ->
+ File.rm_rf!(emoji_path)
+ end)
+
+ [message: message, path: emoji_path]
+ end
+
+ test "does nothing by default", %{message: message} do
+ refute "firedfox" in installed()
+
+ assert {:ok, _message} = StealEmojiPolicy.filter(message)
+
+ refute "firedfox" in installed()
+ end
+
+ test "Steals emoji on unknown shortcode from allowed remote host", %{
+ message: message,
+ path: path
+ } do
+ refute "firedfox" in installed()
+ refute File.exists?(path)
+
+ Tesla.Mock.mock(fn %{method: :get, url: "https://example.org/emoji/firedfox.png"} ->
+ %Tesla.Env{status: 200, body: File.read!("test/fixtures/image.jpg")}
+ end)
+
+ clear_config(:mrf_steal_emoji, hosts: ["example.org"], size_limit: 284_468)
+
+ assert {:ok, _message} = StealEmojiPolicy.filter(message)
+
+ assert "firedfox" in installed()
+ assert File.exists?(path)
+
+ assert path
+ |> Path.join("firedfox.png")
+ |> File.exists?()
+ end
+
+ test "reject shortcode", %{message: message} do
+ refute "firedfox" in installed()
+
+ clear_config(:mrf_steal_emoji,
+ hosts: ["example.org"],
+ size_limit: 284_468,
+ rejected_shortcodes: [~r/firedfox/]
+ )
+
+ assert {:ok, _message} = StealEmojiPolicy.filter(message)
+
+ refute "firedfox" in installed()
+ end
+
+ test "reject if size is above the limit", %{message: message} do
+ refute "firedfox" in installed()
+
+ Tesla.Mock.mock(fn %{method: :get, url: "https://example.org/emoji/firedfox.png"} ->
+ %Tesla.Env{status: 200, body: File.read!("test/fixtures/image.jpg")}
+ end)
+
+ clear_config(:mrf_steal_emoji, hosts: ["example.org"], size_limit: 50_000)
+
+ assert {:ok, _message} = StealEmojiPolicy.filter(message)
+
+ refute "firedfox" in installed()
+ end
+
+ test "reject if host returns error", %{message: message} do
+ refute "firedfox" in installed()
+
+ Tesla.Mock.mock(fn %{method: :get, url: "https://example.org/emoji/firedfox.png"} ->
+ {:ok, %Tesla.Env{status: 404, body: "Not found"}}
+ end)
+
+ clear_config(:mrf_steal_emoji, hosts: ["example.org"], size_limit: 284_468)
+
+ ExUnit.CaptureLog.capture_log(fn ->
+ assert {:ok, _message} = StealEmojiPolicy.filter(message)
+ end) =~ "MRF.StealEmojiPolicy: Failed to fetch https://example.org/emoji/firedfox.png"
+
+ refute "firedfox" in installed()
+ end
+
+ defp installed, do: Emoji.get_all() |> Enum.map(fn {k, _} -> k end)
+end
diff --git a/test/web/activity_pub/mrf/subchain_policy_test.exs b/test/pleroma/web/activity_pub/mrf/subchain_policy_test.exs
index fff66cb7e..4f5cc466c 100644
--- a/test/web/activity_pub/mrf/subchain_policy_test.exs
+++ b/test/pleroma/web/activity_pub/mrf/subchain_policy_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.SubchainPolicyTest do
@@ -16,7 +16,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SubchainPolicyTest do
setup do: clear_config([:mrf_subchain, :match_actor])
test "it matches and processes subchains when the actor matches a configured target" do
- Pleroma.Config.put([:mrf_subchain, :match_actor], %{
+ clear_config([:mrf_subchain, :match_actor], %{
~r/^https:\/\/banned.com/s => [DropPolicy]
})
@@ -24,7 +24,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SubchainPolicyTest do
end
test "it doesn't match and process subchains when the actor doesn't match a configured target" do
- Pleroma.Config.put([:mrf_subchain, :match_actor], %{
+ clear_config([:mrf_subchain, :match_actor], %{
~r/^https:\/\/borked.com/s => [DropPolicy]
})
diff --git a/test/web/activity_pub/mrf/tag_policy_test.exs b/test/pleroma/web/activity_pub/mrf/tag_policy_test.exs
index 6ff71d640..faaadff79 100644
--- a/test/web/activity_pub/mrf/tag_policy_test.exs
+++ b/test/pleroma/web/activity_pub/mrf/tag_policy_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.TagPolicyTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
import Pleroma.Factory
alias Pleroma.Web.ActivityPub.MRF.TagPolicy
@@ -29,7 +29,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicyTest do
actor = insert(:user, tags: ["mrf_tag:disable-remote-subscription"])
follower = insert(:user, tags: ["mrf_tag:disable-remote-subscription"], local: true)
message = %{"object" => actor.ap_id, "type" => "Follow", "actor" => follower.ap_id}
- assert {:ok, message} = TagPolicy.filter(message)
+ assert {:ok, _message} = TagPolicy.filter(message)
end
end
@@ -114,7 +114,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicyTest do
except_message = %{
"actor" => actor.ap_id,
"type" => "Create",
- "object" => %{"tag" => ["test", "nsfw"], "attachment" => ["file1"], "sensitive" => true}
+ "object" => %{"tag" => ["test"], "attachment" => ["file1"], "sensitive" => true}
}
assert TagPolicy.filter(message) == {:ok, except_message}
diff --git a/test/web/activity_pub/mrf/user_allowlist_policy_test.exs b/test/pleroma/web/activity_pub/mrf/user_allow_list_policy_test.exs
index 8e1ad5bc8..f0432ea42 100644
--- a/test/web/activity_pub/mrf/user_allowlist_policy_test.exs
+++ b/test/pleroma/web/activity_pub/mrf/user_allow_list_policy_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.UserAllowListPolicyTest do
use Pleroma.DataCase
@@ -17,14 +17,14 @@ defmodule Pleroma.Web.ActivityPub.MRF.UserAllowListPolicyTest do
test "pass filter if allow list isn't empty and user in allow list" do
actor = insert(:user)
- Pleroma.Config.put([:mrf_user_allowlist], %{"localhost" => [actor.ap_id, "test-ap-id"]})
+ clear_config([:mrf_user_allowlist], %{"localhost" => [actor.ap_id, "test-ap-id"]})
message = %{"actor" => actor.ap_id}
assert UserAllowListPolicy.filter(message) == {:ok, message}
end
test "rejected if allow list isn't empty and user not in allow list" do
actor = insert(:user)
- Pleroma.Config.put([:mrf_user_allowlist], %{"localhost" => ["test-ap-id"]})
+ clear_config([:mrf_user_allowlist], %{"localhost" => ["test-ap-id"]})
message = %{"actor" => actor.ap_id}
assert {:reject, _} = UserAllowListPolicy.filter(message)
end
diff --git a/test/web/activity_pub/mrf/vocabulary_policy_test.exs b/test/pleroma/web/activity_pub/mrf/vocabulary_policy_test.exs
index 2bceb67ee..87d1d79b5 100644
--- a/test/web/activity_pub/mrf/vocabulary_policy_test.exs
+++ b/test/pleroma/web/activity_pub/mrf/vocabulary_policy_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicyTest do
@@ -11,7 +11,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicyTest do
setup do: clear_config([:mrf_vocabulary, :accept])
test "it accepts based on parent activity type" do
- Pleroma.Config.put([:mrf_vocabulary, :accept], ["Like"])
+ clear_config([:mrf_vocabulary, :accept], ["Like"])
message = %{
"type" => "Like",
@@ -22,7 +22,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicyTest do
end
test "it accepts based on child object type" do
- Pleroma.Config.put([:mrf_vocabulary, :accept], ["Create", "Note"])
+ clear_config([:mrf_vocabulary, :accept], ["Create", "Note"])
message = %{
"type" => "Create",
@@ -36,7 +36,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicyTest do
end
test "it does not accept disallowed child objects" do
- Pleroma.Config.put([:mrf_vocabulary, :accept], ["Create", "Note"])
+ clear_config([:mrf_vocabulary, :accept], ["Create", "Note"])
message = %{
"type" => "Create",
@@ -50,7 +50,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicyTest do
end
test "it does not accept disallowed parent types" do
- Pleroma.Config.put([:mrf_vocabulary, :accept], ["Announce", "Note"])
+ clear_config([:mrf_vocabulary, :accept], ["Announce", "Note"])
message = %{
"type" => "Create",
@@ -68,7 +68,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicyTest do
setup do: clear_config([:mrf_vocabulary, :reject])
test "it rejects based on parent activity type" do
- Pleroma.Config.put([:mrf_vocabulary, :reject], ["Like"])
+ clear_config([:mrf_vocabulary, :reject], ["Like"])
message = %{
"type" => "Like",
@@ -79,7 +79,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicyTest do
end
test "it rejects based on child object type" do
- Pleroma.Config.put([:mrf_vocabulary, :reject], ["Note"])
+ clear_config([:mrf_vocabulary, :reject], ["Note"])
message = %{
"type" => "Create",
@@ -93,7 +93,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicyTest do
end
test "it passes through objects that aren't disallowed" do
- Pleroma.Config.put([:mrf_vocabulary, :reject], ["Like"])
+ clear_config([:mrf_vocabulary, :reject], ["Like"])
message = %{
"type" => "Announce",
diff --git a/test/web/activity_pub/mrf/mrf_test.exs b/test/pleroma/web/activity_pub/mrf_test.exs
index a63b25423..6ab27bc86 100644
--- a/test/web/activity_pub/mrf/mrf_test.exs
+++ b/test/pleroma/web/activity_pub/mrf_test.exs
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.ActivityPub.MRFTest do
use ExUnit.Case, async: true
use Pleroma.Tests.Helpers
@@ -59,10 +63,26 @@ defmodule Pleroma.Web.ActivityPub.MRFTest do
end
end
+ describe "instance_list_from_tuples/1" do
+ test "returns a list of instances from a list of {instance, reason} tuples" do
+ list = [{"some.tld", "a reason"}, {"other.tld", "another reason"}]
+ expected = ["some.tld", "other.tld"]
+
+ assert MRF.instance_list_from_tuples(list) == expected
+ end
+ end
+
describe "describe/0" do
test "it works as expected with noop policy" do
+ clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.NoOpPolicy])
+
expected = %{
- mrf_policies: ["NoOpPolicy"],
+ mrf_policies: ["NoOpPolicy", "HashtagPolicy"],
+ mrf_hashtag: %{
+ federated_timeline_removal: [],
+ reject: [],
+ sensitive: ["nsfw"]
+ },
exclusions: false
}
@@ -73,12 +93,33 @@ defmodule Pleroma.Web.ActivityPub.MRFTest do
clear_config([:mrf, :policies], [MRFModuleMock])
expected = %{
- mrf_policies: ["MRFModuleMock"],
+ mrf_policies: ["MRFModuleMock", "HashtagPolicy"],
mrf_module_mock: "some config data",
+ mrf_hashtag: %{
+ federated_timeline_removal: [],
+ reject: [],
+ sensitive: ["nsfw"]
+ },
exclusions: false
}
{:ok, ^expected} = MRF.describe()
end
end
+
+ test "config_descriptions/0" do
+ descriptions = MRF.config_descriptions()
+
+ good_mrf = Enum.find(descriptions, fn %{key: key} -> key == :good_mrf end)
+
+ assert good_mrf == %{
+ key: :good_mrf,
+ related_policy: "Fixtures.Modules.GoodMRF",
+ label: "Good MRF",
+ description: "Some description",
+ group: :pleroma,
+ tab: :mrf,
+ type: :group
+ }
+ end
end
diff --git a/test/web/activity_pub/object_validators/accept_validation_test.exs b/test/pleroma/web/activity_pub/object_validators/accept_validation_test.exs
index d6111ba41..ddb302f6e 100644
--- a/test/web/activity_pub/object_validators/accept_validation_test.exs
+++ b/test/pleroma/web/activity_pub/object_validators/accept_validation_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ObjectValidators.AcceptValidationTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.ObjectValidator
diff --git a/test/web/activity_pub/object_validators/announce_validation_test.exs b/test/pleroma/web/activity_pub/object_validators/announce_validation_test.exs
index 623342f76..20964e855 100644
--- a/test/web/activity_pub/object_validators/announce_validation_test.exs
+++ b/test/pleroma/web/activity_pub/object_validators/announce_validation_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnnouncValidationTest do
- use Pleroma.DataCase
+defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnnounceValidationTest do
+ use Pleroma.DataCase, async: true
alias Pleroma.Object
alias Pleroma.Web.ActivityPub.Builder
@@ -18,7 +18,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnnouncValidationTest do
announcer = insert(:user)
{:ok, post_activity} = CommonAPI.post(user, %{status: "uguu"})
- object = Object.normalize(post_activity, false)
+ object = Object.normalize(post_activity, fetch: false)
{:ok, valid_announce, []} = Builder.announce(announcer, object)
%{
@@ -33,6 +33,18 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnnouncValidationTest do
assert {:ok, _object, _meta} = ObjectValidator.validate(valid_announce, [])
end
+ test "keeps announced object context", %{valid_announce: valid_announce} do
+ assert %Object{data: %{"context" => object_context}} =
+ Object.get_cached_by_ap_id(valid_announce["object"])
+
+ {:ok, %{"context" => context}, _} =
+ valid_announce
+ |> Map.put("context", "https://example.org/invalid_context_id")
+ |> ObjectValidator.validate([])
+
+ assert context == object_context
+ end
+
test "returns an error if the object can't be found", %{valid_announce: valid_announce} do
without_object =
valid_announce
@@ -51,16 +63,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnnouncValidationTest do
assert {:object, {"can't find object", []}} in cng.errors
end
- test "returns an error if we don't have the actor", %{valid_announce: valid_announce} do
- nonexisting_actor =
- valid_announce
- |> Map.put("actor", "https://gensokyo.2hu/users/raymoo")
-
- {:error, cng} = ObjectValidator.validate(nonexisting_actor, [])
-
- assert {:actor, {"can't find user", []}} in cng.errors
- end
-
test "returns an error if the actor already announced the object", %{
valid_announce: valid_announce,
announcer: announcer,
@@ -81,7 +83,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnnouncValidationTest do
{:ok, post_activity} =
CommonAPI.post(user, %{status: "a secret post", visibility: "private"})
- object = Object.normalize(post_activity, false)
+ object = Object.normalize(post_activity, fetch: false)
# Another user can't announce it
{:ok, announce, []} = Builder.announce(announcer, object, public: false)
diff --git a/test/web/activity_pub/object_validators/note_validator_test.exs b/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs
index 30c481ffb..720c17d8d 100644
--- a/test/web/activity_pub/object_validators/note_validator_test.exs
+++ b/test/pleroma/web/activity_pub/object_validators/article_note_page_validator_test.exs
@@ -1,11 +1,11 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Web.ActivityPub.ObjectValidators.NoteValidatorTest do
- use Pleroma.DataCase
+defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidatorTest do
+ use Pleroma.DataCase, async: true
- alias Pleroma.Web.ActivityPub.ObjectValidators.NoteValidator
+ alias Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator
alias Pleroma.Web.ActivityPub.Utils
import Pleroma.Factory
@@ -29,7 +29,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.NoteValidatorTest do
end
test "a basic note validates", %{note: note} do
- %{valid?: true} = NoteValidator.cast_and_validate(note)
+ %{valid?: true} = ArticleNotePageValidator.cast_and_validate(note)
end
end
end
diff --git a/test/web/activity_pub/object_validators/attachment_validator_test.exs b/test/pleroma/web/activity_pub/object_validators/attachment_validator_test.exs
index 558bb3131..9150b8d41 100644
--- a/test/web/activity_pub/object_validators/attachment_validator_test.exs
+++ b/test/pleroma/web/activity_pub/object_validators/attachment_validator_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidatorTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator
@@ -33,7 +33,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidatorTest do
"http://mastodon.example.org/system/media_attachments/files/000/000/002/original/334ce029e7bfb920.jpg",
"type" => "Document",
"name" => nil,
- "mediaType" => "image/jpeg"
+ "mediaType" => "image/jpeg",
+ "blurhash" => "UD9jJz~VSbR#xT$~%KtQX9R,WAs9RjWBs:of"
}
{:ok, attachment} =
@@ -50,13 +51,14 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidatorTest do
] = attachment.url
assert attachment.mediaType == "image/jpeg"
+ assert attachment.blurhash == "UD9jJz~VSbR#xT$~%KtQX9R,WAs9RjWBs:of"
end
test "it handles our own uploads" do
user = insert(:user)
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}
@@ -70,5 +72,70 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidatorTest do
assert attachment.mediaType == "image/jpeg"
end
+
+ test "it handles image dimensions" do
+ attachment = %{
+ "url" => [
+ %{
+ "type" => "Link",
+ "mediaType" => "image/jpeg",
+ "href" => "https://example.com/images/1.jpg",
+ "width" => 200,
+ "height" => 100
+ }
+ ],
+ "type" => "Document",
+ "name" => nil,
+ "mediaType" => "image/jpeg"
+ }
+
+ {:ok, attachment} =
+ AttachmentValidator.cast_and_validate(attachment)
+ |> Ecto.Changeset.apply_action(:insert)
+
+ assert [
+ %{
+ href: "https://example.com/images/1.jpg",
+ type: "Link",
+ mediaType: "image/jpeg",
+ width: 200,
+ height: 100
+ }
+ ] = attachment.url
+
+ assert attachment.mediaType == "image/jpeg"
+ end
+
+ test "it transforms image dimentions to our internal format" do
+ attachment = %{
+ "type" => "Document",
+ "name" => "Hello world",
+ "url" => "https://media.example.tld/1.jpg",
+ "width" => 880,
+ "height" => 960,
+ "mediaType" => "image/jpeg",
+ "blurhash" => "eTKL26+HDjcEIBVl;ds+K6t301W.t7nit7y1E,R:v}ai4nXSt7V@of"
+ }
+
+ expected = %AttachmentValidator{
+ type: "Document",
+ name: "Hello world",
+ mediaType: "image/jpeg",
+ blurhash: "eTKL26+HDjcEIBVl;ds+K6t301W.t7nit7y1E,R:v}ai4nXSt7V@of",
+ url: [
+ %AttachmentValidator.UrlObjectValidator{
+ type: "Link",
+ mediaType: "image/jpeg",
+ href: "https://media.example.tld/1.jpg",
+ width: 880,
+ height: 960
+ }
+ ]
+ }
+
+ {:ok, ^expected} =
+ AttachmentValidator.cast_and_validate(attachment)
+ |> Ecto.Changeset.apply_action(:insert)
+ end
end
end
diff --git a/test/web/activity_pub/object_validators/block_validation_test.exs b/test/pleroma/web/activity_pub/object_validators/block_validation_test.exs
index c08d4b2e8..ad6190892 100644
--- a/test/web/activity_pub/object_validators/block_validation_test.exs
+++ b/test/pleroma/web/activity_pub/object_validators/block_validation_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ObjectValidators.BlockValidationTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.ObjectValidator
diff --git a/test/web/activity_pub/object_validators/chat_validation_test.exs b/test/pleroma/web/activity_pub/object_validators/chat_validation_test.exs
index 16e4808e5..def2a10b4 100644
--- a/test/web/activity_pub/object_validators/chat_validation_test.exs
+++ b/test/pleroma/web/activity_pub/object_validators/chat_validation_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ObjectValidators.ChatValidationTest do
@@ -17,7 +17,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ChatValidationTest do
user = insert(:user)
recipient = insert(:user)
{:ok, activity} = CommonAPI.post_chat_message(user, recipient, "hey")
- object = Object.normalize(activity, false)
+ object = Object.normalize(activity, fetch: false)
{:ok, create_data, _} = Builder.create(user, object.data, [recipient.ap_id])
@@ -68,7 +68,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ChatValidationTest do
test "validates for a basic object we build", %{valid_chat_message: valid_chat_message} do
assert {:ok, object, _meta} = ObjectValidator.validate(valid_chat_message, [])
- assert Map.put(valid_chat_message, "attachment", nil) == object
+ assert valid_chat_message == object
assert match?(%{"firefox" => _}, object["emoji"])
end
@@ -77,7 +77,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ChatValidationTest do
user: user
} do
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}
@@ -98,7 +98,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ChatValidationTest do
user: user
} do
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}
@@ -119,7 +119,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ChatValidationTest do
user: user
} do
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}
@@ -149,7 +149,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ChatValidationTest do
test "does not validate if the message is longer than the remote_limit", %{
valid_chat_message: valid_chat_message
} do
- Pleroma.Config.put([:instance, :remote_limit], 2)
+ clear_config([:instance, :remote_limit], 2)
refute match?({:ok, _object, _meta}, ObjectValidator.validate(valid_chat_message, []))
end
diff --git a/test/web/activity_pub/object_validators/delete_validation_test.exs b/test/pleroma/web/activity_pub/object_validators/delete_validation_test.exs
index 02683b899..7ae4399ed 100644
--- a/test/web/activity_pub/object_validators/delete_validation_test.exs
+++ b/test/pleroma/web/activity_pub/object_validators/delete_validation_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ObjectValidators.DeleteValidationTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Object
alias Pleroma.Web.ActivityPub.Builder
diff --git a/test/web/activity_pub/object_validators/emoji_react_validation_test.exs b/test/pleroma/web/activity_pub/object_validators/emoji_react_handling_test.exs
index 582e6d785..7fd98266a 100644
--- a/test/web/activity_pub/object_validators/emoji_react_validation_test.exs
+++ b/test/pleroma/web/activity_pub/object_validators/emoji_react_handling_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactHandlingTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.ObjectValidator
diff --git a/test/web/activity_pub/object_validators/follow_validation_test.exs b/test/pleroma/web/activity_pub/object_validators/follow_validation_test.exs
index 6e1378be2..d2a9b72a5 100644
--- a/test/web/activity_pub/object_validators/follow_validation_test.exs
+++ b/test/pleroma/web/activity_pub/object_validators/follow_validation_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ObjectValidators.FollowValidationTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.ObjectValidator
diff --git a/test/web/activity_pub/object_validators/like_validation_test.exs b/test/pleroma/web/activity_pub/object_validators/like_validation_test.exs
index 2c033b7e2..e9ad817f1 100644
--- a/test/web/activity_pub/object_validators/like_validation_test.exs
+++ b/test/pleroma/web/activity_pub/object_validators/like_validation_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ObjectValidators.LikeValidationTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Web.ActivityPub.ObjectValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
@@ -40,17 +40,30 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.LikeValidationTest do
assert LikeValidator.cast_and_validate(valid_like).valid?
end
- test "sets the 'to' field to the object actor if no recipients are given", %{
+ test "Add object actor from 'to' field if it doesn't owns the like", %{valid_like: valid_like} do
+ user = insert(:user)
+
+ object_actor = valid_like["actor"]
+
+ valid_like =
+ valid_like
+ |> Map.put("actor", user.ap_id)
+ |> Map.put("to", [])
+
+ {:ok, object, _meta} = ObjectValidator.validate(valid_like, [])
+ assert object_actor in object["to"]
+ end
+
+ test "Removes object actor from 'to' field if it owns the like", %{
valid_like: valid_like,
user: user
} do
- without_recipients =
+ valid_like =
valid_like
- |> Map.delete("to")
+ |> Map.put("to", [user.ap_id])
- {:ok, object, _meta} = ObjectValidator.validate(without_recipients, [])
-
- assert object["to"] == [user.ap_id]
+ {:ok, object, _meta} = ObjectValidator.validate(valid_like, [])
+ refute user.ap_id in object["to"]
end
test "sets the context field to the context of the object if no context is given", %{
@@ -66,16 +79,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.LikeValidationTest do
assert object["context"] == post_activity.data["context"]
end
- test "it errors when the actor is missing or not known", %{valid_like: valid_like} do
- without_actor = Map.delete(valid_like, "actor")
-
- refute LikeValidator.cast_and_validate(without_actor).valid?
-
- with_invalid_actor = Map.put(valid_like, "actor", "invalidactor")
-
- refute LikeValidator.cast_and_validate(with_invalid_actor).valid?
- end
-
test "it errors when the object is missing or not known", %{valid_like: valid_like} do
without_object = Map.delete(valid_like, "object")
diff --git a/test/web/activity_pub/object_validators/reject_validation_test.exs b/test/pleroma/web/activity_pub/object_validators/reject_validation_test.exs
index 370bb6e5c..562656a5f 100644
--- a/test/web/activity_pub/object_validators/reject_validation_test.exs
+++ b/test/pleroma/web/activity_pub/object_validators/reject_validation_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ObjectValidators.RejectValidationTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.ObjectValidator
diff --git a/test/web/activity_pub/object_validators/undo_validation_test.exs b/test/pleroma/web/activity_pub/object_validators/undo_handling_test.exs
index 75bbcc4b6..505ca2d2f 100644
--- a/test/web/activity_pub/object_validators/undo_validation_test.exs
+++ b/test/pleroma/web/activity_pub/object_validators/undo_handling_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ObjectValidators.UndoHandlingTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.ObjectValidator
diff --git a/test/web/activity_pub/object_validators/update_validation_test.exs b/test/pleroma/web/activity_pub/object_validators/update_handling_test.exs
index 5e80cf731..15e4a82cd 100644
--- a/test/web/activity_pub/object_validators/update_validation_test.exs
+++ b/test/pleroma/web/activity_pub/object_validators/update_handling_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ObjectValidators.UpdateHandlingTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.ObjectValidator
diff --git a/test/pleroma/web/activity_pub/pipeline_test.exs b/test/pleroma/web/activity_pub/pipeline_test.exs
new file mode 100644
index 000000000..e606fa3d1
--- /dev/null
+++ b/test/pleroma/web/activity_pub/pipeline_test.exs
@@ -0,0 +1,103 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.PipelineTest do
+ use Pleroma.DataCase, async: true
+
+ import Mox
+ import Pleroma.Factory
+
+ alias Pleroma.ConfigMock
+ alias Pleroma.Web.ActivityPub.ActivityPubMock
+ alias Pleroma.Web.ActivityPub.MRFMock
+ alias Pleroma.Web.ActivityPub.ObjectValidatorMock
+ alias Pleroma.Web.ActivityPub.SideEffectsMock
+ alias Pleroma.Web.FederatorMock
+
+ setup :verify_on_exit!
+
+ describe "common_pipeline/2" do
+ setup do
+ ObjectValidatorMock
+ |> expect(:validate, fn o, m -> {:ok, o, m} end)
+
+ MRFMock
+ |> expect(:pipeline_filter, fn o, m -> {:ok, o, m} end)
+
+ SideEffectsMock
+ |> expect(:handle, fn o, m -> {:ok, o, m} end)
+ |> expect(:handle_after_transaction, fn m -> m end)
+
+ :ok
+ end
+
+ test "when given an `object_data` in meta, Federation will receive a the original activity with the `object` field set to this embedded object" do
+ activity = insert(:note_activity)
+ object = %{"id" => "1", "type" => "Love"}
+ meta = [local: true, object_data: object]
+
+ activity_with_object = %{activity | data: Map.put(activity.data, "object", object)}
+
+ ActivityPubMock
+ |> expect(:persist, fn _, m -> {:ok, activity, m} end)
+
+ FederatorMock
+ |> expect(:publish, fn ^activity_with_object -> :ok end)
+
+ ConfigMock
+ |> expect(:get, fn [:instance, :federating] -> true end)
+
+ assert {:ok, ^activity, ^meta} =
+ Pleroma.Web.ActivityPub.Pipeline.common_pipeline(
+ activity.data,
+ meta
+ )
+ end
+
+ test "it goes through validation, filtering, persisting, side effects and federation for local activities" do
+ activity = insert(:note_activity)
+ meta = [local: true]
+
+ ActivityPubMock
+ |> expect(:persist, fn _, m -> {:ok, activity, m} end)
+
+ FederatorMock
+ |> expect(:publish, fn ^activity -> :ok end)
+
+ ConfigMock
+ |> expect(:get, fn [:instance, :federating] -> true end)
+
+ assert {:ok, ^activity, ^meta} =
+ Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity.data, meta)
+ end
+
+ test "it goes through validation, filtering, persisting, side effects without federation for remote activities" do
+ activity = insert(:note_activity)
+ meta = [local: false]
+
+ ActivityPubMock
+ |> expect(:persist, fn _, m -> {:ok, activity, m} end)
+
+ ConfigMock
+ |> expect(:get, fn [:instance, :federating] -> true end)
+
+ assert {:ok, ^activity, ^meta} =
+ Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity.data, meta)
+ end
+
+ test "it goes through validation, filtering, persisting, side effects without federation for local activities if federation is deactivated" do
+ activity = insert(:note_activity)
+ meta = [local: true]
+
+ ActivityPubMock
+ |> expect(:persist, fn _, m -> {:ok, activity, m} end)
+
+ ConfigMock
+ |> expect(:get, fn [:instance, :federating] -> false end)
+
+ assert {:ok, ^activity, ^meta} =
+ Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity.data, meta)
+ end
+ end
+end
diff --git a/test/web/activity_pub/publisher_test.exs b/test/pleroma/web/activity_pub/publisher_test.exs
index b9388b966..b50e22bbe 100644
--- a/test/web/activity_pub/publisher_test.exs
+++ b/test/pleroma/web/activity_pub/publisher_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.PublisherTest do
@@ -38,7 +38,7 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
},
%{
"rel" => "http://ostatus.org/schema/1.0/subscribe",
- "template" => "#{Pleroma.Web.base_url()}/ostatus_subscribe?acct={uri}"
+ "template" => "#{Pleroma.Web.Endpoint.url()}/ostatus_subscribe?acct={uri}"
}
]
@@ -267,6 +267,80 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
end
describe "publish/2" do
+ test_with_mock "doesn't publish a non-public activity to quarantined instances.",
+ Pleroma.Web.Federator.Publisher,
+ [:passthrough],
+ [] do
+ Config.put([:instance, :quarantined_instances], [{"domain.com", "some reason"}])
+
+ follower =
+ insert(:user, %{
+ local: false,
+ inbox: "https://domain.com/users/nick1/inbox",
+ ap_enabled: true
+ })
+
+ actor = insert(:user, follower_address: follower.ap_id)
+
+ {:ok, follower, actor} = Pleroma.User.follow(follower, actor)
+ actor = refresh_record(actor)
+
+ note_activity =
+ insert(:followers_only_note_activity,
+ user: actor,
+ recipients: [follower.ap_id]
+ )
+
+ res = Publisher.publish(actor, note_activity)
+
+ assert res == :ok
+
+ assert not called(
+ Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{
+ inbox: "https://domain.com/users/nick1/inbox",
+ actor_id: actor.id,
+ id: note_activity.data["id"]
+ })
+ )
+ end
+
+ test_with_mock "Publishes a non-public activity to non-quarantined instances.",
+ Pleroma.Web.Federator.Publisher,
+ [:passthrough],
+ [] do
+ Config.put([:instance, :quarantined_instances], [{"somedomain.com", "some reason"}])
+
+ follower =
+ insert(:user, %{
+ local: false,
+ inbox: "https://domain.com/users/nick1/inbox",
+ ap_enabled: true
+ })
+
+ actor = insert(:user, follower_address: follower.ap_id)
+
+ {:ok, follower, actor} = Pleroma.User.follow(follower, actor)
+ actor = refresh_record(actor)
+
+ note_activity =
+ insert(:followers_only_note_activity,
+ user: actor,
+ recipients: [follower.ap_id]
+ )
+
+ res = Publisher.publish(actor, note_activity)
+
+ assert res == :ok
+
+ assert called(
+ Pleroma.Web.Federator.Publisher.enqueue_one(Publisher, %{
+ inbox: "https://domain.com/users/nick1/inbox",
+ actor_id: actor.id,
+ id: note_activity.data["id"]
+ })
+ )
+ end
+
test_with_mock "publishes an activity with BCC to all relevant peers.",
Pleroma.Web.Federator.Publisher,
[:passthrough],
@@ -281,8 +355,7 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
actor = insert(:user, follower_address: follower.ap_id)
user = insert(:user)
- {:ok, _follower_one} = Pleroma.User.follow(follower, actor)
- actor = refresh_record(actor)
+ {:ok, follower, actor} = Pleroma.User.follow(follower, actor)
note_activity =
insert(:note_activity,
@@ -323,7 +396,7 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
actor = insert(:user)
note_activity = insert(:note_activity, user: actor)
- object = Object.normalize(note_activity)
+ object = Object.normalize(note_activity, fetch: false)
activity_path = String.trim_leading(note_activity.data["id"], Pleroma.Web.Endpoint.url())
object_path = String.trim_leading(object.data["id"], Pleroma.Web.Endpoint.url())
diff --git a/test/web/activity_pub/relay_test.exs b/test/pleroma/web/activity_pub/relay_test.exs
index 9d657ac4f..d6de7d61e 100644
--- a/test/web/activity_pub/relay_test.exs
+++ b/test/pleroma/web/activity_pub/relay_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.RelayTest do
@@ -63,6 +63,46 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do
assert activity.data["to"] == [user.ap_id]
refute "#{user.ap_id}/followers" in User.following(service_actor)
end
+
+ test "force unfollow when target service is dead" do
+ user = insert(:user)
+ user_ap_id = user.ap_id
+ user_id = user.id
+
+ Tesla.Mock.mock(fn %{method: :get, url: ^user_ap_id} ->
+ %Tesla.Env{status: 404}
+ end)
+
+ service_actor = Relay.get_actor()
+ CommonAPI.follow(service_actor, user)
+ assert "#{user.ap_id}/followers" in User.following(service_actor)
+
+ assert Pleroma.Repo.get_by(
+ Pleroma.FollowingRelationship,
+ follower_id: service_actor.id,
+ following_id: user_id
+ )
+
+ Pleroma.Repo.delete(user)
+ User.invalidate_cache(user)
+
+ assert {:ok, %Activity{} = activity} = Relay.unfollow(user_ap_id, %{force: true})
+
+ assert refresh_record(service_actor).following_count == 0
+
+ refute Pleroma.Repo.get_by(
+ Pleroma.FollowingRelationship,
+ follower_id: service_actor.id,
+ following_id: user_id
+ )
+
+ assert activity.actor == "#{Pleroma.Web.Endpoint.url()}/relay"
+ assert user.ap_id in activity.recipients
+ assert activity.data["type"] == "Undo"
+ assert activity.data["actor"] == service_actor.ap_id
+ assert activity.data["to"] == [user_ap_id]
+ refute "#{user.ap_id}/followers" in User.following(service_actor)
+ end
end
describe "publish/1" do
@@ -108,7 +148,7 @@ defmodule Pleroma.Web.ActivityPub.RelayTest do
assert {:ok, %Activity{} = activity} = Relay.publish(note)
assert activity.data["type"] == "Announce"
assert activity.data["actor"] == service_actor.ap_id
- assert activity.data["to"] == [service_actor.follower_address]
+ assert service_actor.follower_address in activity.data["to"]
assert called(Pleroma.Web.Federator.publish(activity))
end
diff --git a/test/pleroma/web/activity_pub/side_effects/delete_test.exs b/test/pleroma/web/activity_pub/side_effects/delete_test.exs
new file mode 100644
index 000000000..20f0d4b70
--- /dev/null
+++ b/test/pleroma/web/activity_pub/side_effects/delete_test.exs
@@ -0,0 +1,147 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.SideEffects.DeleteTest do
+ use Oban.Testing, repo: Pleroma.Repo
+ use Pleroma.DataCase, async: true
+
+ alias Pleroma.Activity
+ alias Pleroma.Object
+ alias Pleroma.Repo
+ alias Pleroma.Tests.ObanHelpers
+ alias Pleroma.User
+ alias Pleroma.Web.ActivityPub.ActivityPub
+ alias Pleroma.Web.ActivityPub.Builder
+ alias Pleroma.Web.ActivityPub.SideEffects
+ alias Pleroma.Web.CommonAPI
+
+ alias Pleroma.LoggerMock
+ alias Pleroma.Web.ActivityPub.ActivityPubMock
+
+ import Mox
+ import Pleroma.Factory
+
+ describe "user deletion" do
+ setup do
+ user = insert(:user)
+
+ {:ok, delete_user_data, _meta} = Builder.delete(user, user.ap_id)
+ {:ok, delete_user, _meta} = ActivityPub.persist(delete_user_data, local: true)
+
+ %{
+ user: user,
+ delete_user: delete_user
+ }
+ end
+
+ test "it handles user deletions", %{delete_user: delete, user: user} do
+ {:ok, _delete, _} = SideEffects.handle(delete)
+ ObanHelpers.perform_all()
+
+ refute User.get_cached_by_ap_id(user.ap_id).is_active
+ end
+ end
+
+ describe "object deletion" do
+ setup do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, op} = CommonAPI.post(other_user, %{status: "big oof"})
+ {:ok, post} = CommonAPI.post(user, %{status: "hey", in_reply_to_id: op})
+ {:ok, favorite} = CommonAPI.favorite(user, post.id)
+ object = Object.normalize(post, fetch: false)
+ {:ok, delete_data, _meta} = Builder.delete(user, object.data["id"])
+ {:ok, delete, _meta} = ActivityPub.persist(delete_data, local: true)
+
+ %{
+ user: user,
+ delete: delete,
+ post: post,
+ object: object,
+ op: op,
+ favorite: favorite
+ }
+ end
+
+ test "it handles object deletions", %{
+ delete: delete,
+ post: post,
+ object: object,
+ user: user,
+ op: op,
+ favorite: favorite
+ } do
+ object_id = object.id
+ user_id = user.id
+
+ ActivityPubMock
+ |> expect(:stream_out, fn ^delete -> nil end)
+ |> expect(:stream_out_participations, fn %Object{id: ^object_id}, %User{id: ^user_id} ->
+ nil
+ end)
+
+ {:ok, _delete, _} = SideEffects.handle(delete)
+ user = User.get_cached_by_ap_id(object.data["actor"])
+
+ object = Object.get_by_id(object.id)
+ assert object.data["type"] == "Tombstone"
+ refute Activity.get_by_id(post.id)
+ refute Activity.get_by_id(favorite.id)
+
+ user = User.get_by_id(user.id)
+ assert user.note_count == 0
+
+ object = Object.normalize(op.data["object"], fetch: false)
+
+ assert object.data["repliesCount"] == 0
+ end
+
+ test "it handles object deletions when the object itself has been pruned", %{
+ delete: delete,
+ post: post,
+ object: object,
+ user: user,
+ op: op
+ } do
+ object_id = object.id
+ user_id = user.id
+
+ ActivityPubMock
+ |> expect(:stream_out, fn ^delete -> nil end)
+ |> expect(:stream_out_participations, fn %Object{id: ^object_id}, %User{id: ^user_id} ->
+ nil
+ end)
+
+ {:ok, _delete, _} = SideEffects.handle(delete)
+ user = User.get_cached_by_ap_id(object.data["actor"])
+
+ object = Object.get_by_id(object.id)
+ assert object.data["type"] == "Tombstone"
+ refute Activity.get_by_id(post.id)
+
+ user = User.get_by_id(user.id)
+ assert user.note_count == 0
+
+ object = Object.normalize(op.data["object"], fetch: false)
+
+ assert object.data["repliesCount"] == 0
+ end
+
+ test "it logs issues with objects deletion", %{
+ delete: delete,
+ object: object
+ } do
+ {:ok, _object} =
+ object
+ |> Object.change(%{data: Map.delete(object.data, "actor")})
+ |> Repo.update()
+
+ LoggerMock
+ |> expect(:error, fn str -> assert str =~ "The object doesn't have an actor" end)
+
+ {:error, :no_object_actor} = SideEffects.handle(delete)
+ end
+ end
+end
diff --git a/test/web/activity_pub/side_effects_test.exs b/test/pleroma/web/activity_pub/side_effects_test.exs
index 9efbaad04..c6155ed18 100644
--- a/test/web/activity_pub/side_effects_test.exs
+++ b/test/pleroma/web/activity_pub/side_effects_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
@@ -19,7 +19,6 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
alias Pleroma.Web.ActivityPub.SideEffects
alias Pleroma.Web.CommonAPI
- import ExUnit.CaptureLog
import Mock
import Pleroma.Factory
@@ -89,6 +88,16 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
assert User.blocks?(user, blocked)
end
+ test "it updates following relationship", %{user: user, blocked: blocked, block: block} do
+ {:ok, _, _} = SideEffects.handle(block)
+
+ refute Pleroma.FollowingRelationship.get(user, blocked)
+ assert User.get_follow_state(user, blocked) == nil
+ assert User.get_follow_state(blocked, user) == nil
+ assert User.get_follow_state(user, blocked, nil) == nil
+ assert User.get_follow_state(blocked, user, nil) == nil
+ end
+
test "it blocks but does not unfollow if the relevant setting is set", %{
user: user,
blocked: blocked,
@@ -108,7 +117,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
describe "update users" do
setup do
- user = insert(:user)
+ user = insert(:user, local: false)
{:ok, update_data, []} = Builder.update(user, %{"id" => user.ap_id, "name" => "new name!"})
{:ok, update, _meta} = ActivityPub.persist(update_data, local: true)
@@ -131,115 +140,6 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
end
end
- describe "delete objects" do
- setup do
- user = insert(:user)
- other_user = insert(:user)
-
- {:ok, op} = CommonAPI.post(other_user, %{status: "big oof"})
- {:ok, post} = CommonAPI.post(user, %{status: "hey", in_reply_to_id: op})
- {:ok, favorite} = CommonAPI.favorite(user, post.id)
- object = Object.normalize(post)
- {:ok, delete_data, _meta} = Builder.delete(user, object.data["id"])
- {:ok, delete_user_data, _meta} = Builder.delete(user, user.ap_id)
- {:ok, delete, _meta} = ActivityPub.persist(delete_data, local: true)
- {:ok, delete_user, _meta} = ActivityPub.persist(delete_user_data, local: true)
-
- %{
- user: user,
- delete: delete,
- post: post,
- object: object,
- delete_user: delete_user,
- op: op,
- favorite: favorite
- }
- end
-
- test "it handles object deletions", %{
- delete: delete,
- post: post,
- object: object,
- user: user,
- op: op,
- favorite: favorite
- } do
- with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough],
- stream_out: fn _ -> nil end,
- stream_out_participations: fn _, _ -> nil end do
- {:ok, delete, _} = SideEffects.handle(delete)
- user = User.get_cached_by_ap_id(object.data["actor"])
-
- assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(delete))
- assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out_participations(object, user))
- end
-
- object = Object.get_by_id(object.id)
- assert object.data["type"] == "Tombstone"
- refute Activity.get_by_id(post.id)
- refute Activity.get_by_id(favorite.id)
-
- user = User.get_by_id(user.id)
- assert user.note_count == 0
-
- object = Object.normalize(op.data["object"], false)
-
- assert object.data["repliesCount"] == 0
- end
-
- test "it handles object deletions when the object itself has been pruned", %{
- delete: delete,
- post: post,
- object: object,
- user: user,
- op: op
- } do
- with_mock Pleroma.Web.ActivityPub.ActivityPub, [:passthrough],
- stream_out: fn _ -> nil end,
- stream_out_participations: fn _, _ -> nil end do
- {:ok, delete, _} = SideEffects.handle(delete)
- user = User.get_cached_by_ap_id(object.data["actor"])
-
- assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out(delete))
- assert called(Pleroma.Web.ActivityPub.ActivityPub.stream_out_participations(object, user))
- end
-
- object = Object.get_by_id(object.id)
- assert object.data["type"] == "Tombstone"
- refute Activity.get_by_id(post.id)
-
- user = User.get_by_id(user.id)
- assert user.note_count == 0
-
- object = Object.normalize(op.data["object"], false)
-
- assert object.data["repliesCount"] == 0
- end
-
- test "it handles user deletions", %{delete_user: delete, user: user} do
- {:ok, _delete, _} = SideEffects.handle(delete)
- ObanHelpers.perform_all()
-
- assert User.get_cached_by_ap_id(user.ap_id).deactivated
- end
-
- test "it logs issues with objects deletion", %{
- delete: delete,
- object: object
- } do
- {:ok, object} =
- object
- |> Object.change(%{data: Map.delete(object.data, "actor")})
- |> Repo.update()
-
- Object.invalid_object_cache(object)
-
- assert capture_log(fn ->
- {:error, :no_object_actor} = SideEffects.handle(delete)
- end) =~ "object doesn't have an actor"
- end
- end
-
describe "EmojiReact objects" do
setup do
poster = insert(:user)
@@ -267,22 +167,38 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
end
end
+ describe "Question objects" do
+ setup do
+ user = insert(:user)
+ question = build(:question, user: user)
+ question_activity = build(:question_activity, question: question)
+ activity_data = Map.put(question_activity.data, "object", question.data["id"])
+ meta = [object_data: question.data, local: false]
+
+ {:ok, activity, meta} = ActivityPub.persist(activity_data, meta)
+
+ %{activity: activity, meta: meta}
+ end
+
+ test "enqueues the poll end", %{activity: activity, meta: meta} do
+ {:ok, activity, meta} = SideEffects.handle(activity, meta)
+
+ assert_enqueued(
+ worker: Pleroma.Workers.PollWorker,
+ args: %{op: "poll_end", activity_id: activity.id},
+ scheduled_at: NaiveDateTime.from_iso8601!(meta[:object_data]["closed"])
+ )
+ end
+ end
+
describe "delete users with confirmation pending" do
setup do
- user = insert(:user, confirmation_pending: true)
+ user = insert(:user, is_confirmed: false)
{:ok, delete_user_data, _meta} = Builder.delete(user, user.ap_id)
{:ok, delete_user, _meta} = ActivityPub.persist(delete_user_data, local: true)
{:ok, delete: delete_user, user: user}
end
- test "when activation is not required", %{delete: delete, user: user} do
- clear_config([:instance, :account_activation_required], false)
- {:ok, _, _} = SideEffects.handle(delete)
- ObanHelpers.perform_all()
-
- assert User.get_cached_by_id(user.id).deactivated
- end
-
test "when activation is required", %{delete: delete, user: user} do
clear_config([:instance, :account_activation_required], true)
{:ok, _, _} = SideEffects.handle(delete)
@@ -636,4 +552,74 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
end
end
end
+
+ describe "removing a follower" do
+ setup do
+ user = insert(:user)
+ followed = insert(:user)
+
+ {:ok, _, _, follow_activity} = CommonAPI.follow(user, followed)
+
+ {:ok, reject_data, []} = Builder.reject(followed, follow_activity)
+ {:ok, reject, _meta} = ActivityPub.persist(reject_data, local: true)
+
+ %{user: user, followed: followed, reject: reject}
+ end
+
+ test "", %{user: user, followed: followed, reject: reject} do
+ assert User.following?(user, followed)
+ assert Pleroma.FollowingRelationship.get(user, followed)
+
+ {:ok, _, _} = SideEffects.handle(reject)
+
+ refute User.following?(user, followed)
+ refute Pleroma.FollowingRelationship.get(user, followed)
+ assert User.get_follow_state(user, followed) == nil
+ assert User.get_follow_state(user, followed, nil) == nil
+ end
+ end
+
+ describe "removing a follower from remote" do
+ setup do
+ user = insert(:user)
+ followed = insert(:user, local: false)
+
+ # Mock a local-to-remote follow
+ {:ok, follow_data, []} = Builder.follow(user, followed)
+
+ follow_data =
+ follow_data
+ |> Map.put("state", "accept")
+
+ {:ok, follow, _meta} = ActivityPub.persist(follow_data, local: true)
+ {:ok, _, _} = SideEffects.handle(follow)
+
+ # Mock a remote-to-local accept
+ {:ok, accept_data, _} = Builder.accept(followed, follow)
+ {:ok, accept, _} = ActivityPub.persist(accept_data, local: false)
+ {:ok, _, _} = SideEffects.handle(accept)
+
+ # Mock a remote-to-local reject
+ {:ok, reject_data, []} = Builder.reject(followed, follow)
+ {:ok, reject, _meta} = ActivityPub.persist(reject_data, local: false)
+
+ %{user: user, followed: followed, reject: reject}
+ end
+
+ test "", %{user: user, followed: followed, reject: reject} do
+ assert User.following?(user, followed)
+ assert Pleroma.FollowingRelationship.get(user, followed)
+
+ {:ok, _, _} = SideEffects.handle(reject)
+
+ refute User.following?(user, followed)
+ refute Pleroma.FollowingRelationship.get(user, followed)
+
+ assert Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(user, followed).data["state"] ==
+ "reject"
+
+ assert User.get_follow_state(user, followed) == nil
+ assert User.get_follow_state(user, followed, nil) == nil
+ end
+ end
end
diff --git a/test/web/activity_pub/transmogrifier/accept_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/accept_handling_test.exs
index 77d468f5c..58490076d 100644
--- a/test/web/activity_pub/transmogrifier/accept_handling_test.exs
+++ b/test/pleroma/web/activity_pub/transmogrifier/accept_handling_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.Transmogrifier.AcceptHandlingTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Transmogrifier
@@ -15,14 +15,14 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AcceptHandlingTest do
follower = insert(:user)
followed = insert(:user)
- {:ok, follower} = User.follow(follower, followed)
+ {:ok, follower, followed} = User.follow(follower, followed)
assert User.following?(follower, followed) == true
{:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed)
accept_data =
File.read!("test/fixtures/mastodon-accept-activity.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("actor", followed.ap_id)
object =
@@ -46,13 +46,13 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AcceptHandlingTest do
test "it works for incoming accepts which are referenced by IRI only" do
follower = insert(:user)
- followed = insert(:user, locked: true)
+ followed = insert(:user, is_locked: true)
{:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed)
accept_data =
File.read!("test/fixtures/mastodon-accept-activity.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("actor", followed.ap_id)
|> Map.put("object", follow_activity.data["id"])
@@ -72,11 +72,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AcceptHandlingTest do
test "it fails for incoming accepts which cannot be correlated" do
follower = insert(:user)
- followed = insert(:user, locked: true)
+ followed = insert(:user, is_locked: true)
accept_data =
File.read!("test/fixtures/mastodon-accept-activity.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("actor", followed.ap_id)
accept_data =
diff --git a/test/pleroma/web/activity_pub/transmogrifier/add_remove_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/add_remove_handling_test.exs
new file mode 100644
index 000000000..b17c0e7bf
--- /dev/null
+++ b/test/pleroma/web/activity_pub/transmogrifier/add_remove_handling_test.exs
@@ -0,0 +1,178 @@
+defmodule Pleroma.Web.ActivityPub.Transmogrifier.AddRemoveHandlingTest do
+ use Oban.Testing, repo: Pleroma.Repo
+ use Pleroma.DataCase, async: true
+
+ require Pleroma.Constants
+
+ import Pleroma.Factory
+
+ alias Pleroma.User
+ alias Pleroma.Web.ActivityPub.Transmogrifier
+
+ test "it accepts Add/Remove activities" do
+ user =
+ "test/fixtures/users_mock/user.json"
+ |> File.read!()
+ |> String.replace("{{nickname}}", "lain")
+
+ object_id = "c61d6733-e256-4fe1-ab13-1e369789423f"
+
+ object =
+ "test/fixtures/statuses/note.json"
+ |> File.read!()
+ |> String.replace("{{nickname}}", "lain")
+ |> String.replace("{{object_id}}", object_id)
+
+ object_url = "https://example.com/objects/#{object_id}"
+
+ actor = "https://example.com/users/lain"
+
+ Tesla.Mock.mock(fn
+ %{
+ method: :get,
+ url: ^actor
+ } ->
+ %Tesla.Env{
+ status: 200,
+ body: user,
+ headers: [{"content-type", "application/activity+json"}]
+ }
+
+ %{
+ method: :get,
+ url: ^object_url
+ } ->
+ %Tesla.Env{
+ status: 200,
+ body: object,
+ headers: [{"content-type", "application/activity+json"}]
+ }
+
+ %{method: :get, url: "https://example.com/users/lain/collections/featured"} ->
+ %Tesla.Env{
+ status: 200,
+ body:
+ "test/fixtures/users_mock/masto_featured.json"
+ |> File.read!()
+ |> String.replace("{{domain}}", "example.com")
+ |> String.replace("{{nickname}}", "lain"),
+ headers: [{"content-type", "application/activity+json"}]
+ }
+ end)
+
+ message = %{
+ "id" => "https://example.com/objects/d61d6733-e256-4fe1-ab13-1e369789423f",
+ "actor" => actor,
+ "object" => object_url,
+ "target" => "https://example.com/users/lain/collections/featured",
+ "type" => "Add",
+ "to" => [Pleroma.Constants.as_public()],
+ "cc" => ["https://example.com/users/lain/followers"],
+ "bcc" => [],
+ "bto" => []
+ }
+
+ assert {:ok, activity} = Transmogrifier.handle_incoming(message)
+ assert activity.data == message
+ user = User.get_cached_by_ap_id(actor)
+ assert user.pinned_objects[object_url]
+
+ remove = %{
+ "id" => "http://localhost:400/objects/d61d6733-e256-4fe1-ab13-1e369789423d",
+ "actor" => actor,
+ "object" => object_url,
+ "target" => "https://example.com/users/lain/collections/featured",
+ "type" => "Remove",
+ "to" => [Pleroma.Constants.as_public()],
+ "cc" => ["https://example.com/users/lain/followers"],
+ "bcc" => [],
+ "bto" => []
+ }
+
+ assert {:ok, activity} = Transmogrifier.handle_incoming(remove)
+ assert activity.data == remove
+
+ user = refresh_record(user)
+ refute user.pinned_objects[object_url]
+ end
+
+ test "Add/Remove activities for remote users without featured address" do
+ user = insert(:user, local: false, domain: "example.com")
+
+ user =
+ user
+ |> Ecto.Changeset.change(featured_address: nil)
+ |> Repo.update!()
+
+ %{host: host} = URI.parse(user.ap_id)
+
+ user_data =
+ "test/fixtures/users_mock/user.json"
+ |> File.read!()
+ |> String.replace("{{nickname}}", user.nickname)
+
+ object_id = "c61d6733-e256-4fe1-ab13-1e369789423f"
+
+ object =
+ "test/fixtures/statuses/note.json"
+ |> File.read!()
+ |> String.replace("{{nickname}}", user.nickname)
+ |> String.replace("{{object_id}}", object_id)
+
+ object_url = "https://#{host}/objects/#{object_id}"
+
+ actor = "https://#{host}/users/#{user.nickname}"
+
+ featured = "https://#{host}/users/#{user.nickname}/collections/featured"
+
+ Tesla.Mock.mock(fn
+ %{
+ method: :get,
+ url: ^actor
+ } ->
+ %Tesla.Env{
+ status: 200,
+ body: user_data,
+ headers: [{"content-type", "application/activity+json"}]
+ }
+
+ %{
+ method: :get,
+ url: ^object_url
+ } ->
+ %Tesla.Env{
+ status: 200,
+ body: object,
+ headers: [{"content-type", "application/activity+json"}]
+ }
+
+ %{method: :get, url: ^featured} ->
+ %Tesla.Env{
+ status: 200,
+ body:
+ "test/fixtures/users_mock/masto_featured.json"
+ |> File.read!()
+ |> String.replace("{{domain}}", "#{host}")
+ |> String.replace("{{nickname}}", user.nickname),
+ headers: [{"content-type", "application/activity+json"}]
+ }
+ end)
+
+ message = %{
+ "id" => "https://#{host}/objects/d61d6733-e256-4fe1-ab13-1e369789423f",
+ "actor" => actor,
+ "object" => object_url,
+ "target" => "https://#{host}/users/#{user.nickname}/collections/featured",
+ "type" => "Add",
+ "to" => [Pleroma.Constants.as_public()],
+ "cc" => ["https://#{host}/users/#{user.nickname}/followers"],
+ "bcc" => [],
+ "bto" => []
+ }
+
+ assert {:ok, activity} = Transmogrifier.handle_incoming(message)
+ assert activity.data == message
+ user = User.get_cached_by_ap_id(actor)
+ assert user.pinned_objects[object_url]
+ end
+end
diff --git a/test/web/activity_pub/transmogrifier/announce_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/announce_handling_test.exs
index e895636b5..524acddaf 100644
--- a/test/web/activity_pub/transmogrifier/announce_handling_test.exs
+++ b/test/pleroma/web/activity_pub/transmogrifier/announce_handling_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnnounceHandlingTest do
@@ -36,7 +36,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnnounceHandlingTest do
end
test "it works for incoming announces with actor being inlined (kroeg)" do
- data = File.read!("test/fixtures/kroeg-announce-with-inline-actor.json") |> Poison.decode!()
+ data = File.read!("test/fixtures/kroeg-announce-with-inline-actor.json") |> Jason.decode!()
_user = insert(:user, local: false, ap_id: data["actor"]["id"])
other_user = insert(:user)
@@ -55,12 +55,16 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnnounceHandlingTest do
test "it works for incoming announces, fetching the announced object" do
data =
File.read!("test/fixtures/mastodon-announce.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", "http://mastodon.example.org/users/admin/statuses/99541947525187367")
Tesla.Mock.mock(fn
%{method: :get} ->
- %Tesla.Env{status: 200, body: File.read!("test/fixtures/mastodon-note-object.json")}
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/mastodon-note-object.json"),
+ headers: HttpRequestMock.activitypub_object_headers()
+ }
end)
_user = insert(:user, local: false, ap_id: data["actor"])
@@ -86,7 +90,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnnounceHandlingTest do
data =
File.read!("test/fixtures/mastodon-announce.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", activity.data["object"])
_user = insert(:user, local: false, ap_id: data["actor"])
@@ -109,7 +113,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnnounceHandlingTest do
test "it works for incoming announces with an inlined activity" do
data =
File.read!("test/fixtures/mastodon-announce-private.json")
- |> Poison.decode!()
+ |> Jason.decode!()
_user =
insert(:user,
@@ -126,7 +130,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnnounceHandlingTest do
assert data["id"] ==
"http://mastodon.example.org/users/admin/statuses/99542391527669785/activity"
- object = Object.normalize(data["object"])
+ object = Object.normalize(data["object"], fetch: false)
assert object.data["id"] == "http://mastodon.example.org/@admin/99541947525187368"
assert object.data["content"] == "this is a private toot"
@@ -140,33 +144,10 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnnounceHandlingTest do
data =
File.read!("test/fixtures/bogus-mastodon-announce.json")
- |> Poison.decode!()
+ |> Jason.decode!()
_user = insert(:user, local: false, ap_id: data["actor"])
- assert {:error, e} = Transmogrifier.handle_incoming(data)
- end
-
- test "it does not clobber the addressing on announce activities" do
- user = insert(:user)
- {:ok, activity} = CommonAPI.post(user, %{status: "hey"})
-
- data =
- File.read!("test/fixtures/mastodon-announce.json")
- |> Poison.decode!()
- |> Map.put("object", Object.normalize(activity).data["id"])
- |> Map.put("to", ["http://mastodon.example.org/users/admin/followers"])
- |> Map.put("cc", [])
-
- _user =
- insert(:user,
- local: false,
- ap_id: data["actor"],
- follower_address: "http://mastodon.example.org/users/admin/followers"
- )
-
- {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
-
- assert data["to"] == ["http://mastodon.example.org/users/admin/followers"]
+ assert {:error, _e} = Transmogrifier.handle_incoming(data)
end
end
diff --git a/test/web/activity_pub/transmogrifier/answer_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/answer_handling_test.exs
index 0f6605c3f..9c2ef547b 100644
--- a/test/web/activity_pub/transmogrifier/answer_handling_test.exs
+++ b/test/pleroma/web/activity_pub/transmogrifier/answer_handling_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnswerHandlingTest do
@@ -26,22 +26,23 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnswerHandlingTest do
poll: %{options: ["suya", "suya.", "suya.."], expires_in: 10}
})
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
+ assert object.data["repliesCount"] == nil
data =
File.read!("test/fixtures/mastodon-vote.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Kernel.put_in(["to"], user.ap_id)
|> Kernel.put_in(["object", "inReplyTo"], object.data["id"])
|> Kernel.put_in(["object", "to"], user.ap_id)
{:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
- answer_object = Object.normalize(activity)
+ answer_object = Object.normalize(activity, fetch: false)
assert answer_object.data["type"] == "Answer"
assert answer_object.data["inReplyTo"] == object.data["id"]
new_object = Object.get_by_ap_id(object.data["id"])
- assert new_object.data["replies_count"] == object.data["replies_count"]
+ assert new_object.data["repliesCount"] == nil
assert Enum.any?(
new_object.data["oneOf"],
@@ -61,11 +62,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AnswerHandlingTest do
poll: %{options: ["suya", "suya.", "suya.."], expires_in: 10}
})
- poll_object = Object.normalize(poll_activity)
+ poll_object = Object.normalize(poll_activity, fetch: false)
# TODO: Replace with CommonAPI vote creation when implemented
data =
File.read!("test/fixtures/mastodon-vote.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Kernel.put_in(["to"], user.ap_id)
|> Kernel.put_in(["object", "inReplyTo"], poll_object.data["id"])
|> Kernel.put_in(["object", "to"], user.ap_id)
diff --git a/test/pleroma/web/activity_pub/transmogrifier/article_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/article_handling_test.exs
new file mode 100644
index 000000000..5dbc5eb95
--- /dev/null
+++ b/test/pleroma/web/activity_pub/transmogrifier/article_handling_test.exs
@@ -0,0 +1,82 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.Transmogrifier.ArticleHandlingTest do
+ use Oban.Testing, repo: Pleroma.Repo
+ use Pleroma.DataCase
+
+ alias Pleroma.Activity
+ alias Pleroma.Object
+ alias Pleroma.Object.Fetcher
+ alias Pleroma.Web.ActivityPub.Transmogrifier
+
+ test "Pterotype (Wordpress Plugin) Article" do
+ Tesla.Mock.mock(fn %{url: "https://wedistribute.org/wp-json/pterotype/v1/actor/-blog"} ->
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/tesla_mock/wedistribute-user.json"),
+ headers: HttpRequestMock.activitypub_object_headers()
+ }
+ end)
+
+ data =
+ File.read!("test/fixtures/tesla_mock/wedistribute-create-article.json") |> Jason.decode!()
+
+ {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+
+ object = Object.normalize(data["object"], fetch: false)
+
+ assert object.data["name"] == "The end is near: Mastodon plans to drop OStatus support"
+
+ assert object.data["summary"] ==
+ "One of the largest platforms in the federated social web is dropping the protocol that it started with."
+
+ assert object.data["url"] == "https://wedistribute.org/2019/07/mastodon-drops-ostatus/"
+ end
+
+ test "Plume Article" do
+ Tesla.Mock.mock(fn
+ %{url: "https://baptiste.gelez.xyz/~/PlumeDevelopment/this-month-in-plume-june-2018/"} ->
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/tesla_mock/baptiste.gelex.xyz-article.json"),
+ headers: HttpRequestMock.activitypub_object_headers()
+ }
+
+ %{url: "https://baptiste.gelez.xyz/@/BaptisteGelez"} ->
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/tesla_mock/baptiste.gelex.xyz-user.json"),
+ headers: HttpRequestMock.activitypub_object_headers()
+ }
+ end)
+
+ {:ok, object} =
+ Fetcher.fetch_object_from_id(
+ "https://baptiste.gelez.xyz/~/PlumeDevelopment/this-month-in-plume-june-2018/"
+ )
+
+ assert object.data["name"] == "This Month in Plume: June 2018"
+
+ assert object.data["url"] ==
+ "https://baptiste.gelez.xyz/~/PlumeDevelopment/this-month-in-plume-june-2018/"
+ end
+
+ test "Prismo Article" do
+ Tesla.Mock.mock(fn %{url: "https://prismo.news/@mxb"} ->
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/tesla_mock/https___prismo.news__mxb.json"),
+ headers: HttpRequestMock.activitypub_object_headers()
+ }
+ end)
+
+ data = File.read!("test/fixtures/prismo-url-map.json") |> Jason.decode!()
+
+ {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+ object = Object.normalize(data["object"], fetch: false)
+
+ assert object.data["url"] == "https://prismo.news/posts/83"
+ end
+end
diff --git a/test/web/activity_pub/transmogrifier/audio_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/audio_handling_test.exs
index 0636d00c5..a0942ce8b 100644
--- a/test/web/activity_pub/transmogrifier/audio_handling_test.exs
+++ b/test/pleroma/web/activity_pub/transmogrifier/audio_handling_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.Transmogrifier.AudioHandlingTest do
@@ -24,6 +24,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AudioHandlingTest do
"actor" => "http://mastodon.example.org/users/admin",
"object" => %{
"type" => "Audio",
+ "to" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "cc" => [],
"id" => "http://mastodon.example.org/users/admin/listens/1234",
"attributedTo" => "http://mastodon.example.org/users/admin",
"title" => "lain radio episode 1",
@@ -35,7 +37,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AudioHandlingTest do
{:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
assert object.data["title"] == "lain radio episode 1"
assert object.data["artist"] == "lain"
@@ -48,19 +50,22 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AudioHandlingTest do
%{url: "https://channels.tests.funkwhale.audio/federation/actors/compositions"} ->
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/funkwhale_channel.json")
+ body: File.read!("test/fixtures/tesla_mock/funkwhale_channel.json"),
+ headers: HttpRequestMock.activitypub_object_headers()
}
end)
- data = File.read!("test/fixtures/tesla_mock/funkwhale_create_audio.json") |> Poison.decode!()
+ data = File.read!("test/fixtures/tesla_mock/funkwhale_create_audio.json") |> Jason.decode!()
{:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
- assert object = Object.normalize(activity, false)
+ assert object = Object.normalize(activity, fetch: false)
assert object.data["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
- assert object.data["cc"] == []
+ assert object.data["cc"] == [
+ "https://channels.tests.funkwhale.audio/federation/actors/compositions/followers"
+ ]
assert object.data["url"] == "https://channels.tests.funkwhale.audio/library/tracks/74"
@@ -68,7 +73,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.AudioHandlingTest do
%{
"mediaType" => "audio/ogg",
"type" => "Link",
- "name" => nil,
"url" => [
%{
"href" =>
diff --git a/test/web/activity_pub/transmogrifier/block_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/block_handling_test.exs
index 71f1a0ed5..70da06d2e 100644
--- a/test/web/activity_pub/transmogrifier/block_handling_test.exs
+++ b/test/pleroma/web/activity_pub/transmogrifier/block_handling_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.Transmogrifier.BlockHandlingTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Activity
alias Pleroma.User
@@ -16,7 +16,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.BlockHandlingTest do
data =
File.read!("test/fixtures/mastodon-block-activity.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", user.ap_id)
blocker = insert(:user, ap_id: data["actor"])
@@ -36,12 +36,12 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.BlockHandlingTest do
data =
File.read!("test/fixtures/mastodon-block-activity.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", blocked.ap_id)
|> Map.put("actor", blocker.ap_id)
- {:ok, blocker} = User.follow(blocker, blocked)
- {:ok, blocked} = User.follow(blocked, blocker)
+ {:ok, blocker, blocked} = User.follow(blocker, blocked)
+ {:ok, blocked, blocker} = User.follow(blocked, blocker)
assert User.following?(blocker, blocked)
assert User.following?(blocked, blocker)
diff --git a/test/web/activity_pub/transmogrifier/chat_message_test.exs b/test/pleroma/web/activity_pub/transmogrifier/chat_message_test.exs
index 31274c067..958675835 100644
--- a/test/web/activity_pub/transmogrifier/chat_message_test.exs
+++ b/test/pleroma/web/activity_pub/transmogrifier/chat_message_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.Transmogrifier.ChatMessageTest do
@@ -53,7 +53,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.ChatMessageTest do
test "it rejects messages that don't contain content" do
data =
File.read!("test/fixtures/create-chat-message.json")
- |> Poison.decode!()
+ |> Jason.decode!()
object =
data["object"]
@@ -79,7 +79,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.ChatMessageTest do
test "it rejects messages that don't concern local users" do
data =
File.read!("test/fixtures/create-chat-message.json")
- |> Poison.decode!()
+ |> Jason.decode!()
_author =
insert(:user, ap_id: data["actor"], local: false, last_refreshed_at: DateTime.utc_now())
@@ -97,7 +97,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.ChatMessageTest do
test "it rejects messages where the `to` field of activity and object don't match" do
data =
File.read!("test/fixtures/create-chat-message.json")
- |> Poison.decode!()
+ |> Jason.decode!()
author = insert(:user, ap_id: data["actor"])
_recipient = insert(:user, ap_id: List.first(data["to"]))
@@ -115,7 +115,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.ChatMessageTest do
data =
File.read!("test/fixtures/create-chat-message.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("actor", "http://mastodon.example.org/users/admin")
|> put_in(["object", "actor"], "http://mastodon.example.org/users/admin")
@@ -127,14 +127,14 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.ChatMessageTest do
test "it doesn't work for deactivated users" do
data =
File.read!("test/fixtures/create-chat-message.json")
- |> Poison.decode!()
+ |> Jason.decode!()
_author =
insert(:user,
ap_id: data["actor"],
local: false,
last_refreshed_at: DateTime.utc_now(),
- deactivated: true
+ is_active: false
)
_recipient = insert(:user, ap_id: List.first(data["to"]), local: true)
@@ -145,7 +145,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.ChatMessageTest do
test "it inserts it and creates a chat" do
data =
File.read!("test/fixtures/create-chat-message.json")
- |> Poison.decode!()
+ |> Jason.decode!()
author =
insert(:user, ap_id: data["actor"], local: false, last_refreshed_at: DateTime.utc_now())
diff --git a/test/web/activity_pub/transmogrifier/delete_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/delete_handling_test.exs
index c9a53918c..b7160bf58 100644
--- a/test/web/activity_pub/transmogrifier/delete_handling_test.exs
+++ b/test/pleroma/web/activity_pub/transmogrifier/delete_handling_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.Transmogrifier.DeleteHandlingTest do
@@ -25,7 +25,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.DeleteHandlingTest do
data =
File.read!("test/fixtures/mastodon-delete.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("actor", deleting_user.ap_id)
|> put_in(["object", "id"], activity.data["object"])
@@ -40,7 +40,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.DeleteHandlingTest do
assert actor == deleting_user.ap_id
# Objects are replaced by a tombstone object.
- object = Object.normalize(activity.data["object"])
+ object = Object.normalize(activity.data["object"], fetch: false)
assert object.data["type"] == "Tombstone"
end
@@ -48,16 +48,17 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.DeleteHandlingTest do
activity = insert(:note_activity)
{:ok, object} =
- Object.normalize(activity.data["object"])
+ Object.normalize(activity.data["object"], fetch: false)
|> Repo.delete()
+ # TODO: mock cachex
Cachex.del(:object_cache, "object:#{object.data["id"]}")
deleting_user = insert(:user)
data =
File.read!("test/fixtures/mastodon-delete.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("actor", deleting_user.ap_id)
|> put_in(["object", "id"], activity.data["object"])
@@ -78,7 +79,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.DeleteHandlingTest do
data =
File.read!("test/fixtures/mastodon-delete.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("actor", ap_id)
|> put_in(["object", "id"], activity.data["object"])
@@ -91,12 +92,12 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.DeleteHandlingTest do
data =
File.read!("test/fixtures/mastodon-delete-user.json")
- |> Poison.decode!()
+ |> Jason.decode!()
{:ok, _} = Transmogrifier.handle_incoming(data)
ObanHelpers.perform_all()
- assert User.get_cached_by_ap_id(ap_id).deactivated
+ refute User.get_cached_by_ap_id(ap_id).is_active
end
test "it fails for incoming user deletes with spoofed origin" do
@@ -104,7 +105,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.DeleteHandlingTest do
data =
File.read!("test/fixtures/mastodon-delete-user.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("actor", ap_id)
assert match?({:error, _}, Transmogrifier.handle_incoming(data))
diff --git a/test/web/activity_pub/transmogrifier/emoji_react_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/emoji_react_handling_test.exs
index 0fb056b50..20424ee82 100644
--- a/test/web/activity_pub/transmogrifier/emoji_react_handling_test.exs
+++ b/test/pleroma/web/activity_pub/transmogrifier/emoji_react_handling_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.Transmogrifier.EmojiReactHandlingTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Activity
alias Pleroma.Object
@@ -19,7 +19,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.EmojiReactHandlingTest do
data =
File.read!("test/fixtures/emoji-reaction.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", activity.data["object"])
|> Map.put("actor", other_user.ap_id)
@@ -44,7 +44,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.EmojiReactHandlingTest do
data =
File.read!("test/fixtures/emoji-reaction-too-long.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", activity.data["object"])
|> Map.put("actor", other_user.ap_id)
@@ -52,7 +52,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.EmojiReactHandlingTest do
data =
File.read!("test/fixtures/emoji-reaction-no-emoji.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", activity.data["object"])
|> Map.put("actor", other_user.ap_id)
diff --git a/test/web/activity_pub/transmogrifier/event_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/event_handling_test.exs
index 7f1ef2cbd..14f5f704a 100644
--- a/test/web/activity_pub/transmogrifier/event_handling_test.exs
+++ b/test/pleroma/web/activity_pub/transmogrifier/event_handling_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.Transmogrifier.EventHandlingTest do
@@ -13,13 +13,15 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.EventHandlingTest do
%{url: "https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39"} ->
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/mobilizon.org-event.json")
+ body: File.read!("test/fixtures/tesla_mock/mobilizon.org-event.json"),
+ headers: HttpRequestMock.activitypub_object_headers()
}
%{url: "https://mobilizon.org/@tcit"} ->
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/mobilizon.org-user.json")
+ body: File.read!("test/fixtures/tesla_mock/mobilizon.org-user.json"),
+ headers: HttpRequestMock.activitypub_object_headers()
}
end)
@@ -29,7 +31,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.EventHandlingTest do
)
assert object.data["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
- assert object.data["cc"] == []
+ assert object.data["cc"] == ["https://mobilizon.org/@tcit/followers"]
assert object.data["url"] ==
"https://mobilizon.org/events/252d5816-00a3-4a89-a66f-15bf65c33e39"
diff --git a/test/web/activity_pub/transmogrifier/follow_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/follow_handling_test.exs
index 757d90941..604444a4c 100644
--- a/test/web/activity_pub/transmogrifier/follow_handling_test.exs
+++ b/test/pleroma/web/activity_pub/transmogrifier/follow_handling_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do
@@ -28,7 +28,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do
data =
File.read!("test/fixtures/osada-follow-activity.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", user.ap_id)
{:ok, %Activity{data: data, local: false} = activity} = Transmogrifier.handle_incoming(data)
@@ -47,7 +47,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do
data =
File.read!("test/fixtures/mastodon-follow-activity.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", user.ap_id)
{:ok, %Activity{data: data, local: false} = activity} = Transmogrifier.handle_incoming(data)
@@ -65,11 +65,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do
end
test "with locked accounts, it does create a Follow, but not an Accept" do
- user = insert(:user, locked: true)
+ user = insert(:user, is_locked: true)
data =
File.read!("test/fixtures/mastodon-follow-activity.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", user.ap_id)
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
@@ -100,7 +100,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do
data =
File.read!("test/fixtures/mastodon-follow-activity.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", user.ap_id)
{:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(data)
@@ -116,7 +116,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do
data =
File.read!("test/fixtures/mastodon-follow-activity.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("id", String.replace(data["id"], "2", "3"))
|> Map.put("object", user.ap_id)
@@ -133,7 +133,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do
end
test "it rejects incoming follow requests from blocked users when deny_follow_blocked is enabled" do
- Pleroma.Config.put([:user, :deny_follow_blocked], true)
+ clear_config([:user, :deny_follow_blocked], true)
user = insert(:user)
{:ok, target} = User.get_or_fetch("http://mastodon.example.org/users/admin")
@@ -142,7 +142,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do
data =
File.read!("test/fixtures/mastodon-follow-activity.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", user.ap_id)
{:ok, %Activity{data: %{"id" => id}}} = Transmogrifier.handle_incoming(data)
@@ -157,7 +157,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do
data =
File.read!("test/fixtures/mastodon-follow-activity.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", user.ap_id)
with_mock Pleroma.User, [:passthrough], follow: fn _, _, _ -> {:error, :testing} end do
@@ -174,7 +174,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do
data =
File.read!("test/fixtures/hubzilla-follow-activity.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", user.ap_id)
|> Utils.normalize_params()
@@ -188,11 +188,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do
test "it works for incoming follows to locked account" do
pending_follower = insert(:user, ap_id: "http://mastodon.example.org/users/admin")
- user = insert(:user, locked: true)
+ user = insert(:user, is_locked: true)
data =
File.read!("test/fixtures/mastodon-follow-activity.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", user.ap_id)
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
diff --git a/test/web/activity_pub/transmogrifier/like_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/like_handling_test.exs
index 53fe1d550..57d74349a 100644
--- a/test/web/activity_pub/transmogrifier/like_handling_test.exs
+++ b/test/pleroma/web/activity_pub/transmogrifier/like_handling_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.Transmogrifier.LikeHandlingTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Activity
alias Pleroma.Web.ActivityPub.Transmogrifier
@@ -18,7 +18,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.LikeHandlingTest do
data =
File.read!("test/fixtures/mastodon-like.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", activity.data["object"])
_actor = insert(:user, ap_id: data["actor"], local: false)
@@ -40,7 +40,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.LikeHandlingTest do
data =
File.read!("test/fixtures/misskey-like.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", activity.data["object"])
_actor = insert(:user, ap_id: data["actor"], local: false)
@@ -61,7 +61,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.LikeHandlingTest do
data =
File.read!("test/fixtures/misskey-like.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", activity.data["object"])
|> Map.put("_misskey_reaction", "⭐")
diff --git a/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs
new file mode 100644
index 000000000..1846b2291
--- /dev/null
+++ b/test/pleroma/web/activity_pub/transmogrifier/note_handling_test.exs
@@ -0,0 +1,710 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.Transmogrifier.NoteHandlingTest do
+ use Oban.Testing, repo: Pleroma.Repo
+ use Pleroma.DataCase
+
+ alias Pleroma.Activity
+ alias Pleroma.Object
+ alias Pleroma.User
+ alias Pleroma.Web.ActivityPub.Transmogrifier
+ alias Pleroma.Web.ActivityPub.Utils
+ alias Pleroma.Web.CommonAPI
+
+ import Mock
+ import Pleroma.Factory
+
+ setup_all do
+ Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
+ :ok
+ end
+
+ setup do: clear_config([:instance, :max_remote_account_fields])
+
+ describe "handle_incoming" do
+ test "it works for incoming notices with tag not being an array (kroeg)" do
+ data = File.read!("test/fixtures/kroeg-array-less-emoji.json") |> Jason.decode!()
+
+ {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+ object = Object.normalize(data["object"], fetch: false)
+
+ assert object.data["emoji"] == %{
+ "icon_e_smile" => "https://puckipedia.com/forum/images/smilies/icon_e_smile.png"
+ }
+
+ data = File.read!("test/fixtures/kroeg-array-less-hashtag.json") |> Jason.decode!()
+
+ {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+ object = Object.normalize(data["object"], fetch: false)
+
+ assert "test" in Object.tags(object)
+ assert Object.hashtags(object) == ["test"]
+ end
+
+ test "it ignores an incoming notice if we already have it" do
+ activity = insert(:note_activity)
+
+ data =
+ File.read!("test/fixtures/mastodon-post-activity.json")
+ |> Jason.decode!()
+ |> Map.put("object", Object.normalize(activity, fetch: false).data)
+
+ {:ok, returned_activity} = Transmogrifier.handle_incoming(data)
+
+ assert activity == returned_activity
+ end
+
+ @tag capture_log: true
+ test "it fetches reply-to activities if we don't have them" do
+ data =
+ File.read!("test/fixtures/mastodon-post-activity.json")
+ |> Jason.decode!()
+
+ object =
+ data["object"]
+ |> Map.put("inReplyTo", "https://mstdn.io/users/mayuutann/statuses/99568293732299394")
+
+ data = Map.put(data, "object", object)
+ {:ok, returned_activity} = Transmogrifier.handle_incoming(data)
+ returned_object = Object.normalize(returned_activity, fetch: false)
+
+ assert %Activity{} =
+ Activity.get_create_by_object_ap_id(
+ "https://mstdn.io/users/mayuutann/statuses/99568293732299394"
+ )
+
+ assert returned_object.data["inReplyTo"] ==
+ "https://mstdn.io/users/mayuutann/statuses/99568293732299394"
+ end
+
+ test "it does not fetch reply-to activities beyond max replies depth limit" do
+ data =
+ File.read!("test/fixtures/mastodon-post-activity.json")
+ |> Jason.decode!()
+
+ object =
+ data["object"]
+ |> Map.put("inReplyTo", "https://shitposter.club/notice/2827873")
+
+ data = Map.put(data, "object", object)
+
+ with_mock Pleroma.Web.Federator,
+ allowed_thread_distance?: fn _ -> false end do
+ {:ok, returned_activity} = Transmogrifier.handle_incoming(data)
+
+ returned_object = Object.normalize(returned_activity, fetch: false)
+
+ refute Activity.get_create_by_object_ap_id(
+ "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
+ )
+
+ assert returned_object.data["inReplyTo"] == "https://shitposter.club/notice/2827873"
+ end
+ end
+
+ test "it does not crash if the object in inReplyTo can't be fetched" do
+ data =
+ File.read!("test/fixtures/mastodon-post-activity.json")
+ |> Jason.decode!()
+
+ object =
+ data["object"]
+ |> Map.put("inReplyTo", "https://404.site/whatever")
+
+ data =
+ data
+ |> Map.put("object", object)
+
+ assert {:ok, _returned_activity} = Transmogrifier.handle_incoming(data)
+ end
+
+ test "it does not work for deactivated users" do
+ data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!()
+
+ insert(:user, ap_id: data["actor"], is_active: false)
+
+ assert {:error, _} = Transmogrifier.handle_incoming(data)
+ end
+
+ test "it works for incoming notices" do
+ data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!()
+
+ {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+
+ assert data["id"] ==
+ "http://mastodon.example.org/users/admin/statuses/99512778738411822/activity"
+
+ assert data["context"] ==
+ "tag:mastodon.example.org,2018-02-12:objectId=20:objectType=Conversation"
+
+ assert data["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
+
+ assert data["cc"] == [
+ "http://localtesting.pleroma.lol/users/lain",
+ "http://mastodon.example.org/users/admin/followers"
+ ]
+
+ assert data["actor"] == "http://mastodon.example.org/users/admin"
+
+ object_data = Object.normalize(data["object"], fetch: false).data
+
+ assert object_data["id"] ==
+ "http://mastodon.example.org/users/admin/statuses/99512778738411822"
+
+ assert object_data["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
+
+ assert object_data["cc"] == [
+ "http://localtesting.pleroma.lol/users/lain",
+ "http://mastodon.example.org/users/admin/followers"
+ ]
+
+ assert object_data["actor"] == "http://mastodon.example.org/users/admin"
+ assert object_data["attributedTo"] == "http://mastodon.example.org/users/admin"
+
+ assert object_data["context"] ==
+ "tag:mastodon.example.org,2018-02-12:objectId=20:objectType=Conversation"
+
+ assert object_data["sensitive"] == true
+
+ user = User.get_cached_by_ap_id(object_data["actor"])
+
+ assert user.note_count == 1
+ end
+
+ test "it works for incoming notices without the sensitive property but an nsfw hashtag" do
+ data = File.read!("test/fixtures/mastodon-post-activity-nsfw.json") |> Jason.decode!()
+
+ {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+
+ object_data = Object.normalize(data["object"], fetch: false).data
+
+ assert object_data["sensitive"] == true
+ end
+
+ test "it works for incoming notices with hashtags" do
+ data = File.read!("test/fixtures/mastodon-post-activity-hashtag.json") |> Jason.decode!()
+
+ {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+ object = Object.normalize(data["object"], fetch: false)
+
+ assert match?(
+ %{
+ "href" => "http://localtesting.pleroma.lol/users/lain",
+ "name" => "@lain@localtesting.pleroma.lol",
+ "type" => "Mention"
+ },
+ Enum.at(object.data["tag"], 0)
+ )
+
+ assert match?(
+ %{
+ "href" => "http://mastodon.example.org/tags/moo",
+ "name" => "#moo",
+ "type" => "Hashtag"
+ },
+ Enum.at(object.data["tag"], 1)
+ )
+
+ assert "moo" == Enum.at(object.data["tag"], 2)
+ end
+
+ test "it works for incoming notices with contentMap" do
+ data = File.read!("test/fixtures/mastodon-post-activity-contentmap.json") |> Jason.decode!()
+
+ {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+ object = Object.normalize(data["object"], fetch: false)
+
+ assert object.data["content"] ==
+ "<p><span class=\"h-card\"><a href=\"http://localtesting.pleroma.lol/users/lain\" class=\"u-url mention\">@<span>lain</span></a></span></p>"
+ end
+
+ test "it works for incoming notices with to/cc not being an array (kroeg)" do
+ data = File.read!("test/fixtures/kroeg-post-activity.json") |> Jason.decode!()
+
+ {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+ object = Object.normalize(data["object"], fetch: false)
+
+ assert object.data["content"] ==
+ "<p>henlo from my Psion netBook</p><p>message sent from my Psion netBook</p>"
+ end
+
+ test "it ensures that as:Public activities make it to their followers collection" do
+ user = insert(:user)
+
+ data =
+ File.read!("test/fixtures/mastodon-post-activity.json")
+ |> Jason.decode!()
+ |> Map.put("actor", user.ap_id)
+ |> Map.put("to", ["https://www.w3.org/ns/activitystreams#Public"])
+ |> Map.put("cc", [])
+
+ object =
+ data["object"]
+ |> Map.put("attributedTo", user.ap_id)
+ |> Map.put("to", ["https://www.w3.org/ns/activitystreams#Public"])
+ |> Map.put("cc", [])
+ |> Map.put("id", user.ap_id <> "/activities/12345678")
+
+ data = Map.put(data, "object", object)
+
+ {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+
+ assert data["cc"] == [User.ap_followers(user)]
+ end
+
+ test "it ensures that address fields become lists" do
+ user = insert(:user)
+
+ data =
+ File.read!("test/fixtures/mastodon-post-activity.json")
+ |> Jason.decode!()
+ |> Map.put("actor", user.ap_id)
+ |> Map.put("cc", nil)
+
+ object =
+ data["object"]
+ |> Map.put("attributedTo", user.ap_id)
+ |> Map.put("cc", nil)
+ |> Map.put("id", user.ap_id <> "/activities/12345678")
+
+ data = Map.put(data, "object", object)
+
+ {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+
+ refute is_nil(data["cc"])
+ end
+
+ test "it strips internal likes" do
+ data =
+ File.read!("test/fixtures/mastodon-post-activity.json")
+ |> Jason.decode!()
+
+ likes = %{
+ "first" =>
+ "http://mastodon.example.org/objects/dbdbc507-52c8-490d-9b7c-1e1d52e5c132/likes?page=1",
+ "id" => "http://mastodon.example.org/objects/dbdbc507-52c8-490d-9b7c-1e1d52e5c132/likes",
+ "totalItems" => 3,
+ "type" => "OrderedCollection"
+ }
+
+ object = Map.put(data["object"], "likes", likes)
+ data = Map.put(data, "object", object)
+
+ {:ok, %Activity{} = activity} = Transmogrifier.handle_incoming(data)
+
+ object = Object.normalize(activity)
+
+ assert object.data["likes"] == []
+ end
+
+ test "it strips internal reactions" do
+ user = insert(:user)
+ {:ok, activity} = CommonAPI.post(user, %{status: "#cofe"})
+ {:ok, _} = CommonAPI.react_with_emoji(activity.id, user, "📢")
+
+ %{object: object} = Activity.get_by_id_with_object(activity.id)
+ assert Map.has_key?(object.data, "reactions")
+ assert Map.has_key?(object.data, "reaction_count")
+
+ object_data = Transmogrifier.strip_internal_fields(object.data)
+ refute Map.has_key?(object_data, "reactions")
+ refute Map.has_key?(object_data, "reaction_count")
+ end
+
+ test "it correctly processes messages with non-array to field" do
+ data =
+ File.read!("test/fixtures/mastodon-post-activity.json")
+ |> Poison.decode!()
+ |> Map.put("to", "https://www.w3.org/ns/activitystreams#Public")
+ |> put_in(["object", "to"], "https://www.w3.org/ns/activitystreams#Public")
+
+ assert {:ok, activity} = Transmogrifier.handle_incoming(data)
+
+ assert [
+ "http://localtesting.pleroma.lol/users/lain",
+ "http://mastodon.example.org/users/admin/followers"
+ ] == activity.data["cc"]
+
+ assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["to"]
+ end
+
+ test "it correctly processes messages with non-array cc field" do
+ data =
+ File.read!("test/fixtures/mastodon-post-activity.json")
+ |> Poison.decode!()
+ |> Map.put("cc", "http://mastodon.example.org/users/admin/followers")
+ |> put_in(["object", "cc"], "http://mastodon.example.org/users/admin/followers")
+
+ assert {:ok, activity} = Transmogrifier.handle_incoming(data)
+
+ assert ["http://mastodon.example.org/users/admin/followers"] == activity.data["cc"]
+ assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["to"]
+ end
+
+ test "it correctly processes messages with weirdness in address fields" do
+ data =
+ File.read!("test/fixtures/mastodon-post-activity.json")
+ |> Poison.decode!()
+ |> Map.put("cc", ["http://mastodon.example.org/users/admin/followers", ["¿"]])
+ |> put_in(["object", "cc"], ["http://mastodon.example.org/users/admin/followers", ["¿"]])
+
+ assert {:ok, activity} = Transmogrifier.handle_incoming(data)
+
+ assert ["http://mastodon.example.org/users/admin/followers"] == activity.data["cc"]
+ assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["to"]
+ end
+ end
+
+ describe "`handle_incoming/2`, Mastodon format `replies` handling" do
+ setup do: clear_config([:activitypub, :note_replies_output_limit], 5)
+ setup do: clear_config([:instance, :federation_incoming_replies_max_depth])
+
+ setup do
+ data =
+ "test/fixtures/mastodon-post-activity.json"
+ |> File.read!()
+ |> Jason.decode!()
+
+ items = get_in(data, ["object", "replies", "first", "items"])
+ assert length(items) > 0
+
+ %{data: data, items: items}
+ end
+
+ test "schedules background fetching of `replies` items if max thread depth limit allows", %{
+ data: data,
+ items: items
+ } do
+ clear_config([:instance, :federation_incoming_replies_max_depth], 10)
+
+ {:ok, activity} = Transmogrifier.handle_incoming(data)
+
+ object = Object.normalize(activity.data["object"])
+
+ assert object.data["replies"] == items
+
+ for id <- items do
+ job_args = %{"op" => "fetch_remote", "id" => id, "depth" => 1}
+ assert_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker, args: job_args)
+ end
+ end
+
+ test "does NOT schedule background fetching of `replies` beyond max thread depth limit allows",
+ %{data: data} do
+ clear_config([:instance, :federation_incoming_replies_max_depth], 0)
+
+ {:ok, _activity} = Transmogrifier.handle_incoming(data)
+
+ assert all_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker) == []
+ end
+ end
+
+ describe "`handle_incoming/2`, Pleroma format `replies` handling" do
+ setup do: clear_config([:activitypub, :note_replies_output_limit], 5)
+ setup do: clear_config([:instance, :federation_incoming_replies_max_depth])
+
+ setup do
+ replies = %{
+ "type" => "Collection",
+ "items" => [Utils.generate_object_id(), Utils.generate_object_id()]
+ }
+
+ activity =
+ File.read!("test/fixtures/mastodon-post-activity.json")
+ |> Poison.decode!()
+ |> Kernel.put_in(["object", "replies"], replies)
+
+ %{activity: activity}
+ end
+
+ test "schedules background fetching of `replies` items if max thread depth limit allows", %{
+ activity: activity
+ } do
+ clear_config([:instance, :federation_incoming_replies_max_depth], 1)
+
+ assert {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(activity)
+ object = Object.normalize(data["object"])
+
+ for id <- object.data["replies"] do
+ job_args = %{"op" => "fetch_remote", "id" => id, "depth" => 1}
+ assert_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker, args: job_args)
+ end
+ end
+
+ test "does NOT schedule background fetching of `replies` beyond max thread depth limit allows",
+ %{activity: activity} do
+ clear_config([:instance, :federation_incoming_replies_max_depth], 0)
+
+ {:ok, _activity} = Transmogrifier.handle_incoming(activity)
+
+ assert all_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker) == []
+ end
+ end
+
+ describe "reserialization" do
+ test "successfully reserializes a message with inReplyTo == nil" do
+ user = insert(:user)
+
+ message = %{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "to" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "cc" => [],
+ "type" => "Create",
+ "object" => %{
+ "to" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "cc" => [],
+ "id" => Utils.generate_object_id(),
+ "type" => "Note",
+ "content" => "Hi",
+ "inReplyTo" => nil,
+ "attributedTo" => user.ap_id
+ },
+ "actor" => user.ap_id
+ }
+
+ {:ok, activity} = Transmogrifier.handle_incoming(message)
+
+ {:ok, _} = Transmogrifier.prepare_outgoing(activity.data)
+ end
+
+ test "successfully reserializes a message with AS2 objects in IR" do
+ user = insert(:user)
+
+ message = %{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "to" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "cc" => [],
+ "type" => "Create",
+ "object" => %{
+ "to" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "cc" => [],
+ "id" => Utils.generate_object_id(),
+ "type" => "Note",
+ "content" => "Hi",
+ "inReplyTo" => nil,
+ "attributedTo" => user.ap_id,
+ "tag" => [
+ %{"name" => "#2hu", "href" => "http://example.com/2hu", "type" => "Hashtag"},
+ %{"name" => "Bob", "href" => "http://example.com/bob", "type" => "Mention"}
+ ]
+ },
+ "actor" => user.ap_id
+ }
+
+ {:ok, activity} = Transmogrifier.handle_incoming(message)
+
+ {:ok, _} = Transmogrifier.prepare_outgoing(activity.data)
+ end
+ end
+
+ describe "fix_in_reply_to/2" do
+ setup do: clear_config([:instance, :federation_incoming_replies_max_depth])
+
+ setup do
+ data = Jason.decode!(File.read!("test/fixtures/mastodon-post-activity.json"))
+ [data: data]
+ end
+
+ test "returns not modified object when hasn't containts inReplyTo field", %{data: data} do
+ assert Transmogrifier.fix_in_reply_to(data) == data
+ end
+
+ test "returns object with inReplyTo when denied incoming reply", %{data: data} do
+ clear_config([:instance, :federation_incoming_replies_max_depth], 0)
+
+ object_with_reply =
+ Map.put(data["object"], "inReplyTo", "https://shitposter.club/notice/2827873")
+
+ modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
+ assert modified_object["inReplyTo"] == "https://shitposter.club/notice/2827873"
+
+ object_with_reply =
+ Map.put(data["object"], "inReplyTo", %{"id" => "https://shitposter.club/notice/2827873"})
+
+ modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
+ assert modified_object["inReplyTo"] == %{"id" => "https://shitposter.club/notice/2827873"}
+
+ object_with_reply =
+ Map.put(data["object"], "inReplyTo", ["https://shitposter.club/notice/2827873"])
+
+ modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
+ assert modified_object["inReplyTo"] == ["https://shitposter.club/notice/2827873"]
+
+ object_with_reply = Map.put(data["object"], "inReplyTo", [])
+ modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
+ assert modified_object["inReplyTo"] == []
+ end
+
+ @tag capture_log: true
+ test "returns modified object when allowed incoming reply", %{data: data} do
+ object_with_reply =
+ Map.put(
+ data["object"],
+ "inReplyTo",
+ "https://mstdn.io/users/mayuutann/statuses/99568293732299394"
+ )
+
+ clear_config([:instance, :federation_incoming_replies_max_depth], 5)
+ modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
+
+ assert modified_object["inReplyTo"] ==
+ "https://mstdn.io/users/mayuutann/statuses/99568293732299394"
+
+ assert modified_object["context"] ==
+ "tag:shitposter.club,2018-02-22:objectType=thread:nonce=e5a7c72d60a9c0e4"
+ end
+ end
+
+ describe "fix_attachments/1" do
+ test "returns not modified object" do
+ data = Jason.decode!(File.read!("test/fixtures/mastodon-post-activity.json"))
+ assert Transmogrifier.fix_attachments(data) == data
+ end
+
+ test "returns modified object when attachment is map" do
+ assert Transmogrifier.fix_attachments(%{
+ "attachment" => %{
+ "mediaType" => "video/mp4",
+ "url" => "https://peertube.moe/stat-480.mp4"
+ }
+ }) == %{
+ "attachment" => [
+ %{
+ "mediaType" => "video/mp4",
+ "type" => "Document",
+ "url" => [
+ %{
+ "href" => "https://peertube.moe/stat-480.mp4",
+ "mediaType" => "video/mp4",
+ "type" => "Link"
+ }
+ ]
+ }
+ ]
+ }
+ end
+
+ test "returns modified object when attachment is list" do
+ assert Transmogrifier.fix_attachments(%{
+ "attachment" => [
+ %{"mediaType" => "video/mp4", "url" => "https://pe.er/stat-480.mp4"},
+ %{"mimeType" => "video/mp4", "href" => "https://pe.er/stat-480.mp4"}
+ ]
+ }) == %{
+ "attachment" => [
+ %{
+ "mediaType" => "video/mp4",
+ "type" => "Document",
+ "url" => [
+ %{
+ "href" => "https://pe.er/stat-480.mp4",
+ "mediaType" => "video/mp4",
+ "type" => "Link"
+ }
+ ]
+ },
+ %{
+ "mediaType" => "video/mp4",
+ "type" => "Document",
+ "url" => [
+ %{
+ "href" => "https://pe.er/stat-480.mp4",
+ "mediaType" => "video/mp4",
+ "type" => "Link"
+ }
+ ]
+ }
+ ]
+ }
+ end
+ end
+
+ describe "fix_emoji/1" do
+ test "returns not modified object when object not contains tags" do
+ data = Jason.decode!(File.read!("test/fixtures/mastodon-post-activity.json"))
+ assert Transmogrifier.fix_emoji(data) == data
+ end
+
+ test "returns object with emoji when object contains list tags" do
+ assert Transmogrifier.fix_emoji(%{
+ "tag" => [
+ %{"type" => "Emoji", "name" => ":bib:", "icon" => %{"url" => "/test"}},
+ %{"type" => "Hashtag"}
+ ]
+ }) == %{
+ "emoji" => %{"bib" => "/test"},
+ "tag" => [
+ %{"icon" => %{"url" => "/test"}, "name" => ":bib:", "type" => "Emoji"},
+ %{"type" => "Hashtag"}
+ ]
+ }
+ end
+
+ test "returns object with emoji when object contains map tag" do
+ assert Transmogrifier.fix_emoji(%{
+ "tag" => %{"type" => "Emoji", "name" => ":bib:", "icon" => %{"url" => "/test"}}
+ }) == %{
+ "emoji" => %{"bib" => "/test"},
+ "tag" => %{"icon" => %{"url" => "/test"}, "name" => ":bib:", "type" => "Emoji"}
+ }
+ end
+ end
+
+ describe "set_replies/1" do
+ setup do: clear_config([:activitypub, :note_replies_output_limit], 2)
+
+ test "returns unmodified object if activity doesn't have self-replies" do
+ data = Jason.decode!(File.read!("test/fixtures/mastodon-post-activity.json"))
+ assert Transmogrifier.set_replies(data) == data
+ end
+
+ test "sets `replies` collection with a limited number of self-replies" do
+ [user, another_user] = insert_list(2, :user)
+
+ {:ok, %{id: id1} = activity} = CommonAPI.post(user, %{status: "1"})
+
+ {:ok, %{id: id2} = self_reply1} =
+ CommonAPI.post(user, %{status: "self-reply 1", in_reply_to_status_id: id1})
+
+ {:ok, self_reply2} =
+ CommonAPI.post(user, %{status: "self-reply 2", in_reply_to_status_id: id1})
+
+ # Assuming to _not_ be present in `replies` due to :note_replies_output_limit is set to 2
+ {:ok, _} = CommonAPI.post(user, %{status: "self-reply 3", in_reply_to_status_id: id1})
+
+ {:ok, _} =
+ CommonAPI.post(user, %{
+ status: "self-reply to self-reply",
+ in_reply_to_status_id: id2
+ })
+
+ {:ok, _} =
+ CommonAPI.post(another_user, %{
+ status: "another user's reply",
+ in_reply_to_status_id: id1
+ })
+
+ object = Object.normalize(activity, fetch: false)
+ replies_uris = Enum.map([self_reply1, self_reply2], fn a -> a.object.data["id"] end)
+
+ assert %{"type" => "Collection", "items" => ^replies_uris} =
+ Transmogrifier.set_replies(object.data)["replies"]
+ end
+ end
+
+ test "take_emoji_tags/1" do
+ user = insert(:user, %{emoji: %{"firefox" => "https://example.org/firefox.png"}})
+
+ assert Transmogrifier.take_emoji_tags(user) == [
+ %{
+ "icon" => %{"type" => "Image", "url" => "https://example.org/firefox.png"},
+ "id" => "https://example.org/firefox.png",
+ "name" => ":firefox:",
+ "type" => "Emoji",
+ "updated" => "1970-01-01T00:00:00Z"
+ }
+ ]
+ end
+end
diff --git a/test/pleroma/web/activity_pub/transmogrifier/page_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/page_handling_test.exs
new file mode 100644
index 000000000..4ac71e066
--- /dev/null
+++ b/test/pleroma/web/activity_pub/transmogrifier/page_handling_test.exs
@@ -0,0 +1,36 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.Transmogrifier.PageHandlingTest do
+ use Oban.Testing, repo: Pleroma.Repo
+ use Pleroma.DataCase
+
+ alias Pleroma.Object.Fetcher
+
+ test "Lemmy Page" do
+ Tesla.Mock.mock(fn
+ %{url: "https://enterprise.lemmy.ml/post/3"} ->
+ %Tesla.Env{
+ status: 200,
+ headers: [{"content-type", "application/activity+json"}],
+ body: File.read!("test/fixtures/tesla_mock/lemmy-page.json")
+ }
+
+ %{url: "https://enterprise.lemmy.ml/u/nutomic"} ->
+ %Tesla.Env{
+ status: 200,
+ headers: [{"content-type", "application/activity+json"}],
+ body: File.read!("test/fixtures/tesla_mock/lemmy-user.json")
+ }
+ end)
+
+ {:ok, object} = Fetcher.fetch_object_from_id("https://enterprise.lemmy.ml/post/3")
+
+ assert object.data["summary"] == "Hello Federation!"
+ assert object.data["published"] == "2020-09-14T15:03:11.909105Z"
+
+ # WAT
+ assert object.data["url"] == "https://enterprise.lemmy.ml/pictrs/image/US52d9DPvf.jpg"
+ end
+end
diff --git a/test/web/activity_pub/transmogrifier/question_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/question_handling_test.exs
index 74ee79543..32cf51e59 100644
--- a/test/web/activity_pub/transmogrifier/question_handling_test.exs
+++ b/test/pleroma/web/activity_pub/transmogrifier/question_handling_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.Transmogrifier.QuestionHandlingTest do
@@ -18,11 +18,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.QuestionHandlingTest do
end
test "Mastodon Question activity" do
- data = File.read!("test/fixtures/mastodon-question-activity.json") |> Poison.decode!()
+ data = File.read!("test/fixtures/mastodon-question-activity.json") |> Jason.decode!()
{:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
- object = Object.normalize(activity, false)
+ object = Object.normalize(activity, fetch: false)
assert object.data["url"] == "https://mastodon.sdf.org/@rinpatch/102070944809637304"
@@ -65,7 +65,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.QuestionHandlingTest do
{:ok, reply_activity} = CommonAPI.post(user, %{status: "hewwo", in_reply_to_id: activity.id})
- reply_object = Object.normalize(reply_activity, false)
+ reply_object = Object.normalize(reply_activity, fetch: false)
assert reply_object.data["context"] == object.data["context"]
assert reply_object.data["context_id"] == object.data["context_id"]
@@ -97,11 +97,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.QuestionHandlingTest do
data =
File.read!("test/fixtures/mastodon-question-activity.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Kernel.put_in(["object", "oneOf"], options)
{:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
- object = Object.normalize(activity, false)
+ object = Object.normalize(activity, fetch: false)
assert Enum.sort(object.data["oneOf"]) == Enum.sort(options)
end
@@ -142,12 +142,12 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.QuestionHandlingTest do
data =
File.read!("test/fixtures/mastodon-question-activity.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Kernel.put_in(["object", "oneOf"], options)
|> Kernel.put_in(["object", "tag"], tag)
{:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
- object = Object.normalize(activity, false)
+ object = Object.normalize(activity, fetch: false)
assert object.data["oneOf"] == options
@@ -157,18 +157,18 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.QuestionHandlingTest do
}
end
- test "returns an error if received a second time" do
- data = File.read!("test/fixtures/mastodon-question-activity.json") |> Poison.decode!()
+ test "returns same activity if received a second time" do
+ data = File.read!("test/fixtures/mastodon-question-activity.json") |> Jason.decode!()
assert {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
- assert {:error, {:validate_object, {:error, _}}} = Transmogrifier.handle_incoming(data)
+ assert {:ok, ^activity} = Transmogrifier.handle_incoming(data)
end
test "accepts a Question with no content" do
data =
File.read!("test/fixtures/mastodon-question-activity.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Kernel.put_in(["object", "content"], "")
assert {:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(data)
diff --git a/test/web/activity_pub/transmogrifier/reject_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/reject_handling_test.exs
index 7592fbe1c..355e664d4 100644
--- a/test/web/activity_pub/transmogrifier/reject_handling_test.exs
+++ b/test/pleroma/web/activity_pub/transmogrifier/reject_handling_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.Transmogrifier.RejectHandlingTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Activity
alias Pleroma.User
@@ -14,11 +14,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.RejectHandlingTest do
test "it fails for incoming rejects which cannot be correlated" do
follower = insert(:user)
- followed = insert(:user, locked: true)
+ followed = insert(:user, is_locked: true)
accept_data =
File.read!("test/fixtures/mastodon-reject-activity.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("actor", followed.ap_id)
accept_data =
@@ -33,16 +33,16 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.RejectHandlingTest do
test "it works for incoming rejects which are referenced by IRI only" do
follower = insert(:user)
- followed = insert(:user, locked: true)
+ followed = insert(:user, is_locked: true)
- {:ok, follower} = User.follow(follower, followed)
+ {:ok, follower, followed} = User.follow(follower, followed)
{:ok, _, _, follow_activity} = CommonAPI.follow(follower, followed)
assert User.following?(follower, followed) == true
reject_data =
File.read!("test/fixtures/mastodon-reject-activity.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("actor", followed.ap_id)
|> Map.put("object", follow_activity.data["id"])
@@ -58,7 +58,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.RejectHandlingTest do
data =
File.read!("test/fixtures/mastodon-follow-activity.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", user.ap_id)
|> Map.put("id", "")
diff --git a/test/web/activity_pub/transmogrifier/undo_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/undo_handling_test.exs
index 8683f7135..f6e40722c 100644
--- a/test/web/activity_pub/transmogrifier/undo_handling_test.exs
+++ b/test/pleroma/web/activity_pub/transmogrifier/undo_handling_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.Transmogrifier.UndoHandlingTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Activity
alias Pleroma.Object
@@ -21,7 +21,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UndoHandlingTest do
data =
File.read!("test/fixtures/mastodon-undo-like.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", reaction_activity.data["id"])
|> Map.put("actor", user.ap_id)
@@ -38,7 +38,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UndoHandlingTest do
data =
File.read!("test/fixtures/mastodon-undo-like.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", activity.data["object"])
assert Transmogrifier.handle_incoming(data) == :error
@@ -50,7 +50,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UndoHandlingTest do
like_data =
File.read!("test/fixtures/mastodon-like.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", activity.data["object"])
_liker = insert(:user, ap_id: like_data["actor"], local: false)
@@ -59,7 +59,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UndoHandlingTest do
data =
File.read!("test/fixtures/mastodon-undo-like.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", like_data)
|> Map.put("actor", like_data["actor"])
@@ -81,7 +81,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UndoHandlingTest do
like_data =
File.read!("test/fixtures/mastodon-like.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", activity.data["object"])
_liker = insert(:user, ap_id: like_data["actor"], local: false)
@@ -90,7 +90,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UndoHandlingTest do
data =
File.read!("test/fixtures/mastodon-undo-like.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", like_data["id"])
|> Map.put("actor", like_data["actor"])
@@ -108,7 +108,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UndoHandlingTest do
announce_data =
File.read!("test/fixtures/mastodon-announce.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", activity.data["object"])
_announcer = insert(:user, ap_id: announce_data["actor"], local: false)
@@ -118,7 +118,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UndoHandlingTest do
data =
File.read!("test/fixtures/mastodon-undo-announce.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", announce_data)
|> Map.put("actor", announce_data["actor"])
@@ -135,7 +135,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UndoHandlingTest do
follow_data =
File.read!("test/fixtures/mastodon-follow-activity.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", user.ap_id)
_follower = insert(:user, ap_id: follow_data["actor"], local: false)
@@ -144,7 +144,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UndoHandlingTest do
data =
File.read!("test/fixtures/mastodon-unfollow-activity.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", follow_data)
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
@@ -162,7 +162,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UndoHandlingTest do
block_data =
File.read!("test/fixtures/mastodon-block-activity.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", user.ap_id)
_blocker = insert(:user, ap_id: block_data["actor"], local: false)
@@ -171,7 +171,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UndoHandlingTest do
data =
File.read!("test/fixtures/mastodon-unblock-activity.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", block_data)
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
diff --git a/test/web/activity_pub/transmogrifier/user_update_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/user_update_handling_test.exs
index 64636656c..b1a064772 100644
--- a/test/web/activity_pub/transmogrifier/user_update_handling_test.exs
+++ b/test/pleroma/web/activity_pub/transmogrifier/user_update_handling_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.Transmogrifier.UserUpdateHandlingTest do
@@ -14,7 +14,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UserUpdateHandlingTest do
test "it works for incoming update activities" do
user = insert(:user, local: false)
- update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!()
+ update_data = File.read!("test/fixtures/mastodon-update.json") |> Jason.decode!()
object =
update_data["object"]
@@ -58,7 +58,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UserUpdateHandlingTest do
{:ok, _activity} =
"test/fixtures/mastodon-update.json"
|> File.read!()
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("actor", actor)
|> Map.update!("object", fn object ->
object
@@ -82,7 +82,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UserUpdateHandlingTest do
assert user.fields == []
- update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!()
+ update_data = File.read!("test/fixtures/mastodon-update.json") |> Jason.decode!()
object =
update_data["object"]
@@ -103,7 +103,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UserUpdateHandlingTest do
%{"name" => "foo1", "value" => "updated"}
]
- Pleroma.Config.put([:instance, :max_remote_account_fields], 2)
+ clear_config([:instance, :max_remote_account_fields], 2)
update_data =
update_data
@@ -138,7 +138,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UserUpdateHandlingTest do
test "it works for incoming update activities which lock the account" do
user = insert(:user, local: false)
- update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!()
+ update_data = File.read!("test/fixtures/mastodon-update.json") |> Jason.decode!()
object =
update_data["object"]
@@ -154,6 +154,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.UserUpdateHandlingTest do
{:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(update_data)
user = User.get_cached_by_ap_id(user.ap_id)
- assert user.locked == true
+ assert user.is_locked == true
end
end
diff --git a/test/pleroma/web/activity_pub/transmogrifier/video_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/video_handling_test.exs
new file mode 100644
index 000000000..87c53ebf4
--- /dev/null
+++ b/test/pleroma/web/activity_pub/transmogrifier/video_handling_test.exs
@@ -0,0 +1,122 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.Transmogrifier.VideoHandlingTest do
+ use Oban.Testing, repo: Pleroma.Repo
+ use Pleroma.DataCase
+
+ alias Pleroma.Activity
+ alias Pleroma.Object
+ alias Pleroma.Object.Fetcher
+ alias Pleroma.Web.ActivityPub.Transmogrifier
+
+ setup_all do
+ Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
+ :ok
+ end
+
+ test "skip converting the content when it is nil" do
+ data =
+ File.read!("test/fixtures/tesla_mock/framatube.org-video.json")
+ |> Jason.decode!()
+ |> Kernel.put_in(["object", "content"], nil)
+
+ {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
+
+ assert object = Object.normalize(activity, fetch: false)
+
+ assert object.data["content"] == nil
+ end
+
+ test "it converts content of object to html" do
+ data = File.read!("test/fixtures/tesla_mock/framatube.org-video.json") |> Jason.decode!()
+
+ {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
+
+ assert object = Object.normalize(activity, fetch: false)
+
+ assert object.data["content"] ==
+ "<p>Après avoir mené avec un certain succès la campagne « Dégooglisons Internet » en 2014, l’association Framasoft annonce fin 2019 arrêter progressivement un certain nombre de ses services alternatifs aux GAFAM. Pourquoi ?</p><p>Transcription par @aprilorg ici : <a href=\"https://www.april.org/deframasoftisons-internet-pierre-yves-gosset-framasoft\">https://www.april.org/deframasoftisons-internet-pierre-yves-gosset-framasoft</a></p>"
+ end
+
+ test "it remaps video URLs as attachments if necessary" do
+ {:ok, object} =
+ Fetcher.fetch_object_from_id(
+ "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3"
+ )
+
+ assert object.data["url"] ==
+ "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3"
+
+ assert object.data["attachment"] == [
+ %{
+ "type" => "Link",
+ "mediaType" => "video/mp4",
+ "url" => [
+ %{
+ "href" =>
+ "https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4",
+ "mediaType" => "video/mp4",
+ "type" => "Link",
+ "width" => 480
+ }
+ ]
+ }
+ ]
+
+ data = File.read!("test/fixtures/tesla_mock/framatube.org-video.json") |> Jason.decode!()
+
+ {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
+
+ assert object = Object.normalize(activity, fetch: false)
+
+ assert object.data["attachment"] == [
+ %{
+ "type" => "Link",
+ "mediaType" => "video/mp4",
+ "url" => [
+ %{
+ "href" =>
+ "https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4",
+ "mediaType" => "video/mp4",
+ "type" => "Link",
+ "height" => 1080
+ }
+ ]
+ }
+ ]
+
+ assert object.data["url"] ==
+ "https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206"
+ end
+
+ test "it works for peertube videos with only their mpegURL map" do
+ data =
+ File.read!("test/fixtures/peertube/video-object-mpegURL-only.json")
+ |> Jason.decode!()
+
+ {:ok, %Activity{local: false} = activity} = Transmogrifier.handle_incoming(data)
+
+ assert object = Object.normalize(activity, fetch: false)
+
+ assert object.data["attachment"] == [
+ %{
+ "type" => "Link",
+ "mediaType" => "video/mp4",
+ "url" => [
+ %{
+ "href" =>
+ "https://peertube.stream/static/streaming-playlists/hls/abece3c3-b9c6-47f4-8040-f3eed8c602e6/abece3c3-b9c6-47f4-8040-f3eed8c602e6-1080-fragmented.mp4",
+ "mediaType" => "video/mp4",
+ "type" => "Link",
+ "height" => 1080
+ }
+ ]
+ }
+ ]
+
+ assert object.data["url"] ==
+ "https://peertube.stream/videos/watch/abece3c3-b9c6-47f4-8040-f3eed8c602e6"
+ end
+end
diff --git a/test/pleroma/web/activity_pub/transmogrifier_test.exs b/test/pleroma/web/activity_pub/transmogrifier_test.exs
new file mode 100644
index 000000000..06daf6a9f
--- /dev/null
+++ b/test/pleroma/web/activity_pub/transmogrifier_test.exs
@@ -0,0 +1,567 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
+ use Oban.Testing, repo: Pleroma.Repo
+ use Pleroma.DataCase
+
+ alias Pleroma.Activity
+ alias Pleroma.Object
+ alias Pleroma.Tests.ObanHelpers
+ alias Pleroma.User
+ alias Pleroma.Web.ActivityPub.Transmogrifier
+ alias Pleroma.Web.ActivityPub.Utils
+ alias Pleroma.Web.AdminAPI.AccountView
+ alias Pleroma.Web.CommonAPI
+
+ import Mock
+ import Pleroma.Factory
+ import ExUnit.CaptureLog
+
+ setup_all do
+ Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
+ :ok
+ end
+
+ setup do: clear_config([:instance, :max_remote_account_fields])
+
+ describe "handle_incoming" do
+ test "it works for incoming unfollows with an existing follow" do
+ user = insert(:user)
+
+ follow_data =
+ File.read!("test/fixtures/mastodon-follow-activity.json")
+ |> Jason.decode!()
+ |> Map.put("object", user.ap_id)
+
+ {:ok, %Activity{data: _, local: false}} = Transmogrifier.handle_incoming(follow_data)
+
+ data =
+ File.read!("test/fixtures/mastodon-unfollow-activity.json")
+ |> Jason.decode!()
+ |> Map.put("object", follow_data)
+
+ {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+
+ assert data["type"] == "Undo"
+ assert data["object"]["type"] == "Follow"
+ assert data["object"]["object"] == user.ap_id
+ assert data["actor"] == "http://mastodon.example.org/users/admin"
+
+ refute User.following?(User.get_cached_by_ap_id(data["actor"]), user)
+ end
+
+ test "it accepts Flag activities" do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
+ object = Object.normalize(activity, fetch: false)
+
+ note_obj = %{
+ "type" => "Note",
+ "id" => activity.data["id"],
+ "content" => "test post",
+ "published" => object.data["published"],
+ "actor" => AccountView.render("show.json", %{user: user, skip_visibility_check: true})
+ }
+
+ message = %{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "cc" => [user.ap_id],
+ "object" => [user.ap_id, activity.data["id"]],
+ "type" => "Flag",
+ "content" => "blocked AND reported!!!",
+ "actor" => other_user.ap_id
+ }
+
+ assert {:ok, activity} = Transmogrifier.handle_incoming(message)
+
+ assert activity.data["object"] == [user.ap_id, note_obj]
+ assert activity.data["content"] == "blocked AND reported!!!"
+ assert activity.data["actor"] == other_user.ap_id
+ assert activity.data["cc"] == [user.ap_id]
+ end
+
+ test "it accepts Move activities" do
+ old_user = insert(:user)
+ new_user = insert(:user)
+
+ message = %{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "type" => "Move",
+ "actor" => old_user.ap_id,
+ "object" => old_user.ap_id,
+ "target" => new_user.ap_id
+ }
+
+ assert :error = Transmogrifier.handle_incoming(message)
+
+ {:ok, _new_user} = User.update_and_set_cache(new_user, %{also_known_as: [old_user.ap_id]})
+
+ assert {:ok, %Activity{} = activity} = Transmogrifier.handle_incoming(message)
+ assert activity.actor == old_user.ap_id
+ assert activity.data["actor"] == old_user.ap_id
+ assert activity.data["object"] == old_user.ap_id
+ assert activity.data["target"] == new_user.ap_id
+ assert activity.data["type"] == "Move"
+ end
+ end
+
+ describe "prepare outgoing" do
+ test "it inlines private announced objects" do
+ user = insert(:user)
+
+ {:ok, activity} = CommonAPI.post(user, %{status: "hey", visibility: "private"})
+
+ {:ok, announce_activity} = CommonAPI.repeat(activity.id, user)
+
+ {:ok, modified} = Transmogrifier.prepare_outgoing(announce_activity.data)
+
+ assert modified["object"]["content"] == "hey"
+ assert modified["object"]["actor"] == modified["object"]["attributedTo"]
+ end
+
+ test "it turns mentions into tags" do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{status: "hey, @#{other_user.nickname}, how are ya? #2hu"})
+
+ with_mock Pleroma.Notification,
+ get_notified_from_activity: fn _, _ -> [] end do
+ {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
+
+ object = modified["object"]
+
+ expected_mention = %{
+ "href" => other_user.ap_id,
+ "name" => "@#{other_user.nickname}",
+ "type" => "Mention"
+ }
+
+ expected_tag = %{
+ "href" => Pleroma.Web.Endpoint.url() <> "/tags/2hu",
+ "type" => "Hashtag",
+ "name" => "#2hu"
+ }
+
+ refute called(Pleroma.Notification.get_notified_from_activity(:_, :_))
+ assert Enum.member?(object["tag"], expected_tag)
+ assert Enum.member?(object["tag"], expected_mention)
+ end
+ end
+
+ test "it adds the json-ld context and the conversation property" do
+ user = insert(:user)
+
+ {:ok, activity} = CommonAPI.post(user, %{status: "hey"})
+ {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
+
+ assert modified["@context"] == Utils.make_json_ld_header()["@context"]
+
+ assert modified["object"]["conversation"] == modified["context"]
+ end
+
+ test "it sets the 'attributedTo' property to the actor of the object if it doesn't have one" do
+ user = insert(:user)
+
+ {:ok, activity} = CommonAPI.post(user, %{status: "hey"})
+ {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
+
+ assert modified["object"]["actor"] == modified["object"]["attributedTo"]
+ end
+
+ test "it strips internal hashtag data" do
+ user = insert(:user)
+
+ {:ok, activity} = CommonAPI.post(user, %{status: "#2hu"})
+
+ expected_tag = %{
+ "href" => Pleroma.Web.Endpoint.url() <> "/tags/2hu",
+ "type" => "Hashtag",
+ "name" => "#2hu"
+ }
+
+ {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
+
+ assert modified["object"]["tag"] == [expected_tag]
+ end
+
+ test "it strips internal fields" do
+ user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ status: "#2hu :firefox:",
+ generator: %{type: "Application", name: "TestClient", url: "https://pleroma.social"}
+ })
+
+ # Ensure injected application data made it into the activity
+ # as we don't have a Token to derive it from, otherwise it will
+ # be nil and the test will pass
+ assert %{
+ type: "Application",
+ name: "TestClient",
+ url: "https://pleroma.social"
+ } == activity.object.data["generator"]
+
+ {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
+
+ assert length(modified["object"]["tag"]) == 2
+
+ assert is_nil(modified["object"]["emoji"])
+ assert is_nil(modified["object"]["like_count"])
+ assert is_nil(modified["object"]["announcements"])
+ assert is_nil(modified["object"]["announcement_count"])
+ assert is_nil(modified["object"]["context_id"])
+ assert is_nil(modified["object"]["generator"])
+ end
+
+ test "it strips internal fields of article" do
+ activity = insert(:article_activity)
+
+ {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
+
+ assert length(modified["object"]["tag"]) == 2
+
+ assert is_nil(modified["object"]["emoji"])
+ assert is_nil(modified["object"]["like_count"])
+ assert is_nil(modified["object"]["announcements"])
+ assert is_nil(modified["object"]["announcement_count"])
+ assert is_nil(modified["object"]["context_id"])
+ assert is_nil(modified["object"]["likes"])
+ end
+
+ test "the directMessage flag is present" do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, activity} = CommonAPI.post(user, %{status: "2hu :moominmamma:"})
+
+ {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
+
+ assert modified["directMessage"] == false
+
+ {:ok, activity} = CommonAPI.post(user, %{status: "@#{other_user.nickname} :moominmamma:"})
+
+ {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
+
+ assert modified["directMessage"] == false
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ status: "@#{other_user.nickname} :moominmamma:",
+ visibility: "direct"
+ })
+
+ {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
+
+ assert modified["directMessage"] == true
+ end
+
+ test "it strips BCC field" do
+ user = insert(:user)
+ {:ok, list} = Pleroma.List.create("foo", user)
+
+ {:ok, activity} = CommonAPI.post(user, %{status: "foobar", visibility: "list:#{list.id}"})
+
+ {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
+
+ assert is_nil(modified["bcc"])
+ end
+
+ test "it can handle Listen activities" do
+ listen_activity = insert(:listen)
+
+ {:ok, modified} = Transmogrifier.prepare_outgoing(listen_activity.data)
+
+ assert modified["type"] == "Listen"
+
+ user = insert(:user)
+
+ {:ok, activity} = CommonAPI.listen(user, %{"title" => "lain radio episode 1"})
+
+ {:ok, _modified} = Transmogrifier.prepare_outgoing(activity.data)
+ end
+
+ test "custom emoji urls are URI encoded" do
+ # :dinosaur: filename has a space -> dino walking.gif
+ user = insert(:user)
+
+ {:ok, activity} = CommonAPI.post(user, %{status: "everybody do the dinosaur :dinosaur:"})
+
+ {:ok, prepared} = Transmogrifier.prepare_outgoing(activity.data)
+
+ assert length(prepared["object"]["tag"]) == 1
+
+ url = prepared["object"]["tag"] |> List.first() |> Map.get("icon") |> Map.get("url")
+
+ assert url == "http://localhost:4001/emoji/dino%20walking.gif"
+ end
+ end
+
+ describe "user upgrade" do
+ test "it upgrades a user to activitypub" do
+ user =
+ insert(:user, %{
+ nickname: "rye@niu.moe",
+ local: false,
+ ap_id: "https://niu.moe/users/rye",
+ follower_address: User.ap_followers(%User{nickname: "rye@niu.moe"})
+ })
+
+ user_two = insert(:user)
+ Pleroma.FollowingRelationship.follow(user_two, user, :follow_accept)
+
+ {:ok, activity} = CommonAPI.post(user, %{status: "test"})
+ {:ok, unrelated_activity} = CommonAPI.post(user_two, %{status: "test"})
+ assert "http://localhost:4001/users/rye@niu.moe/followers" in activity.recipients
+
+ user = User.get_cached_by_id(user.id)
+ assert user.note_count == 1
+
+ {:ok, user} = Transmogrifier.upgrade_user_from_ap_id("https://niu.moe/users/rye")
+ ObanHelpers.perform_all()
+
+ assert user.ap_enabled
+ assert user.note_count == 1
+ assert user.follower_address == "https://niu.moe/users/rye/followers"
+ assert user.following_address == "https://niu.moe/users/rye/following"
+
+ user = User.get_cached_by_id(user.id)
+ assert user.note_count == 1
+
+ activity = Activity.get_by_id(activity.id)
+ assert user.follower_address in activity.recipients
+
+ assert %{
+ "url" => [
+ %{
+ "href" =>
+ "https://cdn.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg"
+ }
+ ]
+ } = user.avatar
+
+ assert %{
+ "url" => [
+ %{
+ "href" =>
+ "https://cdn.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png"
+ }
+ ]
+ } = user.banner
+
+ refute "..." in activity.recipients
+
+ unrelated_activity = Activity.get_by_id(unrelated_activity.id)
+ refute user.follower_address in unrelated_activity.recipients
+
+ user_two = User.get_cached_by_id(user_two.id)
+ assert User.following?(user_two, user)
+ refute "..." in User.following(user_two)
+ end
+ end
+
+ describe "actor rewriting" do
+ test "it fixes the actor URL property to be a proper URI" do
+ data = %{
+ "url" => %{"href" => "http://example.com"}
+ }
+
+ rewritten = Transmogrifier.maybe_fix_user_object(data)
+ assert rewritten["url"] == "http://example.com"
+ end
+ end
+
+ describe "actor origin containment" do
+ test "it rejects activities which reference objects with bogus origins" do
+ data = %{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "id" => "http://mastodon.example.org/users/admin/activities/1234",
+ "actor" => "http://mastodon.example.org/users/admin",
+ "to" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "object" => "https://info.pleroma.site/activity.json",
+ "type" => "Announce"
+ }
+
+ assert capture_log(fn ->
+ {:error, _} = Transmogrifier.handle_incoming(data)
+ end) =~ "Object containment failed"
+ end
+
+ test "it rejects activities which reference objects that have an incorrect attribution (variant 1)" do
+ data = %{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "id" => "http://mastodon.example.org/users/admin/activities/1234",
+ "actor" => "http://mastodon.example.org/users/admin",
+ "to" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "object" => "https://info.pleroma.site/activity2.json",
+ "type" => "Announce"
+ }
+
+ assert capture_log(fn ->
+ {:error, _} = Transmogrifier.handle_incoming(data)
+ end) =~ "Object containment failed"
+ end
+
+ test "it rejects activities which reference objects that have an incorrect attribution (variant 2)" do
+ data = %{
+ "@context" => "https://www.w3.org/ns/activitystreams",
+ "id" => "http://mastodon.example.org/users/admin/activities/1234",
+ "actor" => "http://mastodon.example.org/users/admin",
+ "to" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "object" => "https://info.pleroma.site/activity3.json",
+ "type" => "Announce"
+ }
+
+ assert capture_log(fn ->
+ {:error, _} = Transmogrifier.handle_incoming(data)
+ end) =~ "Object containment failed"
+ end
+ end
+
+ describe "fix_explicit_addressing" do
+ setup do
+ user = insert(:user)
+ [user: user]
+ end
+
+ test "moves non-explicitly mentioned actors to cc", %{user: user} do
+ explicitly_mentioned_actors = [
+ "https://pleroma.gold/users/user1",
+ "https://pleroma.gold/user2"
+ ]
+
+ object = %{
+ "actor" => user.ap_id,
+ "to" => explicitly_mentioned_actors ++ ["https://social.beepboop.ga/users/dirb"],
+ "cc" => [],
+ "tag" =>
+ Enum.map(explicitly_mentioned_actors, fn href ->
+ %{"type" => "Mention", "href" => href}
+ end)
+ }
+
+ fixed_object = Transmogrifier.fix_explicit_addressing(object, user.follower_address)
+ assert Enum.all?(explicitly_mentioned_actors, &(&1 in fixed_object["to"]))
+ refute "https://social.beepboop.ga/users/dirb" in fixed_object["to"]
+ assert "https://social.beepboop.ga/users/dirb" in fixed_object["cc"]
+ end
+
+ test "does not move actor's follower collection to cc", %{user: user} do
+ object = %{
+ "actor" => user.ap_id,
+ "to" => [user.follower_address],
+ "cc" => []
+ }
+
+ fixed_object = Transmogrifier.fix_explicit_addressing(object, user.follower_address)
+ assert user.follower_address in fixed_object["to"]
+ refute user.follower_address in fixed_object["cc"]
+ end
+
+ test "removes recipient's follower collection from cc", %{user: user} do
+ recipient = insert(:user)
+
+ object = %{
+ "actor" => user.ap_id,
+ "to" => [recipient.ap_id, "https://www.w3.org/ns/activitystreams#Public"],
+ "cc" => [user.follower_address, recipient.follower_address]
+ }
+
+ fixed_object = Transmogrifier.fix_explicit_addressing(object, user.follower_address)
+
+ assert user.follower_address in fixed_object["cc"]
+ refute recipient.follower_address in fixed_object["cc"]
+ refute recipient.follower_address in fixed_object["to"]
+ end
+ end
+
+ describe "fix_summary/1" do
+ test "returns fixed object" do
+ assert Transmogrifier.fix_summary(%{"summary" => nil}) == %{"summary" => ""}
+ assert Transmogrifier.fix_summary(%{"summary" => "ok"}) == %{"summary" => "ok"}
+ assert Transmogrifier.fix_summary(%{}) == %{"summary" => ""}
+ end
+ end
+
+ describe "fix_url/1" do
+ test "fixes data for object when url is map" do
+ object = %{
+ "url" => %{
+ "type" => "Link",
+ "mimeType" => "video/mp4",
+ "href" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4"
+ }
+ }
+
+ assert Transmogrifier.fix_url(object) == %{
+ "url" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4"
+ }
+ end
+
+ test "returns non-modified object" do
+ assert Transmogrifier.fix_url(%{"type" => "Text"}) == %{"type" => "Text"}
+ end
+ end
+
+ describe "get_obj_helper/2" do
+ test "returns nil when cannot normalize object" do
+ assert capture_log(fn ->
+ refute Transmogrifier.get_obj_helper("test-obj-id")
+ end) =~ "Unsupported URI scheme"
+ end
+
+ @tag capture_log: true
+ test "returns {:ok, %Object{}} for success case" do
+ assert {:ok, %Object{}} =
+ Transmogrifier.get_obj_helper(
+ "https://mstdn.io/users/mayuutann/statuses/99568293732299394"
+ )
+ end
+ end
+
+ describe "fix_attachments/1" do
+ test "puts dimensions into attachment url field" do
+ object = %{
+ "attachment" => [
+ %{
+ "type" => "Document",
+ "name" => "Hello world",
+ "url" => "https://media.example.tld/1.jpg",
+ "width" => 880,
+ "height" => 960,
+ "mediaType" => "image/jpeg",
+ "blurhash" => "eTKL26+HDjcEIBVl;ds+K6t301W.t7nit7y1E,R:v}ai4nXSt7V@of"
+ }
+ ]
+ }
+
+ expected = %{
+ "attachment" => [
+ %{
+ "type" => "Document",
+ "name" => "Hello world",
+ "url" => [
+ %{
+ "type" => "Link",
+ "mediaType" => "image/jpeg",
+ "href" => "https://media.example.tld/1.jpg",
+ "width" => 880,
+ "height" => 960
+ }
+ ],
+ "mediaType" => "image/jpeg",
+ "blurhash" => "eTKL26+HDjcEIBVl;ds+K6t301W.t7nit7y1E,R:v}ai4nXSt7V@of"
+ }
+ ]
+ }
+
+ assert Transmogrifier.fix_attachments(object) == expected
+ end
+ end
+end
diff --git a/test/web/activity_pub/utils_test.exs b/test/pleroma/web/activity_pub/utils_test.exs
index d50213545..62dc02f61 100644
--- a/test/web/activity_pub/utils_test.exs
+++ b/test/pleroma/web/activity_pub/utils_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.UtilsTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.Repo
@@ -165,7 +165,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do
}
})
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
{:ok, votes, object} = CommonAPI.vote(other_user, object, [0, 1])
assert Enum.sort(Utils.get_existing_votes(other_user.ap_id, object)) == Enum.sort(votes)
end
@@ -183,7 +183,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do
}
})
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
{:ok, [vote], object} = CommonAPI.vote(other_user, object, [0])
{:ok, _activity} = CommonAPI.favorite(user, activity.id)
[fetched_vote] = Utils.get_existing_votes(other_user.ap_id, object)
@@ -193,7 +193,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do
describe "update_follow_state_for_all/2" do
test "updates the state of all Follow activities with the same actor and object" do
- user = insert(:user, locked: true)
+ user = insert(:user, is_locked: true)
follower = insert(:user)
{:ok, _, _, follow_activity} = CommonAPI.follow(follower, user)
@@ -213,11 +213,25 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do
assert refresh_record(follow_activity).data["state"] == "accept"
assert refresh_record(follow_activity_two).data["state"] == "accept"
end
+
+ test "also updates the state of accepted follows" do
+ user = insert(:user)
+ follower = insert(:user)
+
+ {:ok, _, _, follow_activity} = CommonAPI.follow(follower, user)
+ {:ok, _, _, follow_activity_two} = CommonAPI.follow(follower, user)
+
+ {:ok, follow_activity_two} =
+ Utils.update_follow_state_for_all(follow_activity_two, "reject")
+
+ assert refresh_record(follow_activity).data["state"] == "reject"
+ assert refresh_record(follow_activity_two).data["state"] == "reject"
+ end
end
describe "update_follow_state/2" do
test "updates the state of the given follow activity" do
- user = insert(:user, locked: true)
+ user = insert(:user, is_locked: true)
follower = insert(:user)
{:ok, _, _, follow_activity} = CommonAPI.follow(follower, user)
@@ -242,7 +256,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do
test "updates likes" do
user = insert(:user)
activity = insert(:note_activity)
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
assert {:ok, updated_object} =
Utils.update_element_in_object(
@@ -302,7 +316,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do
describe "get_existing_like/2" do
test "fetches existing like" do
note_activity = insert(:note_activity)
- assert object = Object.normalize(note_activity)
+ assert object = Object.normalize(note_activity, fetch: false)
user = insert(:user)
refute Utils.get_existing_like(user.ap_id, object)
@@ -320,7 +334,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do
test "fetches existing announce" do
note_activity = insert(:note_activity)
- assert object = Object.normalize(note_activity)
+ assert object = Object.normalize(note_activity, fetch: false)
actor = insert(:user)
{:ok, announce} = CommonAPI.repeat(note_activity.id, actor)
@@ -412,7 +426,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do
describe "lazy_put_activity_defaults/2" do
test "returns map with id and published data" do
note_activity = insert(:note_activity)
- object = Object.normalize(note_activity)
+ object = Object.normalize(note_activity, fetch: false)
res = Utils.lazy_put_activity_defaults(%{"context" => object.data["id"]})
assert res["context"] == object.data["id"]
assert res["context_id"] == object.id
@@ -431,7 +445,7 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do
test "returns activity data with object" do
note_activity = insert(:note_activity)
- object = Object.normalize(note_activity)
+ object = Object.normalize(note_activity, fetch: false)
res =
Utils.lazy_put_activity_defaults(%{
diff --git a/test/web/activity_pub/views/object_view_test.exs b/test/pleroma/web/activity_pub/views/object_view_test.exs
index f0389845d..923515dec 100644
--- a/test/web/activity_pub/views/object_view_test.exs
+++ b/test/pleroma/web/activity_pub/views/object_view_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ObjectViewTest do
@@ -24,7 +24,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectViewTest do
test "renders a note activity" do
note = insert(:note_activity)
- object = Object.normalize(note)
+ object = Object.normalize(note, fetch: false)
result = ObjectView.render("object.json", %{object: note})
@@ -56,7 +56,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectViewTest do
test "renders a like activity" do
note = insert(:note_activity)
- object = Object.normalize(note)
+ object = Object.normalize(note, fetch: false)
user = insert(:user)
{:ok, like_activity} = CommonAPI.favorite(user, note.id)
@@ -70,7 +70,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectViewTest do
test "renders an announce activity" do
note = insert(:note_activity)
- object = Object.normalize(note)
+ object = Object.normalize(note, fetch: false)
user = insert(:user)
{:ok, announce_activity} = CommonAPI.repeat(note.id, user)
diff --git a/test/web/activity_pub/views/user_view_test.exs b/test/pleroma/web/activity_pub/views/user_view_test.exs
index 98c7c9d09..f2de4d332 100644
--- a/test/web/activity_pub/views/user_view_test.exs
+++ b/test/pleroma/web/activity_pub/views/user_view_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.UserViewTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
import Pleroma.Factory
alias Pleroma.User
@@ -80,6 +80,12 @@ defmodule Pleroma.Web.ActivityPub.UserViewTest do
assert %{"invisible" => true} = UserView.render("service.json", %{user: user})
end
+ test "renders AKAs" do
+ akas = ["https://i.tusooa.xyz/users/test-pleroma"]
+ user = insert(:user, also_known_as: akas)
+ assert %{"alsoKnownAs" => ^akas} = UserView.render("user.json", %{user: user})
+ end
+
describe "endpoints" do
test "local users have a usable endpoints structure" do
user = insert(:user)
diff --git a/test/web/activity_pub/visibilty_test.exs b/test/pleroma/web/activity_pub/visibility_test.exs
index 8e9354c65..23485225d 100644
--- a/test/web/activity_pub/visibilty_test.exs
+++ b/test/pleroma/web/activity_pub/visibility_test.exs
@@ -1,11 +1,12 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.VisibilityTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Activity
+ alias Pleroma.Object
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.CommonAPI
import Pleroma.Factory
@@ -15,7 +16,7 @@ defmodule Pleroma.Web.ActivityPub.VisibilityTest do
mentioned = insert(:user)
following = insert(:user)
unrelated = insert(:user)
- {:ok, following} = Pleroma.User.follow(following, user)
+ {:ok, following, user} = Pleroma.User.follow(following, user)
{:ok, list} = Pleroma.List.create("foo", user)
Pleroma.List.follow(list, unrelated)
@@ -107,7 +108,7 @@ defmodule Pleroma.Web.ActivityPub.VisibilityTest do
assert Visibility.is_list?(list)
end
- test "visible_for_user?", %{
+ test "visible_for_user? Activity", %{
public: public,
private: private,
direct: direct,
@@ -149,17 +150,83 @@ defmodule Pleroma.Web.ActivityPub.VisibilityTest do
refute Visibility.visible_for_user?(private, unrelated)
refute Visibility.visible_for_user?(direct, unrelated)
+ # Public and unlisted visible for unauthenticated
+
+ assert Visibility.visible_for_user?(public, nil)
+ assert Visibility.visible_for_user?(unlisted, nil)
+ refute Visibility.visible_for_user?(private, nil)
+ refute Visibility.visible_for_user?(direct, nil)
+
# Visible for a list member
assert Visibility.visible_for_user?(list, unrelated)
end
+ test "visible_for_user? Object", %{
+ public: public,
+ private: private,
+ direct: direct,
+ unlisted: unlisted,
+ user: user,
+ mentioned: mentioned,
+ following: following,
+ unrelated: unrelated,
+ list: list
+ } do
+ public = Object.normalize(public)
+ private = Object.normalize(private)
+ unlisted = Object.normalize(unlisted)
+ direct = Object.normalize(direct)
+ list = Object.normalize(list)
+
+ # All visible to author
+
+ assert Visibility.visible_for_user?(public, user)
+ assert Visibility.visible_for_user?(private, user)
+ assert Visibility.visible_for_user?(unlisted, user)
+ assert Visibility.visible_for_user?(direct, user)
+ assert Visibility.visible_for_user?(list, user)
+
+ # All visible to a mentioned user
+
+ assert Visibility.visible_for_user?(public, mentioned)
+ assert Visibility.visible_for_user?(private, mentioned)
+ assert Visibility.visible_for_user?(unlisted, mentioned)
+ assert Visibility.visible_for_user?(direct, mentioned)
+ assert Visibility.visible_for_user?(list, mentioned)
+
+ # DM not visible for just follower
+
+ assert Visibility.visible_for_user?(public, following)
+ assert Visibility.visible_for_user?(private, following)
+ assert Visibility.visible_for_user?(unlisted, following)
+ refute Visibility.visible_for_user?(direct, following)
+ refute Visibility.visible_for_user?(list, following)
+
+ # Public and unlisted visible for unrelated user
+
+ assert Visibility.visible_for_user?(public, unrelated)
+ assert Visibility.visible_for_user?(unlisted, unrelated)
+ refute Visibility.visible_for_user?(private, unrelated)
+ refute Visibility.visible_for_user?(direct, unrelated)
+
+ # Public and unlisted visible for unauthenticated
+
+ assert Visibility.visible_for_user?(public, nil)
+ assert Visibility.visible_for_user?(unlisted, nil)
+ refute Visibility.visible_for_user?(private, nil)
+ refute Visibility.visible_for_user?(direct, nil)
+
+ # Visible for a list member
+ # assert Visibility.visible_for_user?(list, unrelated)
+ end
+
test "doesn't die when the user doesn't exist",
%{
direct: direct,
user: user
} do
Repo.delete(user)
- Cachex.clear(:user_cache)
+ Pleroma.User.invalidate_cache(user)
refute Visibility.is_private?(direct)
end
diff --git a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs
new file mode 100644
index 000000000..f8cd103c6
--- /dev/null
+++ b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs
@@ -0,0 +1,968 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
+ use Pleroma.Web.ConnCase
+ use Oban.Testing, repo: Pleroma.Repo
+
+ import ExUnit.CaptureLog
+ import Pleroma.Factory
+ import Swoosh.TestAssertions
+
+ alias Pleroma.Activity
+ alias Pleroma.MFA
+ alias Pleroma.ModerationLog
+ alias Pleroma.Repo
+ alias Pleroma.Tests.ObanHelpers
+ alias Pleroma.User
+ alias Pleroma.Web.CommonAPI
+
+ setup_all do
+ Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
+
+ :ok
+ end
+
+ setup do
+ admin = insert(:user, is_admin: true)
+ token = insert(:oauth_admin_token, user: admin)
+
+ conn =
+ build_conn()
+ |> assign(:user, admin)
+ |> assign(:token, token)
+
+ {:ok, %{admin: admin, token: token, conn: conn}}
+ end
+
+ test "with valid `admin_token` query parameter, skips OAuth scopes check" do
+ clear_config([:admin_token], "password123")
+
+ user = insert(:user)
+
+ conn = get(build_conn(), "/api/pleroma/admin/users/#{user.nickname}?admin_token=password123")
+
+ assert json_response(conn, 200)
+ end
+
+ test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope",
+ %{admin: admin} do
+ user = insert(:user)
+ url = "/api/pleroma/admin/users/#{user.nickname}"
+
+ good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
+ good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
+ good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
+
+ bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
+ bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
+ bad_token3 = nil
+
+ for good_token <- [good_token1, good_token2, good_token3] do
+ conn =
+ build_conn()
+ |> assign(:user, admin)
+ |> assign(:token, good_token)
+ |> get(url)
+
+ assert json_response(conn, 200)
+ end
+
+ for good_token <- [good_token1, good_token2, good_token3] do
+ conn =
+ build_conn()
+ |> assign(:user, nil)
+ |> assign(:token, good_token)
+ |> get(url)
+
+ assert json_response(conn, :forbidden)
+ end
+
+ for bad_token <- [bad_token1, bad_token2, bad_token3] do
+ conn =
+ build_conn()
+ |> assign(:user, admin)
+ |> assign(:token, bad_token)
+ |> get(url)
+
+ assert json_response(conn, :forbidden)
+ end
+ end
+
+ describe "PUT /api/pleroma/admin/users/tag" do
+ setup %{conn: conn} do
+ user1 = insert(:user, %{tags: ["x"]})
+ user2 = insert(:user, %{tags: ["y"]})
+ user3 = insert(:user, %{tags: ["unchanged"]})
+
+ conn =
+ conn
+ |> put_req_header("accept", "application/json")
+ |> put(
+ "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
+ "#{user2.nickname}&tags[]=foo&tags[]=bar"
+ )
+
+ %{conn: conn, user1: user1, user2: user2, user3: user3}
+ end
+
+ test "it appends specified tags to users with specified nicknames", %{
+ conn: conn,
+ admin: admin,
+ user1: user1,
+ user2: user2
+ } do
+ assert empty_json_response(conn)
+ assert User.get_cached_by_id(user1.id).tags == ["x", "foo", "bar"]
+ assert User.get_cached_by_id(user2.id).tags == ["y", "foo", "bar"]
+
+ log_entry = Repo.one(ModerationLog)
+
+ users =
+ [user1.nickname, user2.nickname]
+ |> Enum.map(&"@#{&1}")
+ |> Enum.join(", ")
+
+ tags = ["foo", "bar"] |> Enum.join(", ")
+
+ assert ModerationLog.get_log_entry_message(log_entry) ==
+ "@#{admin.nickname} added tags: #{tags} to users: #{users}"
+ end
+
+ test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
+ assert empty_json_response(conn)
+ assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
+ end
+ end
+
+ describe "DELETE /api/pleroma/admin/users/tag" do
+ setup %{conn: conn} do
+ user1 = insert(:user, %{tags: ["x"]})
+ user2 = insert(:user, %{tags: ["y", "z"]})
+ user3 = insert(:user, %{tags: ["unchanged"]})
+
+ conn =
+ conn
+ |> put_req_header("accept", "application/json")
+ |> delete(
+ "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
+ "#{user2.nickname}&tags[]=x&tags[]=z"
+ )
+
+ %{conn: conn, user1: user1, user2: user2, user3: user3}
+ end
+
+ test "it removes specified tags from users with specified nicknames", %{
+ conn: conn,
+ admin: admin,
+ user1: user1,
+ user2: user2
+ } do
+ assert empty_json_response(conn)
+ assert User.get_cached_by_id(user1.id).tags == []
+ assert User.get_cached_by_id(user2.id).tags == ["y"]
+
+ log_entry = Repo.one(ModerationLog)
+
+ users =
+ [user1.nickname, user2.nickname]
+ |> Enum.map(&"@#{&1}")
+ |> Enum.join(", ")
+
+ tags = ["x", "z"] |> Enum.join(", ")
+
+ assert ModerationLog.get_log_entry_message(log_entry) ==
+ "@#{admin.nickname} removed tags: #{tags} from users: #{users}"
+ end
+
+ test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
+ assert empty_json_response(conn)
+ assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
+ end
+ end
+
+ describe "/api/pleroma/admin/users/:nickname/permission_group" do
+ test "GET is giving user_info", %{admin: admin, conn: conn} do
+ conn =
+ conn
+ |> put_req_header("accept", "application/json")
+ |> get("/api/pleroma/admin/users/#{admin.nickname}/permission_group/")
+
+ assert json_response(conn, 200) == %{
+ "is_admin" => true,
+ "is_moderator" => false
+ }
+ end
+
+ test "/:right POST, can add to a permission group", %{admin: admin, conn: conn} do
+ user = insert(:user)
+
+ conn =
+ conn
+ |> put_req_header("accept", "application/json")
+ |> post("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
+
+ assert json_response(conn, 200) == %{
+ "is_admin" => true
+ }
+
+ log_entry = Repo.one(ModerationLog)
+
+ assert ModerationLog.get_log_entry_message(log_entry) ==
+ "@#{admin.nickname} made @#{user.nickname} admin"
+ end
+
+ test "/:right POST, can add to a permission group (multiple)", %{admin: admin, conn: conn} do
+ user_one = insert(:user)
+ user_two = insert(:user)
+
+ conn =
+ conn
+ |> put_req_header("accept", "application/json")
+ |> post("/api/pleroma/admin/users/permission_group/admin", %{
+ nicknames: [user_one.nickname, user_two.nickname]
+ })
+
+ assert json_response(conn, 200) == %{"is_admin" => true}
+
+ log_entry = Repo.one(ModerationLog)
+
+ assert ModerationLog.get_log_entry_message(log_entry) ==
+ "@#{admin.nickname} made @#{user_one.nickname}, @#{user_two.nickname} admin"
+ end
+
+ test "/:right DELETE, can remove from a permission group", %{admin: admin, conn: conn} do
+ user = insert(:user, is_admin: true)
+
+ conn =
+ conn
+ |> put_req_header("accept", "application/json")
+ |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
+
+ assert json_response(conn, 200) == %{"is_admin" => false}
+
+ log_entry = Repo.one(ModerationLog)
+
+ assert ModerationLog.get_log_entry_message(log_entry) ==
+ "@#{admin.nickname} revoked admin role from @#{user.nickname}"
+ end
+
+ test "/:right DELETE, can remove from a permission group (multiple)", %{
+ admin: admin,
+ conn: conn
+ } do
+ user_one = insert(:user, is_admin: true)
+ user_two = insert(:user, is_admin: true)
+
+ conn =
+ conn
+ |> put_req_header("accept", "application/json")
+ |> delete("/api/pleroma/admin/users/permission_group/admin", %{
+ nicknames: [user_one.nickname, user_two.nickname]
+ })
+
+ assert json_response(conn, 200) == %{"is_admin" => false}
+
+ log_entry = Repo.one(ModerationLog)
+
+ assert ModerationLog.get_log_entry_message(log_entry) ==
+ "@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{user_two.nickname}"
+ end
+ end
+
+ test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do
+ user = insert(:user)
+
+ conn =
+ conn
+ |> put_req_header("accept", "application/json")
+ |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset")
+
+ resp = json_response(conn, 200)
+
+ assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"])
+ end
+
+ describe "PUT disable_mfa" do
+ test "returns 200 and disable 2fa", %{conn: conn} do
+ user =
+ insert(:user,
+ multi_factor_authentication_settings: %MFA.Settings{
+ enabled: true,
+ totp: %MFA.Settings.TOTP{secret: "otp_secret", confirmed: true}
+ }
+ )
+
+ response =
+ conn
+ |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: user.nickname})
+ |> json_response(200)
+
+ assert response == user.nickname
+ mfa_settings = refresh_record(user).multi_factor_authentication_settings
+
+ refute mfa_settings.enabled
+ refute mfa_settings.totp.confirmed
+ end
+
+ test "returns 404 if user not found", %{conn: conn} do
+ response =
+ conn
+ |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: "nickname"})
+ |> json_response(404)
+
+ assert response == %{"error" => "Not found"}
+ end
+ end
+
+ describe "GET /api/pleroma/admin/restart" do
+ setup do: clear_config(:configurable_from_database, true)
+
+ test "pleroma restarts", %{conn: conn} do
+ capture_log(fn ->
+ assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
+ end) =~ "pleroma restarted"
+
+ refute Restarter.Pleroma.need_reboot?()
+ end
+ end
+
+ test "need_reboot flag", %{conn: conn} do
+ assert conn
+ |> get("/api/pleroma/admin/need_reboot")
+ |> json_response(200) == %{"need_reboot" => false}
+
+ Restarter.Pleroma.need_reboot()
+
+ assert conn
+ |> get("/api/pleroma/admin/need_reboot")
+ |> json_response(200) == %{"need_reboot" => true}
+
+ on_exit(fn -> Restarter.Pleroma.refresh() end)
+ end
+
+ describe "GET /api/pleroma/admin/users/:nickname/statuses" do
+ setup do
+ user = insert(:user)
+
+ insert(:note_activity, user: user)
+ insert(:note_activity, user: user)
+ insert(:note_activity, user: user)
+
+ %{user: user}
+ end
+
+ test "renders user's statuses", %{conn: conn, user: user} do
+ conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
+
+ assert %{"total" => 3, "activities" => activities} = json_response(conn, 200)
+ assert length(activities) == 3
+ end
+
+ test "renders user's statuses with pagination", %{conn: conn, user: user} do
+ %{"total" => 3, "activities" => [activity1]} =
+ conn
+ |> get("/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=1&page=1")
+ |> json_response(200)
+
+ %{"total" => 3, "activities" => [activity2]} =
+ conn
+ |> get("/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=1&page=2")
+ |> json_response(200)
+
+ refute activity1 == activity2
+ end
+
+ test "doesn't return private statuses by default", %{conn: conn, user: user} do
+ {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
+
+ {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
+
+ %{"total" => 4, "activities" => activities} =
+ conn
+ |> get("/api/pleroma/admin/users/#{user.nickname}/statuses")
+ |> json_response(200)
+
+ assert length(activities) == 4
+ end
+
+ test "returns private statuses with godmode on", %{conn: conn, user: user} do
+ {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
+
+ {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
+
+ %{"total" => 5, "activities" => activities} =
+ conn
+ |> get("/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
+ |> json_response(200)
+
+ assert length(activities) == 5
+ end
+
+ test "excludes reblogs by default", %{conn: conn, user: user} do
+ other_user = insert(:user)
+ {:ok, activity} = CommonAPI.post(user, %{status: "."})
+ {:ok, %Activity{}} = CommonAPI.repeat(activity.id, other_user)
+
+ assert %{"total" => 0, "activities" => []} ==
+ conn
+ |> get("/api/pleroma/admin/users/#{other_user.nickname}/statuses")
+ |> json_response(200)
+
+ assert %{"total" => 1, "activities" => [_]} =
+ conn
+ |> get(
+ "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true"
+ )
+ |> json_response(200)
+ end
+ end
+
+ describe "GET /api/pleroma/admin/users/:nickname/chats" do
+ setup do
+ user = insert(:user)
+ recipients = insert_list(3, :user)
+
+ Enum.each(recipients, fn recipient ->
+ CommonAPI.post_chat_message(user, recipient, "yo")
+ end)
+
+ %{user: user}
+ end
+
+ test "renders user's chats", %{conn: conn, user: user} do
+ conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/chats")
+
+ assert json_response(conn, 200) |> length() == 3
+ end
+ end
+
+ describe "GET /api/pleroma/admin/users/:nickname/chats unauthorized" do
+ setup do
+ user = insert(:user)
+ recipient = insert(:user)
+ CommonAPI.post_chat_message(user, recipient, "yo")
+ %{conn: conn} = oauth_access(["read:chats"])
+ %{conn: conn, user: user}
+ end
+
+ test "returns 403", %{conn: conn, user: user} do
+ conn
+ |> get("/api/pleroma/admin/users/#{user.nickname}/chats")
+ |> json_response(403)
+ end
+ end
+
+ describe "GET /api/pleroma/admin/users/:nickname/chats unauthenticated" do
+ setup do
+ user = insert(:user)
+ recipient = insert(:user)
+ CommonAPI.post_chat_message(user, recipient, "yo")
+ %{conn: build_conn(), user: user}
+ end
+
+ test "returns 403", %{conn: conn, user: user} do
+ conn
+ |> get("/api/pleroma/admin/users/#{user.nickname}/chats")
+ |> json_response(403)
+ end
+ end
+
+ describe "GET /api/pleroma/admin/moderation_log" do
+ setup do
+ moderator = insert(:user, is_moderator: true)
+
+ %{moderator: moderator}
+ end
+
+ test "returns the log", %{conn: conn, admin: admin} do
+ Repo.insert(%ModerationLog{
+ data: %{
+ actor: %{
+ "id" => admin.id,
+ "nickname" => admin.nickname,
+ "type" => "user"
+ },
+ action: "relay_follow",
+ target: "https://example.org/relay"
+ },
+ inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
+ })
+
+ Repo.insert(%ModerationLog{
+ data: %{
+ actor: %{
+ "id" => admin.id,
+ "nickname" => admin.nickname,
+ "type" => "user"
+ },
+ action: "relay_unfollow",
+ target: "https://example.org/relay"
+ },
+ inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
+ })
+
+ conn = get(conn, "/api/pleroma/admin/moderation_log")
+
+ response = json_response(conn, 200)
+ [first_entry, second_entry] = response["items"]
+
+ assert response["total"] == 2
+ assert first_entry["data"]["action"] == "relay_unfollow"
+
+ assert first_entry["message"] ==
+ "@#{admin.nickname} unfollowed relay: https://example.org/relay"
+
+ assert second_entry["data"]["action"] == "relay_follow"
+
+ assert second_entry["message"] ==
+ "@#{admin.nickname} followed relay: https://example.org/relay"
+ end
+
+ test "returns the log with pagination", %{conn: conn, admin: admin} do
+ Repo.insert(%ModerationLog{
+ data: %{
+ actor: %{
+ "id" => admin.id,
+ "nickname" => admin.nickname,
+ "type" => "user"
+ },
+ action: "relay_follow",
+ target: "https://example.org/relay"
+ },
+ inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
+ })
+
+ Repo.insert(%ModerationLog{
+ data: %{
+ actor: %{
+ "id" => admin.id,
+ "nickname" => admin.nickname,
+ "type" => "user"
+ },
+ action: "relay_unfollow",
+ target: "https://example.org/relay"
+ },
+ inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
+ })
+
+ conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
+
+ response1 = json_response(conn1, 200)
+ [first_entry] = response1["items"]
+
+ assert response1["total"] == 2
+ assert response1["items"] |> length() == 1
+ assert first_entry["data"]["action"] == "relay_unfollow"
+
+ assert first_entry["message"] ==
+ "@#{admin.nickname} unfollowed relay: https://example.org/relay"
+
+ conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
+
+ response2 = json_response(conn2, 200)
+ [second_entry] = response2["items"]
+
+ assert response2["total"] == 2
+ assert response2["items"] |> length() == 1
+ assert second_entry["data"]["action"] == "relay_follow"
+
+ assert second_entry["message"] ==
+ "@#{admin.nickname} followed relay: https://example.org/relay"
+ end
+
+ test "filters log by date", %{conn: conn, admin: admin} do
+ first_date = "2017-08-15T15:47:06Z"
+ second_date = "2017-08-20T15:47:06Z"
+
+ Repo.insert(%ModerationLog{
+ data: %{
+ actor: %{
+ "id" => admin.id,
+ "nickname" => admin.nickname,
+ "type" => "user"
+ },
+ action: "relay_follow",
+ target: "https://example.org/relay"
+ },
+ inserted_at: NaiveDateTime.from_iso8601!(first_date)
+ })
+
+ Repo.insert(%ModerationLog{
+ data: %{
+ actor: %{
+ "id" => admin.id,
+ "nickname" => admin.nickname,
+ "type" => "user"
+ },
+ action: "relay_unfollow",
+ target: "https://example.org/relay"
+ },
+ inserted_at: NaiveDateTime.from_iso8601!(second_date)
+ })
+
+ conn1 =
+ get(
+ conn,
+ "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
+ )
+
+ response1 = json_response(conn1, 200)
+ [first_entry] = response1["items"]
+
+ assert response1["total"] == 1
+ assert first_entry["data"]["action"] == "relay_unfollow"
+
+ assert first_entry["message"] ==
+ "@#{admin.nickname} unfollowed relay: https://example.org/relay"
+ end
+
+ test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
+ Repo.insert(%ModerationLog{
+ data: %{
+ actor: %{
+ "id" => admin.id,
+ "nickname" => admin.nickname,
+ "type" => "user"
+ },
+ action: "relay_follow",
+ target: "https://example.org/relay"
+ }
+ })
+
+ Repo.insert(%ModerationLog{
+ data: %{
+ actor: %{
+ "id" => moderator.id,
+ "nickname" => moderator.nickname,
+ "type" => "user"
+ },
+ action: "relay_unfollow",
+ target: "https://example.org/relay"
+ }
+ })
+
+ conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
+
+ response1 = json_response(conn1, 200)
+ [first_entry] = response1["items"]
+
+ assert response1["total"] == 1
+ assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
+ end
+
+ test "returns log filtered by search", %{conn: conn, moderator: moderator} do
+ ModerationLog.insert_log(%{
+ actor: moderator,
+ action: "relay_follow",
+ target: "https://example.org/relay"
+ })
+
+ ModerationLog.insert_log(%{
+ actor: moderator,
+ action: "relay_unfollow",
+ target: "https://example.org/relay"
+ })
+
+ conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
+
+ response1 = json_response(conn1, 200)
+ [first_entry] = response1["items"]
+
+ assert response1["total"] == 1
+
+ assert get_in(first_entry, ["data", "message"]) ==
+ "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
+ end
+ end
+
+ test "gets a remote users when [:instance, :limit_to_local_content] is set to :unauthenticated",
+ %{conn: conn} do
+ clear_config(Pleroma.Config.get([:instance, :limit_to_local_content]), :unauthenticated)
+ user = insert(:user, %{local: false, nickname: "u@peer1.com"})
+ conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
+
+ assert json_response(conn, 200)
+ end
+
+ describe "GET /users/:nickname/credentials" do
+ test "gets the user credentials", %{conn: conn} do
+ user = insert(:user)
+ conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
+
+ response = assert json_response(conn, 200)
+ assert response["email"] == user.email
+ end
+
+ test "returns 403 if requested by a non-admin" do
+ user = insert(:user)
+
+ conn =
+ build_conn()
+ |> assign(:user, user)
+ |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
+
+ assert json_response(conn, :forbidden)
+ end
+ end
+
+ describe "PATCH /users/:nickname/credentials" do
+ setup do
+ user = insert(:user)
+ [user: user]
+ end
+
+ test "changes password and email", %{conn: conn, admin: admin, user: user} do
+ assert user.password_reset_pending == false
+
+ conn =
+ patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
+ "password" => "new_password",
+ "email" => "new_email@example.com",
+ "name" => "new_name"
+ })
+
+ assert json_response(conn, 200) == %{"status" => "success"}
+
+ ObanHelpers.perform_all()
+
+ updated_user = User.get_by_id(user.id)
+
+ assert updated_user.email == "new_email@example.com"
+ assert updated_user.name == "new_name"
+ assert updated_user.password_hash != user.password_hash
+ assert updated_user.password_reset_pending == true
+
+ [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
+
+ assert ModerationLog.get_log_entry_message(log_entry1) ==
+ "@#{admin.nickname} updated users: @#{user.nickname}"
+
+ assert ModerationLog.get_log_entry_message(log_entry2) ==
+ "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
+ end
+
+ test "returns 403 if requested by a non-admin", %{user: user} do
+ conn =
+ build_conn()
+ |> assign(:user, user)
+ |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
+ "password" => "new_password",
+ "email" => "new_email@example.com",
+ "name" => "new_name"
+ })
+
+ assert json_response(conn, :forbidden)
+ end
+
+ test "changes actor type from permitted list", %{conn: conn, user: user} do
+ assert user.actor_type == "Person"
+
+ assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
+ "actor_type" => "Service"
+ })
+ |> json_response(200) == %{"status" => "success"}
+
+ updated_user = User.get_by_id(user.id)
+
+ assert updated_user.actor_type == "Service"
+
+ assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
+ "actor_type" => "Application"
+ })
+ |> json_response(400) == %{"errors" => %{"actor_type" => "is invalid"}}
+ end
+
+ test "update non existing user", %{conn: conn} do
+ assert patch(conn, "/api/pleroma/admin/users/non-existing/credentials", %{
+ "password" => "new_password"
+ })
+ |> json_response(404) == %{"error" => "Not found"}
+ end
+ end
+
+ describe "PATCH /users/:nickname/force_password_reset" do
+ test "sets password_reset_pending to true", %{conn: conn} do
+ user = insert(:user)
+ assert user.password_reset_pending == false
+
+ conn =
+ patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
+
+ assert empty_json_response(conn) == ""
+
+ ObanHelpers.perform_all()
+
+ assert User.get_by_id(user.id).password_reset_pending == true
+ end
+ end
+
+ describe "PATCH /confirm_email" do
+ test "it confirms emails of two users", %{conn: conn, admin: admin} do
+ [first_user, second_user] = insert_pair(:user, is_confirmed: false)
+
+ refute first_user.is_confirmed
+ refute second_user.is_confirmed
+
+ ret_conn =
+ patch(conn, "/api/pleroma/admin/users/confirm_email", %{
+ nicknames: [
+ first_user.nickname,
+ second_user.nickname
+ ]
+ })
+
+ assert ret_conn.status == 200
+
+ first_user = User.get_by_id(first_user.id)
+ second_user = User.get_by_id(second_user.id)
+
+ assert first_user.is_confirmed
+ assert second_user.is_confirmed
+
+ log_entry = Repo.one(ModerationLog)
+
+ assert ModerationLog.get_log_entry_message(log_entry) ==
+ "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{second_user.nickname}"
+ end
+ end
+
+ describe "PATCH /resend_confirmation_email" do
+ test "it resend emails for two users", %{conn: conn, admin: admin} do
+ [first_user, second_user] = insert_pair(:user, is_confirmed: false)
+
+ ret_conn =
+ patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
+ nicknames: [
+ first_user.nickname,
+ second_user.nickname
+ ]
+ })
+
+ assert ret_conn.status == 200
+
+ log_entry = Repo.one(ModerationLog)
+
+ assert ModerationLog.get_log_entry_message(log_entry) ==
+ "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{second_user.nickname}"
+
+ ObanHelpers.perform_all()
+
+ Pleroma.Emails.UserEmail.account_confirmation_email(first_user)
+ # temporary hackney fix until hackney max_connections bug is fixed
+ # https://git.pleroma.social/pleroma/pleroma/-/issues/2101
+ |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]])
+ |> assert_email_sent()
+ end
+ end
+
+ describe "/api/pleroma/admin/stats" do
+ test "status visibility count", %{conn: conn} do
+ user = insert(:user)
+ CommonAPI.post(user, %{visibility: "public", status: "hey"})
+ CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
+ CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
+
+ response =
+ conn
+ |> get("/api/pleroma/admin/stats")
+ |> json_response(200)
+
+ assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
+ response["status_visibility"]
+ end
+
+ test "by instance", %{conn: conn} do
+ user1 = insert(:user)
+ instance2 = "instance2.tld"
+ user2 = insert(:user, %{ap_id: "https://#{instance2}/@actor"})
+
+ CommonAPI.post(user1, %{visibility: "public", status: "hey"})
+ CommonAPI.post(user2, %{visibility: "unlisted", status: "hey"})
+ CommonAPI.post(user2, %{visibility: "private", status: "hey"})
+
+ response =
+ conn
+ |> get("/api/pleroma/admin/stats", instance: instance2)
+ |> json_response(200)
+
+ assert %{"direct" => 0, "private" => 1, "public" => 0, "unlisted" => 1} =
+ response["status_visibility"]
+ end
+ end
+
+ describe "/api/pleroma/backups" do
+ test "it creates a backup", %{conn: conn} do
+ admin = %{id: admin_id, nickname: admin_nickname} = insert(:user, is_admin: true)
+ token = insert(:oauth_admin_token, user: admin)
+ user = %{id: user_id, nickname: user_nickname} = insert(:user)
+
+ assert "" ==
+ conn
+ |> assign(:user, admin)
+ |> assign(:token, token)
+ |> post("/api/pleroma/admin/backups", %{nickname: user.nickname})
+ |> json_response(200)
+
+ assert [backup] = Repo.all(Pleroma.User.Backup)
+
+ ObanHelpers.perform_all()
+
+ email = Pleroma.Emails.UserEmail.backup_is_ready_email(backup, admin.id)
+
+ assert String.contains?(email.html_body, "Admin @#{admin.nickname} requested a full backup")
+ assert_email_sent(to: {user.name, user.email}, html_body: email.html_body)
+
+ log_message = "@#{admin_nickname} requested account backup for @#{user_nickname}"
+
+ assert [
+ %{
+ data: %{
+ "action" => "create_backup",
+ "actor" => %{
+ "id" => ^admin_id,
+ "nickname" => ^admin_nickname
+ },
+ "message" => ^log_message,
+ "subject" => %{
+ "id" => ^user_id,
+ "nickname" => ^user_nickname
+ }
+ }
+ }
+ ] = Pleroma.ModerationLog |> Repo.all()
+ end
+
+ test "it doesn't limit admins", %{conn: conn} do
+ admin = insert(:user, is_admin: true)
+ token = insert(:oauth_admin_token, user: admin)
+ user = insert(:user)
+
+ assert "" ==
+ conn
+ |> assign(:user, admin)
+ |> assign(:token, token)
+ |> post("/api/pleroma/admin/backups", %{nickname: user.nickname})
+ |> json_response(200)
+
+ assert [_backup] = Repo.all(Pleroma.User.Backup)
+
+ assert "" ==
+ conn
+ |> assign(:user, admin)
+ |> assign(:token, token)
+ |> post("/api/pleroma/admin/backups", %{nickname: user.nickname})
+ |> json_response(200)
+
+ assert Repo.aggregate(Pleroma.User.Backup, :count) == 2
+ end
+ end
+end
+
+# Needed for testing
+defmodule Pleroma.Web.Endpoint.NotReal do
+end
+
+defmodule Pleroma.Captcha.NotReal do
+end
diff --git a/test/pleroma/web/admin_api/controllers/chat_controller_test.exs b/test/pleroma/web/admin_api/controllers/chat_controller_test.exs
new file mode 100644
index 000000000..0e8f7beef
--- /dev/null
+++ b/test/pleroma/web/admin_api/controllers/chat_controller_test.exs
@@ -0,0 +1,218 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.AdminAPI.ChatControllerTest do
+ use Pleroma.Web.ConnCase, async: true
+
+ import Pleroma.Factory
+
+ alias Pleroma.Chat
+ alias Pleroma.Chat.MessageReference
+ alias Pleroma.ModerationLog
+ alias Pleroma.Object
+ alias Pleroma.Repo
+ alias Pleroma.Web.CommonAPI
+
+ defp admin_setup do
+ admin = insert(:user, is_admin: true)
+ token = insert(:oauth_admin_token, user: admin)
+
+ conn =
+ build_conn()
+ |> assign(:user, admin)
+ |> assign(:token, token)
+
+ {:ok, %{admin: admin, token: token, conn: conn}}
+ end
+
+ describe "DELETE /api/pleroma/admin/chats/:id/messages/:message_id" do
+ setup do: admin_setup()
+
+ test "it deletes a message from the chat", %{conn: conn, admin: admin} do
+ user = insert(:user)
+ recipient = insert(:user)
+
+ {:ok, message} =
+ CommonAPI.post_chat_message(user, recipient, "Hello darkness my old friend")
+
+ object = Object.normalize(message, fetch: false)
+
+ chat = Chat.get(user.id, recipient.ap_id)
+ recipient_chat = Chat.get(recipient.id, user.ap_id)
+
+ cm_ref = MessageReference.for_chat_and_object(chat, object)
+ recipient_cm_ref = MessageReference.for_chat_and_object(recipient_chat, object)
+
+ result =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> delete("/api/pleroma/admin/chats/#{chat.id}/messages/#{cm_ref.id}")
+ |> json_response_and_validate_schema(200)
+
+ log_entry = Repo.one(ModerationLog)
+
+ assert ModerationLog.get_log_entry_message(log_entry) ==
+ "@#{admin.nickname} deleted chat message ##{cm_ref.id}"
+
+ assert result["id"] == cm_ref.id
+ refute MessageReference.get_by_id(cm_ref.id)
+ refute MessageReference.get_by_id(recipient_cm_ref.id)
+ assert %{data: %{"type" => "Tombstone"}} = Object.get_by_id(object.id)
+ end
+ end
+
+ describe "GET /api/pleroma/admin/chats/:id/messages" do
+ setup do: admin_setup()
+
+ test "it paginates", %{conn: conn} do
+ user = insert(:user)
+ recipient = insert(:user)
+
+ Enum.each(1..30, fn _ ->
+ {:ok, _} = CommonAPI.post_chat_message(user, recipient, "hey")
+ end)
+
+ chat = Chat.get(user.id, recipient.ap_id)
+
+ result =
+ conn
+ |> get("/api/pleroma/admin/chats/#{chat.id}/messages")
+ |> json_response_and_validate_schema(200)
+
+ assert length(result) == 20
+
+ result =
+ conn
+ |> get("/api/pleroma/admin/chats/#{chat.id}/messages?max_id=#{List.last(result)["id"]}")
+ |> json_response_and_validate_schema(200)
+
+ assert length(result) == 10
+ end
+
+ test "it returns the messages for a given chat", %{conn: conn} do
+ user = insert(:user)
+ other_user = insert(:user)
+ third_user = insert(:user)
+
+ {:ok, _} = CommonAPI.post_chat_message(user, other_user, "hey")
+ {:ok, _} = CommonAPI.post_chat_message(user, third_user, "hey")
+ {:ok, _} = CommonAPI.post_chat_message(user, other_user, "how are you?")
+ {:ok, _} = CommonAPI.post_chat_message(other_user, user, "fine, how about you?")
+
+ chat = Chat.get(user.id, other_user.ap_id)
+
+ result =
+ conn
+ |> get("/api/pleroma/admin/chats/#{chat.id}/messages")
+ |> json_response_and_validate_schema(200)
+
+ result
+ |> Enum.each(fn message ->
+ assert message["chat_id"] == chat.id |> to_string()
+ end)
+
+ assert length(result) == 3
+ end
+ end
+
+ describe "GET /api/pleroma/admin/chats/:id" do
+ setup do: admin_setup()
+
+ test "it returns a chat", %{conn: conn} do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id)
+
+ result =
+ conn
+ |> get("/api/pleroma/admin/chats/#{chat.id}")
+ |> json_response_and_validate_schema(200)
+
+ assert result["id"] == to_string(chat.id)
+ assert %{} = result["sender"]
+ assert %{} = result["receiver"]
+ refute result["account"]
+ end
+ end
+
+ describe "unauthorized chat moderation" do
+ setup do
+ user = insert(:user)
+ recipient = insert(:user)
+
+ {:ok, message} = CommonAPI.post_chat_message(user, recipient, "Yo")
+ object = Object.normalize(message, fetch: false)
+ chat = Chat.get(user.id, recipient.ap_id)
+ cm_ref = MessageReference.for_chat_and_object(chat, object)
+
+ %{conn: conn} = oauth_access(["read:chats", "write:chats"])
+ %{conn: conn, chat: chat, cm_ref: cm_ref}
+ end
+
+ test "DELETE /api/pleroma/admin/chats/:id/messages/:message_id", %{
+ conn: conn,
+ chat: chat,
+ cm_ref: cm_ref
+ } do
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> delete("/api/pleroma/admin/chats/#{chat.id}/messages/#{cm_ref.id}")
+ |> json_response(403)
+
+ assert MessageReference.get_by_id(cm_ref.id) == cm_ref
+ end
+
+ test "GET /api/pleroma/admin/chats/:id/messages", %{conn: conn, chat: chat} do
+ conn
+ |> get("/api/pleroma/admin/chats/#{chat.id}/messages")
+ |> json_response(403)
+ end
+
+ test "GET /api/pleroma/admin/chats/:id", %{conn: conn, chat: chat} do
+ conn
+ |> get("/api/pleroma/admin/chats/#{chat.id}")
+ |> json_response(403)
+ end
+ end
+
+ describe "unauthenticated chat moderation" do
+ setup do
+ user = insert(:user)
+ recipient = insert(:user)
+
+ {:ok, message} = CommonAPI.post_chat_message(user, recipient, "Yo")
+ object = Object.normalize(message, fetch: false)
+ chat = Chat.get(user.id, recipient.ap_id)
+ cm_ref = MessageReference.for_chat_and_object(chat, object)
+
+ %{conn: build_conn(), chat: chat, cm_ref: cm_ref}
+ end
+
+ test "DELETE /api/pleroma/admin/chats/:id/messages/:message_id", %{
+ conn: conn,
+ chat: chat,
+ cm_ref: cm_ref
+ } do
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> delete("/api/pleroma/admin/chats/#{chat.id}/messages/#{cm_ref.id}")
+ |> json_response(403)
+
+ assert MessageReference.get_by_id(cm_ref.id) == cm_ref
+ end
+
+ test "GET /api/pleroma/admin/chats/:id/messages", %{conn: conn, chat: chat} do
+ conn
+ |> get("/api/pleroma/admin/chats/#{chat.id}/messages")
+ |> json_response(403)
+ end
+
+ test "GET /api/pleroma/admin/chats/:id", %{conn: conn, chat: chat} do
+ conn
+ |> get("/api/pleroma/admin/chats/#{chat.id}")
+ |> json_response(403)
+ end
+ end
+end
diff --git a/test/web/admin_api/controllers/config_controller_test.exs b/test/pleroma/web/admin_api/controllers/config_controller_test.exs
index 4e897455f..7c786c389 100644
--- a/test/web/admin_api/controllers/config_controller_test.exs
+++ b/test/pleroma/web/admin_api/controllers/config_controller_test.exs
@@ -1,14 +1,13 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do
- use Pleroma.Web.ConnCase, async: true
+ use Pleroma.Web.ConnCase
import ExUnit.CaptureLog
import Pleroma.Factory
- alias Pleroma.Config
alias Pleroma.ConfigDB
setup do
@@ -27,12 +26,12 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do
setup do: clear_config(:configurable_from_database, true)
test "when configuration from database is off", %{conn: conn} do
- Config.put(:configurable_from_database, false)
+ clear_config(:configurable_from_database, false)
conn = get(conn, "/api/pleroma/admin/config")
assert json_response_and_validate_schema(conn, 400) ==
%{
- "error" => "To use this endpoint you need to enable configuration from database."
+ "error" => "You must enable configurable_from_database in your config file."
}
end
@@ -162,14 +161,16 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do
end
end
- test "POST /api/pleroma/admin/config error", %{conn: conn} do
+ test "POST /api/pleroma/admin/config with configdb disabled", %{conn: conn} do
+ clear_config(:configurable_from_database, false)
+
conn =
conn
|> put_req_header("content-type", "application/json")
|> post("/api/pleroma/admin/config", %{"configs" => []})
assert json_response_and_validate_schema(conn, 400) ==
- %{"error" => "To use this endpoint you need to enable configuration from database."}
+ %{"error" => "You must enable configurable_from_database in your config file."}
end
describe "POST /api/pleroma/admin/config" do
@@ -408,8 +409,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do
end
test "saving config which need pleroma reboot", %{conn: conn} do
- chat = Config.get(:chat)
- on_exit(fn -> Config.put(:chat, chat) end)
+ clear_config([:shout, :enabled], true)
assert conn
|> put_req_header("content-type", "application/json")
@@ -417,7 +417,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do
"/api/pleroma/admin/config",
%{
configs: [
- %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]}
+ %{group: ":pleroma", key: ":shout", value: [%{"tuple" => [":enabled", true]}]}
]
}
)
@@ -426,7 +426,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do
%{
"db" => [":enabled"],
"group" => ":pleroma",
- "key" => ":chat",
+ "key" => ":shout",
"value" => [%{"tuple" => [":enabled", true]}]
}
],
@@ -454,8 +454,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do
end
test "update setting which need reboot, don't change reboot flag until reboot", %{conn: conn} do
- chat = Config.get(:chat)
- on_exit(fn -> Config.put(:chat, chat) end)
+ clear_config([:shout, :enabled], true)
assert conn
|> put_req_header("content-type", "application/json")
@@ -463,7 +462,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do
"/api/pleroma/admin/config",
%{
configs: [
- %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]}
+ %{group: ":pleroma", key: ":shout", value: [%{"tuple" => [":enabled", true]}]}
]
}
)
@@ -472,7 +471,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do
%{
"db" => [":enabled"],
"group" => ":pleroma",
- "key" => ":chat",
+ "key" => ":shout",
"value" => [%{"tuple" => [":enabled", true]}]
}
],
@@ -1411,15 +1410,84 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do
"need_reboot" => false
}
end
+
+ test "custom instance thumbnail", %{conn: conn} do
+ clear_config([:instance])
+
+ params = %{
+ "group" => ":pleroma",
+ "key" => ":instance",
+ "value" => [
+ %{
+ "tuple" => [
+ ":instance_thumbnail",
+ "https://example.com/media/new_thumbnail.jpg"
+ ]
+ }
+ ]
+ }
+
+ assert conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/pleroma/admin/config", %{"configs" => [params]})
+ |> json_response_and_validate_schema(200) ==
+ %{
+ "configs" => [
+ %{
+ "db" => [":instance_thumbnail"],
+ "group" => ":pleroma",
+ "key" => ":instance",
+ "value" => params["value"]
+ }
+ ],
+ "need_reboot" => false
+ }
+
+ assert conn
+ |> get("/api/v1/instance")
+ |> json_response_and_validate_schema(200)
+ |> Map.take(["thumbnail"]) ==
+ %{"thumbnail" => "https://example.com/media/new_thumbnail.jpg"}
+ end
+
+ test "Concurrent Limiter", %{conn: conn} do
+ clear_config([ConcurrentLimiter])
+
+ params = %{
+ "group" => ":pleroma",
+ "key" => "ConcurrentLimiter",
+ "value" => [
+ %{
+ "tuple" => [
+ "Pleroma.Web.RichMedia.Helpers",
+ [
+ %{"tuple" => [":max_running", 6]},
+ %{"tuple" => [":max_waiting", 6]}
+ ]
+ ]
+ },
+ %{
+ "tuple" => [
+ "Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy",
+ [
+ %{"tuple" => [":max_running", 7]},
+ %{"tuple" => [":max_waiting", 7]}
+ ]
+ ]
+ }
+ ]
+ }
+
+ assert conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/pleroma/admin/config", %{"configs" => [params]})
+ |> json_response_and_validate_schema(200)
+ end
end
describe "GET /api/pleroma/admin/config/descriptions" do
test "structure", %{conn: conn} do
- admin = insert(:user, is_admin: true)
-
- conn =
- assign(conn, :user, admin)
- |> get("/api/pleroma/admin/config/descriptions")
+ conn = get(conn, "/api/pleroma/admin/config/descriptions")
assert [child | _others] = json_response_and_validate_schema(conn, 200)
@@ -1437,11 +1505,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do
{:esshd}
])
- admin = insert(:user, is_admin: true)
-
- conn =
- assign(conn, :user, admin)
- |> get("/api/pleroma/admin/config/descriptions")
+ conn = get(conn, "/api/pleroma/admin/config/descriptions")
children = json_response_and_validate_schema(conn, 200)
diff --git a/test/pleroma/web/admin_api/controllers/frontend_controller_test.exs b/test/pleroma/web/admin_api/controllers/frontend_controller_test.exs
new file mode 100644
index 000000000..200682ba9
--- /dev/null
+++ b/test/pleroma/web/admin_api/controllers/frontend_controller_test.exs
@@ -0,0 +1,155 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.AdminAPI.FrontendControllerTest do
+ use Pleroma.Web.ConnCase
+
+ import Pleroma.Factory
+
+ alias Pleroma.Config
+
+ @dir "test/frontend_static_test"
+
+ setup do
+ clear_config([:instance, :static_dir], @dir)
+ File.mkdir_p!(Pleroma.Frontend.dir())
+
+ on_exit(fn ->
+ File.rm_rf(@dir)
+ end)
+
+ admin = insert(:user, is_admin: true)
+ token = insert(:oauth_admin_token, user: admin)
+
+ conn =
+ build_conn()
+ |> assign(:user, admin)
+ |> assign(:token, token)
+
+ {:ok, %{admin: admin, token: token, conn: conn}}
+ end
+
+ describe "GET /api/pleroma/admin/frontends" do
+ test "it lists available frontends", %{conn: conn} do
+ response =
+ conn
+ |> get("/api/pleroma/admin/frontends")
+ |> json_response_and_validate_schema(:ok)
+
+ assert Enum.map(response, & &1["name"]) ==
+ Enum.map(Config.get([:frontends, :available]), fn {_, map} -> map["name"] end)
+
+ refute Enum.any?(response, fn frontend -> frontend["installed"] == true end)
+ end
+
+ test "it lists available frontends when no frontend folder was created yet", %{conn: conn} do
+ File.rm_rf(@dir)
+
+ response =
+ conn
+ |> get("/api/pleroma/admin/frontends")
+ |> json_response_and_validate_schema(:ok)
+
+ assert Enum.map(response, & &1["name"]) ==
+ Enum.map(Config.get([:frontends, :available]), fn {_, map} -> map["name"] end)
+
+ refute Enum.any?(response, fn frontend -> frontend["installed"] == true end)
+ end
+ end
+
+ describe "POST /api/pleroma/admin/frontends/install" do
+ test "from available frontends", %{conn: conn} do
+ clear_config([:frontends, :available], %{
+ "pleroma" => %{
+ "ref" => "fantasy",
+ "name" => "pleroma",
+ "build_url" => "http://gensokyo.2hu/builds/${ref}"
+ }
+ })
+
+ Tesla.Mock.mock(fn %{url: "http://gensokyo.2hu/builds/fantasy"} ->
+ %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/frontend_dist.zip")}
+ end)
+
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/pleroma/admin/frontends/install", %{name: "pleroma"})
+ |> json_response_and_validate_schema(:ok)
+
+ assert File.exists?(Path.join([@dir, "frontends", "pleroma", "fantasy", "test.txt"]))
+
+ response =
+ conn
+ |> get("/api/pleroma/admin/frontends")
+ |> json_response_and_validate_schema(:ok)
+
+ assert response == [
+ %{
+ "build_url" => "http://gensokyo.2hu/builds/${ref}",
+ "git" => nil,
+ "installed" => true,
+ "name" => "pleroma",
+ "ref" => "fantasy"
+ }
+ ]
+ end
+
+ test "from a file", %{conn: conn} do
+ clear_config([:frontends, :available], %{
+ "pleroma" => %{
+ "ref" => "fantasy",
+ "name" => "pleroma",
+ "build_dir" => ""
+ }
+ })
+
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/pleroma/admin/frontends/install", %{
+ name: "pleroma",
+ file: "test/fixtures/tesla_mock/frontend.zip"
+ })
+ |> json_response_and_validate_schema(:ok)
+
+ assert File.exists?(Path.join([@dir, "frontends", "pleroma", "fantasy", "test.txt"]))
+ end
+
+ test "from an URL", %{conn: conn} do
+ Tesla.Mock.mock(fn %{url: "http://gensokyo.2hu/madeup.zip"} ->
+ %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/frontend.zip")}
+ end)
+
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/pleroma/admin/frontends/install", %{
+ name: "unknown",
+ ref: "baka",
+ build_url: "http://gensokyo.2hu/madeup.zip",
+ build_dir: ""
+ })
+ |> json_response_and_validate_schema(:ok)
+
+ assert File.exists?(Path.join([@dir, "frontends", "unknown", "baka", "test.txt"]))
+ end
+
+ test "failing returns an error", %{conn: conn} do
+ Tesla.Mock.mock(fn %{url: "http://gensokyo.2hu/madeup.zip"} ->
+ %Tesla.Env{status: 404, body: ""}
+ end)
+
+ result =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/pleroma/admin/frontends/install", %{
+ name: "unknown",
+ ref: "baka",
+ build_url: "http://gensokyo.2hu/madeup.zip",
+ build_dir: ""
+ })
+ |> json_response_and_validate_schema(400)
+
+ assert result == %{"error" => "Could not download or unzip the frontend"}
+ end
+ end
+end
diff --git a/test/pleroma/web/admin_api/controllers/instance_controller_test.exs b/test/pleroma/web/admin_api/controllers/instance_controller_test.exs
new file mode 100644
index 000000000..c78307fc8
--- /dev/null
+++ b/test/pleroma/web/admin_api/controllers/instance_controller_test.exs
@@ -0,0 +1,80 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.AdminAPI.InstanceControllerTest do
+ use Pleroma.Web.ConnCase
+ use Oban.Testing, repo: Pleroma.Repo
+
+ import Pleroma.Factory
+
+ alias Pleroma.Repo
+ alias Pleroma.Tests.ObanHelpers
+ alias Pleroma.Web.CommonAPI
+
+ setup_all do
+ Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
+
+ :ok
+ end
+
+ setup do
+ admin = insert(:user, is_admin: true)
+ token = insert(:oauth_admin_token, user: admin)
+
+ conn =
+ build_conn()
+ |> assign(:user, admin)
+ |> assign(:token, token)
+
+ {:ok, %{admin: admin, token: token, conn: conn}}
+ end
+
+ test "GET /instances/:instance/statuses", %{conn: conn} do
+ user = insert(:user, local: false, ap_id: "https://archae.me/users/archaeme")
+ user2 = insert(:user, local: false, ap_id: "https://test.com/users/test")
+ insert_pair(:note_activity, user: user)
+ activity = insert(:note_activity, user: user2)
+
+ %{"total" => 2, "activities" => activities} =
+ conn |> get("/api/pleroma/admin/instances/archae.me/statuses") |> json_response(200)
+
+ assert length(activities) == 2
+
+ %{"total" => 1, "activities" => [_]} =
+ conn |> get("/api/pleroma/admin/instances/test.com/statuses") |> json_response(200)
+
+ %{"total" => 0, "activities" => []} =
+ conn |> get("/api/pleroma/admin/instances/nonexistent.com/statuses") |> json_response(200)
+
+ CommonAPI.repeat(activity.id, user)
+
+ %{"total" => 2, "activities" => activities} =
+ conn |> get("/api/pleroma/admin/instances/archae.me/statuses") |> json_response(200)
+
+ assert length(activities) == 2
+
+ %{"total" => 3, "activities" => activities} =
+ conn
+ |> get("/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
+ |> json_response(200)
+
+ assert length(activities) == 3
+ end
+
+ test "DELETE /instances/:instance", %{conn: conn} do
+ user = insert(:user, nickname: "lain@lain.com")
+ post = insert(:note_activity, user: user)
+
+ response =
+ conn
+ |> delete("/api/pleroma/admin/instances/lain.com")
+ |> json_response(200)
+
+ [:ok] = ObanHelpers.perform_all()
+
+ assert response == "lain.com"
+ refute Repo.reload(user).is_active
+ refute Repo.reload(post)
+ end
+end
diff --git a/test/pleroma/web/admin_api/controllers/instance_document_controller_test.exs b/test/pleroma/web/admin_api/controllers/instance_document_controller_test.exs
new file mode 100644
index 000000000..e100f6929
--- /dev/null
+++ b/test/pleroma/web/admin_api/controllers/instance_document_controller_test.exs
@@ -0,0 +1,105 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.AdminAPI.InstanceDocumentControllerTest do
+ use Pleroma.Web.ConnCase, async: true
+ import Pleroma.Factory
+
+ @dir "test/tmp/instance_static"
+ @default_instance_panel ~s(<p>Welcome to <a href="https://pleroma.social" target="_blank">Pleroma!</a></p>)
+
+ setup do
+ File.mkdir_p!(@dir)
+ on_exit(fn -> File.rm_rf(@dir) end)
+ end
+
+ setup do: clear_config([:instance, :static_dir], @dir)
+
+ setup do
+ admin = insert(:user, is_admin: true)
+ token = insert(:oauth_admin_token, user: admin)
+
+ conn =
+ build_conn()
+ |> assign(:user, admin)
+ |> assign(:token, token)
+
+ {:ok, %{admin: admin, token: token, conn: conn}}
+ end
+
+ describe "GET /api/pleroma/admin/instance_document/:name" do
+ test "return the instance document url", %{conn: conn} do
+ conn = get(conn, "/api/pleroma/admin/instance_document/instance-panel")
+
+ assert content = html_response(conn, 200)
+ assert String.contains?(content, @default_instance_panel)
+ end
+
+ test "it returns 403 if requested by a non-admin" do
+ non_admin_user = insert(:user)
+ token = insert(:oauth_token, user: non_admin_user)
+
+ conn =
+ build_conn()
+ |> assign(:user, non_admin_user)
+ |> assign(:token, token)
+ |> get("/api/pleroma/admin/instance_document/instance-panel")
+
+ assert json_response(conn, :forbidden)
+ end
+
+ test "it returns 404 if the instance document with the given name doesn't exist", %{
+ conn: conn
+ } do
+ conn = get(conn, "/api/pleroma/admin/instance_document/1234")
+
+ assert json_response_and_validate_schema(conn, 404)
+ end
+ end
+
+ describe "PATCH /api/pleroma/admin/instance_document/:name" do
+ test "uploads the instance document", %{conn: conn} do
+ image = %Plug.Upload{
+ content_type: "text/html",
+ path: Path.absname("test/fixtures/custom_instance_panel.html"),
+ filename: "custom_instance_panel.html"
+ }
+
+ conn =
+ conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> patch("/api/pleroma/admin/instance_document/instance-panel", %{
+ "file" => image
+ })
+
+ assert %{"url" => url} = json_response_and_validate_schema(conn, 200)
+ index = get(build_conn(), url)
+ assert html_response(index, 200) == "<h2>Custom instance panel</h2>"
+ end
+ end
+
+ describe "DELETE /api/pleroma/admin/instance_document/:name" do
+ test "deletes the instance document", %{conn: conn} do
+ File.mkdir!(@dir <> "/instance/")
+ File.write!(@dir <> "/instance/panel.html", "Custom instance panel")
+
+ conn_resp =
+ conn
+ |> get("/api/pleroma/admin/instance_document/instance-panel")
+
+ assert html_response(conn_resp, 200) == "Custom instance panel"
+
+ conn
+ |> delete("/api/pleroma/admin/instance_document/instance-panel")
+ |> json_response_and_validate_schema(200)
+
+ conn_resp =
+ conn
+ |> get("/api/pleroma/admin/instance_document/instance-panel")
+
+ assert content = html_response(conn_resp, 200)
+ assert String.contains?(content, @default_instance_panel)
+ end
+ end
+end
diff --git a/test/web/admin_api/controllers/invite_controller_test.exs b/test/pleroma/web/admin_api/controllers/invite_controller_test.exs
index ab186c5e7..6366061c8 100644
--- a/test/web/admin_api/controllers/invite_controller_test.exs
+++ b/test/pleroma/web/admin_api/controllers/invite_controller_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.AdminAPI.InviteControllerTest do
@@ -7,7 +7,6 @@ defmodule Pleroma.Web.AdminAPI.InviteControllerTest do
import Pleroma.Factory
- alias Pleroma.Config
alias Pleroma.Repo
alias Pleroma.UserInviteToken
@@ -119,8 +118,8 @@ defmodule Pleroma.Web.AdminAPI.InviteControllerTest do
setup do: clear_config([:instance, :invites_enabled])
test "it returns 500 if `invites_enabled` is not enabled", %{conn: conn} do
- Config.put([:instance, :registrations_open], false)
- Config.put([:instance, :invites_enabled], false)
+ clear_config([:instance, :registrations_open], false)
+ clear_config([:instance, :invites_enabled], false)
conn =
conn
@@ -138,8 +137,8 @@ defmodule Pleroma.Web.AdminAPI.InviteControllerTest do
end
test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do
- Config.put([:instance, :registrations_open], true)
- Config.put([:instance, :invites_enabled], true)
+ clear_config([:instance, :registrations_open], true)
+ clear_config([:instance, :invites_enabled], true)
conn =
conn
diff --git a/test/web/admin_api/controllers/media_proxy_cache_controller_test.exs b/test/pleroma/web/admin_api/controllers/media_proxy_cache_controller_test.exs
index f243d1fb2..1818c8a8e 100644
--- a/test/web/admin_api/controllers/media_proxy_cache_controller_test.exs
+++ b/test/pleroma/web/admin_api/controllers/media_proxy_cache_controller_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.AdminAPI.MediaProxyCacheControllerTest do
@@ -13,10 +13,6 @@ defmodule Pleroma.Web.AdminAPI.MediaProxyCacheControllerTest do
setup do: clear_config([:media_proxy])
setup do
- on_exit(fn -> Cachex.clear(:banned_urls_cache) end)
- end
-
- setup do
admin = insert(:user, is_admin: true)
token = insert(:oauth_admin_token, user: admin)
@@ -25,9 +21,9 @@ defmodule Pleroma.Web.AdminAPI.MediaProxyCacheControllerTest do
|> assign(:user, admin)
|> assign(:token, token)
- Config.put([:media_proxy, :enabled], true)
- Config.put([:media_proxy, :invalidation, :enabled], true)
- Config.put([:media_proxy, :invalidation, :provider], MediaProxy.Invalidation.Script)
+ clear_config([:media_proxy, :enabled], true)
+ clear_config([:media_proxy, :invalidation, :enabled], true)
+ clear_config([:media_proxy, :invalidation, :provider], MediaProxy.Invalidation.Script)
{:ok, %{admin: admin, token: token, conn: conn}}
end
@@ -51,30 +47,34 @@ defmodule Pleroma.Web.AdminAPI.MediaProxyCacheControllerTest do
assert response["page_size"] == 2
assert response["count"] == 5
- assert response["urls"] == [
- "http://localhost:4001/media/fb1f4d.jpg",
- "http://localhost:4001/media/a688346.jpg"
- ]
+ results = response["urls"]
response =
conn
|> get("/api/pleroma/admin/media_proxy_caches?page_size=2&page=2")
|> json_response_and_validate_schema(200)
- assert response["urls"] == [
- "http://localhost:4001/media/gb1f44.jpg",
- "http://localhost:4001/media/tb13f47.jpg"
- ]
-
assert response["page_size"] == 2
assert response["count"] == 5
+ results = results ++ response["urls"]
+
response =
conn
|> get("/api/pleroma/admin/media_proxy_caches?page_size=2&page=3")
|> json_response_and_validate_schema(200)
- assert response["urls"] == ["http://localhost:4001/media/wb1f46.jpg"]
+ results = results ++ response["urls"]
+
+ assert results |> Enum.sort() ==
+ [
+ "http://localhost:4001/media/wb1f46.jpg",
+ "http://localhost:4001/media/gb1f44.jpg",
+ "http://localhost:4001/media/tb13f47.jpg",
+ "http://localhost:4001/media/fb1f4d.jpg",
+ "http://localhost:4001/media/a688346.jpg"
+ ]
+ |> Enum.sort()
end
test "search banned MediaProxy URLs", %{conn: conn} do
@@ -92,9 +92,9 @@ defmodule Pleroma.Web.AdminAPI.MediaProxyCacheControllerTest do
|> get("/api/pleroma/admin/media_proxy_caches?page_size=2&query=F44")
|> json_response_and_validate_schema(200)
- assert response["urls"] == [
- "http://localhost:4001/media/gb1f44.jpg",
- "http://localhost:4001/media/ff44b1f4d.jpg"
+ assert response["urls"] |> Enum.sort() == [
+ "http://localhost:4001/media/ff44b1f4d.jpg",
+ "http://localhost:4001/media/gb1f44.jpg"
]
assert response["page_size"] == 2
diff --git a/test/web/admin_api/controllers/oauth_app_controller_test.exs b/test/pleroma/web/admin_api/controllers/o_auth_app_controller_test.exs
index ed7c4172c..d9b25719a 100644
--- a/test/web/admin_api/controllers/oauth_app_controller_test.exs
+++ b/test/pleroma/web/admin_api/controllers/o_auth_app_controller_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.AdminAPI.OAuthAppControllerTest do
@@ -8,8 +8,7 @@ defmodule Pleroma.Web.AdminAPI.OAuthAppControllerTest do
import Pleroma.Factory
- alias Pleroma.Config
- alias Pleroma.Web
+ alias Pleroma.Web.Endpoint
setup do
admin = insert(:user, is_admin: true)
@@ -37,7 +36,7 @@ defmodule Pleroma.Web.AdminAPI.OAuthAppControllerTest do
end
test "success", %{conn: conn} do
- base_url = Web.base_url()
+ base_url = Endpoint.url()
app_name = "Trusted app"
response =
@@ -59,7 +58,7 @@ defmodule Pleroma.Web.AdminAPI.OAuthAppControllerTest do
end
test "with trusted", %{conn: conn} do
- base_url = Web.base_url()
+ base_url = Endpoint.url()
app_name = "Trusted app"
response =
diff --git a/test/web/admin_api/controllers/relay_controller_test.exs b/test/pleroma/web/admin_api/controllers/relay_controller_test.exs
index adadf2b5c..11a480cc0 100644
--- a/test/web/admin_api/controllers/relay_controller_test.exs
+++ b/test/pleroma/web/admin_api/controllers/relay_controller_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.AdminAPI.RelayControllerTest do
@@ -7,7 +7,6 @@ defmodule Pleroma.Web.AdminAPI.RelayControllerTest do
import Pleroma.Factory
- alias Pleroma.Config
alias Pleroma.ModerationLog
alias Pleroma.Repo
alias Pleroma.User
@@ -61,7 +60,7 @@ defmodule Pleroma.Web.AdminAPI.RelayControllerTest do
conn = get(conn, "/api/pleroma/admin/relay")
- assert json_response_and_validate_schema(conn, 200)["relays"] == [
+ assert json_response_and_validate_schema(conn, 200)["relays"] |> Enum.sort() == [
%{
"actor" => "http://mastodon.example.org/users/admin",
"followed_back" => true
diff --git a/test/web/admin_api/controllers/report_controller_test.exs b/test/pleroma/web/admin_api/controllers/report_controller_test.exs
index 57946e6bb..99cc7bbd0 100644
--- a/test/web/admin_api/controllers/report_controller_test.exs
+++ b/test/pleroma/web/admin_api/controllers/report_controller_test.exs
@@ -1,14 +1,13 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.AdminAPI.ReportControllerTest do
- use Pleroma.Web.ConnCase
+ use Pleroma.Web.ConnCase, async: true
import Pleroma.Factory
alias Pleroma.Activity
- alias Pleroma.Config
alias Pleroma.ModerationLog
alias Pleroma.Repo
alias Pleroma.ReportNote
@@ -38,12 +37,21 @@ defmodule Pleroma.Web.AdminAPI.ReportControllerTest do
status_ids: [activity.id]
})
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/pleroma/admin/reports/#{report_id}/notes", %{
+ content: "this is an admin note"
+ })
+
response =
conn
|> get("/api/pleroma/admin/reports/#{report_id}")
|> json_response_and_validate_schema(:ok)
assert response["id"] == report_id
+
+ [notes] = response["notes"]
+ assert notes["content"] == "this is an admin note"
end
test "returns 404 when report id is invalid", %{conn: conn} do
@@ -114,13 +122,13 @@ defmodule Pleroma.Web.AdminAPI.ReportControllerTest do
})
|> json_response_and_validate_schema(:no_content)
- activity = Activity.get_by_id(id)
+ activity = Activity.get_by_id_with_user_actor(id)
assert activity.data["state"] == "resolved"
log_entry = Repo.one(ModerationLog)
assert ModerationLog.get_log_entry_message(log_entry) ==
- "@#{admin.nickname} updated report ##{id} with 'resolved' state"
+ "@#{admin.nickname} updated report ##{id} (on user @#{activity.user_actor.nickname}) with 'resolved' state"
end
test "closes report", %{conn: conn, id: id, admin: admin} do
@@ -133,13 +141,13 @@ defmodule Pleroma.Web.AdminAPI.ReportControllerTest do
})
|> json_response_and_validate_schema(:no_content)
- activity = Activity.get_by_id(id)
+ activity = Activity.get_by_id_with_user_actor(id)
assert activity.data["state"] == "closed"
log_entry = Repo.one(ModerationLog)
assert ModerationLog.get_log_entry_message(log_entry) ==
- "@#{admin.nickname} updated report ##{id} with 'closed' state"
+ "@#{admin.nickname} updated report ##{id} (on user @#{activity.user_actor.nickname}) with 'closed' state"
end
test "returns 400 when state is unknown", %{conn: conn, id: id} do
@@ -185,18 +193,18 @@ defmodule Pleroma.Web.AdminAPI.ReportControllerTest do
})
|> json_response_and_validate_schema(:no_content)
- activity = Activity.get_by_id(id)
- second_activity = Activity.get_by_id(second_report_id)
+ activity = Activity.get_by_id_with_user_actor(id)
+ second_activity = Activity.get_by_id_with_user_actor(second_report_id)
assert activity.data["state"] == "resolved"
assert second_activity.data["state"] == "closed"
[first_log_entry, second_log_entry] = Repo.all(ModerationLog)
assert ModerationLog.get_log_entry_message(first_log_entry) ==
- "@#{admin.nickname} updated report ##{id} with 'resolved' state"
+ "@#{admin.nickname} updated report ##{id} (on user @#{activity.user_actor.nickname}) with 'resolved' state"
assert ModerationLog.get_log_entry_message(second_log_entry) ==
- "@#{admin.nickname} updated report ##{second_report_id} with 'closed' state"
+ "@#{admin.nickname} updated report ##{second_report_id} (on user @#{second_activity.user_actor.nickname}) with 'closed' state"
end
end
@@ -295,7 +303,7 @@ defmodule Pleroma.Web.AdminAPI.ReportControllerTest do
|> get("/api/pleroma/admin/reports")
assert json_response(conn, :forbidden) ==
- %{"error" => "User is not an admin."}
+ %{"error" => "User is not a staff member."}
end
test "returns 403 when requested by anonymous" do
diff --git a/test/web/admin_api/controllers/status_controller_test.exs b/test/pleroma/web/admin_api/controllers/status_controller_test.exs
index eff78fb0a..3fdf23ba2 100644
--- a/test/web/admin_api/controllers/status_controller_test.exs
+++ b/test/pleroma/web/admin_api/controllers/status_controller_test.exs
@@ -1,14 +1,13 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.AdminAPI.StatusControllerTest do
- use Pleroma.Web.ConnCase
+ use Pleroma.Web.ConnCase, async: true
import Pleroma.Factory
alias Pleroma.Activity
- alias Pleroma.Config
alias Pleroma.ModerationLog
alias Pleroma.Repo
alias Pleroma.User
@@ -48,8 +47,8 @@ defmodule Pleroma.Web.AdminAPI.StatusControllerTest do
assert account["id"] == actor.id
assert account["nickname"] == actor.nickname
- assert account["deactivated"] == actor.deactivated
- assert account["confirmation_pending"] == actor.confirmation_pending
+ assert account["is_active"] == actor.is_active
+ assert account["is_confirmed"] == actor.is_confirmed
end
end
diff --git a/test/pleroma/web/admin_api/controllers/user_controller_test.exs b/test/pleroma/web/admin_api/controllers/user_controller_test.exs
new file mode 100644
index 000000000..b199fa704
--- /dev/null
+++ b/test/pleroma/web/admin_api/controllers/user_controller_test.exs
@@ -0,0 +1,967 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.AdminAPI.UserControllerTest do
+ use Pleroma.Web.ConnCase
+ use Oban.Testing, repo: Pleroma.Repo
+
+ import Mock
+ import Pleroma.Factory
+
+ alias Pleroma.HTML
+ alias Pleroma.ModerationLog
+ alias Pleroma.Repo
+ alias Pleroma.Tests.ObanHelpers
+ alias Pleroma.User
+ alias Pleroma.Web.ActivityPub.Relay
+ alias Pleroma.Web.CommonAPI
+ alias Pleroma.Web.Endpoint
+ alias Pleroma.Web.MediaProxy
+
+ setup_all do
+ Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
+
+ :ok
+ end
+
+ setup do
+ admin = insert(:user, is_admin: true)
+ token = insert(:oauth_admin_token, user: admin)
+
+ conn =
+ build_conn()
+ |> assign(:user, admin)
+ |> assign(:token, token)
+
+ {:ok, %{admin: admin, token: token, conn: conn}}
+ end
+
+ test "with valid `admin_token` query parameter, skips OAuth scopes check" do
+ clear_config([:admin_token], "password123")
+
+ user = insert(:user)
+
+ conn = get(build_conn(), "/api/pleroma/admin/users/#{user.nickname}?admin_token=password123")
+
+ assert json_response_and_validate_schema(conn, 200)
+ end
+
+ test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope",
+ %{admin: admin} do
+ user = insert(:user)
+ url = "/api/pleroma/admin/users/#{user.nickname}"
+
+ good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
+ good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
+ good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
+
+ bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
+ bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
+ bad_token3 = nil
+
+ for good_token <- [good_token1, good_token2, good_token3] do
+ conn =
+ build_conn()
+ |> assign(:user, admin)
+ |> assign(:token, good_token)
+ |> get(url)
+
+ assert json_response_and_validate_schema(conn, 200)
+ end
+
+ for good_token <- [good_token1, good_token2, good_token3] do
+ conn =
+ build_conn()
+ |> assign(:user, nil)
+ |> assign(:token, good_token)
+ |> get(url)
+
+ assert json_response(conn, :forbidden)
+ end
+
+ for bad_token <- [bad_token1, bad_token2, bad_token3] do
+ conn =
+ build_conn()
+ |> assign(:user, admin)
+ |> assign(:token, bad_token)
+ |> get(url)
+
+ assert json_response_and_validate_schema(conn, :forbidden)
+ end
+ end
+
+ describe "DELETE /api/pleroma/admin/users" do
+ test "single user", %{admin: admin, conn: conn} do
+ clear_config([:instance, :federating], true)
+
+ user =
+ insert(:user,
+ avatar: %{"url" => [%{"href" => "https://someurl"}]},
+ banner: %{"url" => [%{"href" => "https://somebanner"}]},
+ bio: "Hello world!",
+ name: "A guy"
+ )
+
+ # Create some activities to check they got deleted later
+ follower = insert(:user)
+ {:ok, _} = CommonAPI.post(user, %{status: "test"})
+ {:ok, _, _, _} = CommonAPI.follow(user, follower)
+ {:ok, _, _, _} = CommonAPI.follow(follower, user)
+ user = Repo.get(User, user.id)
+ assert user.note_count == 1
+ assert user.follower_count == 1
+ assert user.following_count == 1
+ assert user.is_active
+
+ with_mock Pleroma.Web.Federator,
+ publish: fn _ -> nil end,
+ perform: fn _, _ -> nil end do
+ conn =
+ conn
+ |> put_req_header("accept", "application/json")
+ |> delete("/api/pleroma/admin/users?nickname=#{user.nickname}")
+
+ ObanHelpers.perform_all()
+
+ refute User.get_by_nickname(user.nickname).is_active
+
+ log_entry = Repo.one(ModerationLog)
+
+ assert ModerationLog.get_log_entry_message(log_entry) ==
+ "@#{admin.nickname} deleted users: @#{user.nickname}"
+
+ assert json_response_and_validate_schema(conn, 200) == [user.nickname]
+
+ user = Repo.get(User, user.id)
+ refute user.is_active
+
+ assert user.avatar == %{}
+ assert user.banner == %{}
+ assert user.note_count == 0
+ assert user.follower_count == 0
+ assert user.following_count == 0
+ assert user.bio == ""
+ assert user.name == nil
+
+ assert called(Pleroma.Web.Federator.publish(:_))
+ end
+ end
+
+ test "multiple users", %{admin: admin, conn: conn} do
+ user_one = insert(:user)
+ user_two = insert(:user)
+
+ response =
+ conn
+ |> put_req_header("accept", "application/json")
+ |> put_req_header("content-type", "application/json")
+ |> delete("/api/pleroma/admin/users", %{
+ nicknames: [user_one.nickname, user_two.nickname]
+ })
+ |> json_response_and_validate_schema(200)
+
+ log_entry = Repo.one(ModerationLog)
+
+ assert ModerationLog.get_log_entry_message(log_entry) ==
+ "@#{admin.nickname} deleted users: @#{user_one.nickname}, @#{user_two.nickname}"
+
+ assert response -- [user_one.nickname, user_two.nickname] == []
+ end
+ end
+
+ describe "/api/pleroma/admin/users" do
+ test "Create", %{conn: conn} do
+ response =
+ conn
+ |> put_req_header("accept", "application/json")
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/pleroma/admin/users", %{
+ "users" => [
+ %{
+ "nickname" => "lain",
+ "email" => "lain@example.org",
+ "password" => "test"
+ },
+ %{
+ "nickname" => "lain2",
+ "email" => "lain2@example.org",
+ "password" => "test"
+ }
+ ]
+ })
+ |> json_response_and_validate_schema(200)
+ |> Enum.map(&Map.get(&1, "type"))
+
+ assert response == ["success", "success"]
+
+ log_entry = Repo.one(ModerationLog)
+
+ assert ["lain", "lain2"] -- Enum.map(log_entry.data["subjects"], & &1["nickname"]) == []
+ end
+
+ test "Cannot create user with existing email", %{conn: conn} do
+ user = insert(:user)
+
+ conn =
+ conn
+ |> put_req_header("accept", "application/json")
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/pleroma/admin/users", %{
+ "users" => [
+ %{
+ "nickname" => "lain",
+ "email" => user.email,
+ "password" => "test"
+ }
+ ]
+ })
+
+ assert json_response_and_validate_schema(conn, 409) == [
+ %{
+ "code" => 409,
+ "data" => %{
+ "email" => user.email,
+ "nickname" => "lain"
+ },
+ "error" => "email has already been taken",
+ "type" => "error"
+ }
+ ]
+ end
+
+ test "Cannot create user with existing nickname", %{conn: conn} do
+ user = insert(:user)
+
+ conn =
+ conn
+ |> put_req_header("accept", "application/json")
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/pleroma/admin/users", %{
+ "users" => [
+ %{
+ "nickname" => user.nickname,
+ "email" => "someuser@plerama.social",
+ "password" => "test"
+ }
+ ]
+ })
+
+ assert json_response_and_validate_schema(conn, 409) == [
+ %{
+ "code" => 409,
+ "data" => %{
+ "email" => "someuser@plerama.social",
+ "nickname" => user.nickname
+ },
+ "error" => "nickname has already been taken",
+ "type" => "error"
+ }
+ ]
+ end
+
+ test "Multiple user creation works in transaction", %{conn: conn} do
+ user = insert(:user)
+
+ conn =
+ conn
+ |> put_req_header("accept", "application/json")
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/pleroma/admin/users", %{
+ "users" => [
+ %{
+ "nickname" => "newuser",
+ "email" => "newuser@pleroma.social",
+ "password" => "test"
+ },
+ %{
+ "nickname" => "lain",
+ "email" => user.email,
+ "password" => "test"
+ }
+ ]
+ })
+
+ assert json_response_and_validate_schema(conn, 409) == [
+ %{
+ "code" => 409,
+ "data" => %{
+ "email" => user.email,
+ "nickname" => "lain"
+ },
+ "error" => "email has already been taken",
+ "type" => "error"
+ },
+ %{
+ "code" => 409,
+ "data" => %{
+ "email" => "newuser@pleroma.social",
+ "nickname" => "newuser"
+ },
+ "error" => "",
+ "type" => "error"
+ }
+ ]
+
+ assert User.get_by_nickname("newuser") === nil
+ end
+ end
+
+ describe "/api/pleroma/admin/users/:nickname" do
+ test "Show", %{conn: conn} do
+ user = insert(:user)
+
+ conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
+
+ assert user_response(user) == json_response_and_validate_schema(conn, 200)
+ end
+
+ test "when the user doesn't exist", %{conn: conn} do
+ user = build(:user)
+
+ conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
+
+ assert %{"error" => "Not found"} == json_response_and_validate_schema(conn, 404)
+ end
+ end
+
+ describe "/api/pleroma/admin/users/follow" do
+ test "allows to force-follow another user", %{admin: admin, conn: conn} do
+ user = insert(:user)
+ follower = insert(:user)
+
+ conn
+ |> put_req_header("accept", "application/json")
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/pleroma/admin/users/follow", %{
+ "follower" => follower.nickname,
+ "followed" => user.nickname
+ })
+
+ user = User.get_cached_by_id(user.id)
+ follower = User.get_cached_by_id(follower.id)
+
+ assert User.following?(follower, user)
+
+ log_entry = Repo.one(ModerationLog)
+
+ assert ModerationLog.get_log_entry_message(log_entry) ==
+ "@#{admin.nickname} made @#{follower.nickname} follow @#{user.nickname}"
+ end
+ end
+
+ describe "/api/pleroma/admin/users/unfollow" do
+ test "allows to force-unfollow another user", %{admin: admin, conn: conn} do
+ user = insert(:user)
+ follower = insert(:user)
+
+ User.follow(follower, user)
+
+ conn
+ |> put_req_header("accept", "application/json")
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/pleroma/admin/users/unfollow", %{
+ "follower" => follower.nickname,
+ "followed" => user.nickname
+ })
+
+ user = User.get_cached_by_id(user.id)
+ follower = User.get_cached_by_id(follower.id)
+
+ refute User.following?(follower, user)
+
+ log_entry = Repo.one(ModerationLog)
+
+ assert ModerationLog.get_log_entry_message(log_entry) ==
+ "@#{admin.nickname} made @#{follower.nickname} unfollow @#{user.nickname}"
+ end
+ end
+
+ describe "GET /api/pleroma/admin/users" do
+ test "renders users array for the first page", %{conn: conn, admin: admin} do
+ user = insert(:user, local: false, tags: ["foo", "bar"])
+ user2 = insert(:user, is_approved: false, registration_reason: "I'm a chill dude")
+
+ conn = get(conn, "/api/pleroma/admin/users?page=1")
+
+ users = [
+ user_response(
+ user2,
+ %{
+ "local" => true,
+ "is_approved" => false,
+ "registration_reason" => "I'm a chill dude",
+ "actor_type" => "Person"
+ }
+ ),
+ user_response(user, %{"local" => false, "tags" => ["foo", "bar"]}),
+ user_response(
+ admin,
+ %{"roles" => %{"admin" => true, "moderator" => false}}
+ )
+ ]
+
+ assert json_response_and_validate_schema(conn, 200) == %{
+ "count" => 3,
+ "page_size" => 50,
+ "users" => users
+ }
+ end
+
+ test "pagination works correctly with service users", %{conn: conn} do
+ service1 = User.get_or_create_service_actor_by_ap_id(Endpoint.url() <> "/meido", "meido")
+
+ insert_list(25, :user)
+
+ assert %{"count" => 26, "page_size" => 10, "users" => users1} =
+ conn
+ |> get("/api/pleroma/admin/users?page=1&filters=", %{page_size: "10"})
+ |> json_response_and_validate_schema(200)
+
+ assert Enum.count(users1) == 10
+ assert service1 not in users1
+
+ assert %{"count" => 26, "page_size" => 10, "users" => users2} =
+ conn
+ |> get("/api/pleroma/admin/users?page=2&filters=", %{page_size: "10"})
+ |> json_response_and_validate_schema(200)
+
+ assert Enum.count(users2) == 10
+ assert service1 not in users2
+
+ assert %{"count" => 26, "page_size" => 10, "users" => users3} =
+ conn
+ |> get("/api/pleroma/admin/users?page=3&filters=", %{page_size: "10"})
+ |> json_response_and_validate_schema(200)
+
+ assert Enum.count(users3) == 6
+ assert service1 not in users3
+ end
+
+ test "renders empty array for the second page", %{conn: conn} do
+ insert(:user)
+
+ conn = get(conn, "/api/pleroma/admin/users?page=2")
+
+ assert json_response_and_validate_schema(conn, 200) == %{
+ "count" => 2,
+ "page_size" => 50,
+ "users" => []
+ }
+ end
+
+ test "regular search", %{conn: conn} do
+ user = insert(:user, nickname: "bob")
+
+ conn = get(conn, "/api/pleroma/admin/users?query=bo")
+
+ assert json_response_and_validate_schema(conn, 200) == %{
+ "count" => 1,
+ "page_size" => 50,
+ "users" => [user_response(user, %{"local" => true})]
+ }
+ end
+
+ test "search by domain", %{conn: conn} do
+ user = insert(:user, nickname: "nickname@domain.com")
+ insert(:user)
+
+ conn = get(conn, "/api/pleroma/admin/users?query=domain.com")
+
+ assert json_response_and_validate_schema(conn, 200) == %{
+ "count" => 1,
+ "page_size" => 50,
+ "users" => [user_response(user)]
+ }
+ end
+
+ test "search by full nickname", %{conn: conn} do
+ user = insert(:user, nickname: "nickname@domain.com")
+ insert(:user)
+
+ conn = get(conn, "/api/pleroma/admin/users?query=nickname@domain.com")
+
+ assert json_response_and_validate_schema(conn, 200) == %{
+ "count" => 1,
+ "page_size" => 50,
+ "users" => [user_response(user)]
+ }
+ end
+
+ test "search by display name", %{conn: conn} do
+ user = insert(:user, name: "Display name")
+ insert(:user)
+
+ conn = get(conn, "/api/pleroma/admin/users?name=display")
+
+ assert json_response_and_validate_schema(conn, 200) == %{
+ "count" => 1,
+ "page_size" => 50,
+ "users" => [user_response(user)]
+ }
+ end
+
+ test "search by email", %{conn: conn} do
+ user = insert(:user, email: "email@example.com")
+ insert(:user)
+
+ conn = get(conn, "/api/pleroma/admin/users?email=email@example.com")
+
+ assert json_response_and_validate_schema(conn, 200) == %{
+ "count" => 1,
+ "page_size" => 50,
+ "users" => [user_response(user)]
+ }
+ end
+
+ test "regular search with page size", %{conn: conn} do
+ user = insert(:user, nickname: "aalice")
+ user2 = insert(:user, nickname: "alice")
+
+ conn1 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=1")
+
+ assert json_response_and_validate_schema(conn1, 200) == %{
+ "count" => 2,
+ "page_size" => 1,
+ "users" => [user_response(user2)]
+ }
+
+ conn2 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=2")
+
+ assert json_response_and_validate_schema(conn2, 200) == %{
+ "count" => 2,
+ "page_size" => 1,
+ "users" => [user_response(user)]
+ }
+ end
+
+ test "only local users" do
+ admin = insert(:user, is_admin: true, nickname: "john")
+ token = insert(:oauth_admin_token, user: admin)
+ user = insert(:user, nickname: "bob")
+
+ insert(:user, nickname: "bobb", local: false)
+
+ conn =
+ build_conn()
+ |> assign(:user, admin)
+ |> assign(:token, token)
+ |> get("/api/pleroma/admin/users?query=bo&filters=local")
+
+ assert json_response_and_validate_schema(conn, 200) == %{
+ "count" => 1,
+ "page_size" => 50,
+ "users" => [user_response(user)]
+ }
+ end
+
+ test "only local users with no query", %{conn: conn, admin: old_admin} do
+ admin = insert(:user, is_admin: true, nickname: "john")
+ user = insert(:user, nickname: "bob")
+
+ insert(:user, nickname: "bobb", local: false)
+
+ conn = get(conn, "/api/pleroma/admin/users?filters=local")
+
+ users = [
+ user_response(user),
+ user_response(admin, %{
+ "roles" => %{"admin" => true, "moderator" => false}
+ }),
+ user_response(old_admin, %{
+ "is_active" => true,
+ "roles" => %{"admin" => true, "moderator" => false}
+ })
+ ]
+
+ assert json_response_and_validate_schema(conn, 200) == %{
+ "count" => 3,
+ "page_size" => 50,
+ "users" => users
+ }
+ end
+
+ test "only unconfirmed users", %{conn: conn} do
+ sad_user = insert(:user, nickname: "sadboy", is_confirmed: false)
+ old_user = insert(:user, nickname: "oldboy", is_confirmed: false)
+
+ insert(:user, nickname: "happyboy", is_approved: true)
+ insert(:user, is_confirmed: true)
+
+ result =
+ conn
+ |> get("/api/pleroma/admin/users?filters=unconfirmed")
+ |> json_response_and_validate_schema(200)
+
+ users =
+ Enum.map([old_user, sad_user], fn user ->
+ user_response(user, %{
+ "is_confirmed" => false,
+ "is_approved" => true
+ })
+ end)
+
+ assert result == %{"count" => 2, "page_size" => 50, "users" => users}
+ end
+
+ test "only unapproved users", %{conn: conn} do
+ user =
+ insert(:user,
+ nickname: "sadboy",
+ is_approved: false,
+ registration_reason: "Plz let me in!"
+ )
+
+ insert(:user, nickname: "happyboy", is_approved: true)
+
+ conn = get(conn, "/api/pleroma/admin/users?filters=need_approval")
+
+ users = [
+ user_response(
+ user,
+ %{"is_approved" => false, "registration_reason" => "Plz let me in!"}
+ )
+ ]
+
+ assert json_response_and_validate_schema(conn, 200) == %{
+ "count" => 1,
+ "page_size" => 50,
+ "users" => users
+ }
+ end
+
+ test "load only admins", %{conn: conn, admin: admin} do
+ second_admin = insert(:user, is_admin: true)
+ insert(:user)
+ insert(:user)
+
+ conn = get(conn, "/api/pleroma/admin/users?filters=is_admin")
+
+ users = [
+ user_response(second_admin, %{
+ "is_active" => true,
+ "roles" => %{"admin" => true, "moderator" => false}
+ }),
+ user_response(admin, %{
+ "is_active" => true,
+ "roles" => %{"admin" => true, "moderator" => false}
+ })
+ ]
+
+ assert json_response_and_validate_schema(conn, 200) == %{
+ "count" => 2,
+ "page_size" => 50,
+ "users" => users
+ }
+ end
+
+ test "load only moderators", %{conn: conn} do
+ moderator = insert(:user, is_moderator: true)
+ insert(:user)
+ insert(:user)
+
+ conn = get(conn, "/api/pleroma/admin/users?filters=is_moderator")
+
+ assert json_response_and_validate_schema(conn, 200) == %{
+ "count" => 1,
+ "page_size" => 50,
+ "users" => [
+ user_response(moderator, %{
+ "is_active" => true,
+ "roles" => %{"admin" => false, "moderator" => true}
+ })
+ ]
+ }
+ end
+
+ test "load users with actor_type is Person", %{admin: admin, conn: conn} do
+ insert(:user, actor_type: "Service")
+ insert(:user, actor_type: "Application")
+
+ user1 = insert(:user)
+ user2 = insert(:user)
+
+ response =
+ conn
+ |> get(user_path(conn, :index), %{actor_types: ["Person"]})
+ |> json_response_and_validate_schema(200)
+
+ users = [
+ user_response(user2),
+ user_response(user1),
+ user_response(admin, %{"roles" => %{"admin" => true, "moderator" => false}})
+ ]
+
+ assert response == %{"count" => 3, "page_size" => 50, "users" => users}
+ end
+
+ test "load users with actor_type is Person and Service", %{admin: admin, conn: conn} do
+ user_service = insert(:user, actor_type: "Service")
+ insert(:user, actor_type: "Application")
+
+ user1 = insert(:user)
+ user2 = insert(:user)
+
+ response =
+ conn
+ |> get(user_path(conn, :index), %{actor_types: ["Person", "Service"]})
+ |> json_response_and_validate_schema(200)
+
+ users = [
+ user_response(user2),
+ user_response(user1),
+ user_response(user_service, %{"actor_type" => "Service"}),
+ user_response(admin, %{"roles" => %{"admin" => true, "moderator" => false}})
+ ]
+
+ assert response == %{"count" => 4, "page_size" => 50, "users" => users}
+ end
+
+ test "load users with actor_type is Service", %{conn: conn} do
+ user_service = insert(:user, actor_type: "Service")
+ insert(:user, actor_type: "Application")
+ insert(:user)
+ insert(:user)
+
+ response =
+ conn
+ |> get(user_path(conn, :index), %{actor_types: ["Service"]})
+ |> json_response_and_validate_schema(200)
+
+ users = [user_response(user_service, %{"actor_type" => "Service"})]
+
+ assert response == %{"count" => 1, "page_size" => 50, "users" => users}
+ end
+
+ test "load users with tags list", %{conn: conn} do
+ user1 = insert(:user, tags: ["first"])
+ user2 = insert(:user, tags: ["second"])
+ insert(:user)
+ insert(:user)
+
+ conn = get(conn, "/api/pleroma/admin/users?tags[]=first&tags[]=second")
+
+ users = [
+ user_response(user2, %{"tags" => ["second"]}),
+ user_response(user1, %{"tags" => ["first"]})
+ ]
+
+ assert json_response_and_validate_schema(conn, 200) == %{
+ "count" => 2,
+ "page_size" => 50,
+ "users" => users
+ }
+ end
+
+ test "`active` filters out users pending approval", %{token: token} do
+ insert(:user, is_approved: false)
+ %{id: user_id} = insert(:user, is_approved: true)
+ %{id: admin_id} = token.user
+
+ conn =
+ build_conn()
+ |> assign(:user, token.user)
+ |> assign(:token, token)
+ |> get("/api/pleroma/admin/users?filters=active")
+
+ assert %{
+ "count" => 2,
+ "page_size" => 50,
+ "users" => [
+ %{"id" => ^user_id},
+ %{"id" => ^admin_id}
+ ]
+ } = json_response_and_validate_schema(conn, 200)
+ end
+
+ test "it works with multiple filters" do
+ admin = insert(:user, nickname: "john", is_admin: true)
+ token = insert(:oauth_admin_token, user: admin)
+ user = insert(:user, nickname: "bob", local: false, is_active: false)
+
+ insert(:user, nickname: "ken", local: true, is_active: false)
+ insert(:user, nickname: "bobb", local: false, is_active: true)
+
+ conn =
+ build_conn()
+ |> assign(:user, admin)
+ |> assign(:token, token)
+ |> get("/api/pleroma/admin/users?filters=deactivated,external")
+
+ assert json_response_and_validate_schema(conn, 200) == %{
+ "count" => 1,
+ "page_size" => 50,
+ "users" => [user_response(user)]
+ }
+ end
+
+ test "it omits relay user", %{admin: admin, conn: conn} do
+ assert %User{} = Relay.get_actor()
+
+ conn = get(conn, "/api/pleroma/admin/users")
+
+ assert json_response_and_validate_schema(conn, 200) == %{
+ "count" => 1,
+ "page_size" => 50,
+ "users" => [
+ user_response(admin, %{"roles" => %{"admin" => true, "moderator" => false}})
+ ]
+ }
+ end
+ end
+
+ test "PATCH /api/pleroma/admin/users/activate", %{admin: admin, conn: conn} do
+ user_one = insert(:user, is_active: false)
+ user_two = insert(:user, is_active: false)
+
+ conn =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> patch(
+ "/api/pleroma/admin/users/activate",
+ %{nicknames: [user_one.nickname, user_two.nickname]}
+ )
+
+ response = json_response_and_validate_schema(conn, 200)
+ assert Enum.map(response["users"], & &1["is_active"]) == [true, true]
+
+ log_entry = Repo.one(ModerationLog)
+
+ assert ModerationLog.get_log_entry_message(log_entry) ==
+ "@#{admin.nickname} activated users: @#{user_one.nickname}, @#{user_two.nickname}"
+ end
+
+ test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do
+ user_one = insert(:user, is_active: true)
+ user_two = insert(:user, is_active: true)
+
+ conn =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> patch(
+ "/api/pleroma/admin/users/deactivate",
+ %{nicknames: [user_one.nickname, user_two.nickname]}
+ )
+
+ response = json_response_and_validate_schema(conn, 200)
+ assert Enum.map(response["users"], & &1["is_active"]) == [false, false]
+
+ log_entry = Repo.one(ModerationLog)
+
+ assert ModerationLog.get_log_entry_message(log_entry) ==
+ "@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}"
+ end
+
+ test "PATCH /api/pleroma/admin/users/approve", %{admin: admin, conn: conn} do
+ user_one = insert(:user, is_approved: false)
+ user_two = insert(:user, is_approved: false)
+
+ conn =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> patch(
+ "/api/pleroma/admin/users/approve",
+ %{nicknames: [user_one.nickname, user_two.nickname]}
+ )
+
+ response = json_response_and_validate_schema(conn, 200)
+ assert Enum.map(response["users"], & &1["is_approved"]) == [true, true]
+
+ log_entry = Repo.one(ModerationLog)
+
+ assert ModerationLog.get_log_entry_message(log_entry) ==
+ "@#{admin.nickname} approved users: @#{user_one.nickname}, @#{user_two.nickname}"
+ end
+
+ test "PATCH /api/pleroma/admin/users/suggest", %{admin: admin, conn: conn} do
+ user1 = insert(:user, is_suggested: false)
+ user2 = insert(:user, is_suggested: false)
+
+ response =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> patch(
+ "/api/pleroma/admin/users/suggest",
+ %{nicknames: [user1.nickname, user2.nickname]}
+ )
+ |> json_response_and_validate_schema(200)
+
+ assert Enum.map(response["users"], & &1["is_suggested"]) == [true, true]
+ [user1, user2] = Repo.reload!([user1, user2])
+
+ assert user1.is_suggested
+ assert user2.is_suggested
+
+ log_entry = Repo.one(ModerationLog)
+
+ assert ModerationLog.get_log_entry_message(log_entry) ==
+ "@#{admin.nickname} added suggested users: @#{user1.nickname}, @#{user2.nickname}"
+ end
+
+ test "PATCH /api/pleroma/admin/users/unsuggest", %{admin: admin, conn: conn} do
+ user1 = insert(:user, is_suggested: true)
+ user2 = insert(:user, is_suggested: true)
+
+ response =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> patch(
+ "/api/pleroma/admin/users/unsuggest",
+ %{nicknames: [user1.nickname, user2.nickname]}
+ )
+ |> json_response_and_validate_schema(200)
+
+ assert Enum.map(response["users"], & &1["is_suggested"]) == [false, false]
+ [user1, user2] = Repo.reload!([user1, user2])
+
+ refute user1.is_suggested
+ refute user2.is_suggested
+
+ log_entry = Repo.one(ModerationLog)
+
+ assert ModerationLog.get_log_entry_message(log_entry) ==
+ "@#{admin.nickname} removed suggested users: @#{user1.nickname}, @#{user2.nickname}"
+ end
+
+ test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do
+ user = insert(:user)
+
+ conn =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> patch("/api/pleroma/admin/users/#{user.nickname}/toggle_activation")
+
+ assert json_response_and_validate_schema(conn, 200) ==
+ user_response(
+ user,
+ %{"is_active" => !user.is_active}
+ )
+
+ log_entry = Repo.one(ModerationLog)
+
+ assert ModerationLog.get_log_entry_message(log_entry) ==
+ "@#{admin.nickname} deactivated users: @#{user.nickname}"
+ end
+
+ defp user_response(user, attrs \\ %{}) do
+ %{
+ "is_active" => user.is_active,
+ "id" => user.id,
+ "email" => user.email,
+ "nickname" => user.nickname,
+ "roles" => %{"admin" => false, "moderator" => false},
+ "local" => user.local,
+ "tags" => [],
+ "avatar" => User.avatar_url(user) |> MediaProxy.url(),
+ "display_name" => HTML.strip_tags(user.name || user.nickname),
+ "is_confirmed" => true,
+ "is_approved" => true,
+ "is_suggested" => false,
+ "url" => user.ap_id,
+ "registration_reason" => nil,
+ "actor_type" => "Person",
+ "created_at" => CommonAPI.Utils.to_masto_date(user.inserted_at)
+ }
+ |> Map.merge(attrs)
+ end
+end
diff --git a/test/web/admin_api/search_test.exs b/test/pleroma/web/admin_api/search_test.exs
index b974cedd5..2335c5228 100644
--- a/test/web/admin_api/search_test.exs
+++ b/test/pleroma/web/admin_api/search_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.AdminAPI.SearchTest do
- use Pleroma.Web.ConnCase
+ use Pleroma.Web.ConnCase, async: true
alias Pleroma.Web.AdminAPI.Search
@@ -47,9 +47,9 @@ defmodule Pleroma.Web.AdminAPI.SearchTest do
end
test "it returns active/deactivated users" do
- insert(:user, deactivated: true)
- insert(:user, deactivated: true)
- insert(:user, deactivated: false)
+ insert(:user, is_active: false)
+ insert(:user, is_active: false)
+ insert(:user, is_active: true)
{:ok, _results, active_count} =
Search.user(%{
@@ -70,7 +70,7 @@ defmodule Pleroma.Web.AdminAPI.SearchTest do
test "it returns specific user" do
insert(:user)
insert(:user)
- user = insert(:user, nickname: "bob", local: true, deactivated: false)
+ user = insert(:user, nickname: "bob", local: true, is_active: true)
{:ok, _results, total_count} = Search.user(%{query: ""})
@@ -143,6 +143,20 @@ defmodule Pleroma.Web.AdminAPI.SearchTest do
assert user2 in users
end
+ test "it returns users by actor_types" do
+ user_service = insert(:user, actor_type: "Service")
+ user_application = insert(:user, actor_type: "Application")
+ user1 = insert(:user)
+ user2 = insert(:user)
+
+ {:ok, [^user_service], 1} = Search.user(%{actor_types: ["Service"]})
+ {:ok, [^user_application], 1} = Search.user(%{actor_types: ["Application"]})
+ {:ok, [^user2, ^user1], 2} = Search.user(%{actor_types: ["Person"]})
+
+ {:ok, [^user2, ^user1, ^user_service], 3} =
+ Search.user(%{actor_types: ["Person", "Service"]})
+ end
+
test "it returns user by display name" do
user = insert(:user, name: "Display name")
insert(:user)
@@ -168,7 +182,7 @@ defmodule Pleroma.Web.AdminAPI.SearchTest do
end
test "it returns unapproved user" do
- unapproved = insert(:user, approval_pending: true)
+ unapproved = insert(:user, is_approved: false)
insert(:user)
insert(:user)
@@ -177,5 +191,26 @@ defmodule Pleroma.Web.AdminAPI.SearchTest do
assert total == 3
assert count == 1
end
+
+ test "it returns unconfirmed user" do
+ unconfirmed = insert(:user, is_confirmed: false)
+ insert(:user)
+ insert(:user)
+
+ {:ok, _results, total} = Search.user()
+ {:ok, [^unconfirmed], count} = Search.user(%{unconfirmed: true})
+ assert total == 3
+ assert count == 1
+ end
+
+ # Note: as in Mastodon, `is_discoverable` doesn't anyhow relate to user searchability
+ test "it returns non-discoverable users" do
+ insert(:user)
+ insert(:user, is_discoverable: false)
+
+ {:ok, _results, total} = Search.user()
+
+ assert total == 2
+ end
end
end
diff --git a/test/pleroma/web/admin_api/views/account_view_test.exs b/test/pleroma/web/admin_api/views/account_view_test.exs
new file mode 100644
index 000000000..025726c73
--- /dev/null
+++ b/test/pleroma/web/admin_api/views/account_view_test.exs
@@ -0,0 +1,16 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.AdminAPI.AccountViewTest do
+ use Pleroma.DataCase, async: true
+ import Pleroma.Factory
+ alias Pleroma.Web.AdminAPI.AccountView
+
+ describe "show.json" do
+ test "renders the user's email" do
+ user = insert(:user, email: "yolo@yolofam.tld")
+ assert %{"email" => "yolo@yolofam.tld"} = AccountView.render("show.json", %{user: user})
+ end
+ end
+end
diff --git a/test/pleroma/web/admin_api/views/moderation_log_view_test.exs b/test/pleroma/web/admin_api/views/moderation_log_view_test.exs
new file mode 100644
index 000000000..4efe4c4c8
--- /dev/null
+++ b/test/pleroma/web/admin_api/views/moderation_log_view_test.exs
@@ -0,0 +1,103 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+defmodule Pleroma.Web.AdminAPI.ModerationLogViewTest do
+ use Pleroma.DataCase, async: true
+
+ alias Pleroma.Web.AdminAPI.ModerationLogView
+
+ describe "renders `report_note_delete` log messages" do
+ setup do
+ log1 = %Pleroma.ModerationLog{
+ id: 1,
+ data: %{
+ "action" => "report_note_delete",
+ "actor" => %{"id" => "A1I7G8", "nickname" => "admin", "type" => "user"},
+ "message" => "@admin deleted note 'mistake' from report #A1I7be on user @b-612",
+ "subject" => %{"id" => "A1I7be", "state" => "open", "type" => "report"},
+ "subject_actor" => %{"id" => "A1I7G8", "nickname" => "b-612", "type" => "user"},
+ "text" => "mistake"
+ },
+ inserted_at: ~N[2020-11-17 14:13:20]
+ }
+
+ log2 = %Pleroma.ModerationLog{
+ id: 2,
+ data: %{
+ "action" => "report_note_delete",
+ "actor" => %{"id" => "A1I7G8", "nickname" => "admin", "type" => "user"},
+ "message" => "@admin deleted note 'fake user' from report #A1I7be on user @j-612",
+ "subject" => %{"id" => "A1I7be", "state" => "open", "type" => "report"},
+ "subject_actor" => %{"id" => "A1I7G8", "nickname" => "j-612", "type" => "user"},
+ "text" => "fake user"
+ },
+ inserted_at: ~N[2020-11-17 14:13:20]
+ }
+
+ {:ok, %{log1: log1, log2: log2}}
+ end
+
+ test "renders `report_note_delete` log messages", %{log1: log1, log2: log2} do
+ assert ModerationLogView.render(
+ "index.json",
+ %{log: %{items: [log1, log2], count: 2}}
+ ) == %{
+ items: [
+ %{
+ id: 1,
+ data: %{
+ "action" => "report_note_delete",
+ "actor" => %{"id" => "A1I7G8", "nickname" => "admin", "type" => "user"},
+ "message" =>
+ "@admin deleted note 'mistake' from report #A1I7be on user @b-612",
+ "subject" => %{"id" => "A1I7be", "state" => "open", "type" => "report"},
+ "subject_actor" => %{
+ "id" => "A1I7G8",
+ "nickname" => "b-612",
+ "type" => "user"
+ },
+ "text" => "mistake"
+ },
+ message: "@admin deleted note 'mistake' from report #A1I7be on user @b-612",
+ time: 1_605_622_400
+ },
+ %{
+ id: 2,
+ data: %{
+ "action" => "report_note_delete",
+ "actor" => %{"id" => "A1I7G8", "nickname" => "admin", "type" => "user"},
+ "message" =>
+ "@admin deleted note 'fake user' from report #A1I7be on user @j-612",
+ "subject" => %{"id" => "A1I7be", "state" => "open", "type" => "report"},
+ "subject_actor" => %{
+ "id" => "A1I7G8",
+ "nickname" => "j-612",
+ "type" => "user"
+ },
+ "text" => "fake user"
+ },
+ message: "@admin deleted note 'fake user' from report #A1I7be on user @j-612",
+ time: 1_605_622_400
+ }
+ ],
+ total: 2
+ }
+ end
+
+ test "renders `report_note_delete` log message", %{log1: log} do
+ assert ModerationLogView.render("show.json", %{log_entry: log}) == %{
+ id: 1,
+ data: %{
+ "action" => "report_note_delete",
+ "actor" => %{"id" => "A1I7G8", "nickname" => "admin", "type" => "user"},
+ "message" => "@admin deleted note 'mistake' from report #A1I7be on user @b-612",
+ "subject" => %{"id" => "A1I7be", "state" => "open", "type" => "report"},
+ "subject_actor" => %{"id" => "A1I7G8", "nickname" => "b-612", "type" => "user"},
+ "text" => "mistake"
+ },
+ message: "@admin deleted note 'mistake' from report #A1I7be on user @b-612",
+ time: 1_605_622_400
+ }
+ end
+ end
+end
diff --git a/test/web/admin_api/views/report_view_test.exs b/test/pleroma/web/admin_api/views/report_view_test.exs
index 5a02292be..093e2d95d 100644
--- a/test/web/admin_api/views/report_view_test.exs
+++ b/test/pleroma/web/admin_api/views/report_view_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.AdminAPI.ReportViewTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
import Pleroma.Factory
@@ -143,4 +143,29 @@ defmodule Pleroma.Web.AdminAPI.ReportViewTest do
assert %{} = ReportView.render("show.json", Report.extract_report_info(activity))
end
+
+ test "reports are ordered newest first" do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, report1} =
+ CommonAPI.report(user, %{
+ account_id: other_user.id,
+ comment: "first report"
+ })
+
+ {:ok, report2} =
+ CommonAPI.report(user, %{
+ account_id: other_user.id,
+ comment: "second report"
+ })
+
+ %{reports: rendered} =
+ ReportView.render("index.json",
+ reports: Pleroma.Web.ActivityPub.Utils.get_reports(%{}, 1, 50)
+ )
+
+ assert report2.id == rendered |> Enum.at(0) |> Map.get(:id)
+ assert report1.id == rendered |> Enum.at(1) |> Map.get(:id)
+ end
end
diff --git a/test/web/api_spec/schema_examples_test.exs b/test/pleroma/web/api_spec/schema_examples_test.exs
index f00e834fc..981890d77 100644
--- a/test/web/api_spec/schema_examples_test.exs
+++ b/test/pleroma/web/api_spec/schema_examples_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ApiSpec.SchemaExamplesTest do
diff --git a/test/web/auth/auth_test_controller_test.exs b/test/pleroma/web/auth/auth_controller_test.exs
index fed52b7f3..a869389e3 100644
--- a/test/web/auth/auth_test_controller_test.exs
+++ b/test/pleroma/web/auth/auth_controller_test.exs
@@ -1,8 +1,8 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Tests.AuthTestControllerTest do
+defmodule Pleroma.Web.Auth.AuthControllerTest do
use Pleroma.Web.ConnCase
import Pleroma.Factory
diff --git a/test/web/auth/authenticator_test.exs b/test/pleroma/web/auth/authenticator_test.exs
index d54253343..26779df03 100644
--- a/test/web/auth/authenticator_test.exs
+++ b/test/pleroma/web/auth/authenticator_test.exs
@@ -1,42 +1,42 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Auth.AuthenticatorTest do
- use Pleroma.Web.ConnCase
+ use Pleroma.Web.ConnCase, async: true
- alias Pleroma.Web.Auth.Authenticator
+ alias Pleroma.Web.Auth.Helpers
import Pleroma.Factory
describe "fetch_user/1" do
test "returns user by name" do
user = insert(:user)
- assert Authenticator.fetch_user(user.nickname) == user
+ assert Helpers.fetch_user(user.nickname) == user
end
test "returns user by email" do
user = insert(:user)
- assert Authenticator.fetch_user(user.email) == user
+ assert Helpers.fetch_user(user.email) == user
end
test "returns nil" do
- assert Authenticator.fetch_user("email") == nil
+ assert Helpers.fetch_user("email") == nil
end
end
describe "fetch_credentials/1" do
test "returns name and password from authorization params" do
params = %{"authorization" => %{"name" => "test", "password" => "test-pass"}}
- assert Authenticator.fetch_credentials(params) == {:ok, {"test", "test-pass"}}
+ assert Helpers.fetch_credentials(params) == {:ok, {"test", "test-pass"}}
end
test "returns name and password with grant_type 'password'" do
params = %{"grant_type" => "password", "username" => "test", "password" => "test-pass"}
- assert Authenticator.fetch_credentials(params) == {:ok, {"test", "test-pass"}}
+ assert Helpers.fetch_credentials(params) == {:ok, {"test", "test-pass"}}
end
test "returns error" do
- assert Authenticator.fetch_credentials(%{}) == {:error, :invalid_credentials}
+ assert Helpers.fetch_credentials(%{}) == {:error, :invalid_credentials}
end
end
end
diff --git a/test/web/auth/basic_auth_test.exs b/test/pleroma/web/auth/basic_auth_test.exs
index bf6e3d2fc..2816aae4c 100644
--- a/test/web/auth/basic_auth_test.exs
+++ b/test/pleroma/web/auth/basic_auth_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Auth.BasicAuthTest do
- use Pleroma.Web.ConnCase
+ use Pleroma.Web.ConnCase, async: true
import Pleroma.Factory
@@ -11,7 +11,7 @@ defmodule Pleroma.Web.Auth.BasicAuthTest do
conn: conn
} do
user = insert(:user)
- assert Pbkdf2.verify_pass("test", user.password_hash)
+ assert Pleroma.Password.Pbkdf2.verify_pass("test", user.password_hash)
basic_auth_contents =
(URI.encode_www_form(user.nickname) <> ":" <> URI.encode_www_form("test"))
diff --git a/test/web/auth/pleroma_authenticator_test.exs b/test/pleroma/web/auth/pleroma_authenticator_test.exs
index 1ba0dfecc..b1397c523 100644
--- a/test/web/auth/pleroma_authenticator_test.exs
+++ b/test/pleroma/web/auth/pleroma_authenticator_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Auth.PleromaAuthenticatorTest do
- use Pleroma.Web.ConnCase
+ use Pleroma.Web.ConnCase, async: true
alias Pleroma.Web.Auth.PleromaAuthenticator
import Pleroma.Factory
@@ -11,7 +11,13 @@ defmodule Pleroma.Web.Auth.PleromaAuthenticatorTest do
setup do
password = "testpassword"
name = "AgentSmith"
- user = insert(:user, nickname: name, password_hash: Pbkdf2.hash_pwd_salt(password))
+
+ user =
+ insert(:user,
+ nickname: name,
+ password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password)
+ )
+
{:ok, [user: user, name: name, password: password]}
end
diff --git a/test/web/auth/totp_authenticator_test.exs b/test/pleroma/web/auth/totp_authenticator_test.exs
index 84d4cd840..ac4209f2d 100644
--- a/test/web/auth/totp_authenticator_test.exs
+++ b/test/pleroma/web/auth/totp_authenticator_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Auth.TOTPAuthenticatorTest do
- use Pleroma.Web.ConnCase
+ use Pleroma.Web.ConnCase, async: true
alias Pleroma.MFA
alias Pleroma.MFA.BackupCodes
@@ -34,7 +34,7 @@ defmodule Pleroma.Web.Auth.TOTPAuthenticatorTest do
hashed_codes =
backup_codes
- |> Enum.map(&Pbkdf2.hash_pwd_salt(&1))
+ |> Enum.map(&Pleroma.Password.Pbkdf2.hash_pwd_salt(&1))
user =
insert(:user,
diff --git a/test/web/common_api/common_api_utils_test.exs b/test/pleroma/web/common_api/utils_test.exs
index e67c10b93..fc01f820a 100644
--- a/test/web/common_api/common_api_utils_test.exs
+++ b/test/pleroma/web/common_api/utils_test.exs
@@ -1,11 +1,12 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.CommonAPI.UtilsTest do
alias Pleroma.Builders.UserBuilder
alias Pleroma.Object
alias Pleroma.Web.CommonAPI
+ alias Pleroma.Web.CommonAPI.ActivityDraft
alias Pleroma.Web.CommonAPI.Utils
use Pleroma.DataCase
@@ -159,11 +160,116 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do
{output, _, _} = Utils.format_input(text, "text/markdown")
assert output ==
- ~s(<p><strong>hello world</strong></p><p><em>another <span class="h-card"><a class="u-url mention" data-user="#{
- user.id
- }" href="http://foo.com/user__test" rel="ugc">@<span>user__test</span></a></span> and <span class="h-card"><a class="u-url mention" data-user="#{
- user.id
- }" href="http://foo.com/user__test" rel="ugc">@<span>user__test</span></a></span> <a href="http://google.com" rel="ugc">google.com</a> paragraph</em></p>)
+ ~s(<p><strong>hello world</strong></p><p><em>another <span class="h-card"><a class="u-url mention" data-user="#{user.id}" href="http://foo.com/user__test" rel="ugc">@<span>user__test</span></a></span> and <span class="h-card"><a class="u-url mention" data-user="#{user.id}" href="http://foo.com/user__test" rel="ugc">@<span>user__test</span></a></span> <a href="http://google.com" rel="ugc">google.com</a> paragraph</em></p>)
+ end
+ end
+
+ describe "format_input/3 with markdown" do
+ test "Paragraph" do
+ code = ~s[Hello\n\nWorld!]
+ {result, [], []} = Utils.format_input(code, "text/markdown")
+ assert result == "<p>Hello</p><p>World!</p>"
+ end
+
+ test "links" do
+ code = "https://en.wikipedia.org/wiki/Animal_Crossing_(video_game)"
+ {result, [], []} = Utils.format_input(code, "text/markdown")
+ assert result == ~s[<p><a href="#{code}">#{code}</a></p>]
+
+ code = "https://github.com/pragdave/earmark/"
+ {result, [], []} = Utils.format_input(code, "text/markdown")
+ assert result == ~s[<p><a href="#{code}">#{code}</a></p>]
+ end
+
+ test "link with local mention" do
+ insert(:user, %{nickname: "lain"})
+
+ code = "https://example.com/@lain"
+ {result, [], []} = Utils.format_input(code, "text/markdown")
+ assert result == ~s[<p><a href="#{code}">#{code}</a></p>]
+ end
+
+ test "local mentions" do
+ mario = insert(:user, %{nickname: "mario"})
+ luigi = insert(:user, %{nickname: "luigi"})
+
+ code = "@mario @luigi yo what's up?"
+ {result, _, []} = Utils.format_input(code, "text/markdown")
+
+ assert result ==
+ ~s[<p><span class="h-card"><a class="u-url mention" data-user="#{mario.id}" href="#{mario.ap_id}" rel="ugc">@<span>mario</span></a></span> <span class="h-card"><a class="u-url mention" data-user="#{luigi.id}" href="#{luigi.ap_id}" rel="ugc">@<span>luigi</span></a></span> yo what’s up?</p>]
+ end
+
+ test "remote mentions" do
+ mario = insert(:user, %{nickname: "mario@mushroom.world", local: false})
+ luigi = insert(:user, %{nickname: "luigi@mushroom.world", local: false})
+
+ code = "@mario@mushroom.world @luigi@mushroom.world yo what's up?"
+ {result, _, []} = Utils.format_input(code, "text/markdown")
+
+ assert result ==
+ ~s[<p><span class="h-card"><a class="u-url mention" data-user="#{mario.id}" href="#{mario.ap_id}" rel="ugc">@<span>mario</span></a></span> <span class="h-card"><a class="u-url mention" data-user="#{luigi.id}" href="#{luigi.ap_id}" rel="ugc">@<span>luigi</span></a></span> yo what’s up?</p>]
+ end
+
+ test "raw HTML" do
+ code = ~s[<a href="http://example.org/">OwO</a><!-- what's this?-->]
+ {result, [], []} = Utils.format_input(code, "text/markdown")
+ assert result == ~s[<a href="http://example.org/">OwO</a>]
+ end
+
+ test "rulers" do
+ code = ~s[before\n\n-----\n\nafter]
+ {result, [], []} = Utils.format_input(code, "text/markdown")
+ assert result == "<p>before</p><hr/><p>after</p>"
+ end
+
+ test "blockquote" do
+ code = ~s[> whoms't are you quoting?]
+ {result, [], []} = Utils.format_input(code, "text/markdown")
+ assert result == "<blockquote><p>whoms’t are you quoting?</p></blockquote>"
+ end
+
+ test "code" do
+ code = ~s[`mix`]
+ {result, [], []} = Utils.format_input(code, "text/markdown")
+ assert result == ~s[<p><code class="inline">mix</code></p>]
+
+ code = ~s[``mix``]
+ {result, [], []} = Utils.format_input(code, "text/markdown")
+ assert result == ~s[<p><code class="inline">mix</code></p>]
+
+ code = ~s[```\nputs "Hello World"\n```]
+ {result, [], []} = Utils.format_input(code, "text/markdown")
+ assert result == ~s[<pre><code>puts &quot;Hello World&quot;</code></pre>]
+
+ code = ~s[ <div>\n </div>]
+ {result, [], []} = Utils.format_input(code, "text/markdown")
+ assert result == ~s[<pre><code>&lt;div&gt;\n&lt;/div&gt;</code></pre>]
+ end
+
+ test "lists" do
+ code = ~s[- one\n- two\n- three\n- four]
+ {result, [], []} = Utils.format_input(code, "text/markdown")
+ assert result == "<ul><li>one</li><li>two</li><li>three</li><li>four</li></ul>"
+
+ code = ~s[1. one\n2. two\n3. three\n4. four\n]
+ {result, [], []} = Utils.format_input(code, "text/markdown")
+ assert result == "<ol><li>one</li><li>two</li><li>three</li><li>four</li></ol>"
+ end
+
+ test "delegated renderers" do
+ code = ~s[*aaaa~*]
+ {result, [], []} = Utils.format_input(code, "text/markdown")
+ assert result == ~s[<p><em>aaaa~</em></p>]
+
+ code = ~s[**aaaa~**]
+ {result, [], []} = Utils.format_input(code, "text/markdown")
+ assert result == ~s[<p><strong>aaaa~</strong></p>]
+
+ # strikethrough
+ code = ~s[~~aaaa~~~]
+ {result, [], []} = Utils.format_input(code, "text/markdown")
+ assert result == ~s[<p><del>aaaa</del>~</p>]
end
end
@@ -235,9 +341,9 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do
test "for public posts, not a reply" do
user = insert(:user)
mentioned_user = insert(:user)
- mentions = [mentioned_user.ap_id]
+ draft = %ActivityDraft{user: user, mentions: [mentioned_user.ap_id], visibility: "public"}
- {to, cc} = Utils.get_to_and_cc(user, mentions, nil, "public", nil)
+ {to, cc} = Utils.get_to_and_cc(draft)
assert length(to) == 2
assert length(cc) == 1
@@ -252,9 +358,15 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do
mentioned_user = insert(:user)
third_user = insert(:user)
{:ok, activity} = CommonAPI.post(third_user, %{status: "uguu"})
- mentions = [mentioned_user.ap_id]
- {to, cc} = Utils.get_to_and_cc(user, mentions, activity, "public", nil)
+ draft = %ActivityDraft{
+ user: user,
+ mentions: [mentioned_user.ap_id],
+ visibility: "public",
+ in_reply_to: activity
+ }
+
+ {to, cc} = Utils.get_to_and_cc(draft)
assert length(to) == 3
assert length(cc) == 1
@@ -268,9 +380,9 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do
test "for unlisted posts, not a reply" do
user = insert(:user)
mentioned_user = insert(:user)
- mentions = [mentioned_user.ap_id]
+ draft = %ActivityDraft{user: user, mentions: [mentioned_user.ap_id], visibility: "unlisted"}
- {to, cc} = Utils.get_to_and_cc(user, mentions, nil, "unlisted", nil)
+ {to, cc} = Utils.get_to_and_cc(draft)
assert length(to) == 2
assert length(cc) == 1
@@ -285,9 +397,15 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do
mentioned_user = insert(:user)
third_user = insert(:user)
{:ok, activity} = CommonAPI.post(third_user, %{status: "uguu"})
- mentions = [mentioned_user.ap_id]
- {to, cc} = Utils.get_to_and_cc(user, mentions, activity, "unlisted", nil)
+ draft = %ActivityDraft{
+ user: user,
+ mentions: [mentioned_user.ap_id],
+ visibility: "unlisted",
+ in_reply_to: activity
+ }
+
+ {to, cc} = Utils.get_to_and_cc(draft)
assert length(to) == 3
assert length(cc) == 1
@@ -301,9 +419,9 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do
test "for private posts, not a reply" do
user = insert(:user)
mentioned_user = insert(:user)
- mentions = [mentioned_user.ap_id]
+ draft = %ActivityDraft{user: user, mentions: [mentioned_user.ap_id], visibility: "private"}
- {to, cc} = Utils.get_to_and_cc(user, mentions, nil, "private", nil)
+ {to, cc} = Utils.get_to_and_cc(draft)
assert length(to) == 2
assert Enum.empty?(cc)
@@ -316,9 +434,15 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do
mentioned_user = insert(:user)
third_user = insert(:user)
{:ok, activity} = CommonAPI.post(third_user, %{status: "uguu"})
- mentions = [mentioned_user.ap_id]
- {to, cc} = Utils.get_to_and_cc(user, mentions, activity, "private", nil)
+ draft = %ActivityDraft{
+ user: user,
+ mentions: [mentioned_user.ap_id],
+ visibility: "private",
+ in_reply_to: activity
+ }
+
+ {to, cc} = Utils.get_to_and_cc(draft)
assert length(to) == 2
assert Enum.empty?(cc)
@@ -330,9 +454,9 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do
test "for direct posts, not a reply" do
user = insert(:user)
mentioned_user = insert(:user)
- mentions = [mentioned_user.ap_id]
+ draft = %ActivityDraft{user: user, mentions: [mentioned_user.ap_id], visibility: "direct"}
- {to, cc} = Utils.get_to_and_cc(user, mentions, nil, "direct", nil)
+ {to, cc} = Utils.get_to_and_cc(draft)
assert length(to) == 1
assert Enum.empty?(cc)
@@ -345,9 +469,15 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do
mentioned_user = insert(:user)
third_user = insert(:user)
{:ok, activity} = CommonAPI.post(third_user, %{status: "uguu"})
- mentions = [mentioned_user.ap_id]
- {to, cc} = Utils.get_to_and_cc(user, mentions, activity, "direct", nil)
+ draft = %ActivityDraft{
+ user: user,
+ mentions: [mentioned_user.ap_id],
+ visibility: "direct",
+ in_reply_to: activity
+ }
+
+ {to, cc} = Utils.get_to_and_cc(draft)
assert length(to) == 1
assert Enum.empty?(cc)
@@ -356,7 +486,14 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do
{:ok, direct_activity} = CommonAPI.post(third_user, %{status: "uguu", visibility: "direct"})
- {to, cc} = Utils.get_to_and_cc(user, mentions, direct_activity, "direct", nil)
+ draft = %ActivityDraft{
+ user: user,
+ mentions: [mentioned_user.ap_id],
+ visibility: "direct",
+ in_reply_to: direct_activity
+ }
+
+ {to, cc} = Utils.get_to_and_cc(draft)
assert length(to) == 2
assert Enum.empty?(cc)
@@ -532,41 +669,6 @@ defmodule Pleroma.Web.CommonAPI.UtilsTest do
end
end
- describe "make_note_data/11" do
- test "returns note data" do
- user = insert(:user)
- note = insert(:note)
- user2 = insert(:user)
- user3 = insert(:user)
-
- assert Utils.make_note_data(
- user.ap_id,
- [user2.ap_id],
- "2hu",
- "<h1>This is :moominmamma: note</h1>",
- [],
- note.id,
- [name: "jimm"],
- "test summary",
- [user3.ap_id],
- false,
- %{"custom_tag" => "test"}
- ) == %{
- "actor" => user.ap_id,
- "attachment" => [],
- "cc" => [user3.ap_id],
- "content" => "<h1>This is :moominmamma: note</h1>",
- "context" => "2hu",
- "sensitive" => false,
- "summary" => "test summary",
- "tag" => ["jimm"],
- "to" => [user2.ap_id],
- "type" => "Note",
- "custom_tag" => "test"
- }
- end
- end
-
describe "maybe_add_attachments/3" do
test "returns parsed results when attachment_links is false" do
assert Utils.maybe_add_attachments(
diff --git a/test/web/common_api/common_api_test.exs b/test/pleroma/web/common_api_test.exs
index 800db9a20..ad0b87543 100644
--- a/test/web/common_api/common_api_test.exs
+++ b/test/pleroma/web/common_api_test.exs
@@ -1,9 +1,11 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.CommonAPITest do
+ use Oban.Testing, repo: Pleroma.Repo
use Pleroma.DataCase
+
alias Pleroma.Activity
alias Pleroma.Chat
alias Pleroma.Conversation.Participation
@@ -16,6 +18,7 @@ defmodule Pleroma.Web.CommonAPITest do
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.AdminAPI.AccountView
alias Pleroma.Web.CommonAPI
+ alias Pleroma.Workers.PollWorker
import Pleroma.Factory
import Mock
@@ -23,10 +26,38 @@ defmodule Pleroma.Web.CommonAPITest do
require Pleroma.Constants
+ setup_all do
+ Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
+ :ok
+ end
+
setup do: clear_config([:instance, :safe_dm_mentions])
setup do: clear_config([:instance, :limit])
setup do: clear_config([:instance, :max_pinned_statuses])
+ describe "posting polls" do
+ test "it posts a poll" do
+ user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ status: "who is the best",
+ poll: %{expires_in: 600, options: ["reimu", "marisa"]}
+ })
+
+ object = Object.normalize(activity, fetch: false)
+
+ assert object.data["type"] == "Question"
+ assert object.data["oneOf"] |> length() == 2
+
+ assert_enqueued(
+ worker: PollWorker,
+ args: %{op: "poll_end", activity_id: activity.id},
+ scheduled_at: NaiveDateTime.from_iso8601!(object.data["closed"])
+ )
+ end
+ end
+
describe "blocking" do
setup do
blocker = insert(:user)
@@ -76,12 +107,26 @@ defmodule Pleroma.Web.CommonAPITest do
describe "posting chat messages" do
setup do: clear_config([:instance, :chat_limit])
+ test "it posts a self-chat" do
+ author = insert(:user)
+ recipient = author
+
+ {:ok, activity} =
+ CommonAPI.post_chat_message(
+ author,
+ recipient,
+ "remember to buy milk when milk truk arive"
+ )
+
+ assert activity.data["type"] == "Create"
+ end
+
test "it posts a chat message without content but with an attachment" do
author = insert(:user)
recipient = insert(:user)
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}
@@ -141,7 +186,7 @@ defmodule Pleroma.Web.CommonAPITest do
assert other_user.ap_id not in activity.recipients
- object = Object.normalize(activity, false)
+ object = Object.normalize(activity, fetch: false)
assert object.data["content"] == "uguu<br/>uguuu"
end
@@ -161,12 +206,10 @@ defmodule Pleroma.Web.CommonAPITest do
assert other_user.ap_id not in activity.recipients
- object = Object.normalize(activity, false)
+ object = Object.normalize(activity, fetch: false)
assert object.data["content"] ==
- "<a href=\"https://example.org\" rel=\"ugc\">https://example.org</a> is the site of <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{
- other_user.id
- }\" href=\"#{other_user.ap_id}\" rel=\"ugc\">@<span>#{other_user.nickname}</span></a></span> <a class=\"hashtag\" data-tag=\"2hu\" href=\"http://localhost:4001/tag/2hu\">#2hu</a>"
+ "<a href=\"https://example.org\" rel=\"ugc\">https://example.org</a> is the site of <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{other_user.id}\" href=\"#{other_user.ap_id}\" rel=\"ugc\">@<span>#{other_user.nickname}</span></a></span> <a class=\"hashtag\" data-tag=\"2hu\" href=\"http://localhost:4001/tag/2hu\">#2hu</a>"
end
test "it posts a chat message" do
@@ -182,7 +225,7 @@ defmodule Pleroma.Web.CommonAPITest do
assert activity.data["type"] == "Create"
assert activity.local
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
assert object.data["type"] == "ChatMessage"
assert object.data["to"] == [recipient.ap_id]
@@ -201,7 +244,7 @@ defmodule Pleroma.Web.CommonAPITest do
end
test "it reject messages over the local limit" do
- Pleroma.Config.put([:instance, :chat_limit], 2)
+ clear_config([:instance, :chat_limit], 2)
author = insert(:user)
recipient = insert(:user)
@@ -215,6 +258,17 @@ defmodule Pleroma.Web.CommonAPITest do
assert message == :content_too_long
end
+
+ test "it reject messages via MRF" do
+ clear_config([:mrf_keyword, :reject], ["GNO"])
+ clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.KeywordPolicy])
+
+ author = insert(:user)
+ recipient = insert(:user)
+
+ assert {:reject, "[KeywordPolicy] Matches with rejected keyword"} ==
+ CommonAPI.post_chat_message(author, recipient, "GNO/Linux")
+ end
end
describe "unblocking" do
@@ -237,7 +291,7 @@ defmodule Pleroma.Web.CommonAPITest do
clear_config([:instance, :federating], true)
- Object.normalize(post, false)
+ Object.normalize(post, fetch: false)
|> Object.prune()
with_mock Pleroma.Web.Federator,
@@ -431,7 +485,7 @@ defmodule Pleroma.Web.CommonAPITest do
jafnhar = insert(:user)
tridi = insert(:user)
- Pleroma.Config.put([:instance, :safe_dm_mentions], true)
+ clear_config([:instance, :safe_dm_mentions], true)
{:ok, activity} =
CommonAPI.post(har, %{
@@ -447,21 +501,55 @@ defmodule Pleroma.Web.CommonAPITest do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "#2hu #2HU"})
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
- assert object.data["tag"] == ["2hu"]
+ assert Object.tags(object) == ["2hu"]
end
test "it adds emoji in the object" do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: ":firefox:"})
- assert Object.normalize(activity).data["emoji"]["firefox"]
+ assert Object.normalize(activity, fetch: false).data["emoji"]["firefox"]
end
describe "posting" do
+ test "it adds an emoji on an external site" do
+ user = insert(:user)
+ {:ok, activity} = CommonAPI.post(user, %{status: "hey :external_emoji:"})
+
+ assert %{"external_emoji" => url} = Object.normalize(activity).data["emoji"]
+ assert url == "https://example.com/emoji.png"
+
+ {:ok, activity} = CommonAPI.post(user, %{status: "hey :blank:"})
+
+ assert %{"blank" => url} = Object.normalize(activity).data["emoji"]
+ assert url == "#{Pleroma.Web.Endpoint.url()}/emoji/blank.png"
+ end
+
+ test "it copies emoji from the subject of the parent post" do
+ %Object{} =
+ object =
+ Object.normalize("https://patch.cx/objects/a399c28e-c821-4820-bc3e-4afeb044c16f",
+ fetch: true
+ )
+
+ activity = Activity.get_create_by_object_ap_id(object.data["id"])
+ user = insert(:user)
+
+ {:ok, reply_activity} =
+ CommonAPI.post(user, %{
+ in_reply_to_id: activity.id,
+ status: ":joker_disapprove:",
+ spoiler_text: ":joker_smile:"
+ })
+
+ assert Object.normalize(reply_activity).data["emoji"]["joker_smile"]
+ refute Object.normalize(reply_activity).data["emoji"]["joker_disapprove"]
+ end
+
test "deactivated users can't post" do
- user = insert(:user, deactivated: true)
+ user = insert(:user, is_active: false)
assert {:error, _} = CommonAPI.post(user, %{status: "ye"})
end
@@ -495,7 +583,7 @@ defmodule Pleroma.Web.CommonAPITest do
content_type: "text/html"
})
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
assert object.data["content"] == "<p><b>2hu</b></p>alert(&#39;xss&#39;)"
assert object.data["source"] == post
@@ -512,9 +600,9 @@ defmodule Pleroma.Web.CommonAPITest do
content_type: "text/markdown"
})
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
- assert object.data["content"] == "<p><b>2hu</b></p>alert(&#39;xss&#39;)"
+ assert object.data["content"] == "<p><b>2hu</b></p>"
assert object.data["source"] == post
end
@@ -585,28 +673,28 @@ defmodule Pleroma.Web.CommonAPITest do
end
test "it validates character limits are correctly enforced" do
- Pleroma.Config.put([:instance, :limit], 5)
+ clear_config([:instance, :limit], 5)
user = insert(:user)
assert {:error, "The status is over the character limit"} =
CommonAPI.post(user, %{status: "foobar"})
- assert {:ok, activity} = CommonAPI.post(user, %{status: "12345"})
+ assert {:ok, _activity} = CommonAPI.post(user, %{status: "12345"})
end
test "it can handle activities that expire" do
user = insert(:user)
- expires_at =
- NaiveDateTime.utc_now()
- |> NaiveDateTime.truncate(:second)
- |> NaiveDateTime.add(1_000_000, :second)
+ expires_at = DateTime.add(DateTime.utc_now(), 1_000_000)
assert {:ok, activity} = CommonAPI.post(user, %{status: "chai", expires_in: 1_000_000})
- assert expiration = Pleroma.ActivityExpiration.get_by_activity_id(activity.id)
- assert expiration.scheduled_at == expires_at
+ assert_enqueued(
+ worker: Pleroma.Workers.PurgeExpiredActivity,
+ args: %{activity_id: activity.id},
+ scheduled_at: expires_at
+ )
end
end
@@ -687,6 +775,22 @@ defmodule Pleroma.Web.CommonAPITest do
refute Visibility.visible_for_user?(announce_activity, nil)
end
+ test "author can repeat own private statuses" do
+ author = insert(:user)
+ follower = insert(:user)
+ CommonAPI.follow(follower, author)
+
+ {:ok, activity} = CommonAPI.post(author, %{status: "cofe", visibility: "private"})
+
+ {:ok, %Activity{} = announce_activity} = CommonAPI.repeat(activity.id, author)
+
+ assert Visibility.is_private?(announce_activity)
+ refute Visibility.visible_for_user?(announce_activity, nil)
+
+ assert Visibility.visible_for_user?(activity, follower)
+ assert {:error, :not_found} = CommonAPI.repeat(activity.id, follower)
+ end
+
test "favoriting a status" do
user = insert(:user)
other_user = insert(:user)
@@ -720,7 +824,7 @@ defmodule Pleroma.Web.CommonAPITest do
describe "pinned statuses" do
setup do
- Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
+ clear_config([:instance, :max_pinned_statuses], 1)
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "HI!!!"})
@@ -728,13 +832,17 @@ defmodule Pleroma.Web.CommonAPITest do
[user: user, activity: activity]
end
+ test "activity not found error", %{user: user} do
+ assert {:error, :not_found} = CommonAPI.pin("id", user)
+ end
+
test "pin status", %{user: user, activity: activity} do
assert {:ok, ^activity} = CommonAPI.pin(activity.id, user)
- id = activity.id
+ %{data: %{"id" => object_id}} = Object.normalize(activity)
user = refresh_record(user)
- assert %User{pinned_activities: [^id]} = user
+ assert user.pinned_objects |> Map.keys() == [object_id]
end
test "pin poll", %{user: user} do
@@ -746,10 +854,11 @@ defmodule Pleroma.Web.CommonAPITest do
assert {:ok, ^activity} = CommonAPI.pin(activity.id, user)
- id = activity.id
+ %{data: %{"id" => object_id}} = Object.normalize(activity)
+
user = refresh_record(user)
- assert %User{pinned_activities: [^id]} = user
+ assert user.pinned_objects |> Map.keys() == [object_id]
end
test "unlisted statuses can be pinned", %{user: user} do
@@ -760,7 +869,7 @@ defmodule Pleroma.Web.CommonAPITest do
test "only self-authored can be pinned", %{activity: activity} do
user = insert(:user)
- assert {:error, "Could not pin"} = CommonAPI.pin(activity.id, user)
+ assert {:error, :ownership_error} = CommonAPI.pin(activity.id, user)
end
test "max pinned statuses", %{user: user, activity: activity_one} do
@@ -770,8 +879,12 @@ defmodule Pleroma.Web.CommonAPITest do
user = refresh_record(user)
- assert {:error, "You have already pinned the maximum number of statuses"} =
- CommonAPI.pin(activity_two.id, user)
+ assert {:error, :pinned_statuses_limit_reached} = CommonAPI.pin(activity_two.id, user)
+ end
+
+ test "only public can be pinned", %{user: user} do
+ {:ok, activity} = CommonAPI.post(user, %{status: "private status", visibility: "private"})
+ {:error, :visibility_error} = CommonAPI.pin(activity.id, user)
end
test "unpin status", %{user: user, activity: activity} do
@@ -785,7 +898,7 @@ defmodule Pleroma.Web.CommonAPITest do
user = refresh_record(user)
- assert %User{pinned_activities: []} = user
+ assert user.pinned_objects == %{}
end
test "should unpin when deleting a status", %{user: user, activity: activity} do
@@ -797,7 +910,40 @@ defmodule Pleroma.Web.CommonAPITest do
user = refresh_record(user)
- assert %User{pinned_activities: []} = user
+ assert user.pinned_objects == %{}
+ end
+
+ test "ephemeral activity won't be deleted if was pinned", %{user: user} do
+ {:ok, activity} = CommonAPI.post(user, %{status: "Hello!", expires_in: 601})
+
+ assert Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity.id)
+
+ {:ok, _activity} = CommonAPI.pin(activity.id, user)
+ refute Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity.id)
+
+ user = refresh_record(user)
+ {:ok, _} = CommonAPI.unpin(activity.id, user)
+
+ # recreates expiration job on unpin
+ assert Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity.id)
+ end
+
+ test "ephemeral activity deletion job won't be deleted on pinning error", %{
+ user: user,
+ activity: activity
+ } do
+ clear_config([:instance, :max_pinned_statuses], 1)
+
+ {:ok, _activity} = CommonAPI.pin(activity.id, user)
+
+ {:ok, activity2} = CommonAPI.post(user, %{status: "another status", expires_in: 601})
+
+ assert Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity2.id)
+
+ user = refresh_record(user)
+ {:error, :pinned_statuses_limit_reached} = CommonAPI.pin(activity2.id, user)
+
+ assert Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity2.id)
end
end
@@ -878,12 +1024,34 @@ defmodule Pleroma.Web.CommonAPITest do
assert CommonAPI.thread_muted?(user, activity)
end
+ test "add expiring mute", %{user: user, activity: activity} do
+ {:ok, _} = CommonAPI.add_mute(user, activity, %{expires_in: 60})
+ assert CommonAPI.thread_muted?(user, activity)
+
+ worker = Pleroma.Workers.MuteExpireWorker
+ args = %{"op" => "unmute_conversation", "user_id" => user.id, "activity_id" => activity.id}
+
+ assert_enqueued(
+ worker: worker,
+ args: args
+ )
+
+ assert :ok = perform_job(worker, args)
+ refute CommonAPI.thread_muted?(user, activity)
+ end
+
test "remove mute", %{user: user, activity: activity} do
CommonAPI.add_mute(user, activity)
{:ok, _} = CommonAPI.remove_mute(user, activity)
refute CommonAPI.thread_muted?(user, activity)
end
+ test "remove mute by ids", %{user: user, activity: activity} do
+ CommonAPI.add_mute(user, activity)
+ {:ok, _} = CommonAPI.remove_mute(user.id, activity.id)
+ refute CommonAPI.thread_muted?(user, activity)
+ end
+
test "check that mutes can't be duplicate", %{user: user, activity: activity} do
CommonAPI.add_mute(user, activity)
{:error, _} = CommonAPI.add_mute(user, activity)
@@ -1041,7 +1209,7 @@ defmodule Pleroma.Web.CommonAPITest do
test "cancels a pending follow for a local user" do
follower = insert(:user)
- followed = insert(:user, locked: true)
+ followed = insert(:user, is_locked: true)
assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} =
CommonAPI.follow(follower, followed)
@@ -1063,7 +1231,7 @@ defmodule Pleroma.Web.CommonAPITest do
test "cancels a pending follow for a remote user" do
follower = insert(:user)
- followed = insert(:user, locked: true, local: false, ap_enabled: true)
+ followed = insert(:user, is_locked: true, local: false, ap_enabled: true)
assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} =
CommonAPI.follow(follower, followed)
@@ -1086,7 +1254,7 @@ defmodule Pleroma.Web.CommonAPITest do
describe "accept_follow_request/2" do
test "after acceptance, it sets all existing pending follow request states to 'accept'" do
- user = insert(:user, locked: true)
+ user = insert(:user, is_locked: true)
follower = insert(:user)
follower_two = insert(:user)
@@ -1106,7 +1274,7 @@ defmodule Pleroma.Web.CommonAPITest do
end
test "after rejection, it sets all existing pending follow request states to 'reject'" do
- user = insert(:user, locked: true)
+ user = insert(:user, is_locked: true)
follower = insert(:user)
follower_two = insert(:user)
@@ -1126,7 +1294,7 @@ defmodule Pleroma.Web.CommonAPITest do
end
test "doesn't create a following relationship if the corresponding follow request doesn't exist" do
- user = insert(:user, locked: true)
+ user = insert(:user, is_locked: true)
not_follower = insert(:user)
CommonAPI.accept_follow_request(not_follower, user)
@@ -1145,7 +1313,7 @@ defmodule Pleroma.Web.CommonAPITest do
poll: %{options: ["Yes", "No"], expires_in: 20}
})
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
{:ok, _, object} = CommonAPI.vote(other_user, object, [0])
@@ -1165,7 +1333,7 @@ defmodule Pleroma.Web.CommonAPITest do
length: 180_000
})
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
assert object.data["title"] == "lain radio episode 1"
@@ -1184,11 +1352,155 @@ defmodule Pleroma.Web.CommonAPITest do
visibility: "private"
})
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
assert object.data["title"] == "lain radio episode 1"
assert Visibility.get_visibility(activity) == "private"
end
end
+
+ describe "get_user/1" do
+ test "gets user by ap_id" do
+ user = insert(:user)
+ assert CommonAPI.get_user(user.ap_id) == user
+ end
+
+ test "gets user by guessed nickname" do
+ user = insert(:user, ap_id: "", nickname: "mario@mushroom.kingdom")
+ assert CommonAPI.get_user("https://mushroom.kingdom/users/mario") == user
+ end
+
+ test "fallback" do
+ assert %User{
+ name: "",
+ ap_id: "",
+ nickname: "erroruser@example.com"
+ } = CommonAPI.get_user("")
+ end
+ end
+
+ describe "with `local` visibility" do
+ setup do: clear_config([:instance, :federating], true)
+
+ test "post" do
+ user = insert(:user)
+
+ with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
+ {:ok, activity} = CommonAPI.post(user, %{status: "#2hu #2HU", visibility: "local"})
+
+ assert Visibility.is_local_public?(activity)
+ assert_not_called(Pleroma.Web.Federator.publish(activity))
+ end
+ end
+
+ test "delete" do
+ user = insert(:user)
+
+ {:ok, %Activity{id: activity_id}} =
+ CommonAPI.post(user, %{status: "#2hu #2HU", visibility: "local"})
+
+ with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
+ assert {:ok, %Activity{data: %{"deleted_activity_id" => ^activity_id}} = activity} =
+ CommonAPI.delete(activity_id, user)
+
+ assert Visibility.is_local_public?(activity)
+ assert_not_called(Pleroma.Web.Federator.publish(activity))
+ end
+ end
+
+ test "repeat" do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, %Activity{id: activity_id}} =
+ CommonAPI.post(other_user, %{status: "cofe", visibility: "local"})
+
+ with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
+ assert {:ok, %Activity{data: %{"type" => "Announce"}} = activity} =
+ CommonAPI.repeat(activity_id, user)
+
+ assert Visibility.is_local_public?(activity)
+ refute called(Pleroma.Web.Federator.publish(activity))
+ end
+ end
+
+ test "unrepeat" do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, %Activity{id: activity_id}} =
+ CommonAPI.post(other_user, %{status: "cofe", visibility: "local"})
+
+ assert {:ok, _} = CommonAPI.repeat(activity_id, user)
+
+ with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
+ assert {:ok, %Activity{data: %{"type" => "Undo"}} = activity} =
+ CommonAPI.unrepeat(activity_id, user)
+
+ assert Visibility.is_local_public?(activity)
+ refute called(Pleroma.Web.Federator.publish(activity))
+ end
+ end
+
+ test "favorite" do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe", visibility: "local"})
+
+ with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
+ assert {:ok, %Activity{data: %{"type" => "Like"}} = activity} =
+ CommonAPI.favorite(user, activity.id)
+
+ assert Visibility.is_local_public?(activity)
+ refute called(Pleroma.Web.Federator.publish(activity))
+ end
+ end
+
+ test "unfavorite" do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe", visibility: "local"})
+
+ {:ok, %Activity{}} = CommonAPI.favorite(user, activity.id)
+
+ with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
+ assert {:ok, activity} = CommonAPI.unfavorite(activity.id, user)
+ assert Visibility.is_local_public?(activity)
+ refute called(Pleroma.Web.Federator.publish(activity))
+ end
+ end
+
+ test "react_with_emoji" do
+ user = insert(:user)
+ other_user = insert(:user)
+ {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe", visibility: "local"})
+
+ with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
+ assert {:ok, %Activity{data: %{"type" => "EmojiReact"}} = activity} =
+ CommonAPI.react_with_emoji(activity.id, user, "👍")
+
+ assert Visibility.is_local_public?(activity)
+ refute called(Pleroma.Web.Federator.publish(activity))
+ end
+ end
+
+ test "unreact_with_emoji" do
+ user = insert(:user)
+ other_user = insert(:user)
+ {:ok, activity} = CommonAPI.post(other_user, %{status: "cofe", visibility: "local"})
+
+ {:ok, _reaction} = CommonAPI.react_with_emoji(activity.id, user, "👍")
+
+ with_mock Pleroma.Web.Federator, publish: fn _ -> :ok end do
+ assert {:ok, %Activity{data: %{"type" => "Undo"}} = activity} =
+ CommonAPI.unreact_with_emoji(activity.id, user, "👍")
+
+ assert Visibility.is_local_public?(activity)
+ refute called(Pleroma.Web.Federator.publish(activity))
+ end
+ end
+ end
end
diff --git a/test/pleroma/web/endpoint/metrics_exporter_test.exs b/test/pleroma/web/endpoint/metrics_exporter_test.exs
new file mode 100644
index 000000000..376e82149
--- /dev/null
+++ b/test/pleroma/web/endpoint/metrics_exporter_test.exs
@@ -0,0 +1,69 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Endpoint.MetricsExporterTest do
+ # Modifies AppEnv, has to stay synchronous
+ use Pleroma.Web.ConnCase
+
+ alias Pleroma.Web.Endpoint.MetricsExporter
+
+ defp config do
+ Application.get_env(:prometheus, MetricsExporter)
+ end
+
+ describe "with default config" do
+ test "does NOT expose app metrics", %{conn: conn} do
+ conn
+ |> get(config()[:path])
+ |> json_response(404)
+ end
+ end
+
+ describe "when enabled" do
+ setup do
+ initial_config = config()
+ on_exit(fn -> Application.put_env(:prometheus, MetricsExporter, initial_config) end)
+
+ Application.put_env(
+ :prometheus,
+ MetricsExporter,
+ Keyword.put(initial_config, :enabled, true)
+ )
+ end
+
+ test "serves app metrics", %{conn: conn} do
+ conn = get(conn, config()[:path])
+ assert response = response(conn, 200)
+
+ for metric <- [
+ "http_requests_total",
+ "http_request_duration_microseconds",
+ "phoenix_controller_call_duration",
+ "telemetry_scrape_duration",
+ "erlang_vm_memory_atom_bytes_total"
+ ] do
+ assert response =~ ~r/#{metric}/
+ end
+ end
+
+ test "when IP whitelist configured, " <>
+ "serves app metrics only if client IP is whitelisted",
+ %{conn: conn} do
+ Application.put_env(
+ :prometheus,
+ MetricsExporter,
+ Keyword.put(config(), :ip_whitelist, ["127.127.127.127", {1, 1, 1, 1}, '255.255.255.255'])
+ )
+
+ conn
+ |> get(config()[:path])
+ |> json_response(404)
+
+ conn
+ |> Map.put(:remote_ip, {127, 127, 127, 127})
+ |> get(config()[:path])
+ |> response(200)
+ end
+ end
+end
diff --git a/test/web/fallback_test.exs b/test/pleroma/web/fallback_test.exs
index a65865860..512baf813 100644
--- a/test/web/fallback_test.exs
+++ b/test/pleroma/web/fallback_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.FallbackTest do
@@ -20,15 +20,26 @@ defmodule Pleroma.Web.FallbackTest do
end
end
+ test "GET /*path adds a title", %{conn: conn} do
+ clear_config([:instance, :name], "a cool title")
+
+ assert conn
+ |> get("/")
+ |> html_response(200) =~ "<title>a cool title</title>"
+ end
+
describe "preloaded data and metadata attached to" do
test "GET /:maybe_nickname_or_id", %{conn: conn} do
+ clear_config([:instance, :name], "a cool title")
+
user = insert(:user)
user_missing = get(conn, "/foo")
user_present = get(conn, "/#{user.nickname}")
- assert(html_response(user_missing, 200) =~ "<!--server-generated-meta-->")
+ assert html_response(user_missing, 200) =~ "<!--server-generated-meta-->"
refute html_response(user_present, 200) =~ "<!--server-generated-meta-->"
assert html_response(user_present, 200) =~ "initial-results"
+ assert html_response(user_present, 200) =~ "<title>a cool title</title>"
end
test "GET /*path", %{conn: conn} do
@@ -44,10 +55,13 @@ defmodule Pleroma.Web.FallbackTest do
describe "preloaded data is attached to" do
test "GET /main/public", %{conn: conn} do
+ clear_config([:instance, :name], "a cool title")
+
public_page = get(conn, "/main/public")
refute html_response(public_page, 200) =~ "<!--server-generated-meta-->"
assert html_response(public_page, 200) =~ "initial-results"
+ assert html_response(public_page, 200) =~ "<title>a cool title</title>"
end
test "GET /main/all", %{conn: conn} do
diff --git a/test/web/federator_test.exs b/test/pleroma/web/federator_test.exs
index 592fdccd1..372b6a73a 100644
--- a/test/web/federator_test.exs
+++ b/test/pleroma/web/federator_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.FederatorTest do
@@ -56,7 +56,7 @@ defmodule Pleroma.Web.FederatorTest do
activity: activity,
relay_mock: relay_mock
} do
- Pleroma.Config.put([:instance, :allow_relay], false)
+ clear_config([:instance, :allow_relay], false)
with_mocks([relay_mock]) do
Federator.publish(activity)
@@ -123,7 +123,8 @@ defmodule Pleroma.Web.FederatorTest do
"type" => "Note",
"content" => "hi world!",
"id" => "http://mastodon.example.org/users/admin/objects/1",
- "attributedTo" => "http://mastodon.example.org/users/admin"
+ "attributedTo" => "http://mastodon.example.org/users/admin",
+ "to" => ["https://www.w3.org/ns/activitystreams#Public"]
},
"to" => ["https://www.w3.org/ns/activitystreams#Public"]
}
@@ -145,7 +146,8 @@ defmodule Pleroma.Web.FederatorTest do
"type" => "Note",
"content" => "hi world!",
"id" => "http://mastodon.example.org/users/admin/objects/1",
- "attributedTo" => "http://mastodon.example.org/users/admin"
+ "attributedTo" => "http://mastodon.example.org/users/admin",
+ "to" => ["https://www.w3.org/ns/activitystreams#Public"]
},
"to" => ["https://www.w3.org/ns/activitystreams#Public"]
}
@@ -155,16 +157,16 @@ defmodule Pleroma.Web.FederatorTest do
end
test "it does not crash if MRF rejects the post" do
- Pleroma.Config.put([:mrf_keyword, :reject], ["lain"])
+ clear_config([:mrf_keyword, :reject], ["lain"])
- Pleroma.Config.put(
+ clear_config(
[:mrf, :policies],
Pleroma.Web.ActivityPub.MRF.KeywordPolicy
)
params =
File.read!("test/fixtures/mastodon-post-activity.json")
- |> Poison.decode!()
+ |> Jason.decode!()
assert {:ok, job} = Federator.incoming_ap_doc(params)
assert {:error, _} = ObanHelpers.perform(job)
diff --git a/test/web/feed/tag_controller_test.exs b/test/pleroma/web/feed/tag_controller_test.exs
index 3c29cd94f..140cdb8bf 100644
--- a/test/web/feed/tag_controller_test.exs
+++ b/test/pleroma/web/feed/tag_controller_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Feed.TagControllerTest do
@@ -15,7 +15,7 @@ defmodule Pleroma.Web.Feed.TagControllerTest do
setup do: clear_config([:feed])
test "gets a feed (ATOM)", %{conn: conn} do
- Pleroma.Config.put(
+ clear_config(
[:feed, :post_title],
%{max_length: 25, omission: "..."}
)
@@ -23,7 +23,7 @@ defmodule Pleroma.Web.Feed.TagControllerTest do
user = insert(:user)
{:ok, activity1} = CommonAPI.post(user, %{status: "yeah #PleromaArt"})
- object = Object.normalize(activity1)
+ object = Object.normalize(activity1, fetch: false)
object_data =
Map.put(object.data, "attachment", [
@@ -82,7 +82,7 @@ defmodule Pleroma.Web.Feed.TagControllerTest do
end
test "gets a feed (RSS)", %{conn: conn} do
- Pleroma.Config.put(
+ clear_config(
[:feed, :post_title],
%{max_length: 25, omission: "..."}
)
@@ -90,7 +90,7 @@ defmodule Pleroma.Web.Feed.TagControllerTest do
user = insert(:user)
{:ok, activity1} = CommonAPI.post(user, %{status: "yeah #PleromaArt"})
- object = Object.normalize(activity1)
+ object = Object.normalize(activity1, fetch: false)
object_data =
Map.put(object.data, "attachment", [
@@ -127,10 +127,10 @@ defmodule Pleroma.Web.Feed.TagControllerTest do
"These are public toots tagged with #pleromaart. You can interact with them if you have an account anywhere in the fediverse."
assert xpath(xml, ~x"//channel/link/text()") ==
- '#{Pleroma.Web.base_url()}/tags/pleromaart.rss'
+ '#{Pleroma.Web.Endpoint.url()}/tags/pleromaart.rss'
assert xpath(xml, ~x"//channel/webfeeds:logo/text()") ==
- '#{Pleroma.Web.base_url()}/static/logo.png'
+ '#{Pleroma.Web.Endpoint.url()}/static/logo.svg'
assert xpath(xml, ~x"//channel/item/title/text()"l) == [
'42 This is :moominmamm...',
@@ -146,8 +146,8 @@ defmodule Pleroma.Web.Feed.TagControllerTest do
"https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4"
]
- obj1 = Object.normalize(activity1)
- obj2 = Object.normalize(activity2)
+ obj1 = Object.normalize(activity1, fetch: false)
+ obj2 = Object.normalize(activity2, fetch: false)
assert xpath(xml, ~x"//channel/item/description/text()"sl) == [
HtmlEntities.decode(FeedView.activity_content(obj2.data)),
@@ -157,7 +157,7 @@ defmodule Pleroma.Web.Feed.TagControllerTest do
response =
conn
|> put_req_header("accept", "application/rss+xml")
- |> get(tag_feed_path(conn, :feed, "pleromaart"))
+ |> get(tag_feed_path(conn, :feed, "pleromaart.rss"))
|> response(200)
xml = parse(response)
@@ -181,4 +181,15 @@ defmodule Pleroma.Web.Feed.TagControllerTest do
'yeah #PleromaArt'
]
end
+
+ describe "private instance" do
+ setup do: clear_config([:instance, :public], false)
+
+ test "returns 404 for tags feed", %{conn: conn} do
+ conn
+ |> put_req_header("accept", "application/rss+xml")
+ |> get(tag_feed_path(conn, :feed, "pleromaart.rss"))
+ |> response(404)
+ end
+ end
end
diff --git a/test/web/feed/user_controller_test.exs b/test/pleroma/web/feed/user_controller_test.exs
index 0d2a61967..6e3f790b2 100644
--- a/test/web/feed/user_controller_test.exs
+++ b/test/pleroma/web/feed/user_controller_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Feed.UserControllerTest do
@@ -8,20 +8,20 @@ defmodule Pleroma.Web.Feed.UserControllerTest do
import Pleroma.Factory
import SweetXml
- alias Pleroma.Config
alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Web.CommonAPI
+ alias Pleroma.Web.Feed.FeedView
- setup do: clear_config([:instance, :federating], true)
+ setup do: clear_config([:static_fe, :enabled], false)
describe "feed" do
setup do: clear_config([:feed])
- test "gets an atom feed", %{conn: conn} do
- Config.put(
+ setup do
+ clear_config(
[:feed, :post_title],
- %{max_length: 10, omission: "..."}
+ %{max_length: 15, omission: "..."}
)
activity = insert(:note_activity)
@@ -29,7 +29,8 @@ defmodule Pleroma.Web.Feed.UserControllerTest do
note =
insert(:note,
data: %{
- "content" => "This is :moominmamma: note ",
+ "content" => "This & this is :moominmamma: note ",
+ "source" => "This & this is :moominmamma: note ",
"attachment" => [
%{
"url" => [
@@ -37,7 +38,9 @@ defmodule Pleroma.Web.Feed.UserControllerTest do
]
}
],
- "inReplyTo" => activity.data["id"]
+ "inReplyTo" => activity.data["id"],
+ "context" => "2hu & as",
+ "summary" => "2hu & as"
}
)
@@ -48,14 +51,18 @@ defmodule Pleroma.Web.Feed.UserControllerTest do
insert(:note,
user: user,
data: %{
- "content" => "42 This is :moominmamma: note ",
+ "content" => "42 & This is :moominmamma: note ",
"inReplyTo" => activity.data["id"]
}
)
note_activity2 = insert(:note_activity, note: note2)
- object = Object.normalize(note_activity)
+ object = Object.normalize(note_activity, fetch: false)
+
+ [user: user, object: object, max_id: note_activity2.id]
+ end
+ test "gets an atom feed", %{conn: conn, user: user, object: object, max_id: max_id} do
resp =
conn
|> put_req_header("accept", "application/atom+xml")
@@ -67,13 +74,15 @@ defmodule Pleroma.Web.Feed.UserControllerTest do
|> SweetXml.parse()
|> SweetXml.xpath(~x"//entry/title/text()"l)
- assert activity_titles == ['42 This...', 'This is...']
- assert resp =~ object.data["content"]
+ assert activity_titles == ['42 &amp; Thi...', 'This &amp; t...']
+ assert resp =~ FeedView.escape(object.data["content"])
+ assert resp =~ FeedView.escape(object.data["summary"])
+ assert resp =~ FeedView.escape(object.data["context"])
resp =
conn
|> put_req_header("accept", "application/atom+xml")
- |> get("/users/#{user.nickname}/feed", %{"max_id" => note_activity2.id})
+ |> get("/users/#{user.nickname}/feed", %{"max_id" => max_id})
|> response(200)
activity_titles =
@@ -81,47 +90,10 @@ defmodule Pleroma.Web.Feed.UserControllerTest do
|> SweetXml.parse()
|> SweetXml.xpath(~x"//entry/title/text()"l)
- assert activity_titles == ['This is...']
+ assert activity_titles == ['This &amp; t...']
end
- test "gets a rss feed", %{conn: conn} do
- Pleroma.Config.put(
- [:feed, :post_title],
- %{max_length: 10, omission: "..."}
- )
-
- activity = insert(:note_activity)
-
- note =
- insert(:note,
- data: %{
- "content" => "This is :moominmamma: note ",
- "attachment" => [
- %{
- "url" => [
- %{"mediaType" => "image/png", "href" => "https://pleroma.gov/image.png"}
- ]
- }
- ],
- "inReplyTo" => activity.data["id"]
- }
- )
-
- note_activity = insert(:note_activity, note: note)
- user = User.get_cached_by_ap_id(note_activity.data["actor"])
-
- note2 =
- insert(:note,
- user: user,
- data: %{
- "content" => "42 This is :moominmamma: note ",
- "inReplyTo" => activity.data["id"]
- }
- )
-
- note_activity2 = insert(:note_activity, note: note2)
- object = Object.normalize(note_activity)
-
+ test "gets a rss feed", %{conn: conn, user: user, object: object, max_id: max_id} do
resp =
conn
|> put_req_header("accept", "application/rss+xml")
@@ -133,13 +105,15 @@ defmodule Pleroma.Web.Feed.UserControllerTest do
|> SweetXml.parse()
|> SweetXml.xpath(~x"//item/title/text()"l)
- assert activity_titles == ['42 This...', 'This is...']
- assert resp =~ object.data["content"]
+ assert activity_titles == ['42 &amp; Thi...', 'This &amp; t...']
+ assert resp =~ FeedView.escape(object.data["content"])
+ assert resp =~ FeedView.escape(object.data["summary"])
+ assert resp =~ FeedView.escape(object.data["context"])
resp =
conn
|> put_req_header("accept", "application/rss+xml")
- |> get("/users/#{user.nickname}/feed.rss", %{"max_id" => note_activity2.id})
+ |> get("/users/#{user.nickname}/feed.rss", %{"max_id" => max_id})
|> response(200)
activity_titles =
@@ -147,7 +121,7 @@ defmodule Pleroma.Web.Feed.UserControllerTest do
|> SweetXml.parse()
|> SweetXml.xpath(~x"//item/title/text()"l)
- assert activity_titles == ['This is...']
+ assert activity_titles == ['This &amp; t...']
end
test "returns 404 for a missing feed", %{conn: conn} do
@@ -192,6 +166,16 @@ defmodule Pleroma.Web.Feed.UserControllerTest do
|> get(user_feed_path(conn, :feed, user.nickname))
|> response(404)
end
+
+ test "does not require authentication on non-federating instances", %{conn: conn} do
+ clear_config([:instance, :federating], false)
+ user = insert(:user)
+
+ conn
+ |> put_req_header("accept", "application/rss+xml")
+ |> get("/users/#{user.nickname}/feed.rss")
+ |> response(200)
+ end
end
# Note: see ActivityPubControllerTest for JSON format tests
@@ -206,19 +190,32 @@ defmodule Pleroma.Web.Feed.UserControllerTest do
|> response(200)
assert response ==
- Fallback.RedirectController.redirector_with_meta(
+ Pleroma.Web.Fallback.RedirectController.redirector_with_meta(
conn,
%{user: user}
).resp_body
end
- test "with html format, it returns error when user is not found", %{conn: conn} do
+ test "with html format, it falls back to frontend when user is remote", %{conn: conn} do
+ user = insert(:user, local: false)
+
+ {:ok, _} = CommonAPI.post(user, %{status: "test"})
+
+ response =
+ conn
+ |> get("/users/#{user.nickname}")
+ |> response(200)
+
+ assert response =~ "</html>"
+ end
+
+ test "with html format, it falls back to frontend when user is not found", %{conn: conn} do
response =
conn
|> get("/users/jimm")
- |> json_response(404)
+ |> response(200)
- assert response == %{"error" => "Not found"}
+ assert response =~ "</html>"
end
test "with non-html / non-json format, it redirects to user feed in atom format", %{
@@ -233,7 +230,9 @@ defmodule Pleroma.Web.Feed.UserControllerTest do
|> get("/users/#{user.nickname}")
assert conn.status == 302
- assert redirected_to(conn) == "#{Pleroma.Web.base_url()}/users/#{user.nickname}/feed.atom"
+
+ assert redirected_to(conn) ==
+ "#{Pleroma.Web.Endpoint.url()}/users/#{user.nickname}/feed.atom"
end
test "with non-html / non-json format, it returns error when user is not found", %{conn: conn} do
@@ -246,4 +245,20 @@ defmodule Pleroma.Web.Feed.UserControllerTest do
assert response == ~S({"error":"Not found"})
end
end
+
+ describe "private instance" do
+ setup do: clear_config([:instance, :public])
+
+ test "returns 404 for user feed", %{conn: conn} do
+ clear_config([:instance, :public], false)
+ user = insert(:user)
+
+ {:ok, _} = CommonAPI.post(user, %{status: "test"})
+
+ assert conn
+ |> put_req_header("accept", "application/atom+xml")
+ |> get(user_feed_path(conn, :feed, user.nickname))
+ |> response(404)
+ end
+ end
end
diff --git a/test/pleroma/web/manifest_controller_test.exs b/test/pleroma/web/manifest_controller_test.exs
new file mode 100644
index 000000000..b7a4940db
--- /dev/null
+++ b/test/pleroma/web/manifest_controller_test.exs
@@ -0,0 +1,17 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ManifestControllerTest do
+ use Pleroma.Web.ConnCase
+
+ setup do
+ clear_config([:instance, :name], "Manifest Test")
+ clear_config([:manifest, :theme_color], "#ff0000")
+ end
+
+ test "manifest.json", %{conn: conn} do
+ conn = get(conn, "/manifest.json")
+ assert %{"name" => "Manifest Test", "theme_color" => "#ff0000"} = json_response(conn, 200)
+ end
+end
diff --git a/test/web/mastodon_api/controllers/account_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs
index 17a1e7d66..374e2048a 100644
--- a/test/web/mastodon_api/controllers/account_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
@@ -29,10 +29,49 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
|> json_response_and_validate_schema(404)
end
+ test "relationship field" do
+ %{conn: conn, user: user} = oauth_access(["read"])
+
+ other_user = insert(:user)
+
+ response =
+ conn
+ |> get("/api/v1/accounts/#{other_user.id}")
+ |> json_response_and_validate_schema(200)
+
+ assert response["id"] == other_user.id
+ assert response["pleroma"]["relationship"] == %{}
+
+ assert %{"pleroma" => %{"relationship" => %{"following" => false, "followed_by" => false}}} =
+ conn
+ |> get("/api/v1/accounts/#{other_user.id}?with_relationships=true")
+ |> json_response_and_validate_schema(200)
+
+ {:ok, _, %{id: other_id}} = User.follow(user, other_user)
+
+ assert %{
+ "id" => ^other_id,
+ "pleroma" => %{"relationship" => %{"following" => true, "followed_by" => false}}
+ } =
+ conn
+ |> get("/api/v1/accounts/#{other_id}?with_relationships=true")
+ |> json_response_and_validate_schema(200)
+
+ {:ok, _, _} = User.follow(other_user, user)
+
+ assert %{
+ "id" => ^other_id,
+ "pleroma" => %{"relationship" => %{"following" => true, "followed_by" => true}}
+ } =
+ conn
+ |> get("/api/v1/accounts/#{other_id}?with_relationships=true")
+ |> json_response_and_validate_schema(200)
+ end
+
test "works by nickname" do
user = insert(:user)
- assert %{"id" => user_id} =
+ assert %{"id" => _user_id} =
build_conn()
|> get("/api/v1/accounts/#{user.nickname}")
|> json_response_and_validate_schema(200)
@@ -43,7 +82,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
user = insert(:user, nickname: "user@example.com", local: false)
- assert %{"id" => user_id} =
+ assert %{"id" => _user_id} =
build_conn()
|> get("/api/v1/accounts/#{user.nickname}")
|> json_response_and_validate_schema(200)
@@ -126,7 +165,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
end
test "returns 404 for deactivated user", %{conn: conn} do
- user = insert(:user, deactivated: true)
+ user = insert(:user, is_active: false)
assert %{"error" => "Can't find user"} =
conn
@@ -256,7 +295,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
end
test "deactivated user", %{conn: conn} do
- user = insert(:user, deactivated: true)
+ user = insert(:user, is_active: false)
assert %{"error" => "Can't find user"} ==
conn
@@ -320,7 +359,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
user_two = insert(:user)
user_three = insert(:user)
- {:ok, _user_three} = User.follow(user_three, user_one)
+ {:ok, _user_three, _user_one} = User.follow(user_three, user_one)
{:ok, activity} = CommonAPI.post(user_one, %{status: "HI!!!"})
@@ -380,7 +419,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
other_user = insert(:user)
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}
@@ -436,6 +475,54 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
conn = get(conn, "/api/v1/accounts/#{user.id}/statuses?exclude_visibilities[]=direct")
assert [%{"id" => ^public_activity_id}] = json_response_and_validate_schema(conn, 200)
end
+
+ test "muted reactions", %{user: user, conn: conn} do
+ user2 = insert(:user)
+ User.mute(user, user2)
+ {:ok, activity} = CommonAPI.post(user, %{status: "."})
+ {:ok, _} = CommonAPI.react_with_emoji(activity.id, user2, "🎅")
+
+ result =
+ conn
+ |> get("/api/v1/accounts/#{user.id}/statuses")
+ |> json_response_and_validate_schema(200)
+
+ assert [
+ %{
+ "pleroma" => %{
+ "emoji_reactions" => []
+ }
+ }
+ ] = result
+
+ result =
+ conn
+ |> get("/api/v1/accounts/#{user.id}/statuses?with_muted=true")
+ |> json_response_and_validate_schema(200)
+
+ assert [
+ %{
+ "pleroma" => %{
+ "emoji_reactions" => [%{"count" => 1, "me" => false, "name" => "🎅"}]
+ }
+ }
+ ] = result
+ end
+
+ test "paginates a user's statuses", %{user: user, conn: conn} do
+ {:ok, post_1} = CommonAPI.post(user, %{status: "first post"})
+ {:ok, post_2} = CommonAPI.post(user, %{status: "second post"})
+
+ response_1 = get(conn, "/api/v1/accounts/#{user.id}/statuses?limit=1")
+ assert [res] = json_response_and_validate_schema(response_1, 200)
+ assert res["id"] == post_2.id
+
+ response_2 = get(conn, "/api/v1/accounts/#{user.id}/statuses?limit=1&max_id=#{res["id"]}")
+ assert [res] = json_response_and_validate_schema(response_2, 200)
+ assert res["id"] == post_1.id
+
+ refute response_1 == response_2
+ end
end
defp local_and_remote_activities(%{local: local, remote: remote}) do
@@ -535,16 +622,55 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
test "getting followers", %{user: user, conn: conn} do
other_user = insert(:user)
- {:ok, %{id: user_id}} = User.follow(user, other_user)
+ {:ok, %{id: user_id}, other_user} = User.follow(user, other_user)
conn = get(conn, "/api/v1/accounts/#{other_user.id}/followers")
assert [%{"id" => ^user_id}] = json_response_and_validate_schema(conn, 200)
end
+ test "following with relationship", %{conn: conn, user: user} do
+ other_user = insert(:user)
+ {:ok, %{id: id}, _} = User.follow(other_user, user)
+
+ assert [
+ %{
+ "id" => ^id,
+ "pleroma" => %{
+ "relationship" => %{
+ "id" => ^id,
+ "following" => false,
+ "followed_by" => true
+ }
+ }
+ }
+ ] =
+ conn
+ |> get("/api/v1/accounts/#{user.id}/followers?with_relationships=true")
+ |> json_response_and_validate_schema(200)
+
+ {:ok, _, _} = User.follow(user, other_user)
+
+ assert [
+ %{
+ "id" => ^id,
+ "pleroma" => %{
+ "relationship" => %{
+ "id" => ^id,
+ "following" => true,
+ "followed_by" => true
+ }
+ }
+ }
+ ] =
+ conn
+ |> get("/api/v1/accounts/#{user.id}/followers?with_relationships=true")
+ |> json_response_and_validate_schema(200)
+ end
+
test "getting followers, hide_followers", %{user: user, conn: conn} do
other_user = insert(:user, hide_followers: true)
- {:ok, _user} = User.follow(user, other_user)
+ {:ok, _user, _other_user} = User.follow(user, other_user)
conn = get(conn, "/api/v1/accounts/#{other_user.id}/followers")
@@ -554,7 +680,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
test "getting followers, hide_followers, same user requesting" do
user = insert(:user)
other_user = insert(:user, hide_followers: true)
- {:ok, _user} = User.follow(user, other_user)
+ {:ok, _user, _other_user} = User.follow(user, other_user)
conn =
build_conn()
@@ -566,9 +692,9 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
end
test "getting followers, pagination", %{user: user, conn: conn} do
- {:ok, %User{id: follower1_id}} = :user |> insert() |> User.follow(user)
- {:ok, %User{id: follower2_id}} = :user |> insert() |> User.follow(user)
- {:ok, %User{id: follower3_id}} = :user |> insert() |> User.follow(user)
+ {:ok, %User{id: follower1_id}, _user} = :user |> insert() |> User.follow(user)
+ {:ok, %User{id: follower2_id}, _user} = :user |> insert() |> User.follow(user)
+ {:ok, %User{id: follower3_id}, _user} = :user |> insert() |> User.follow(user)
assert [%{"id" => ^follower3_id}, %{"id" => ^follower2_id}] =
conn
@@ -583,9 +709,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
assert [%{"id" => ^follower2_id}, %{"id" => ^follower1_id}] =
conn
|> get(
- "/api/v1/accounts/#{user.id}/followers?id=#{user.id}&limit=20&max_id=#{
- follower3_id
- }"
+ "/api/v1/accounts/#{user.id}/followers?id=#{user.id}&limit=20&max_id=#{follower3_id}"
)
|> json_response_and_validate_schema(200)
@@ -604,7 +728,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
test "getting following", %{user: user, conn: conn} do
other_user = insert(:user)
- {:ok, user} = User.follow(user, other_user)
+ {:ok, user, other_user} = User.follow(user, other_user)
conn = get(conn, "/api/v1/accounts/#{user.id}/following")
@@ -612,10 +736,28 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
assert id == to_string(other_user.id)
end
+ test "following with relationship", %{conn: conn, user: user} do
+ other_user = insert(:user)
+ {:ok, user, other_user} = User.follow(user, other_user)
+
+ conn = get(conn, "/api/v1/accounts/#{user.id}/following?with_relationships=true")
+
+ id = other_user.id
+
+ assert [
+ %{
+ "id" => ^id,
+ "pleroma" => %{
+ "relationship" => %{"id" => ^id, "following" => true, "followed_by" => false}
+ }
+ }
+ ] = json_response_and_validate_schema(conn, 200)
+ end
+
test "getting following, hide_follows, other user requesting" do
user = insert(:user, hide_follows: true)
other_user = insert(:user)
- {:ok, user} = User.follow(user, other_user)
+ {:ok, user, other_user} = User.follow(user, other_user)
conn =
build_conn()
@@ -629,7 +771,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
test "getting following, hide_follows, same user requesting" do
user = insert(:user, hide_follows: true)
other_user = insert(:user)
- {:ok, user} = User.follow(user, other_user)
+ {:ok, user, _other_user} = User.follow(user, other_user)
conn =
build_conn()
@@ -644,9 +786,9 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
following1 = insert(:user)
following2 = insert(:user)
following3 = insert(:user)
- {:ok, _} = User.follow(user, following1)
- {:ok, _} = User.follow(user, following2)
- {:ok, _} = User.follow(user, following3)
+ {:ok, _, _} = User.follow(user, following1)
+ {:ok, _, _} = User.follow(user, following2)
+ {:ok, _, _} = User.follow(user, following3)
res_conn = get(conn, "/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
@@ -706,7 +848,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
end
test "cancelling follow request", %{conn: conn} do
- %{id: other_user_id} = insert(:user, %{locked: true})
+ %{id: other_user_id} = insert(:user, %{is_locked: true})
assert %{"id" => ^other_user_id, "following" => false, "requested" => true} =
conn
@@ -737,7 +879,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
assert [] ==
conn
|> get("/api/v1/timelines/home")
- |> json_response(200)
+ |> json_response_and_validate_schema(200)
assert %{"showing_reblogs" => true} =
conn
@@ -748,7 +890,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
assert [%{"id" => ^reblog_id}] =
conn
|> get("/api/v1/timelines/home")
- |> json_response(200)
+ |> json_response_and_validate_schema(200)
end
test "following with reblogs" do
@@ -766,7 +908,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
assert [%{"id" => ^reblog_id}] =
conn
|> get("/api/v1/timelines/home")
- |> json_response(200)
+ |> json_response_and_validate_schema(200)
assert %{"showing_reblogs" => false} =
conn
@@ -777,7 +919,28 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
assert [] ==
conn
|> get("/api/v1/timelines/home")
- |> json_response(200)
+ |> json_response_and_validate_schema(200)
+ end
+
+ test "following with subscription and unsubscribing" do
+ %{conn: conn} = oauth_access(["follow"])
+ followed = insert(:user)
+
+ ret_conn =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/accounts/#{followed.id}/follow", %{notify: true})
+
+ assert %{"id" => _id, "subscribing" => true} =
+ json_response_and_validate_schema(ret_conn, 200)
+
+ ret_conn =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/accounts/#{followed.id}/follow", %{notify: false})
+
+ assert %{"id" => _id, "subscribing" => false} =
+ json_response_and_validate_schema(ret_conn, 200)
end
test "following / unfollowing errors", %{user: user, conn: conn} do
@@ -959,7 +1122,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
assert %{"error" => "{\"email\":[\"Invalid email\"]}"} =
json_response_and_validate_schema(conn, 400)
- Pleroma.Config.put([User, :email_blacklist], [])
+ clear_config([User, :email_blacklist], [])
conn =
build_conn()
@@ -979,8 +1142,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
user = Repo.preload(token_from_db, :user).user
assert user
- refute user.confirmation_pending
- refute user.approval_pending
+ assert user.is_confirmed
+ assert user.is_approved
end
test "registers but does not log in with :account_activation_required", %{conn: conn} do
@@ -1040,7 +1203,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
refute response["token_type"]
user = Repo.get_by(User, email: "lain@example.org")
- assert user.confirmation_pending
+ refute user.is_confirmed
end
test "registers but does not log in with :account_approval_required", %{conn: conn} do
@@ -1102,7 +1265,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
user = Repo.get_by(User, email: "lain@example.org")
- assert user.approval_pending
+ refute user.is_approved
assert user.registration_reason == "I'm a cool dude, bro"
end
@@ -1378,8 +1541,6 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
|> json_response_and_validate_schema(:ok)
assert Token |> Repo.get_by(token: access_token) |> Repo.preload(:user) |> Map.get(:user)
-
- Cachex.del(:used_captcha_cache, token)
end
test "returns 400 if any captcha field is not provided", %{conn: conn} do
@@ -1429,10 +1590,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
test "returns lists to which the account belongs" do
%{user: user, conn: conn} = oauth_access(["read:lists"])
other_user = insert(:user)
- assert {:ok, %Pleroma.List{id: list_id} = list} = Pleroma.List.create("Test List", user)
+ assert {:ok, %Pleroma.List{id: _list_id} = list} = Pleroma.List.create("Test List", user)
{:ok, %{following: _following}} = Pleroma.List.follow(list, other_user)
- assert [%{"id" => list_id, "title" => "Test List"}] =
+ assert [%{"id" => _list_id, "title" => "Test List"}] =
conn
|> get("/api/v1/accounts/#{other_user.id}/lists")
|> json_response_and_validate_schema(200)
@@ -1442,7 +1603,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
describe "verify_credentials" do
test "verify_credentials" do
%{user: user, conn: conn} = oauth_access(["read:accounts"])
- [notification | _] = insert_list(7, :notification, user: user)
+
+ [notification | _] =
+ insert_list(7, :notification, user: user, activity: insert(:note_activity))
+
Pleroma.Notification.set_read_up_to(user, notification.id)
conn = get(conn, "/api/v1/accounts/verify_credentials")
@@ -1484,7 +1648,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
test "returns the relationships for the current user", %{user: user, conn: conn} do
%{id: other_user_id} = other_user = insert(:user)
- {:ok, _user} = User.follow(user, other_user)
+ {:ok, _user, _other_user} = User.follow(user, other_user)
assert [%{"id" => ^other_user_id}] =
conn
@@ -1506,28 +1670,172 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
test "getting a list of mutes" do
%{user: user, conn: conn} = oauth_access(["read:mutes"])
- other_user = insert(:user)
+ %{id: id1} = other_user1 = insert(:user)
+ %{id: id2} = other_user2 = insert(:user)
+ %{id: id3} = other_user3 = insert(:user)
- {:ok, _user_relationships} = User.mute(user, other_user)
+ {:ok, _user_relationships} = User.mute(user, other_user1)
+ {:ok, _user_relationships} = User.mute(user, other_user2)
+ {:ok, _user_relationships} = User.mute(user, other_user3)
+
+ result =
+ conn
+ |> get("/api/v1/mutes")
+ |> json_response_and_validate_schema(200)
- conn = get(conn, "/api/v1/mutes")
+ assert [id1, id2, id3] == Enum.map(result, & &1["id"])
- other_user_id = to_string(other_user.id)
- assert [%{"id" => ^other_user_id}] = json_response_and_validate_schema(conn, 200)
+ result =
+ conn
+ |> get("/api/v1/mutes?limit=1")
+ |> json_response_and_validate_schema(200)
+
+ assert [%{"id" => ^id1}] = result
+
+ result =
+ conn
+ |> get("/api/v1/mutes?since_id=#{id1}")
+ |> json_response_and_validate_schema(200)
+
+ assert [%{"id" => ^id2}, %{"id" => ^id3}] = result
+
+ result =
+ conn
+ |> get("/api/v1/mutes?since_id=#{id1}&max_id=#{id3}")
+ |> json_response_and_validate_schema(200)
+
+ assert [%{"id" => ^id2}] = result
+
+ result =
+ conn
+ |> get("/api/v1/mutes?since_id=#{id1}&limit=1")
+ |> json_response_and_validate_schema(200)
+
+ assert [%{"id" => ^id2}] = result
+ end
+
+ test "list of mutes with with_relationships parameter" do
+ %{user: user, conn: conn} = oauth_access(["read:mutes"])
+ %{id: id1} = other_user1 = insert(:user)
+ %{id: id2} = other_user2 = insert(:user)
+ %{id: id3} = other_user3 = insert(:user)
+
+ {:ok, _, _} = User.follow(other_user1, user)
+ {:ok, _, _} = User.follow(other_user2, user)
+ {:ok, _, _} = User.follow(other_user3, user)
+
+ {:ok, _} = User.mute(user, other_user1)
+ {:ok, _} = User.mute(user, other_user2)
+ {:ok, _} = User.mute(user, other_user3)
+
+ assert [
+ %{
+ "id" => ^id1,
+ "pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}}
+ },
+ %{
+ "id" => ^id2,
+ "pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}}
+ },
+ %{
+ "id" => ^id3,
+ "pleroma" => %{"relationship" => %{"muting" => true, "followed_by" => true}}
+ }
+ ] =
+ conn
+ |> get("/api/v1/mutes?with_relationships=true")
+ |> json_response_and_validate_schema(200)
end
test "getting a list of blocks" do
%{user: user, conn: conn} = oauth_access(["read:blocks"])
- other_user = insert(:user)
+ %{id: id1} = other_user1 = insert(:user)
+ %{id: id2} = other_user2 = insert(:user)
+ %{id: id3} = other_user3 = insert(:user)
- {:ok, _user_relationship} = User.block(user, other_user)
+ {:ok, _user_relationship} = User.block(user, other_user1)
+ {:ok, _user_relationship} = User.block(user, other_user3)
+ {:ok, _user_relationship} = User.block(user, other_user2)
- conn =
+ result =
conn
|> assign(:user, user)
|> get("/api/v1/blocks")
+ |> json_response_and_validate_schema(200)
+
+ assert [id1, id2, id3] == Enum.map(result, & &1["id"])
+
+ result =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/blocks?limit=1")
+ |> json_response_and_validate_schema(200)
+
+ assert [%{"id" => ^id1}] = result
+
+ result =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/blocks?since_id=#{id1}")
+ |> json_response_and_validate_schema(200)
+
+ assert [%{"id" => ^id2}, %{"id" => ^id3}] = result
+
+ result =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/blocks?since_id=#{id1}&max_id=#{id3}")
+ |> json_response_and_validate_schema(200)
+
+ assert [%{"id" => ^id2}] = result
+
+ result =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/blocks?since_id=#{id1}&limit=1")
+ |> json_response_and_validate_schema(200)
+
+ assert [%{"id" => ^id2}] = result
+ end
+
+ test "account lookup", %{conn: conn} do
+ %{nickname: acct} = insert(:user, %{nickname: "nickname"})
+ %{nickname: acct_two} = insert(:user, %{nickname: "nickname@notlocaldoma.in"})
+
+ result =
+ conn
+ |> get("/api/v1/accounts/lookup?acct=#{acct}")
+ |> json_response_and_validate_schema(200)
+
+ assert %{"acct" => ^acct} = result
+
+ result =
+ conn
+ |> get("/api/v1/accounts/lookup?acct=#{acct_two}")
+ |> json_response_and_validate_schema(200)
+
+ assert %{"acct" => ^acct_two} = result
+
+ _result =
+ conn
+ |> get("/api/v1/accounts/lookup?acct=unexisting_nickname")
+ |> json_response_and_validate_schema(404)
+ end
+
+ test "create a note on a user" do
+ %{conn: conn} = oauth_access(["write:accounts", "read:follows"])
+ other_user = insert(:user)
- other_user_id = to_string(other_user.id)
- assert [%{"id" => ^other_user_id}] = json_response_and_validate_schema(conn, 200)
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/accounts/#{other_user.id}/note", %{
+ "comment" => "Example note"
+ })
+
+ assert [%{"note" => "Example note"}] =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> get("/api/v1/accounts/relationships?id=#{other_user.id}")
+ |> json_response_and_validate_schema(200)
end
end
diff --git a/test/web/mastodon_api/controllers/app_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/app_controller_test.exs
index a0b8b126c..bfbb7f32d 100644
--- a/test/web/mastodon_api/controllers/app_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/app_controller_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.AppControllerTest do
@@ -12,25 +12,56 @@ defmodule Pleroma.Web.MastodonAPI.AppControllerTest do
import Pleroma.Factory
test "apps/verify_credentials", %{conn: conn} do
- token = insert(:oauth_token)
+ user_bound_token = insert(:oauth_token)
+ app_bound_token = insert(:oauth_token, user: nil)
+ refute app_bound_token.user
+
+ for token <- [app_bound_token, user_bound_token] do
+ conn =
+ conn
+ |> put_req_header("authorization", "Bearer #{token.token}")
+ |> get("/api/v1/apps/verify_credentials")
+
+ app = Repo.preload(token, :app).app
+
+ expected = %{
+ "name" => app.client_name,
+ "website" => app.website,
+ "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
+ }
+
+ assert expected == json_response_and_validate_schema(conn, 200)
+ end
+ end
+
+ test "creates an oauth app", %{conn: conn} do
+ app_attrs = build(:oauth_app)
conn =
conn
- |> put_req_header("authorization", "Bearer #{token.token}")
- |> get("/api/v1/apps/verify_credentials")
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/apps", %{
+ client_name: app_attrs.client_name,
+ redirect_uris: app_attrs.redirect_uris
+ })
- app = Repo.preload(token, :app).app
+ [app] = Repo.all(App)
expected = %{
"name" => app.client_name,
"website" => app.website,
+ "client_id" => app.client_id,
+ "client_secret" => app.client_secret,
+ "id" => app.id |> to_string(),
+ "redirect_uri" => app.redirect_uris,
"vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
}
assert expected == json_response_and_validate_schema(conn, 200)
+ assert app.user_id == nil
end
- test "creates an oauth app", %{conn: conn} do
+ test "creates an oauth app with a user", %{conn: conn} do
user = insert(:user)
app_attrs = build(:oauth_app)
@@ -56,5 +87,6 @@ defmodule Pleroma.Web.MastodonAPI.AppControllerTest do
}
assert expected == json_response_and_validate_schema(conn, 200)
+ assert app.user_id == user.id
end
end
diff --git a/test/web/mastodon_api/controllers/conversation_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/conversation_controller_test.exs
index 3e21e6bf1..00797a9ea 100644
--- a/test/web/mastodon_api/controllers/conversation_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/conversation_controller_test.exs
@@ -1,10 +1,11 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do
- use Pleroma.Web.ConnCase
+ use Pleroma.Web.ConnCase, async: true
+ alias Pleroma.Conversation.Participation
alias Pleroma.User
alias Pleroma.Web.CommonAPI
@@ -17,7 +18,7 @@ defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do
user_two = insert(:user)
user_three = insert(:user)
- {:ok, user_two} = User.follow(user_two, user_one)
+ {:ok, user_two, user_one} = User.follow(user_two, user_one)
{:ok, %{user: user_one, user_two: user_two, user_three: user_three, conn: conn}}
end
@@ -28,10 +29,10 @@ defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do
user_three: user_three,
conn: conn
} do
- assert User.get_cached_by_id(user_two.id).unread_conversation_count == 0
+ assert Participation.unread_count(user_two) == 0
{:ok, direct} = create_direct_message(user_one, [user_two, user_three])
- assert User.get_cached_by_id(user_two.id).unread_conversation_count == 1
+ assert Participation.unread_count(user_two) == 1
{:ok, _follower_only} =
CommonAPI.post(user_one, %{
@@ -54,12 +55,33 @@ defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do
account_ids = Enum.map(res_accounts, & &1["id"])
assert length(res_accounts) == 2
+ assert user_one.id not in account_ids
assert user_two.id in account_ids
assert user_three.id in account_ids
assert is_binary(res_id)
assert unread == false
assert res_last_status["id"] == direct.id
- assert User.get_cached_by_id(user_one.id).unread_conversation_count == 0
+ assert res_last_status["account"]["id"] == user_one.id
+ assert Participation.unread_count(user_one) == 0
+ end
+
+ test "includes the user if the user is the only participant", %{
+ user: user_one,
+ conn: conn
+ } do
+ {:ok, _direct} = create_direct_message(user_one, [])
+
+ res_conn = get(conn, "/api/v1/conversations")
+
+ assert response = json_response_and_validate_schema(res_conn, 200)
+
+ assert [
+ %{
+ "accounts" => [account]
+ }
+ ] = response
+
+ assert user_one.id == account["id"]
end
test "observes limit params", %{
@@ -134,8 +156,8 @@ defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do
user_two = insert(:user)
{:ok, direct} = create_direct_message(user_one, [user_two])
- assert User.get_cached_by_id(user_one.id).unread_conversation_count == 0
- assert User.get_cached_by_id(user_two.id).unread_conversation_count == 1
+ assert Participation.unread_count(user_one) == 0
+ assert Participation.unread_count(user_two) == 1
user_two_conn =
build_conn()
@@ -155,8 +177,8 @@ defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do
|> post("/api/v1/conversations/#{direct_conversation_id}/read")
|> json_response_and_validate_schema(200)
- assert User.get_cached_by_id(user_one.id).unread_conversation_count == 0
- assert User.get_cached_by_id(user_two.id).unread_conversation_count == 0
+ assert Participation.unread_count(user_one) == 0
+ assert Participation.unread_count(user_two) == 0
# The conversation is marked as unread on reply
{:ok, _} =
@@ -171,8 +193,8 @@ defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do
|> get("/api/v1/conversations")
|> json_response_and_validate_schema(200)
- assert User.get_cached_by_id(user_one.id).unread_conversation_count == 1
- assert User.get_cached_by_id(user_two.id).unread_conversation_count == 0
+ assert Participation.unread_count(user_one) == 1
+ assert Participation.unread_count(user_two) == 0
# A reply doesn't increment the user's unread_conversation_count if the conversation is unread
{:ok, _} =
@@ -182,8 +204,8 @@ defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do
in_reply_to_status_id: direct.id
})
- assert User.get_cached_by_id(user_one.id).unread_conversation_count == 1
- assert User.get_cached_by_id(user_two.id).unread_conversation_count == 0
+ assert Participation.unread_count(user_one) == 1
+ assert Participation.unread_count(user_two) == 0
end
test "(vanilla) Mastodon frontend behaviour", %{user: user_one, conn: conn} do
@@ -192,7 +214,34 @@ defmodule Pleroma.Web.MastodonAPI.ConversationControllerTest do
res_conn = get(conn, "/api/v1/statuses/#{direct.id}/context")
- assert %{"ancestors" => [], "descendants" => []} == json_response(res_conn, 200)
+ assert %{"ancestors" => [], "descendants" => []} ==
+ json_response_and_validate_schema(res_conn, 200)
+ end
+
+ test "Removes a conversation", %{user: user_one, conn: conn} do
+ user_two = insert(:user)
+ token = insert(:oauth_token, user: user_one, scopes: ["read:statuses", "write:conversations"])
+
+ {:ok, _direct} = create_direct_message(user_one, [user_two])
+ {:ok, _direct} = create_direct_message(user_one, [user_two])
+
+ assert [%{"id" => conv1_id}, %{"id" => conv2_id}] =
+ conn
+ |> assign(:token, token)
+ |> get("/api/v1/conversations")
+ |> json_response_and_validate_schema(200)
+
+ assert %{} =
+ conn
+ |> assign(:token, token)
+ |> delete("/api/v1/conversations/#{conv1_id}")
+ |> json_response_and_validate_schema(200)
+
+ assert [%{"id" => ^conv2_id}] =
+ conn
+ |> assign(:token, token)
+ |> get("/api/v1/conversations")
+ |> json_response_and_validate_schema(200)
end
defp create_direct_message(sender, recips) do
diff --git a/test/web/mastodon_api/controllers/custom_emoji_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/custom_emoji_controller_test.exs
index ab0027f90..cbb1d54a6 100644
--- a/test/web/mastodon_api/controllers/custom_emoji_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/custom_emoji_controller_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.CustomEmojiControllerTest do
diff --git a/test/pleroma/web/mastodon_api/controllers/directory_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/directory_controller_test.exs
new file mode 100644
index 000000000..b8f55f832
--- /dev/null
+++ b/test/pleroma/web/mastodon_api/controllers/directory_controller_test.exs
@@ -0,0 +1,46 @@
+defmodule Pleroma.Web.MastodonAPI.DirectoryControllerTest do
+ use Pleroma.Web.ConnCase, async: true
+ alias Pleroma.Web.CommonAPI
+ import Pleroma.Factory
+
+ test "GET /api/v1/directory with :profile_directory disabled returns empty array", %{conn: conn} do
+ clear_config([:instance, :profile_directory], false)
+
+ insert(:user, is_discoverable: true)
+ insert(:user, is_discoverable: true)
+
+ result =
+ conn
+ |> get("/api/v1/directory")
+ |> json_response_and_validate_schema(200)
+
+ assert result == []
+ end
+
+ test "GET /api/v1/directory returns discoverable users only", %{conn: conn} do
+ %{id: user_id} = insert(:user, is_discoverable: true)
+ insert(:user, is_discoverable: false)
+
+ result =
+ conn
+ |> get("/api/v1/directory")
+ |> json_response_and_validate_schema(200)
+
+ assert [%{"id" => ^user_id}] = result
+ end
+
+ test "GET /api/v1/directory returns users sorted by most recent statuses", %{conn: conn} do
+ insert(:user, is_discoverable: true)
+ %{id: user_id} = user = insert(:user, is_discoverable: true)
+ insert(:user, is_discoverable: true)
+
+ {:ok, _activity} = CommonAPI.post(user, %{status: "yay i'm discoverable"})
+
+ result =
+ conn
+ |> get("/api/v1/directory?order=active")
+ |> json_response_and_validate_schema(200)
+
+ assert [%{"id" => ^user_id} | _tail] = result
+ end
+end
diff --git a/test/web/mastodon_api/controllers/domain_block_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/domain_block_controller_test.exs
index 664654500..0c3a7c0cf 100644
--- a/test/web/mastodon_api/controllers/domain_block_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/domain_block_controller_test.exs
@@ -1,8 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.DomainBlockControllerTest do
+ # TODO: Should not need Cachex
use Pleroma.Web.ConnCase
alias Pleroma.User
diff --git a/test/pleroma/web/mastodon_api/controllers/filter_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/filter_controller_test.exs
new file mode 100644
index 000000000..98ab9e717
--- /dev/null
+++ b/test/pleroma/web/mastodon_api/controllers/filter_controller_test.exs
@@ -0,0 +1,415 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.MastodonAPI.FilterControllerTest do
+ use Pleroma.Web.ConnCase, async: true
+ use Oban.Testing, repo: Pleroma.Repo
+
+ import Pleroma.Factory
+
+ alias Pleroma.Filter
+ alias Pleroma.Repo
+ alias Pleroma.Workers.PurgeExpiredFilter
+
+ test "non authenticated creation request", %{conn: conn} do
+ response =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/filters", %{"phrase" => "knights", context: ["home"]})
+ |> json_response(403)
+
+ assert response["error"] == "Invalid credentials."
+ end
+
+ describe "creating" do
+ setup do: oauth_access(["write:filters"])
+
+ test "a common filter", %{conn: conn, user: user} do
+ params = %{
+ phrase: "knights",
+ context: ["home"],
+ irreversible: true
+ }
+
+ response =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/filters", params)
+ |> json_response_and_validate_schema(200)
+
+ assert response["phrase"] == params.phrase
+ assert response["context"] == params.context
+ assert response["irreversible"] == true
+ assert response["id"] != nil
+ assert response["id"] != ""
+ assert response["expires_at"] == nil
+
+ filter = Filter.get(response["id"], user)
+ assert filter.hide == true
+ end
+
+ test "a filter with expires_in", %{conn: conn, user: user} do
+ in_seconds = 600
+
+ response =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/filters", %{
+ "phrase" => "knights",
+ context: ["home"],
+ expires_in: in_seconds
+ })
+ |> json_response_and_validate_schema(200)
+
+ assert response["irreversible"] == false
+
+ expires_at =
+ NaiveDateTime.utc_now()
+ |> NaiveDateTime.add(in_seconds)
+ |> Pleroma.Web.CommonAPI.Utils.to_masto_date()
+
+ assert response["expires_at"] == expires_at
+
+ filter = Filter.get(response["id"], user)
+
+ id = filter.id
+
+ assert_enqueued(
+ worker: PurgeExpiredFilter,
+ args: %{filter_id: filter.id}
+ )
+
+ assert {:ok, %{id: ^id}} =
+ perform_job(PurgeExpiredFilter, %{
+ filter_id: filter.id
+ })
+
+ assert Repo.aggregate(Filter, :count, :id) == 0
+ end
+ end
+
+ test "fetching a list of filters" do
+ %{user: user, conn: conn} = oauth_access(["read:filters"])
+
+ %{filter_id: id1} = insert(:filter, user: user)
+ %{filter_id: id2} = insert(:filter, user: user)
+
+ id1 = to_string(id1)
+ id2 = to_string(id2)
+
+ assert [%{"id" => ^id2}, %{"id" => ^id1}] =
+ conn
+ |> get("/api/v1/filters")
+ |> json_response_and_validate_schema(200)
+ end
+
+ test "fetching a list of filters without token", %{conn: conn} do
+ insert(:filter)
+
+ response =
+ conn
+ |> get("/api/v1/filters")
+ |> json_response(403)
+
+ assert response["error"] == "Invalid credentials."
+ end
+
+ test "get a filter" do
+ %{user: user, conn: conn} = oauth_access(["read:filters"])
+
+ # check whole_word false
+ filter = insert(:filter, user: user, whole_word: false)
+
+ resp1 =
+ conn |> get("/api/v1/filters/#{filter.filter_id}") |> json_response_and_validate_schema(200)
+
+ assert resp1["whole_word"] == false
+
+ # check whole_word true
+ filter = insert(:filter, user: user, whole_word: true)
+
+ resp2 =
+ conn |> get("/api/v1/filters/#{filter.filter_id}") |> json_response_and_validate_schema(200)
+
+ assert resp2["whole_word"] == true
+ end
+
+ test "get a filter not_found error" do
+ filter = insert(:filter)
+ %{conn: conn} = oauth_access(["read:filters"])
+
+ response =
+ conn |> get("/api/v1/filters/#{filter.filter_id}") |> json_response_and_validate_schema(404)
+
+ assert response["error"] == "Record not found"
+ end
+
+ describe "updating a filter" do
+ setup do: oauth_access(["write:filters"])
+
+ test "common" do
+ %{conn: conn, user: user} = oauth_access(["write:filters"])
+
+ filter =
+ insert(:filter,
+ user: user,
+ hide: true,
+ whole_word: true
+ )
+
+ params = %{
+ phrase: "nii",
+ context: ["public"],
+ irreversible: false
+ }
+
+ response =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> put("/api/v1/filters/#{filter.filter_id}", params)
+ |> json_response_and_validate_schema(200)
+
+ assert response["phrase"] == params.phrase
+ assert response["context"] == params.context
+ assert response["irreversible"] == false
+ assert response["whole_word"] == true
+ end
+
+ test "with adding expires_at", %{conn: conn, user: user} do
+ filter = insert(:filter, user: user)
+ in_seconds = 600
+
+ response =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> put("/api/v1/filters/#{filter.filter_id}", %{
+ phrase: "nii",
+ context: ["public"],
+ expires_in: in_seconds,
+ irreversible: true
+ })
+ |> json_response_and_validate_schema(200)
+
+ assert response["irreversible"] == true
+
+ assert response["expires_at"] ==
+ NaiveDateTime.utc_now()
+ |> NaiveDateTime.add(in_seconds)
+ |> Pleroma.Web.CommonAPI.Utils.to_masto_date()
+
+ filter = Filter.get(response["id"], user)
+
+ id = filter.id
+
+ assert_enqueued(
+ worker: PurgeExpiredFilter,
+ args: %{filter_id: id}
+ )
+
+ assert {:ok, %{id: ^id}} =
+ perform_job(PurgeExpiredFilter, %{
+ filter_id: id
+ })
+
+ assert Repo.aggregate(Filter, :count, :id) == 0
+ end
+
+ test "with removing expires_at", %{conn: conn, user: user} do
+ response =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/filters", %{
+ phrase: "cofe",
+ context: ["home"],
+ expires_in: 600
+ })
+ |> json_response_and_validate_schema(200)
+
+ filter = Filter.get(response["id"], user)
+
+ assert_enqueued(
+ worker: PurgeExpiredFilter,
+ args: %{filter_id: filter.id}
+ )
+
+ response =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> put("/api/v1/filters/#{filter.filter_id}", %{
+ phrase: "nii",
+ context: ["public"],
+ expires_in: nil,
+ whole_word: true
+ })
+ |> json_response_and_validate_schema(200)
+
+ refute_enqueued(
+ worker: PurgeExpiredFilter,
+ args: %{filter_id: filter.id}
+ )
+
+ assert response["irreversible"] == false
+ assert response["whole_word"] == true
+ assert response["expires_at"] == nil
+ end
+
+ test "expires_at is the same in create and update so job is in db", %{conn: conn, user: user} do
+ resp1 =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/filters", %{
+ phrase: "cofe",
+ context: ["home"],
+ expires_in: 600
+ })
+ |> json_response_and_validate_schema(200)
+
+ filter = Filter.get(resp1["id"], user)
+
+ assert_enqueued(
+ worker: PurgeExpiredFilter,
+ args: %{filter_id: filter.id}
+ )
+
+ job = PurgeExpiredFilter.get_expiration(filter.id)
+
+ resp2 =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> put("/api/v1/filters/#{filter.filter_id}", %{
+ phrase: "nii",
+ context: ["public"]
+ })
+ |> json_response_and_validate_schema(200)
+
+ updated_filter = Filter.get(resp2["id"], user)
+
+ assert_enqueued(
+ worker: PurgeExpiredFilter,
+ args: %{filter_id: updated_filter.id}
+ )
+
+ after_update = PurgeExpiredFilter.get_expiration(updated_filter.id)
+
+ assert resp1["expires_at"] == resp2["expires_at"]
+
+ assert job.scheduled_at == after_update.scheduled_at
+ end
+
+ test "updating expires_at updates oban job too", %{conn: conn, user: user} do
+ resp1 =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/filters", %{
+ phrase: "cofe",
+ context: ["home"],
+ expires_in: 600
+ })
+ |> json_response_and_validate_schema(200)
+
+ filter = Filter.get(resp1["id"], user)
+
+ assert_enqueued(
+ worker: PurgeExpiredFilter,
+ args: %{filter_id: filter.id}
+ )
+
+ job = PurgeExpiredFilter.get_expiration(filter.id)
+
+ resp2 =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> put("/api/v1/filters/#{filter.filter_id}", %{
+ phrase: "nii",
+ context: ["public"],
+ expires_in: 300
+ })
+ |> json_response_and_validate_schema(200)
+
+ updated_filter = Filter.get(resp2["id"], user)
+
+ assert_enqueued(
+ worker: PurgeExpiredFilter,
+ args: %{filter_id: updated_filter.id}
+ )
+
+ after_update = PurgeExpiredFilter.get_expiration(updated_filter.id)
+
+ refute resp1["expires_at"] == resp2["expires_at"]
+
+ refute job.scheduled_at == after_update.scheduled_at
+ end
+ end
+
+ test "update filter without token", %{conn: conn} do
+ filter = insert(:filter)
+
+ response =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> put("/api/v1/filters/#{filter.filter_id}", %{
+ phrase: "nii",
+ context: ["public"]
+ })
+ |> json_response(403)
+
+ assert response["error"] == "Invalid credentials."
+ end
+
+ describe "delete a filter" do
+ setup do: oauth_access(["write:filters"])
+
+ test "common", %{conn: conn, user: user} do
+ filter = insert(:filter, user: user)
+
+ assert conn
+ |> delete("/api/v1/filters/#{filter.filter_id}")
+ |> json_response_and_validate_schema(200) == %{}
+
+ assert Repo.all(Filter) == []
+ end
+
+ test "with expires_at", %{conn: conn, user: user} do
+ response =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/filters", %{
+ phrase: "cofe",
+ context: ["home"],
+ expires_in: 600
+ })
+ |> json_response_and_validate_schema(200)
+
+ filter = Filter.get(response["id"], user)
+
+ assert_enqueued(
+ worker: PurgeExpiredFilter,
+ args: %{filter_id: filter.id}
+ )
+
+ assert conn
+ |> delete("/api/v1/filters/#{filter.filter_id}")
+ |> json_response_and_validate_schema(200) == %{}
+
+ refute_enqueued(
+ worker: PurgeExpiredFilter,
+ args: %{filter_id: filter.id}
+ )
+
+ assert Repo.all(Filter) == []
+ assert Repo.all(Oban.Job) == []
+ end
+ end
+
+ test "delete a filter without token", %{conn: conn} do
+ filter = insert(:filter)
+
+ response =
+ conn
+ |> delete("/api/v1/filters/#{filter.filter_id}")
+ |> json_response(403)
+
+ assert response["error"] == "Invalid credentials."
+ end
+end
diff --git a/test/web/mastodon_api/controllers/follow_request_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/follow_request_controller_test.exs
index 6749e0e83..069ffb3d6 100644
--- a/test/web/mastodon_api/controllers/follow_request_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/follow_request_controller_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do
- use Pleroma.Web.ConnCase
+ use Pleroma.Web.ConnCase, async: true
alias Pleroma.User
alias Pleroma.Web.CommonAPI
@@ -12,7 +12,7 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do
describe "locked accounts" do
setup do
- user = insert(:user, locked: true)
+ user = insert(:user, is_locked: true)
%{conn: conn} = oauth_access(["follow"], user: user)
%{user: user, conn: conn}
end
@@ -21,7 +21,7 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do
other_user = insert(:user)
{:ok, _, _, _activity} = CommonAPI.follow(other_user, user)
- {:ok, other_user} = User.follow(other_user, user, :follow_pending)
+ {:ok, other_user, user} = User.follow(other_user, user, :follow_pending)
assert User.following?(other_user, user) == false
@@ -35,7 +35,7 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestControllerTest do
other_user = insert(:user)
{:ok, _, _, _activity} = CommonAPI.follow(other_user, user)
- {:ok, other_user} = User.follow(other_user, user, :follow_pending)
+ {:ok, other_user, user} = User.follow(other_user, user, :follow_pending)
user = User.get_cached_by_id(user.id)
other_user = User.get_cached_by_id(other_user.id)
diff --git a/test/web/mastodon_api/controllers/instance_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/instance_controller_test.exs
index 6a9ccd979..e76cbc75b 100644
--- a/test/web/mastodon_api/controllers/instance_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/instance_controller_test.exs
@@ -1,8 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.InstanceControllerTest do
+ # TODO: Should not need Cachex
use Pleroma.Web.ConnCase
alias Pleroma.User
@@ -13,6 +14,9 @@ defmodule Pleroma.Web.MastodonAPI.InstanceControllerTest do
assert result = json_response_and_validate_schema(conn, 200)
email = Pleroma.Config.get([:instance, :email])
+ thumbnail = Pleroma.Web.Endpoint.url() <> Pleroma.Config.get([:instance, :instance_thumbnail])
+ background = Pleroma.Web.Endpoint.url() <> Pleroma.Config.get([:instance, :background_image])
+
# Note: not checking for "max_toot_chars" since it's optional
assert %{
"uri" => _,
@@ -24,7 +28,7 @@ defmodule Pleroma.Web.MastodonAPI.InstanceControllerTest do
"streaming_api" => _
},
"stats" => _,
- "thumbnail" => _,
+ "thumbnail" => from_config_thumbnail,
"languages" => _,
"registrations" => _,
"approval_required" => _,
@@ -33,8 +37,8 @@ defmodule Pleroma.Web.MastodonAPI.InstanceControllerTest do
"avatar_upload_limit" => _,
"background_upload_limit" => _,
"banner_upload_limit" => _,
- "background_image" => _,
- "chat_limit" => _,
+ "background_image" => from_config_background,
+ "shout_limit" => _,
"description_limit" => _
} = result
@@ -43,15 +47,18 @@ defmodule Pleroma.Web.MastodonAPI.InstanceControllerTest do
assert result["pleroma"]["metadata"]["federation"]
assert result["pleroma"]["metadata"]["fields_limits"]
assert result["pleroma"]["vapid_public_key"]
+ assert result["pleroma"]["stats"]["mau"] == 0
assert email == from_config_email
+ assert thumbnail == from_config_thumbnail
+ assert background == from_config_background
end
test "get instance stats", %{conn: conn} do
user = insert(:user, %{local: true})
user2 = insert(:user, %{local: true})
- {:ok, _user2} = User.deactivate(user2, !user2.deactivated)
+ {:ok, _user2} = User.set_activation(user2, false)
insert(:user, %{local: false, nickname: "u@peer1.com"})
insert(:user, %{local: false, nickname: "u@peer2.com"})
diff --git a/test/web/mastodon_api/controllers/list_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/list_controller_test.exs
index 091ec006c..28099837e 100644
--- a/test/web/mastodon_api/controllers/list_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/list_controller_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.ListControllerTest do
- use Pleroma.Web.ConnCase
+ use Pleroma.Web.ConnCase, async: true
alias Pleroma.Repo
@@ -55,30 +55,39 @@ defmodule Pleroma.Web.MastodonAPI.ListControllerTest do
test "adding users to a list" do
%{user: user, conn: conn} = oauth_access(["write:lists"])
other_user = insert(:user)
+ third_user = insert(:user)
{:ok, list} = Pleroma.List.create("name", user)
assert %{} ==
conn
|> put_req_header("content-type", "application/json")
- |> post("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
+ |> post("/api/v1/lists/#{list.id}/accounts", %{
+ "account_ids" => [other_user.id, third_user.id]
+ })
|> json_response_and_validate_schema(:ok)
%Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
- assert following == [other_user.follower_address]
+ assert length(following) == 2
+ assert other_user.follower_address in following
+ assert third_user.follower_address in following
end
test "removing users from a list, body params" do
%{user: user, conn: conn} = oauth_access(["write:lists"])
other_user = insert(:user)
third_user = insert(:user)
+ fourth_user = insert(:user)
{:ok, list} = Pleroma.List.create("name", user)
{:ok, list} = Pleroma.List.follow(list, other_user)
{:ok, list} = Pleroma.List.follow(list, third_user)
+ {:ok, list} = Pleroma.List.follow(list, fourth_user)
assert %{} ==
conn
|> put_req_header("content-type", "application/json")
- |> delete("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
+ |> delete("/api/v1/lists/#{list.id}/accounts", %{
+ "account_ids" => [other_user.id, fourth_user.id]
+ })
|> json_response_and_validate_schema(:ok)
%Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
diff --git a/test/web/mastodon_api/controllers/marker_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/marker_controller_test.exs
index 6dd40fb4a..53aebe8e4 100644
--- a/test/web/mastodon_api/controllers/marker_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/marker_controller_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.MarkerControllerTest do
- use Pleroma.Web.ConnCase
+ use Pleroma.Web.ConnCase, async: true
import Pleroma.Factory
@@ -11,7 +11,7 @@ defmodule Pleroma.Web.MastodonAPI.MarkerControllerTest do
test "gets markers with correct scopes", %{conn: conn} do
user = insert(:user)
token = insert(:oauth_token, user: user, scopes: ["read:statuses"])
- insert_list(7, :notification, user: user)
+ insert_list(7, :notification, user: user, activity: insert(:note_activity))
{:ok, %{"notifications" => marker}} =
Pleroma.Marker.upsert(
diff --git a/test/web/mastodon_api/controllers/media_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/media_controller_test.exs
index 906fd940f..ff988a7fd 100644
--- a/test/web/mastodon_api/controllers/media_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/media_controller_test.exs
@@ -1,10 +1,12 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.MediaControllerTest do
use Pleroma.Web.ConnCase
+ import ExUnit.CaptureLog
+
alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
@@ -14,7 +16,7 @@ defmodule Pleroma.Web.MastodonAPI.MediaControllerTest do
setup do
image = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}
@@ -67,6 +69,59 @@ defmodule Pleroma.Web.MastodonAPI.MediaControllerTest do
object = Object.get_by_id(media["id"])
assert object.data["actor"] == user.ap_id
end
+
+ test "/api/v2/media, upload_limit", %{conn: conn, user: user} do
+ desc = "Description of the binary"
+
+ upload_limit = Config.get([:instance, :upload_limit]) * 8 + 8
+
+ assert :ok ==
+ File.write(Path.absname("test/tmp/large_binary.data"), <<0::size(upload_limit)>>)
+
+ large_binary = %Plug.Upload{
+ content_type: nil,
+ path: Path.absname("test/tmp/large_binary.data"),
+ filename: "large_binary.data"
+ }
+
+ assert capture_log(fn ->
+ assert %{"error" => "file_too_large"} =
+ conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> post("/api/v2/media", %{
+ "file" => large_binary,
+ "description" => desc
+ })
+ |> json_response_and_validate_schema(400)
+ end) =~
+ "[error] Elixir.Pleroma.Upload store (using Pleroma.Uploaders.Local) failed: :file_too_large"
+
+ clear_config([:instance, :upload_limit], upload_limit)
+
+ assert response =
+ conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> post("/api/v2/media", %{
+ "file" => large_binary,
+ "description" => desc
+ })
+ |> json_response_and_validate_schema(202)
+
+ assert media_id = response["id"]
+
+ %{conn: conn} = oauth_access(["read:media"], user: user)
+
+ media =
+ conn
+ |> get("/api/v1/media/#{media_id}")
+ |> json_response_and_validate_schema(200)
+
+ assert media["type"] == "unknown"
+ assert media["description"] == desc
+ assert media["id"]
+
+ assert :ok == File.rm(Path.absname("test/tmp/large_binary.data"))
+ end
end
describe "Update media description" do
@@ -74,7 +129,7 @@ defmodule Pleroma.Web.MastodonAPI.MediaControllerTest do
setup %{user: actor} do
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}
@@ -106,7 +161,7 @@ defmodule Pleroma.Web.MastodonAPI.MediaControllerTest do
setup %{user: actor} do
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}
@@ -140,7 +195,7 @@ defmodule Pleroma.Web.MastodonAPI.MediaControllerTest do
conn
|> get("/api/v1/media/#{object.id}")
- |> json_response(403)
+ |> json_response_and_validate_schema(403)
end
end
end
diff --git a/test/web/mastodon_api/controllers/notification_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs
index 70ef0e8b5..d991f284f 100644
--- a/test/web/mastodon_api/controllers/notification_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do
@@ -44,9 +44,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do
|> get("/api/v1/notifications")
expected_response =
- "hi <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{user.id}\" href=\"#{
- user.ap_id
- }\" rel=\"ugc\">@<span>#{user.nickname}</span></a></span>"
+ "hi <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{user.id}\" href=\"#{user.ap_id}\" rel=\"ugc\">@<span>#{user.nickname}</span></a></span>"
assert [%{"status" => %{"content" => response}} | _rest] =
json_response_and_validate_schema(conn, 200)
@@ -75,6 +73,53 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do
assert [_] = result
end
+ test "by default, does not contain pleroma:report" do
+ %{user: user, conn: conn} = oauth_access(["read:notifications"])
+ other_user = insert(:user)
+ third_user = insert(:user)
+
+ user
+ |> User.admin_api_update(%{is_moderator: true})
+
+ {:ok, activity} = CommonAPI.post(other_user, %{status: "hey"})
+
+ {:ok, _report} =
+ CommonAPI.report(third_user, %{account_id: other_user.id, status_ids: [activity.id]})
+
+ result =
+ conn
+ |> get("/api/v1/notifications")
+ |> json_response_and_validate_schema(200)
+
+ assert [] == result
+
+ result =
+ conn
+ |> get("/api/v1/notifications?include_types[]=pleroma:report")
+ |> json_response_and_validate_schema(200)
+
+ assert [_] = result
+ end
+
+ test "excludes mentions from blockers when blockers_visible is false" do
+ clear_config([:activitypub, :blockers_visible], false)
+
+ %{user: user, conn: conn} = oauth_access(["read:notifications"])
+ blocker = insert(:user)
+
+ {:ok, _} = CommonAPI.block(blocker, user)
+ {:ok, activity} = CommonAPI.post(blocker, %{status: "hi @#{user.nickname}"})
+
+ {:ok, [_notification]} = Notification.create_notifications(activity)
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/notifications")
+
+ assert [] == json_response_and_validate_schema(conn, 200)
+ end
+
test "getting a single notification" do
%{user: user, conn: conn} = oauth_access(["read:notifications"])
other_user = insert(:user)
@@ -86,9 +131,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do
conn = get(conn, "/api/v1/notifications/#{notification.id}")
expected_response =
- "hi <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{user.id}\" href=\"#{
- user.ap_id
- }\" rel=\"ugc\">@<span>#{user.nickname}</span></a></span>"
+ "hi <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{user.id}\" href=\"#{user.ap_id}\" rel=\"ugc\">@<span>#{user.nickname}</span></a></span>"
assert %{"status" => %{"content" => response}} = json_response_and_validate_schema(conn, 200)
assert response == expected_response
@@ -502,7 +545,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do
assert length(json_response_and_validate_schema(ret_conn, 200)) == 1
- {:ok, _user_relationships} = User.mute(user, user2, false)
+ {:ok, _user_relationships} = User.mute(user, user2, %{notifications: false})
conn = get(conn, "/api/v1/notifications")
@@ -527,24 +570,11 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do
assert length(json_response_and_validate_schema(conn, 200)) == 1
end
- @tag capture_log: true
test "see move notifications" do
old_user = insert(:user)
new_user = insert(:user, also_known_as: [old_user.ap_id])
%{user: follower, conn: conn} = oauth_access(["read:notifications"])
- old_user_url = old_user.ap_id
-
- body =
- File.read!("test/fixtures/users_mock/localhost.json")
- |> String.replace("{{nickname}}", old_user.nickname)
- |> Jason.encode!()
-
- Tesla.Mock.mock(fn
- %{method: :get, url: ^old_user_url} ->
- %Tesla.Env{status: 200, body: body}
- end)
-
User.follow(follower, old_user)
Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user)
Pleroma.Tests.ObanHelpers.perform_all()
diff --git a/test/web/mastodon_api/controllers/poll_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/poll_controller_test.exs
index f41de6448..da0a631a9 100644
--- a/test/web/mastodon_api/controllers/poll_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/poll_controller_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.PollControllerTest do
- use Pleroma.Web.ConnCase
+ use Pleroma.Web.ConnCase, async: true
alias Pleroma.Object
alias Pleroma.Web.CommonAPI
@@ -20,7 +20,7 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do
poll: %{options: ["what Mastodon't", "n't what Mastodoes"], expires_in: 20}
})
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
conn = get(conn, "/api/v1/polls/#{object.id}")
@@ -39,7 +39,7 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do
visibility: "private"
})
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
conn = get(conn, "/api/v1/polls/#{object.id}")
@@ -47,6 +47,78 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do
end
end
+ test "own_votes" do
+ %{conn: conn} = oauth_access(["write:statuses", "read:statuses"])
+
+ other_user = insert(:user)
+
+ {:ok, activity} =
+ CommonAPI.post(other_user, %{
+ status: "A very delicious sandwich",
+ poll: %{
+ options: ["Lettuce", "Grilled Bacon", "Tomato"],
+ expires_in: 20,
+ multiple: true
+ }
+ })
+
+ object = Object.normalize(activity, fetch: false)
+
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 2]})
+ |> json_response_and_validate_schema(200)
+
+ object = Object.get_by_id(object.id)
+
+ assert [
+ %{
+ "name" => "Lettuce",
+ "replies" => %{"totalItems" => 1, "type" => "Collection"},
+ "type" => "Note"
+ },
+ %{
+ "name" => "Grilled Bacon",
+ "replies" => %{"totalItems" => 0, "type" => "Collection"},
+ "type" => "Note"
+ },
+ %{
+ "name" => "Tomato",
+ "replies" => %{"totalItems" => 1, "type" => "Collection"},
+ "type" => "Note"
+ }
+ ] == object.data["anyOf"]
+
+ assert %{"replies" => %{"totalItems" => 0}} =
+ Enum.find(object.data["anyOf"], fn %{"name" => name} -> name == "Grilled Bacon" end)
+
+ Enum.each(["Lettuce", "Tomato"], fn title ->
+ %{"replies" => %{"totalItems" => total_items}} =
+ Enum.find(object.data["anyOf"], fn %{"name" => name} -> name == title end)
+
+ assert total_items == 1
+ end)
+
+ assert %{
+ "own_votes" => own_votes,
+ "voted" => true
+ } =
+ conn
+ |> get("/api/v1/polls/#{object.id}")
+ |> json_response_and_validate_schema(200)
+
+ assert 0 in own_votes
+ assert 2 in own_votes
+ # for non authenticated user
+ response =
+ build_conn()
+ |> get("/api/v1/polls/#{object.id}")
+ |> json_response_and_validate_schema(200)
+
+ refute Map.has_key?(response, "own_votes")
+ refute Map.has_key?(response, "voted")
+ end
+
describe "POST /api/v1/polls/:id/votes" do
setup do: oauth_access(["write:statuses"])
@@ -63,14 +135,13 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do
}
})
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
- conn =
- conn
- |> put_req_header("content-type", "application/json")
- |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1, 2]})
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1, 2]})
+ |> json_response_and_validate_schema(200)
- assert json_response_and_validate_schema(conn, 200)
object = Object.get_by_id(object.id)
assert Enum.all?(object.data["anyOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
@@ -85,7 +156,7 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do
poll: %{options: ["Yes", "No"], expires_in: 20}
})
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
assert conn
|> put_req_header("content-type", "application/json")
@@ -106,7 +177,7 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do
poll: %{options: ["half empty", "half full"], expires_in: 20}
})
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
assert conn
|> put_req_header("content-type", "application/json")
@@ -129,7 +200,7 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do
poll: %{options: ["Yes", "No"], expires_in: 20}
})
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
conn =
conn
@@ -158,7 +229,7 @@ defmodule Pleroma.Web.MastodonAPI.PollControllerTest do
visibility: "private"
})
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
conn =
conn
diff --git a/test/web/mastodon_api/controllers/report_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/report_controller_test.exs
index 6636cff96..fcfc4a48a 100644
--- a/test/web/mastodon_api/controllers/report_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/report_controller_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.ReportControllerTest do
- use Pleroma.Web.ConnCase
+ use Pleroma.Web.ConnCase, async: true
alias Pleroma.Web.CommonAPI
diff --git a/test/web/mastodon_api/controllers/scheduled_activity_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/scheduled_activity_controller_test.exs
index 1ff871c89..b28e3df56 100644
--- a/test/web/mastodon_api/controllers/scheduled_activity_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/scheduled_activity_controller_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.ScheduledActivityControllerTest do
@@ -55,7 +55,7 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityControllerTest do
end
test "updates a scheduled activity" do
- Pleroma.Config.put([ScheduledActivity, :enabled], true)
+ clear_config([ScheduledActivity, :enabled], true)
%{user: user, conn: conn} = oauth_access(["write:statuses"])
scheduled_at = Timex.shift(NaiveDateTime.utc_now(), minutes: 60)
@@ -103,7 +103,7 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityControllerTest do
end
test "deletes a scheduled activity" do
- Pleroma.Config.put([ScheduledActivity, :enabled], true)
+ clear_config([ScheduledActivity, :enabled], true)
%{user: user, conn: conn} = oauth_access(["write:statuses"])
scheduled_at = Timex.shift(NaiveDateTime.utc_now(), minutes: 60)
diff --git a/test/web/mastodon_api/controllers/search_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/search_controller_test.exs
index 24d1959f8..e31cd0291 100644
--- a/test/web/mastodon_api/controllers/search_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/search_controller_test.exs
@@ -1,13 +1,13 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do
use Pleroma.Web.ConnCase
alias Pleroma.Object
- alias Pleroma.Web
alias Pleroma.Web.CommonAPI
+ alias Pleroma.Web.Endpoint
import Pleroma.Factory
import ExUnit.CaptureLog
import Tesla.Mock
@@ -61,7 +61,7 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do
assert account["id"] == to_string(user_three.id)
assert results["hashtags"] == [
- %{"name" => "private", "url" => "#{Web.base_url()}/tag/private"}
+ %{"name" => "private", "url" => "#{Endpoint.url()}/tag/private"}
]
[status] = results["statuses"]
@@ -72,7 +72,7 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do
|> json_response_and_validate_schema(200)
assert results["hashtags"] == [
- %{"name" => "天子", "url" => "#{Web.base_url()}/tag/天子"}
+ %{"name" => "天子", "url" => "#{Endpoint.url()}/tag/天子"}
]
[status] = results["statuses"]
@@ -87,8 +87,8 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do
|> json_response_and_validate_schema(200)
assert results["hashtags"] == [
- %{"name" => "explicit", "url" => "#{Web.base_url()}/tag/explicit"},
- %{"name" => "hashtags", "url" => "#{Web.base_url()}/tag/hashtags"}
+ %{"name" => "explicit", "url" => "#{Endpoint.url()}/tag/explicit"},
+ %{"name" => "hashtags", "url" => "#{Endpoint.url()}/tag/hashtags"}
]
results =
@@ -97,9 +97,9 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do
|> json_response_and_validate_schema(200)
assert results["hashtags"] == [
- %{"name" => "john", "url" => "#{Web.base_url()}/tag/john"},
- %{"name" => "doe", "url" => "#{Web.base_url()}/tag/doe"},
- %{"name" => "JohnDoe", "url" => "#{Web.base_url()}/tag/JohnDoe"}
+ %{"name" => "john", "url" => "#{Endpoint.url()}/tag/john"},
+ %{"name" => "doe", "url" => "#{Endpoint.url()}/tag/doe"},
+ %{"name" => "JohnDoe", "url" => "#{Endpoint.url()}/tag/JohnDoe"}
]
results =
@@ -108,9 +108,9 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do
|> json_response_and_validate_schema(200)
assert results["hashtags"] == [
- %{"name" => "accident", "url" => "#{Web.base_url()}/tag/accident"},
- %{"name" => "prone", "url" => "#{Web.base_url()}/tag/prone"},
- %{"name" => "AccidentProne", "url" => "#{Web.base_url()}/tag/AccidentProne"}
+ %{"name" => "accident", "url" => "#{Endpoint.url()}/tag/accident"},
+ %{"name" => "prone", "url" => "#{Endpoint.url()}/tag/prone"},
+ %{"name" => "AccidentProne", "url" => "#{Endpoint.url()}/tag/AccidentProne"}
]
results =
@@ -119,35 +119,29 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do
|> json_response_and_validate_schema(200)
assert results["hashtags"] == [
- %{"name" => "shpuld", "url" => "#{Web.base_url()}/tag/shpuld"}
+ %{"name" => "shpuld", "url" => "#{Endpoint.url()}/tag/shpuld"}
]
results =
conn
|> get(
- "/api/v2/search?#{
- URI.encode_query(%{
- q:
- "https://www.washingtonpost.com/sports/2020/06/10/" <>
- "nascar-ban-display-confederate-flag-all-events-properties/"
- })
- }"
+ "/api/v2/search?#{URI.encode_query(%{q: "https://www.washingtonpost.com/sports/2020/06/10/" <> "nascar-ban-display-confederate-flag-all-events-properties/"})}"
)
|> json_response_and_validate_schema(200)
assert results["hashtags"] == [
- %{"name" => "nascar", "url" => "#{Web.base_url()}/tag/nascar"},
- %{"name" => "ban", "url" => "#{Web.base_url()}/tag/ban"},
- %{"name" => "display", "url" => "#{Web.base_url()}/tag/display"},
- %{"name" => "confederate", "url" => "#{Web.base_url()}/tag/confederate"},
- %{"name" => "flag", "url" => "#{Web.base_url()}/tag/flag"},
- %{"name" => "all", "url" => "#{Web.base_url()}/tag/all"},
- %{"name" => "events", "url" => "#{Web.base_url()}/tag/events"},
- %{"name" => "properties", "url" => "#{Web.base_url()}/tag/properties"},
+ %{"name" => "nascar", "url" => "#{Endpoint.url()}/tag/nascar"},
+ %{"name" => "ban", "url" => "#{Endpoint.url()}/tag/ban"},
+ %{"name" => "display", "url" => "#{Endpoint.url()}/tag/display"},
+ %{"name" => "confederate", "url" => "#{Endpoint.url()}/tag/confederate"},
+ %{"name" => "flag", "url" => "#{Endpoint.url()}/tag/flag"},
+ %{"name" => "all", "url" => "#{Endpoint.url()}/tag/all"},
+ %{"name" => "events", "url" => "#{Endpoint.url()}/tag/events"},
+ %{"name" => "properties", "url" => "#{Endpoint.url()}/tag/properties"},
%{
"name" => "NascarBanDisplayConfederateFlagAllEventsProperties",
"url" =>
- "#{Web.base_url()}/tag/NascarBanDisplayConfederateFlagAllEventsProperties"
+ "#{Endpoint.url()}/tag/NascarBanDisplayConfederateFlagAllEventsProperties"
}
]
end
@@ -156,15 +150,13 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do
results =
conn
|> get(
- "/api/v2/search?#{
- URI.encode_query(%{q: "#some #text #with #hashtags", limit: 2, offset: 1})
- }"
+ "/api/v2/search?#{URI.encode_query(%{q: "#some #text #with #hashtags", limit: 2, offset: 1})}"
)
|> json_response_and_validate_schema(200)
assert results["hashtags"] == [
- %{"name" => "text", "url" => "#{Web.base_url()}/tag/text"},
- %{"name" => "with", "url" => "#{Web.base_url()}/tag/with"}
+ %{"name" => "text", "url" => "#{Endpoint.url()}/tag/text"},
+ %{"name" => "with", "url" => "#{Endpoint.url()}/tag/with"}
]
end
@@ -279,21 +271,25 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do
end
test "search fetches remote statuses and prefers them over other results", %{conn: conn} do
+ old_version = :persistent_term.get({Pleroma.Repo, :postgres_version})
+ :persistent_term.put({Pleroma.Repo, :postgres_version}, 10.0)
+ on_exit(fn -> :persistent_term.put({Pleroma.Repo, :postgres_version}, old_version) end)
+
capture_log(fn ->
{:ok, %{id: activity_id}} =
CommonAPI.post(insert(:user), %{
- status: "check out https://shitposter.club/notice/2827873"
+ status: "check out http://mastodon.example.org/@admin/99541947525187367"
})
results =
conn
- |> get("/api/v1/search?q=https://shitposter.club/notice/2827873")
+ |> get("/api/v1/search?q=http://mastodon.example.org/@admin/99541947525187367")
|> json_response_and_validate_schema(200)
- [status, %{"id" => ^activity_id}] = results["statuses"]
-
- assert status["uri"] ==
- "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
+ assert [
+ %{"url" => "http://mastodon.example.org/@admin/99541947525187367"},
+ %{"id" => ^activity_id}
+ ] = results["statuses"]
end)
end
@@ -305,7 +301,7 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do
})
capture_log(fn ->
- q = Object.normalize(activity).data["id"]
+ q = Object.normalize(activity, fetch: false).data["id"]
results =
conn
diff --git a/test/web/mastodon_api/controllers/status_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs
index f221884e7..ed66d370a 100644
--- a/test/web/mastodon_api/controllers/status_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs
@@ -1,13 +1,12 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
use Pleroma.Web.ConnCase
+ use Oban.Testing, repo: Pleroma.Repo
alias Pleroma.Activity
- alias Pleroma.ActivityExpiration
- alias Pleroma.Config
alias Pleroma.Conversation.Participation
alias Pleroma.Object
alias Pleroma.Repo
@@ -15,7 +14,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
alias Pleroma.Tests.ObanHelpers
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
+ alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.CommonAPI
+ alias Pleroma.Workers.ScheduledActivityWorker
import Pleroma.Factory
@@ -29,8 +30,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
setup do: oauth_access(["write:statuses"])
test "posting a status does not increment reblog_count when relaying", %{conn: conn} do
- Pleroma.Config.put([:instance, :federating], true)
- Pleroma.Config.get([:instance, :allow_relay], true)
+ clear_config([:instance, :federating], true)
+ Config.get([:instance, :allow_relay], true)
response =
conn
@@ -67,10 +68,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
"sensitive" => "0"
})
- {:ok, ttl} = Cachex.ttl(:idempotency_cache, idempotency_key)
- # Six hours
- assert ttl > :timer.seconds(6 * 60 * 60 - 1)
-
assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} =
json_response_and_validate_schema(conn_one, 200)
@@ -86,6 +83,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
"sensitive" => 0
})
+ # Idempotency plug response means detection fail
assert %{"id" => second_id} = json_response(conn_two, 200)
assert id == second_id
@@ -103,7 +101,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
# An activity that will expire:
# 2 hours
- expires_in = 120 * 60
+ expires_in = 2 * 60 * 60
+
+ expires_at = DateTime.add(DateTime.utc_now(), expires_in)
conn_four =
conn
@@ -113,29 +113,22 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
"expires_in" => expires_in
})
- assert fourth_response =
- %{"id" => fourth_id} = json_response_and_validate_schema(conn_four, 200)
-
- assert activity = Activity.get_by_id(fourth_id)
- assert expiration = ActivityExpiration.get_by_activity_id(fourth_id)
+ assert %{"id" => fourth_id} = json_response_and_validate_schema(conn_four, 200)
- estimated_expires_at =
- NaiveDateTime.utc_now()
- |> NaiveDateTime.add(expires_in)
- |> NaiveDateTime.truncate(:second)
-
- # This assert will fail if the test takes longer than a minute. I sure hope it never does:
- assert abs(NaiveDateTime.diff(expiration.scheduled_at, estimated_expires_at, :second)) < 60
+ assert Activity.get_by_id(fourth_id)
- assert fourth_response["pleroma"]["expires_at"] ==
- NaiveDateTime.to_iso8601(expiration.scheduled_at)
+ assert_enqueued(
+ worker: Pleroma.Workers.PurgeExpiredActivity,
+ args: %{activity_id: fourth_id},
+ scheduled_at: expires_at
+ )
end
test "it fails to create a status if `expires_in` is less or equal than an hour", %{
conn: conn
} do
- # 1 hour
- expires_in = 60 * 60
+ # 1 minute
+ expires_in = 1 * 60
assert %{"error" => "Expiry date is too soon"} =
conn
@@ -146,8 +139,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
})
|> json_response_and_validate_schema(422)
- # 30 minutes
- expires_in = 30 * 60
+ # 5 minutes
+ expires_in = 5 * 60
assert %{"error" => "Expiry date is too soon"} =
conn
@@ -160,8 +153,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
end
test "Get MRF reason when posting a status is rejected by one", %{conn: conn} do
- Pleroma.Config.put([:mrf_keyword, :reject], ["GNO"])
- Pleroma.Config.put([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.KeywordPolicy])
+ clear_config([:mrf_keyword, :reject], ["GNO"])
+ clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.KeywordPolicy])
assert %{"error" => "[KeywordPolicy] Matches with rejected keyword"} =
conn
@@ -172,7 +165,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
test "posting an undefined status with an attachment", %{user: user, conn: conn} do
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}
@@ -273,6 +266,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
fake_conn =
conn
+ |> assign(:user, refresh_record(conn.assigns.user))
|> put_req_header("content-type", "application/json")
|> post("/api/v1/statuses", %{
"status" =>
@@ -333,7 +327,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
end
test "posting a status with OGP link preview", %{conn: conn} do
- Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
+ Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
clear_config([:rich_media, :enabled], true)
conn =
@@ -366,6 +360,69 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
assert activity.data["to"] == [user2.ap_id]
assert activity.data["cc"] == []
end
+
+ test "discloses application metadata when enabled" do
+ user = insert(:user, disclose_client: true)
+ %{user: _user, token: token, conn: conn} = oauth_access(["write:statuses"], user: user)
+
+ %Pleroma.Web.OAuth.Token{
+ app: %Pleroma.Web.OAuth.App{
+ client_name: app_name,
+ website: app_website
+ }
+ } = token
+
+ result =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/statuses", %{
+ "status" => "cofe is my copilot"
+ })
+
+ assert %{
+ "content" => "cofe is my copilot"
+ } = json_response_and_validate_schema(result, 200)
+
+ activity = result.assigns.activity.id
+
+ result =
+ conn
+ |> get("api/v1/statuses/#{activity}")
+
+ assert %{
+ "content" => "cofe is my copilot",
+ "application" => %{
+ "name" => ^app_name,
+ "website" => ^app_website
+ }
+ } = json_response_and_validate_schema(result, 200)
+ end
+
+ test "hides application metadata when disabled" do
+ user = insert(:user, disclose_client: false)
+ %{user: _user, token: _token, conn: conn} = oauth_access(["write:statuses"], user: user)
+
+ result =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/statuses", %{
+ "status" => "club mate is my wingman"
+ })
+
+ assert %{"content" => "club mate is my wingman"} =
+ json_response_and_validate_schema(result, 200)
+
+ activity = result.assigns.activity.id
+
+ result =
+ conn
+ |> get("api/v1/statuses/#{activity}")
+
+ assert %{
+ "content" => "club mate is my wingman",
+ "application" => nil
+ } = json_response_and_validate_schema(result, 200)
+ end
end
describe "posting scheduled statuses" do
@@ -392,6 +449,31 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
assert [] == Repo.all(Activity)
end
+ test "with expiration" do
+ %{conn: conn} = oauth_access(["write:statuses", "read:statuses"])
+
+ scheduled_at =
+ NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(6), :millisecond)
+ |> NaiveDateTime.to_iso8601()
+ |> Kernel.<>("Z")
+
+ assert %{"id" => status_id, "params" => %{"expires_in" => 300}} =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/statuses", %{
+ "status" => "scheduled",
+ "scheduled_at" => scheduled_at,
+ "expires_in" => 300
+ })
+ |> json_response_and_validate_schema(200)
+
+ assert %{"id" => ^status_id, "params" => %{"expires_in" => 300}} =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> get("/api/v1/scheduled_statuses/#{status_id}")
+ |> json_response_and_validate_schema(200)
+ end
+
test "ignores nil values", %{conn: conn} do
conn =
conn
@@ -413,7 +495,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|> Kernel.<>("Z")
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}
@@ -525,7 +607,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
end)
assert NaiveDateTime.diff(NaiveDateTime.from_iso8601!(response["poll"]["expires_at"]), time) in 420..430
- refute response["poll"]["expred"]
+ assert response["poll"]["expired"] == false
question = Object.get_by_id(response["poll"]["id"])
@@ -601,6 +683,44 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
%{"error" => error} = json_response_and_validate_schema(conn, 422)
assert error == "Expiration date is too far in the future"
end
+
+ test "scheduled poll", %{conn: conn} do
+ clear_config([ScheduledActivity, :enabled], true)
+
+ scheduled_at =
+ NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(6), :millisecond)
+ |> NaiveDateTime.to_iso8601()
+ |> Kernel.<>("Z")
+
+ %{"id" => scheduled_id} =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/statuses", %{
+ "status" => "very cool poll",
+ "poll" => %{
+ "options" => ~w(a b c),
+ "expires_in" => 420
+ },
+ "scheduled_at" => scheduled_at
+ })
+ |> json_response_and_validate_schema(200)
+
+ assert {:ok, %{id: activity_id}} =
+ perform_job(ScheduledActivityWorker, %{
+ activity_id: scheduled_id
+ })
+
+ refute_enqueued(worker: ScheduledActivityWorker)
+
+ object =
+ Activity
+ |> Repo.get(activity_id)
+ |> Object.normalize()
+
+ assert object.data["content"] == "very cool poll"
+ assert object.data["type"] == "Question"
+ assert length(object.data["oneOf"]) == 3
+ end
end
test "get a status" do
@@ -809,7 +929,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
test "when you created it" do
%{user: author, conn: conn} = oauth_access(["write:statuses"])
activity = insert(:note_activity, user: author)
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
content = object.data["content"]
source = object.data["source"]
@@ -942,7 +1062,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|> get("/api/v1/statuses/#{reblog_activity1.id}")
assert %{
- "reblog" => %{"id" => id, "reblogged" => false, "reblogs_count" => 2},
+ "reblog" => %{"id" => _id, "reblogged" => false, "reblogs_count" => 2},
"reblogged" => false,
"favourited" => false,
"bookmarked" => false
@@ -963,6 +1083,23 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
assert to_string(activity.id) == id
end
+
+ test "author can reblog own private status", %{conn: conn, user: user} do
+ {:ok, activity} = CommonAPI.post(user, %{status: "cofe", visibility: "private"})
+
+ conn =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/statuses/#{activity.id}/reblog")
+
+ assert %{
+ "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1},
+ "reblogged" => true,
+ "visibility" => "private"
+ } = json_response_and_validate_schema(conn, 200)
+
+ assert to_string(activity.id) == id
+ end
end
describe "unreblogging" do
@@ -1075,20 +1212,27 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
setup do: clear_config([:instance, :max_pinned_statuses], 1)
test "pin status", %{conn: conn, user: user, activity: activity} do
- id_str = to_string(activity.id)
+ id = activity.id
- assert %{"id" => ^id_str, "pinned" => true} =
+ assert %{"id" => ^id, "pinned" => true} =
conn
|> put_req_header("content-type", "application/json")
|> post("/api/v1/statuses/#{activity.id}/pin")
|> json_response_and_validate_schema(200)
- assert [%{"id" => ^id_str, "pinned" => true}] =
+ assert [%{"id" => ^id, "pinned" => true}] =
conn
|> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
|> json_response_and_validate_schema(200)
end
+ test "non authenticated user", %{activity: activity} do
+ assert build_conn()
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/statuses/#{activity.id}/pin")
+ |> json_response(403) == %{"error" => "Invalid credentials."}
+ end
+
test "/pin: returns 400 error when activity is not public", %{conn: conn, user: user} do
{:ok, dm} = CommonAPI.post(user, %{status: "test", visibility: "direct"})
@@ -1097,7 +1241,18 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|> put_req_header("content-type", "application/json")
|> post("/api/v1/statuses/#{dm.id}/pin")
- assert json_response_and_validate_schema(conn, 400) == %{"error" => "Could not pin"}
+ assert json_response_and_validate_schema(conn, 422) == %{
+ "error" => "Non-public status cannot be pinned"
+ }
+ end
+
+ test "pin by another user", %{activity: activity} do
+ %{conn: conn} = oauth_access(["write:accounts"])
+
+ assert conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/statuses/#{activity.id}/pin")
+ |> json_response(422) == %{"error" => "Someone else's status cannot be pinned"}
end
test "unpin status", %{conn: conn, user: user, activity: activity} do
@@ -1118,13 +1273,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|> json_response_and_validate_schema(200)
end
- test "/unpin: returns 400 error when activity is not exist", %{conn: conn} do
- conn =
- conn
- |> put_req_header("content-type", "application/json")
- |> post("/api/v1/statuses/1/unpin")
-
- assert json_response_and_validate_schema(conn, 400) == %{"error" => "Could not unpin"}
+ test "/unpin: returns 404 error when activity doesn't exist", %{conn: conn} do
+ assert conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/statuses/1/unpin")
+ |> json_response_and_validate_schema(404) == %{"error" => "Record not found"}
end
test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
@@ -1146,17 +1299,63 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|> post("/api/v1/statuses/#{activity_two.id}/pin")
|> json_response_and_validate_schema(400)
end
+
+ test "on pin removes deletion job, on unpin reschedule deletion" do
+ %{conn: conn} = oauth_access(["write:accounts", "write:statuses"])
+ expires_in = 2 * 60 * 60
+
+ expires_at = DateTime.add(DateTime.utc_now(), expires_in)
+
+ assert %{"id" => id} =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("api/v1/statuses", %{
+ "status" => "oolong",
+ "expires_in" => expires_in
+ })
+ |> json_response_and_validate_schema(200)
+
+ assert_enqueued(
+ worker: Pleroma.Workers.PurgeExpiredActivity,
+ args: %{activity_id: id},
+ scheduled_at: expires_at
+ )
+
+ assert %{"id" => ^id, "pinned" => true} =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/statuses/#{id}/pin")
+ |> json_response_and_validate_schema(200)
+
+ refute_enqueued(
+ worker: Pleroma.Workers.PurgeExpiredActivity,
+ args: %{activity_id: id},
+ scheduled_at: expires_at
+ )
+
+ assert %{"id" => ^id, "pinned" => false} =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/statuses/#{id}/unpin")
+ |> json_response_and_validate_schema(200)
+
+ assert_enqueued(
+ worker: Pleroma.Workers.PurgeExpiredActivity,
+ args: %{activity_id: id},
+ scheduled_at: expires_at
+ )
+ end
end
describe "cards" do
setup do
- Config.put([:rich_media, :enabled], true)
+ clear_config([:rich_media, :enabled], true)
oauth_access(["read:statuses"])
end
test "returns rich-media card", %{conn: conn, user: user} do
- Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
+ Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
{:ok, activity} = CommonAPI.post(user, %{status: "https://example.com/ogp"})
@@ -1201,7 +1400,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
end
test "replaces missing description with an empty string", %{conn: conn, user: user} do
- Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
+ Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
{:ok, activity} = CommonAPI.post(user, %{status: "https://example.com/ogp-missing-data"})
@@ -1337,7 +1536,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
activity = Activity.get_by_id_with_object(id)
- assert Object.normalize(activity).data["inReplyTo"] == Object.normalize(replied_to).data["id"]
+ assert Object.normalize(activity, fetch: false).data["inReplyTo"] ==
+ Object.normalize(replied_to, fetch: false).data["id"]
+
assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
# Reblog from the third user
@@ -1360,7 +1561,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|> assign(:token, insert(:oauth_token, user: user3, scopes: ["read:statuses"]))
|> get("api/v1/timelines/home")
- [reblogged_activity] = json_response(conn3, 200)
+ [reblogged_activity] = json_response_and_validate_schema(conn3, 200)
assert reblogged_activity["reblog"]["in_reply_to_id"] == replied_to.id
@@ -1681,19 +1882,17 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
test "expires_at is nil for another user" do
%{conn: conn, user: user} = oauth_access(["read:statuses"])
+ expires_at = DateTime.add(DateTime.utc_now(), 1_000_000)
{:ok, activity} = CommonAPI.post(user, %{status: "foobar", expires_in: 1_000_000})
- expires_at =
- activity.id
- |> ActivityExpiration.get_by_activity_id()
- |> Map.get(:scheduled_at)
- |> NaiveDateTime.to_iso8601()
-
- assert %{"pleroma" => %{"expires_at" => ^expires_at}} =
+ assert %{"pleroma" => %{"expires_at" => a_expires_at}} =
conn
|> get("/api/v1/statuses/#{activity.id}")
|> json_response_and_validate_schema(:ok)
+ {:ok, a_expires_at, 0} = DateTime.from_iso8601(a_expires_at)
+ assert DateTime.diff(expires_at, a_expires_at) == 0
+
%{conn: conn} = oauth_access(["read:statuses"])
assert %{"pleroma" => %{"expires_at" => nil}} =
@@ -1701,4 +1900,94 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
|> get("/api/v1/statuses/#{activity.id}")
|> json_response_and_validate_schema(:ok)
end
+
+ test "posting a local only status" do
+ %{user: _user, conn: conn} = oauth_access(["write:statuses"])
+
+ conn_one =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/statuses", %{
+ "status" => "cofe",
+ "visibility" => "local"
+ })
+
+ local = Utils.as_local_public()
+
+ assert %{"content" => "cofe", "id" => id, "visibility" => "local"} =
+ json_response_and_validate_schema(conn_one, 200)
+
+ assert %Activity{id: ^id, data: %{"to" => [^local]}} = Activity.get_by_id(id)
+ end
+
+ describe "muted reactions" do
+ test "index" do
+ %{conn: conn, user: user} = oauth_access(["read:statuses"])
+
+ other_user = insert(:user)
+ {:ok, activity} = CommonAPI.post(user, %{status: "test"})
+
+ {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅")
+ User.mute(user, other_user)
+
+ result =
+ conn
+ |> get("/api/v1/statuses/?ids[]=#{activity.id}")
+ |> json_response_and_validate_schema(200)
+
+ assert [
+ %{
+ "pleroma" => %{
+ "emoji_reactions" => []
+ }
+ }
+ ] = result
+
+ result =
+ conn
+ |> get("/api/v1/statuses/?ids[]=#{activity.id}&with_muted=true")
+ |> json_response_and_validate_schema(200)
+
+ assert [
+ %{
+ "pleroma" => %{
+ "emoji_reactions" => [%{"count" => 1, "me" => false, "name" => "🎅"}]
+ }
+ }
+ ] = result
+ end
+
+ test "show" do
+ # %{conn: conn, user: user, token: token} = oauth_access(["read:statuses"])
+ %{conn: conn, user: user, token: _token} = oauth_access(["read:statuses"])
+
+ other_user = insert(:user)
+ {:ok, activity} = CommonAPI.post(user, %{status: "test"})
+
+ {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅")
+ User.mute(user, other_user)
+
+ result =
+ conn
+ |> get("/api/v1/statuses/#{activity.id}")
+ |> json_response_and_validate_schema(200)
+
+ assert %{
+ "pleroma" => %{
+ "emoji_reactions" => []
+ }
+ } = result
+
+ result =
+ conn
+ |> get("/api/v1/statuses/#{activity.id}?with_muted=true")
+ |> json_response_and_validate_schema(200)
+
+ assert %{
+ "pleroma" => %{
+ "emoji_reactions" => [%{"count" => 1, "me" => false, "name" => "🎅"}]
+ }
+ } = result
+ end
+ end
end
diff --git a/test/web/mastodon_api/controllers/subscription_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/subscription_controller_test.exs
index d36bb1ae8..5a3f93d2d 100644
--- a/test/web/mastodon_api/controllers/subscription_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/subscription_controller_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.SubscriptionControllerTest do
- use Pleroma.Web.ConnCase
+ use Pleroma.Web.ConnCase, async: true
import Pleroma.Factory
@@ -45,21 +45,77 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionControllerTest do
end
end
- describe "creates push subscription" do
- test "returns error when push disabled ", %{conn: conn} do
+ describe "when disabled" do
+ test "POST returns error", %{conn: conn} do
+ assert_error_when_disable_push do
+ conn
+ |> post("/api/v1/push/subscription", %{
+ "data" => %{"alerts" => %{"mention" => true}},
+ "subscription" => @sub
+ })
+ |> json_response_and_validate_schema(403)
+ end
+ end
+
+ test "GET returns error", %{conn: conn} do
assert_error_when_disable_push do
conn
- |> post("/api/v1/push/subscription", %{subscription: @sub})
+ |> get("/api/v1/push/subscription", %{})
|> json_response_and_validate_schema(403)
end
end
+ test "PUT returns error", %{conn: conn} do
+ assert_error_when_disable_push do
+ conn
+ |> put("/api/v1/push/subscription", %{data: %{"alerts" => %{"mention" => false}}})
+ |> json_response_and_validate_schema(403)
+ end
+ end
+
+ test "DELETE returns error", %{conn: conn} do
+ assert_error_when_disable_push do
+ conn
+ |> delete("/api/v1/push/subscription", %{})
+ |> json_response_and_validate_schema(403)
+ end
+ end
+ end
+
+ describe "creates push subscription" do
+ test "ignores unsupported types", %{conn: conn} do
+ result =
+ conn
+ |> post("/api/v1/push/subscription", %{
+ "data" => %{
+ "alerts" => %{
+ "fake_unsupported_type" => true
+ }
+ },
+ "subscription" => @sub
+ })
+ |> json_response_and_validate_schema(200)
+
+ refute %{
+ "alerts" => %{
+ "fake_unsupported_type" => true
+ }
+ } == result
+ end
+
test "successful creation", %{conn: conn} do
result =
conn
|> post("/api/v1/push/subscription", %{
"data" => %{
- "alerts" => %{"mention" => true, "test" => true, "pleroma:chat_mention" => true}
+ "alerts" => %{
+ "mention" => true,
+ "favourite" => true,
+ "follow" => true,
+ "reblog" => true,
+ "pleroma:chat_mention" => true,
+ "pleroma:emoji_reaction" => true
+ }
},
"subscription" => @sub
})
@@ -68,7 +124,14 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionControllerTest do
[subscription] = Pleroma.Repo.all(Subscription)
assert %{
- "alerts" => %{"mention" => true, "pleroma:chat_mention" => true},
+ "alerts" => %{
+ "mention" => true,
+ "favourite" => true,
+ "follow" => true,
+ "reblog" => true,
+ "pleroma:chat_mention" => true,
+ "pleroma:emoji_reaction" => true
+ },
"endpoint" => subscription.endpoint,
"id" => to_string(subscription.id),
"server_key" => @server_key
@@ -77,14 +140,6 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionControllerTest do
end
describe "gets a user subscription" do
- test "returns error when push disabled ", %{conn: conn} do
- assert_error_when_disable_push do
- conn
- |> get("/api/v1/push/subscription", %{})
- |> json_response_and_validate_schema(403)
- end
- end
-
test "returns error when user hasn't subscription", %{conn: conn} do
res =
conn
@@ -124,30 +179,47 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionControllerTest do
insert(:push_subscription,
user: user,
token: token,
- data: %{"alerts" => %{"mention" => true}}
+ data: %{
+ "alerts" => %{
+ "mention" => true,
+ "favourite" => true,
+ "follow" => true,
+ "reblog" => true,
+ "pleroma:chat_mention" => true,
+ "pleroma:emoji_reaction" => true
+ }
+ }
)
%{conn: conn, user: user, token: token, subscription: subscription}
end
- test "returns error when push disabled ", %{conn: conn} do
- assert_error_when_disable_push do
- conn
- |> put("/api/v1/push/subscription", %{data: %{"alerts" => %{"mention" => false}}})
- |> json_response_and_validate_schema(403)
- end
- end
-
test "returns updated subsciption", %{conn: conn, subscription: subscription} do
res =
conn
|> put("/api/v1/push/subscription", %{
- data: %{"alerts" => %{"mention" => false, "follow" => true}}
+ data: %{
+ "alerts" => %{
+ "mention" => false,
+ "favourite" => false,
+ "follow" => false,
+ "reblog" => false,
+ "pleroma:chat_mention" => false,
+ "pleroma:emoji_reaction" => false
+ }
+ }
})
|> json_response_and_validate_schema(200)
expect = %{
- "alerts" => %{"follow" => true, "mention" => false},
+ "alerts" => %{
+ "mention" => false,
+ "favourite" => false,
+ "follow" => false,
+ "reblog" => false,
+ "pleroma:chat_mention" => false,
+ "pleroma:emoji_reaction" => false
+ },
"endpoint" => "https://example.com/example/1234",
"id" => to_string(subscription.id),
"server_key" => @server_key
@@ -158,14 +230,6 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionControllerTest do
end
describe "deletes the user subscription" do
- test "returns error when push disabled ", %{conn: conn} do
- assert_error_when_disable_push do
- conn
- |> delete("/api/v1/push/subscription", %{})
- |> json_response_and_validate_schema(403)
- end
- end
-
test "returns error when user hasn't subscription", %{conn: conn} do
res =
conn
diff --git a/test/pleroma/web/mastodon_api/controllers/suggestion_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/suggestion_controller_test.exs
new file mode 100644
index 000000000..89273e67b
--- /dev/null
+++ b/test/pleroma/web/mastodon_api/controllers/suggestion_controller_test.exs
@@ -0,0 +1,83 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.MastodonAPI.SuggestionControllerTest do
+ use Pleroma.Web.ConnCase, async: true
+ alias Pleroma.UserRelationship
+ alias Pleroma.Web.CommonAPI
+ import Pleroma.Factory
+
+ setup do: oauth_access(["read", "write"])
+
+ test "returns empty result", %{conn: conn} do
+ res =
+ conn
+ |> get("/api/v1/suggestions")
+ |> json_response_and_validate_schema(200)
+
+ assert res == []
+ end
+
+ test "returns v2 suggestions", %{conn: conn} do
+ %{id: user_id} = insert(:user, is_suggested: true)
+
+ res =
+ conn
+ |> get("/api/v2/suggestions")
+ |> json_response_and_validate_schema(200)
+
+ assert [%{"source" => "staff", "account" => %{"id" => ^user_id}}] = res
+ end
+
+ test "returns v2 suggestions excluding dismissed accounts", %{conn: conn} do
+ %{id: user_id} = insert(:user, is_suggested: true)
+
+ conn
+ |> delete("/api/v1/suggestions/#{user_id}")
+ |> json_response_and_validate_schema(200)
+
+ res =
+ conn
+ |> get("/api/v2/suggestions")
+ |> json_response_and_validate_schema(200)
+
+ assert [] = res
+ end
+
+ test "returns v2 suggestions excluding blocked accounts", %{conn: conn, user: blocker} do
+ blocked = insert(:user, is_suggested: true)
+ {:ok, _} = CommonAPI.block(blocker, blocked)
+
+ res =
+ conn
+ |> get("/api/v2/suggestions")
+ |> json_response_and_validate_schema(200)
+
+ assert [] = res
+ end
+
+ test "returns v2 suggestions excluding followed accounts", %{conn: conn, user: follower} do
+ followed = insert(:user, is_suggested: true)
+ {:ok, _, _, _} = CommonAPI.follow(follower, followed)
+
+ res =
+ conn
+ |> get("/api/v2/suggestions")
+ |> json_response_and_validate_schema(200)
+
+ assert [] = res
+ end
+
+ test "dismiss suggestion", %{conn: conn, user: source} do
+ target = insert(:user, is_suggested: true)
+
+ res =
+ conn
+ |> delete("/api/v1/suggestions/#{target.id}")
+ |> json_response_and_validate_schema(200)
+
+ assert res == %{}
+ assert UserRelationship.exists?(:suggestion_dismiss, source, target)
+ end
+end
diff --git a/test/web/mastodon_api/controllers/timeline_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs
index 517cabcff..187982d92 100644
--- a/test/web/mastodon_api/controllers/timeline_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/timeline_controller_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
@@ -8,7 +8,6 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
import Pleroma.Factory
import Tesla.Mock
- alias Pleroma.Config
alias Pleroma.User
alias Pleroma.Web.CommonAPI
@@ -55,6 +54,101 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
assert private_activity.id in status_ids
refute direct_activity.id in status_ids
end
+
+ test "muted emotions", %{user: user, conn: conn} do
+ other_user = insert(:user)
+ {:ok, activity} = CommonAPI.post(user, %{status: "."})
+
+ {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅")
+ User.mute(user, other_user)
+
+ result =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/timelines/home")
+ |> json_response_and_validate_schema(200)
+
+ assert [
+ %{
+ "pleroma" => %{
+ "emoji_reactions" => []
+ }
+ }
+ ] = result
+
+ result =
+ conn
+ |> assign(:user, user)
+ |> get("/api/v1/timelines/home?with_muted=true")
+ |> json_response_and_validate_schema(200)
+
+ assert [
+ %{
+ "pleroma" => %{
+ "emoji_reactions" => [%{"count" => 1, "me" => false, "name" => "🎅"}]
+ }
+ }
+ ] = result
+ end
+
+ test "filtering", %{conn: conn, user: user} do
+ local_user = insert(:user)
+ {:ok, user, local_user} = User.follow(user, local_user)
+ {:ok, local_activity} = CommonAPI.post(local_user, %{status: "Status"})
+ with_media = create_with_media_activity(local_user)
+
+ remote_user = insert(:user, local: false)
+ {:ok, _user, remote_user} = User.follow(user, remote_user)
+ remote_activity = create_remote_activity(remote_user)
+
+ without_filter_ids =
+ conn
+ |> get("/api/v1/timelines/home")
+ |> json_response_and_validate_schema(200)
+ |> Enum.map(& &1["id"])
+
+ assert local_activity.id in without_filter_ids
+ assert remote_activity.id in without_filter_ids
+ assert with_media.id in without_filter_ids
+
+ only_local_ids =
+ conn
+ |> get("/api/v1/timelines/home?local=true")
+ |> json_response_and_validate_schema(200)
+ |> Enum.map(& &1["id"])
+
+ assert local_activity.id in only_local_ids
+ refute remote_activity.id in only_local_ids
+ assert with_media.id in only_local_ids
+
+ only_local_media_ids =
+ conn
+ |> get("/api/v1/timelines/home?local=true&only_media=true")
+ |> json_response_and_validate_schema(200)
+ |> Enum.map(& &1["id"])
+
+ refute local_activity.id in only_local_media_ids
+ refute remote_activity.id in only_local_media_ids
+ assert with_media.id in only_local_media_ids
+
+ remote_ids =
+ conn
+ |> get("/api/v1/timelines/home?remote=true")
+ |> json_response_and_validate_schema(200)
+ |> Enum.map(& &1["id"])
+
+ refute local_activity.id in remote_ids
+ assert remote_activity.id in remote_ids
+ refute with_media.id in remote_ids
+
+ assert conn
+ |> get("/api/v1/timelines/home?remote=true&only_media=true")
+ |> json_response_and_validate_schema(200) == []
+
+ assert conn
+ |> get("/api/v1/timelines/home?remote=true&local=true")
+ |> json_response_and_validate_schema(200) == []
+ end
end
describe "public" do
@@ -63,27 +157,80 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "test"})
+ with_media = create_with_media_activity(user)
- _activity = insert(:note_activity, local: false)
+ remote = insert(:note_activity, local: false)
- conn = get(conn, "/api/v1/timelines/public?local=False")
+ assert conn
+ |> get("/api/v1/timelines/public?local=False")
+ |> json_response_and_validate_schema(:ok)
+ |> length == 3
- assert length(json_response_and_validate_schema(conn, :ok)) == 2
+ local_ids =
+ conn
+ |> get("/api/v1/timelines/public?local=True")
+ |> json_response_and_validate_schema(:ok)
+ |> Enum.map(& &1["id"])
- conn = get(build_conn(), "/api/v1/timelines/public?local=True")
+ assert activity.id in local_ids
+ assert with_media.id in local_ids
+ refute remote.id in local_ids
- assert [%{"content" => "test"}] = json_response_and_validate_schema(conn, :ok)
+ local_ids =
+ conn
+ |> get("/api/v1/timelines/public?local=True")
+ |> json_response_and_validate_schema(:ok)
+ |> Enum.map(& &1["id"])
- conn = get(build_conn(), "/api/v1/timelines/public?local=1")
+ assert activity.id in local_ids
+ assert with_media.id in local_ids
+ refute remote.id in local_ids
- assert [%{"content" => "test"}] = json_response_and_validate_schema(conn, :ok)
+ local_ids =
+ conn
+ |> get("/api/v1/timelines/public?local=True&only_media=true")
+ |> json_response_and_validate_schema(:ok)
+ |> Enum.map(& &1["id"])
+
+ refute activity.id in local_ids
+ assert with_media.id in local_ids
+ refute remote.id in local_ids
+
+ local_ids =
+ conn
+ |> get("/api/v1/timelines/public?local=1")
+ |> json_response_and_validate_schema(:ok)
+ |> Enum.map(& &1["id"])
+
+ assert activity.id in local_ids
+ assert with_media.id in local_ids
+ refute remote.id in local_ids
+
+ remote_id = remote.id
+
+ assert [%{"id" => ^remote_id}] =
+ conn
+ |> get("/api/v1/timelines/public?remote=true")
+ |> json_response_and_validate_schema(:ok)
+
+ with_media_id = with_media.id
+
+ assert [%{"id" => ^with_media_id}] =
+ conn
+ |> get("/api/v1/timelines/public?only_media=true")
+ |> json_response_and_validate_schema(:ok)
+
+ assert conn
+ |> get("/api/v1/timelines/public?remote=true&only_media=true")
+ |> json_response_and_validate_schema(:ok) == []
# does not contain repeats
{:ok, _} = CommonAPI.repeat(activity.id, user)
- conn = get(build_conn(), "/api/v1/timelines/public?local=true")
-
- assert [_] = json_response_and_validate_schema(conn, :ok)
+ assert [_, _] =
+ conn
+ |> get("/api/v1/timelines/public?local=true")
+ |> json_response_and_validate_schema(:ok)
end
test "the public timeline includes only public statuses for an authenticated user" do
@@ -101,7 +248,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
test "doesn't return replies if follower is posting with blocked user" do
%{conn: conn, user: blocker} = oauth_access(["read:statuses"])
[blockee, friend] = insert_list(2, :user)
- {:ok, blocker} = User.follow(blocker, friend)
+ {:ok, blocker, friend} = User.follow(blocker, friend)
{:ok, _} = User.block(blocker, blockee)
conn = assign(conn, :user, blocker)
@@ -114,15 +261,41 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
{:ok, _reply_from_friend} =
CommonAPI.post(friend, %{status: "status", in_reply_to_status_id: reply_from_blockee})
- res_conn = get(conn, "/api/v1/timelines/public")
- [%{"id" => ^activity_id}] = json_response_and_validate_schema(res_conn, 200)
+ # Still shows replies from yourself
+ {:ok, %{id: reply_from_me}} =
+ CommonAPI.post(blocker, %{status: "status", in_reply_to_status_id: reply_from_blockee})
+
+ response =
+ get(conn, "/api/v1/timelines/public")
+ |> json_response_and_validate_schema(200)
+
+ assert length(response) == 2
+ [%{"id" => ^reply_from_me}, %{"id" => ^activity_id}] = response
+ end
+
+ test "doesn't return posts from users who blocked you when :blockers_visible is disabled" do
+ clear_config([:activitypub, :blockers_visible], false)
+
+ %{conn: conn, user: blockee} = oauth_access(["read:statuses"])
+ blocker = insert(:user)
+ {:ok, _} = User.block(blocker, blockee)
+
+ conn = assign(conn, :user, blockee)
+
+ {:ok, _} = CommonAPI.post(blocker, %{status: "hey!"})
+
+ response =
+ get(conn, "/api/v1/timelines/public")
+ |> json_response_and_validate_schema(200)
+
+ assert length(response) == 0
end
test "doesn't return replies if follow is posting with users from blocked domain" do
%{conn: conn, user: blocker} = oauth_access(["read:statuses"])
friend = insert(:user)
blockee = insert(:user, ap_id: "https://example.com/users/blocked")
- {:ok, blocker} = User.follow(blocker, friend)
+ {:ok, blocker, friend} = User.follow(blocker, friend)
{:ok, blocker} = User.block_domain(blocker, "example.com")
conn = assign(conn, :user, blocker)
@@ -140,6 +313,60 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
activities = json_response_and_validate_schema(res_conn, 200)
[%{"id" => ^activity_id}] = activities
end
+
+ test "can be filtered by instance", %{conn: conn} do
+ user = insert(:user, ap_id: "https://lain.com/users/lain")
+ insert(:note_activity, local: false)
+ insert(:note_activity, local: false)
+
+ {:ok, _} = CommonAPI.post(user, %{status: "test"})
+
+ conn = get(conn, "/api/v1/timelines/public?instance=lain.com")
+
+ assert length(json_response_and_validate_schema(conn, :ok)) == 1
+ end
+
+ test "muted emotions", %{conn: conn} do
+ user = insert(:user)
+ token = insert(:oauth_token, user: user, scopes: ["read:statuses"])
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> assign(:token, token)
+
+ other_user = insert(:user)
+ {:ok, activity} = CommonAPI.post(user, %{status: "."})
+
+ {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅")
+ User.mute(user, other_user)
+
+ result =
+ conn
+ |> get("/api/v1/timelines/public")
+ |> json_response_and_validate_schema(200)
+
+ assert [
+ %{
+ "pleroma" => %{
+ "emoji_reactions" => []
+ }
+ }
+ ] = result
+
+ result =
+ conn
+ |> get("/api/v1/timelines/public?with_muted=true")
+ |> json_response_and_validate_schema(200)
+
+ assert [
+ %{
+ "pleroma" => %{
+ "emoji_reactions" => [%{"count" => 1, "me" => false, "name" => "🎅"}]
+ }
+ }
+ ] = result
+ end
end
defp local_and_remote_activities do
@@ -239,7 +466,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
user_one = insert(:user)
user_two = insert(:user)
- {:ok, user_two} = User.follow(user_two, user_one)
+ {:ok, user_two, user_one} = User.follow(user_two, user_one)
{:ok, direct} =
CommonAPI.post(user_one, %{
@@ -409,6 +636,115 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
assert id == to_string(activity_one.id)
end
+
+ test "muted emotions", %{user: user, conn: conn} do
+ user2 = insert(:user)
+ user3 = insert(:user)
+ {:ok, activity} = CommonAPI.post(user2, %{status: "."})
+
+ {:ok, _} = CommonAPI.react_with_emoji(activity.id, user3, "🎅")
+ User.mute(user, user3)
+
+ {:ok, list} = Pleroma.List.create("name", user)
+ {:ok, list} = Pleroma.List.follow(list, user2)
+
+ result =
+ conn
+ |> get("/api/v1/timelines/list/#{list.id}")
+ |> json_response_and_validate_schema(200)
+
+ assert [
+ %{
+ "pleroma" => %{
+ "emoji_reactions" => []
+ }
+ }
+ ] = result
+
+ result =
+ conn
+ |> get("/api/v1/timelines/list/#{list.id}?with_muted=true")
+ |> json_response_and_validate_schema(200)
+
+ assert [
+ %{
+ "pleroma" => %{
+ "emoji_reactions" => [%{"count" => 1, "me" => false, "name" => "🎅"}]
+ }
+ }
+ ] = result
+ end
+
+ test "filtering", %{user: user, conn: conn} do
+ {:ok, list} = Pleroma.List.create("name", user)
+
+ local_user = insert(:user)
+ {:ok, local_activity} = CommonAPI.post(local_user, %{status: "Marisa is stupid."})
+ with_media = create_with_media_activity(local_user)
+ {:ok, list} = Pleroma.List.follow(list, local_user)
+
+ remote_user = insert(:user, local: false)
+ remote_activity = create_remote_activity(remote_user)
+ {:ok, list} = Pleroma.List.follow(list, remote_user)
+
+ all_ids =
+ conn
+ |> get("/api/v1/timelines/list/#{list.id}")
+ |> json_response_and_validate_schema(200)
+ |> Enum.map(& &1["id"])
+
+ assert local_activity.id in all_ids
+ assert with_media.id in all_ids
+ assert remote_activity.id in all_ids
+
+ only_local_ids =
+ conn
+ |> get("/api/v1/timelines/list/#{list.id}?local=true")
+ |> json_response_and_validate_schema(200)
+ |> Enum.map(& &1["id"])
+
+ assert local_activity.id in only_local_ids
+ assert with_media.id in only_local_ids
+ refute remote_activity.id in only_local_ids
+
+ only_local_media_ids =
+ conn
+ |> get("/api/v1/timelines/list/#{list.id}?local=true&only_media=true")
+ |> json_response_and_validate_schema(200)
+ |> Enum.map(& &1["id"])
+
+ refute local_activity.id in only_local_media_ids
+ assert with_media.id in only_local_media_ids
+ refute remote_activity.id in only_local_media_ids
+
+ remote_ids =
+ conn
+ |> get("/api/v1/timelines/list/#{list.id}?remote=true")
+ |> json_response_and_validate_schema(200)
+ |> Enum.map(& &1["id"])
+
+ refute local_activity.id in remote_ids
+ refute with_media.id in remote_ids
+ assert remote_activity.id in remote_ids
+
+ assert conn
+ |> get("/api/v1/timelines/list/#{list.id}?remote=true&only_media=true")
+ |> json_response_and_validate_schema(200) == []
+
+ only_media_ids =
+ conn
+ |> get("/api/v1/timelines/list/#{list.id}?only_media=true")
+ |> json_response_and_validate_schema(200)
+ |> Enum.map(& &1["id"])
+
+ refute local_activity.id in only_media_ids
+ assert with_media.id in only_media_ids
+ refute remote_activity.id in only_media_ids
+
+ assert conn
+ |> get("/api/v1/timelines/list/#{list.id}?only_media=true&local=true&remote=true")
+ |> json_response_and_validate_schema(200) == []
+ end
end
describe "hashtag" do
@@ -419,19 +755,85 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
following = insert(:user)
{:ok, activity} = CommonAPI.post(following, %{status: "test #2hu"})
+ with_media = create_with_media_activity(following)
- nconn = get(conn, "/api/v1/timelines/tag/2hu")
+ remote = insert(:user, local: false)
+ remote_activity = create_remote_activity(remote)
- assert [%{"id" => id}] = json_response_and_validate_schema(nconn, :ok)
+ all_ids =
+ conn
+ |> get("/api/v1/timelines/tag/2hu")
+ |> json_response_and_validate_schema(:ok)
+ |> Enum.map(& &1["id"])
- assert id == to_string(activity.id)
+ assert activity.id in all_ids
+ assert with_media.id in all_ids
+ assert remote_activity.id in all_ids
# works for different capitalization too
- nconn = get(conn, "/api/v1/timelines/tag/2HU")
+ all_ids =
+ conn
+ |> get("/api/v1/timelines/tag/2HU")
+ |> json_response_and_validate_schema(:ok)
+ |> Enum.map(& &1["id"])
- assert [%{"id" => id}] = json_response_and_validate_schema(nconn, :ok)
+ assert activity.id in all_ids
+ assert with_media.id in all_ids
+ assert remote_activity.id in all_ids
- assert id == to_string(activity.id)
+ local_ids =
+ conn
+ |> get("/api/v1/timelines/tag/2hu?local=true")
+ |> json_response_and_validate_schema(:ok)
+ |> Enum.map(& &1["id"])
+
+ assert activity.id in local_ids
+ assert with_media.id in local_ids
+ refute remote_activity.id in local_ids
+
+ remote_ids =
+ conn
+ |> get("/api/v1/timelines/tag/2hu?remote=true")
+ |> json_response_and_validate_schema(:ok)
+ |> Enum.map(& &1["id"])
+
+ refute activity.id in remote_ids
+ refute with_media.id in remote_ids
+ assert remote_activity.id in remote_ids
+
+ media_ids =
+ conn
+ |> get("/api/v1/timelines/tag/2hu?only_media=true")
+ |> json_response_and_validate_schema(:ok)
+ |> Enum.map(& &1["id"])
+
+ refute activity.id in media_ids
+ assert with_media.id in media_ids
+ refute remote_activity.id in media_ids
+
+ media_local_ids =
+ conn
+ |> get("/api/v1/timelines/tag/2hu?only_media=true&local=true")
+ |> json_response_and_validate_schema(:ok)
+ |> Enum.map(& &1["id"])
+
+ refute activity.id in media_local_ids
+ assert with_media.id in media_local_ids
+ refute remote_activity.id in media_local_ids
+
+ ids =
+ conn
+ |> get("/api/v1/timelines/tag/2hu?only_media=true&local=true&remote=true")
+ |> json_response_and_validate_schema(:ok)
+ |> Enum.map(& &1["id"])
+
+ refute activity.id in ids
+ refute with_media.id in ids
+ refute remote_activity.id in ids
+
+ assert conn
+ |> get("/api/v1/timelines/tag/2hu?only_media=true&remote=true")
+ |> json_response_and_validate_schema(:ok) == []
end
test "multi-hashtag timeline", %{conn: conn} do
@@ -457,6 +859,48 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
assert [status_none] == json_response_and_validate_schema(all_test, :ok)
end
+
+ test "muted emotions", %{conn: conn} do
+ user = insert(:user)
+ token = insert(:oauth_token, user: user, scopes: ["read:statuses"])
+
+ conn =
+ conn
+ |> assign(:user, user)
+ |> assign(:token, token)
+
+ other_user = insert(:user)
+ {:ok, activity} = CommonAPI.post(user, %{status: "test #2hu"})
+
+ {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅")
+ User.mute(user, other_user)
+
+ result =
+ conn
+ |> get("/api/v1/timelines/tag/2hu")
+ |> json_response_and_validate_schema(200)
+
+ assert [
+ %{
+ "pleroma" => %{
+ "emoji_reactions" => []
+ }
+ }
+ ] = result
+
+ result =
+ conn
+ |> get("/api/v1/timelines/tag/2hu?with_muted=true")
+ |> json_response_and_validate_schema(200)
+
+ assert [
+ %{
+ "pleroma" => %{
+ "emoji_reactions" => [%{"count" => 1, "me" => false, "name" => "🎅"}]
+ }
+ }
+ ] = result
+ end
end
describe "hashtag timeline handling of :restrict_unauthenticated setting" do
@@ -479,10 +923,10 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
%{conn: auth_conn} = oauth_access(["read:statuses"])
res_conn = get(auth_conn, "#{base_uri}?local=true")
- assert length(json_response(res_conn, 200)) == 1
+ assert length(json_response_and_validate_schema(res_conn, 200)) == 1
res_conn = get(auth_conn, "#{base_uri}?local=false")
- assert length(json_response(res_conn, 200)) == 2
+ assert length(json_response_and_validate_schema(res_conn, 200)) == 2
end
test "with default settings on private instances, returns 403 for unauthenticated users", %{
@@ -496,7 +940,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
for local <- [true, false] do
res_conn = get(conn, "#{base_uri}?local=#{local}")
- assert json_response(res_conn, :unauthorized) == error_response
+ assert json_response_and_validate_schema(res_conn, :unauthorized) == error_response
end
ensure_authenticated_access(base_uri)
@@ -513,7 +957,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
for local <- [true, false] do
res_conn = get(conn, "#{base_uri}?local=#{local}")
- assert json_response(res_conn, :unauthorized) == error_response
+ assert json_response_and_validate_schema(res_conn, :unauthorized) == error_response
end
ensure_authenticated_access(base_uri)
@@ -525,10 +969,10 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
clear_config([:restrict_unauthenticated, :timelines, :federated], true)
res_conn = get(conn, "#{base_uri}?local=true")
- assert length(json_response(res_conn, 200)) == 1
+ assert length(json_response_and_validate_schema(res_conn, 200)) == 1
res_conn = get(conn, "#{base_uri}?local=false")
- assert json_response(res_conn, :unauthorized) == error_response
+ assert json_response_and_validate_schema(res_conn, :unauthorized) == error_response
ensure_authenticated_access(base_uri)
end
@@ -540,13 +984,46 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
clear_config([:restrict_unauthenticated, :timelines, :federated], false)
res_conn = get(conn, "#{base_uri}?local=true")
- assert json_response(res_conn, :unauthorized) == error_response
+ assert json_response_and_validate_schema(res_conn, :unauthorized) == error_response
# Note: local activities get delivered as part of federated timeline
res_conn = get(conn, "#{base_uri}?local=false")
- assert length(json_response(res_conn, 200)) == 2
+ assert length(json_response_and_validate_schema(res_conn, 200)) == 2
ensure_authenticated_access(base_uri)
end
end
+
+ defp create_remote_activity(user) do
+ obj =
+ insert(:note, %{
+ data: %{
+ "to" => [
+ "https://www.w3.org/ns/activitystreams#Public",
+ User.ap_followers(user)
+ ]
+ },
+ user: user
+ })
+
+ insert(:note_activity, %{
+ note: obj,
+ recipients: [
+ "https://www.w3.org/ns/activitystreams#Public",
+ User.ap_followers(user)
+ ],
+ user: user,
+ local: false
+ })
+ end
+
+ defp create_with_media_activity(user) do
+ obj = insert(:attachment_note, user: user)
+
+ insert(:note_activity, %{
+ note: obj,
+ recipients: ["https://www.w3.org/ns/activitystreams#Public", User.ap_followers(user)],
+ user: user
+ })
+ end
end
diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/pleroma/web/mastodon_api/mastodon_api_controller_test.exs
index bb4bc4396..c6332bd3e 100644
--- a/test/web/mastodon_api/mastodon_api_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/mastodon_api_controller_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
- use Pleroma.Web.ConnCase
+ use Pleroma.Web.ConnCase, async: true
describe "empty_array/2 (stubs)" do
test "GET /api/v1/accounts/:id/identity_proofs" do
diff --git a/test/web/mastodon_api/mastodon_api_test.exs b/test/pleroma/web/mastodon_api/mastodon_api_test.exs
index 0c5a38bf6..402bfd76f 100644
--- a/test/web/mastodon_api/mastodon_api_test.exs
+++ b/test/pleroma/web/mastodon_api/mastodon_api_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.MastodonAPITest do
- use Pleroma.Web.ConnCase
+ use Pleroma.Web.ConnCase, async: true
alias Pleroma.Notification
alias Pleroma.ScheduledActivity
@@ -16,7 +16,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPITest do
describe "follow/3" do
test "returns error when followed user is deactivated" do
follower = insert(:user)
- user = insert(:user, local: true, deactivated: true)
+ user = insert(:user, local: true, is_active: false)
assert {:error, _error} = MastodonAPI.follow(follower, user)
end
@@ -30,7 +30,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPITest do
test "returns ok if user already followed" do
follower = insert(:user)
user = insert(:user)
- {:ok, follower} = User.follow(follower, user)
+ {:ok, follower, user} = User.follow(follower, user)
{:ok, follower} = MastodonAPI.follow(follower, refresh_record(user))
assert User.following?(follower, user)
end
@@ -41,8 +41,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPITest do
follower1_user = insert(:user)
follower2_user = insert(:user)
user = insert(:user)
- {:ok, _follower1_user} = User.follow(follower1_user, user)
- {:ok, follower2_user} = User.follow(follower2_user, user)
+ {:ok, _follower1_user, _user} = User.follow(follower1_user, user)
+ {:ok, follower2_user, _user} = User.follow(follower2_user, user)
assert MastodonAPI.get_followers(user, %{"limit" => 1}) == [follower2_user]
end
@@ -55,9 +55,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPITest do
followed_two = insert(:user)
followed_three = insert(:user)
- {:ok, user} = User.follow(user, followed_one)
- {:ok, user} = User.follow(user, followed_two)
- {:ok, user} = User.follow(user, followed_three)
+ {:ok, user, followed_one} = User.follow(user, followed_one)
+ {:ok, user, followed_two} = User.follow(user, followed_two)
+ {:ok, user, followed_three} = User.follow(user, followed_three)
res = MastodonAPI.get_friends(user)
assert length(res) == 3
diff --git a/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs b/test/pleroma/web/mastodon_api/update_credentials_test.exs
index 2e6704726..1d2027899 100644
--- a/test/web/mastodon_api/controllers/account_controller/update_credentials_test.exs
+++ b/test/pleroma/web/mastodon_api/update_credentials_test.exs
@@ -1,8 +1,8 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do
+defmodule Pleroma.Web.MastodonAPI.UpdateCredentialsTest do
alias Pleroma.Repo
alias Pleroma.User
@@ -11,8 +11,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do
import Mock
import Pleroma.Factory
- setup do: clear_config([:instance, :max_account_fields])
-
describe "updating credentials" do
setup do: oauth_access(["write:accounts"])
setup :request_content_type
@@ -37,8 +35,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do
|> assign(:user, user)
|> patch("/api/v1/accounts/update_credentials", %{
"pleroma_settings_store" => %{
- masto_fe: %{
- theme: "bla"
+ soapbox_fe: %{
+ themeMode: "bla"
}
}
})
@@ -48,7 +46,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do
assert user_data["pleroma"]["settings_store"] ==
%{
"pleroma_fe" => %{"theme" => "bla"},
- "masto_fe" => %{"theme" => "bla"}
+ "soapbox_fe" => %{"themeMode" => "bla"}
}
user = Repo.get(User, user_data["id"])
@@ -62,8 +60,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do
|> assign(:user, user)
|> patch("/api/v1/accounts/update_credentials", %{
"pleroma_settings_store" => %{
- masto_fe: %{
- theme: "blub"
+ soapbox_fe: %{
+ themeMode: "blub"
}
}
})
@@ -73,7 +71,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do
assert user_data["pleroma"]["settings_store"] ==
%{
"pleroma_fe" => %{"theme" => "bla"},
- "masto_fe" => %{"theme" => "blub"}
+ "soapbox_fe" => %{"themeMode" => "blub"}
}
assert_called(Pleroma.Web.Federator.publish(:_))
@@ -90,9 +88,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do
assert user_data = json_response_and_validate_schema(conn, 200)
assert user_data["note"] ==
- ~s(I drink <a class="hashtag" data-tag="cofe" href="http://localhost:4001/tag/cofe">#cofe</a> with <span class="h-card"><a class="u-url mention" data-user="#{
- user2.id
- }" href="#{user2.ap_id}" rel="ugc">@<span>#{user2.nickname}</span></a></span><br/><br/>suya..)
+ ~s(I drink <a class="hashtag" data-tag="cofe" href="http://localhost:4001/tag/cofe">#cofe</a> with <span class="h-card"><a class="u-url mention" data-user="#{user2.id}" href="#{user2.ap_id}" rel="ugc">@<span>#{user2.nickname}</span></a></span><br/><br/>suya..)
assert user_data["source"]["note"] == raw_bio
@@ -220,9 +216,28 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do
assert update_activity.data["object"]["name"] == "markorepairs"
end
+ test "updates the user's AKAs", %{conn: conn} do
+ conn =
+ patch(conn, "/api/v1/accounts/update_credentials", %{
+ "also_known_as" => ["https://mushroom.kingdom/users/mario"]
+ })
+
+ assert user_data = json_response_and_validate_schema(conn, 200)
+ assert user_data["pleroma"]["also_known_as"] == ["https://mushroom.kingdom/users/mario"]
+ end
+
+ test "doesn't update non-url akas", %{conn: conn} do
+ conn =
+ patch(conn, "/api/v1/accounts/update_credentials", %{
+ "also_known_as" => ["aReallyCoolGuy"]
+ })
+
+ assert json_response_and_validate_schema(conn, 403)
+ end
+
test "updates the user's avatar", %{user: user, conn: conn} do
new_avatar = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}
@@ -246,7 +261,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do
test "updates the user's banner", %{user: user, conn: conn} do
new_header = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}
@@ -265,7 +280,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do
test "updates the user's background", %{conn: conn, user: user} do
new_header = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}
@@ -446,7 +461,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController.UpdateCredentialsTest do
|> patch("/api/v1/accounts/update_credentials", %{"fields_attributes" => fields})
|> json_response_and_validate_schema(403)
- Pleroma.Config.put([:instance, :max_account_fields], 1)
+ clear_config([:instance, :max_account_fields], 1)
fields = [
%{"name" => "foo", "value" => "bar"},
diff --git a/test/web/mastodon_api/views/account_view_test.exs b/test/pleroma/web/mastodon_api/views/account_view_test.exs
index 8f37efa3c..c23ffb966 100644
--- a/test/web/mastodon_api/views/account_view_test.exs
+++ b/test/pleroma/web/mastodon_api/views/account_view_test.exs
@@ -1,11 +1,10 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
use Pleroma.DataCase
- alias Pleroma.Config
alias Pleroma.User
alias Pleroma.UserRelationship
alias Pleroma.Web.CommonAPI
@@ -19,8 +18,6 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
:ok
end
- setup do: clear_config([:instances_favicons, :enabled])
-
test "Represent a user account" do
background_image = %{
"url" => [%{"href" => "https://example.com/images/asuka_hospital.png"}]
@@ -37,7 +34,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
"<script src=\"invalid-html\"></script><span>valid html</span>. a<br>b<br/>c<br >d<br />f '&<>\"",
inserted_at: ~N[2017-08-15 15:47:06.597036],
emoji: %{"karjalanpiirakka" => "/file.png"},
- raw_bio: "valid html. a\nb\nc\nd\nf '&<>\""
+ raw_bio: "valid html. a\nb\nc\nd\nf '&<>\"",
+ also_known_as: ["https://shitposter.zone/users/shp"]
})
expected = %{
@@ -71,19 +69,22 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
sensitive: false,
pleroma: %{
actor_type: "Person",
- discoverable: false
+ discoverable: true
},
fields: []
},
+ fqn: "shp@shitposter.club",
+ last_status_at: nil,
pleroma: %{
ap_id: user.ap_id,
+ also_known_as: ["https://shitposter.zone/users/shp"],
background_image: "https://example.com/images/asuka_hospital.png",
- favicon:
- "https://shitposter.club/plugins/Qvitter/img/gnusocial-favicons/favicon-16x16.png",
- confirmation_pending: false,
+ favicon: nil,
+ is_confirmed: true,
tags: [],
is_admin: false,
is_moderator: false,
+ is_suggested: false,
hide_favorites: true,
hide_followers: false,
hide_follows: false,
@@ -98,22 +99,26 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
assert expected == AccountView.render("show.json", %{user: user, skip_visibility_check: true})
end
- test "Favicon is nil when :instances_favicons is disabled" do
- user = insert(:user)
+ describe "favicon" do
+ setup do
+ [user: insert(:user)]
+ end
- Config.put([:instances_favicons, :enabled], true)
+ test "is parsed when :instance_favicons is enabled", %{user: user} do
+ clear_config([:instances_favicons, :enabled], true)
- assert %{
- pleroma: %{
- favicon:
- "https://shitposter.club/plugins/Qvitter/img/gnusocial-favicons/favicon-16x16.png"
- }
- } = AccountView.render("show.json", %{user: user, skip_visibility_check: true})
-
- Config.put([:instances_favicons, :enabled], false)
+ assert %{
+ pleroma: %{
+ favicon:
+ "https://shitposter.club/plugins/Qvitter/img/gnusocial-favicons/favicon-16x16.png"
+ }
+ } = AccountView.render("show.json", %{user: user, skip_visibility_check: true})
+ end
- assert %{pleroma: %{favicon: nil}} =
- AccountView.render("show.json", %{user: user, skip_visibility_check: true})
+ test "is nil when :instances_favicons is disabled", %{user: user} do
+ assert %{pleroma: %{favicon: nil}} =
+ AccountView.render("show.json", %{user: user, skip_visibility_check: true})
+ end
end
test "Represent the user account for the account owner" do
@@ -166,19 +171,22 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
sensitive: false,
pleroma: %{
actor_type: "Service",
- discoverable: false
+ discoverable: true
},
fields: []
},
+ fqn: "shp@shitposter.club",
+ last_status_at: nil,
pleroma: %{
ap_id: user.ap_id,
+ also_known_as: [],
background_image: nil,
- favicon:
- "https://shitposter.club/plugins/Qvitter/img/gnusocial-favicons/favicon-16x16.png",
- confirmation_pending: false,
+ favicon: nil,
+ is_confirmed: true,
tags: [],
is_admin: false,
is_moderator: false,
+ is_suggested: false,
hide_favorites: true,
hide_followers: false,
hide_follows: false,
@@ -208,7 +216,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
test "Represent a deactivated user for an admin" do
admin = insert(:user, is_admin: true)
- deactivated_user = insert(:user, deactivated: true)
+ deactivated_user = insert(:user, is_active: false)
represented = AccountView.render("show.json", %{user: deactivated_user, for: admin})
assert represented[:pleroma][:deactivated] == true
end
@@ -264,20 +272,22 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
muting: false,
muting_notifications: false,
subscribing: false,
+ notifying: false,
requested: false,
domain_blocking: false,
showing_reblogs: true,
- endorsed: false
+ endorsed: false,
+ note: ""
}
test "represent a relationship for the following and followed user" do
user = insert(:user)
other_user = insert(:user)
- {:ok, user} = User.follow(user, other_user)
- {:ok, other_user} = User.follow(other_user, user)
+ {:ok, user, other_user} = User.follow(user, other_user)
+ {:ok, other_user, user} = User.follow(other_user, user)
{:ok, _subscription} = User.subscribe(user, other_user)
- {:ok, _user_relationships} = User.mute(user, other_user, true)
+ {:ok, _user_relationships} = User.mute(user, other_user, %{notifications: true})
{:ok, _reblog_mute} = CommonAPI.hide_reblogs(user, other_user)
expected =
@@ -289,6 +299,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
muting: true,
muting_notifications: true,
subscribing: true,
+ notifying: true,
showing_reblogs: false,
id: to_string(other_user.id)
}
@@ -301,7 +312,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
user = insert(:user)
other_user = insert(:user)
- {:ok, user} = User.follow(user, other_user)
+ {:ok, user, other_user} = User.follow(user, other_user)
{:ok, _subscription} = User.subscribe(user, other_user)
{:ok, _user_relationship} = User.block(user, other_user)
{:ok, _user_relationship} = User.block(other_user, user)
@@ -332,7 +343,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
test "represent a relationship for the user with a pending follow request" do
user = insert(:user)
- other_user = insert(:user, locked: true)
+ other_user = insert(:user, is_locked: true)
{:ok, user, other_user, _} = CommonAPI.follow(user, other_user)
user = User.get_cached_by_id(user.id)
@@ -449,7 +460,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
test "shows unread_count only to the account owner" do
user = insert(:user)
- insert_list(7, :notification, user: user)
+ insert_list(7, :notification, user: user, activity: insert(:note_activity))
other_user = insert(:user)
user = User.get_cached_by_ap_id(user.ap_id)
@@ -464,6 +475,23 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
%{user: user, for: user}
)[:pleroma][:unread_notifications_count] == 7
end
+
+ test "shows email only to the account owner" do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ user = User.get_cached_by_ap_id(user.ap_id)
+
+ assert AccountView.render(
+ "show.json",
+ %{user: user, for: other_user}
+ )[:pleroma][:email] == nil
+
+ assert AccountView.render(
+ "show.json",
+ %{user: user, for: user}
+ )[:pleroma][:email] == user.email
+ end
end
describe "follow requests counter" do
@@ -481,7 +509,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
end
test "shows non-zero when follow requests are pending" do
- user = insert(:user, locked: true)
+ user = insert(:user, is_locked: true)
assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user})
@@ -493,7 +521,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
end
test "decreases when accepting a follow request" do
- user = insert(:user, locked: true)
+ user = insert(:user, is_locked: true)
assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user})
@@ -510,7 +538,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
end
test "decreases when rejecting a follow request" do
- user = insert(:user, locked: true)
+ user = insert(:user, is_locked: true)
assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user})
@@ -527,22 +555,23 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
end
test "shows non-zero when historical unapproved requests are present" do
- user = insert(:user, locked: true)
+ user = insert(:user, is_locked: true)
assert %{locked: true} = AccountView.render("show.json", %{user: user, for: user})
other_user = insert(:user)
{:ok, _other_user, user, _activity} = CommonAPI.follow(other_user, user)
- {:ok, user} = User.update_and_set_cache(user, %{locked: false})
+ {:ok, user} = User.update_and_set_cache(user, %{is_locked: false})
assert %{locked: false, follow_requests_count: 1} =
AccountView.render("show.json", %{user: user, for: user})
end
end
- test "uses mediaproxy urls when it's enabled" do
+ test "uses mediaproxy urls when it's enabled (regardless of media preview proxy state)" do
clear_config([:media_proxy, :enabled], true)
+ clear_config([:media_preview_proxy, :enabled])
user =
insert(:user,
@@ -551,20 +580,24 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do
emoji: %{"joker_smile" => "https://evil.website/society.png"}
)
- AccountView.render("show.json", %{user: user, skip_visibility_check: true})
- |> Enum.all?(fn
- {key, url} when key in [:avatar, :avatar_static, :header, :header_static] ->
- String.starts_with?(url, Pleroma.Web.base_url())
-
- {:emojis, emojis} ->
- Enum.all?(emojis, fn %{url: url, static_url: static_url} ->
- String.starts_with?(url, Pleroma.Web.base_url()) &&
- String.starts_with?(static_url, Pleroma.Web.base_url())
- end)
-
- _ ->
- true
- end)
- |> assert()
+ with media_preview_enabled <- [false, true] do
+ clear_config([:media_preview_proxy, :enabled], media_preview_enabled)
+
+ AccountView.render("show.json", %{user: user, skip_visibility_check: true})
+ |> Enum.all?(fn
+ {key, url} when key in [:avatar, :avatar_static, :header, :header_static] ->
+ String.starts_with?(url, Pleroma.Web.Endpoint.url())
+
+ {:emojis, emojis} ->
+ Enum.all?(emojis, fn %{url: url, static_url: static_url} ->
+ String.starts_with?(url, Pleroma.Web.Endpoint.url()) &&
+ String.starts_with?(static_url, Pleroma.Web.Endpoint.url())
+ end)
+
+ _ ->
+ true
+ end)
+ |> assert()
+ end
end
end
diff --git a/test/web/mastodon_api/views/conversation_view_test.exs b/test/pleroma/web/mastodon_api/views/conversation_view_test.exs
index 2e8203c9b..9639e95d2 100644
--- a/test/web/mastodon_api/views/conversation_view_test.exs
+++ b/test/pleroma/web/mastodon_api/views/conversation_view_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.ConversationViewTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Conversation.Participation
alias Pleroma.Web.CommonAPI
@@ -36,9 +36,11 @@ defmodule Pleroma.Web.MastodonAPI.ConversationViewTest do
assert conversation.id == participation.id |> to_string()
assert conversation.last_status.id == activity.id
+ assert conversation.last_status.account.id == user.id
assert [account] = conversation.accounts
assert account.id == other_user.id
+
assert conversation.last_status.pleroma.direct_conversation_id == participation.id
end
end
diff --git a/test/web/mastodon_api/views/list_view_test.exs b/test/pleroma/web/mastodon_api/views/list_view_test.exs
index ca99242cb..a62495ebb 100644
--- a/test/web/mastodon_api/views/list_view_test.exs
+++ b/test/pleroma/web/mastodon_api/views/list_view_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.ListViewTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
import Pleroma.Factory
alias Pleroma.Web.MastodonAPI.ListView
diff --git a/test/web/mastodon_api/views/marker_view_test.exs b/test/pleroma/web/mastodon_api/views/marker_view_test.exs
index 48a0a6d33..8d8c16f6c 100644
--- a/test/web/mastodon_api/views/marker_view_test.exs
+++ b/test/pleroma/web/mastodon_api/views/marker_view_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.MarkerViewTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Web.MastodonAPI.MarkerView
import Pleroma.Factory
diff --git a/test/web/mastodon_api/views/notification_view_test.exs b/test/pleroma/web/mastodon_api/views/notification_view_test.exs
index 2f6a808f1..8070c03c9 100644
--- a/test/web/mastodon_api/views/notification_view_test.exs
+++ b/test/pleroma/web/mastodon_api/views/notification_view_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
@@ -12,6 +12,8 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.User
+ alias Pleroma.Web.AdminAPI.Report
+ alias Pleroma.Web.AdminAPI.ReportView
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.CommonAPI.Utils
alias Pleroma.Web.MastodonAPI.AccountView
@@ -42,7 +44,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
{:ok, [notification]} = Notification.create_notifications(activity)
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
chat = Chat.get(recipient.id, user.ap_id)
cm_ref = MessageReference.for_chat_and_object(chat, object)
@@ -142,24 +144,11 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
refute Repo.one(Notification)
end
- @tag capture_log: true
test "Move notification" do
old_user = insert(:user)
new_user = insert(:user, also_known_as: [old_user.ap_id])
follower = insert(:user)
- old_user_url = old_user.ap_id
-
- body =
- File.read!("test/fixtures/users_mock/localhost.json")
- |> String.replace("{{nickname}}", old_user.nickname)
- |> Jason.encode!()
-
- Tesla.Mock.mock(fn
- %{method: :get, url: ^old_user_url} ->
- %Tesla.Env{status: 200, body: body}
- end)
-
User.follow(follower, old_user)
Pleroma.Web.ActivityPub.ActivityPub.move(old_user, new_user)
Pleroma.Tests.ObanHelpers.perform_all()
@@ -207,6 +196,47 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
test_notifications_rendering([notification], user, [expected])
end
+ test "Poll notification" do
+ user = insert(:user)
+ activity = insert(:question_activity, user: user)
+ {:ok, [notification]} = Notification.create_poll_notifications(activity)
+
+ expected = %{
+ id: to_string(notification.id),
+ pleroma: %{is_seen: false, is_muted: false},
+ type: "poll",
+ account:
+ AccountView.render("show.json", %{
+ user: user,
+ for: user
+ }),
+ status: StatusView.render("show.json", %{activity: activity, for: user}),
+ created_at: Utils.to_masto_date(notification.inserted_at)
+ }
+
+ test_notifications_rendering([notification], user, [expected])
+ end
+
+ test "Report notification" do
+ reporting_user = insert(:user)
+ reported_user = insert(:user)
+ {:ok, moderator_user} = insert(:user) |> User.admin_api_update(%{is_moderator: true})
+
+ {:ok, activity} = CommonAPI.report(reporting_user, %{account_id: reported_user.id})
+ {:ok, [notification]} = Notification.create_notifications(activity)
+
+ expected = %{
+ id: to_string(notification.id),
+ pleroma: %{is_seen: false, is_muted: false},
+ type: "pleroma:report",
+ account: AccountView.render("show.json", %{user: reporting_user, for: moderator_user}),
+ created_at: Utils.to_masto_date(notification.inserted_at),
+ report: ReportView.render("show.json", Report.extract_report_info(activity))
+ }
+
+ test_notifications_rendering([notification], moderator_user, [expected])
+ end
+
test "muted notification" do
user = insert(:user)
another_user = insert(:user)
diff --git a/test/web/mastodon_api/views/poll_view_test.exs b/test/pleroma/web/mastodon_api/views/poll_view_test.exs
index b7e2f17ef..224b26cb9 100644
--- a/test/web/mastodon_api/views/poll_view_test.exs
+++ b/test/pleroma/web/mastodon_api/views/poll_view_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.PollViewTest do
@@ -29,7 +29,7 @@ defmodule Pleroma.Web.MastodonAPI.PollViewTest do
}
})
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
expected = %{
emojis: [],
@@ -42,9 +42,8 @@ defmodule Pleroma.Web.MastodonAPI.PollViewTest do
%{title: "yes", votes_count: 0},
%{title: "why are you even asking?", votes_count: 0}
],
- voted: false,
votes_count: 0,
- voters_count: nil
+ voters_count: 0
}
result = PollView.render("show.json", %{object: object})
@@ -72,7 +71,7 @@ defmodule Pleroma.Web.MastodonAPI.PollViewTest do
voter = insert(:user)
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
{:ok, _votes, object} = CommonAPI.vote(voter, object, [0, 1])
@@ -98,7 +97,7 @@ defmodule Pleroma.Web.MastodonAPI.PollViewTest do
}
})
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
assert %{emojis: [%{shortcode: "blank"}]} = PollView.render("show.json", %{object: object})
end
@@ -117,19 +116,21 @@ defmodule Pleroma.Web.MastodonAPI.PollViewTest do
}
})
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
{:ok, _, object} = CommonAPI.vote(other_user, object, [1, 2])
result = PollView.render("show.json", %{object: object, for: other_user})
assert result[:voted] == true
+ assert 1 in result[:own_votes]
+ assert 2 in result[:own_votes]
assert Enum.at(result[:options], 1)[:votes_count] == 1
assert Enum.at(result[:options], 2)[:votes_count] == 1
end
test "does not crash on polls with no end date" do
- object = Object.normalize("https://skippers-bin.com/notes/7x9tmrp97i")
+ object = Object.normalize("https://skippers-bin.com/notes/7x9tmrp97i", fetch: true)
result = PollView.render("show.json", %{object: object})
assert result[:expires_at] == nil
@@ -153,7 +154,7 @@ defmodule Pleroma.Web.MastodonAPI.PollViewTest do
}
})
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
assert %{
options: [
diff --git a/test/web/mastodon_api/views/scheduled_activity_view_test.exs b/test/pleroma/web/mastodon_api/views/scheduled_activity_view_test.exs
index fbfd873ef..e323f3a1f 100644
--- a/test/web/mastodon_api/views/scheduled_activity_view_test.exs
+++ b/test/pleroma/web/mastodon_api/views/scheduled_activity_view_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.ScheduledActivityViewTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.ScheduledActivity
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.CommonAPI
@@ -22,7 +22,7 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityViewTest do
|> NaiveDateTime.to_iso8601()
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}
@@ -58,7 +58,8 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityViewTest do
sensitive: true,
spoiler_text: "spoiler",
text: "hi",
- visibility: "unlisted"
+ visibility: "unlisted",
+ expires_in: nil
},
scheduled_at: Utils.to_masto_date(scheduled_activity.scheduled_at)
}
diff --git a/test/web/mastodon_api/views/status_view_test.exs b/test/pleroma/web/mastodon_api/views/status_view_test.exs
index 70d829979..9dfdf8bf0 100644
--- a/test/web/mastodon_api/views/status_view_test.exs
+++ b/test/pleroma/web/mastodon_api/views/status_view_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
@@ -61,7 +61,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
{:ok, activity} = CommonAPI.post(user, %{status: "yo"})
activity
- |> Object.normalize(false)
+ |> Object.normalize(fetch: false)
|> Object.update_data(%{"reactions" => %{"☕" => [user.ap_id], "x" => 1}})
activity = Activity.get_by_id(activity.id)
@@ -73,6 +73,50 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
]
end
+ test "doesn't show reactions from muted and blocked users" do
+ user = insert(:user)
+ other_user = insert(:user)
+ third_user = insert(:user)
+
+ {:ok, activity} = CommonAPI.post(user, %{status: "dae cofe??"})
+
+ {:ok, _} = User.mute(user, other_user)
+ {:ok, _} = User.block(other_user, third_user)
+
+ {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
+
+ activity = Repo.get(Activity, activity.id)
+ status = StatusView.render("show.json", activity: activity)
+
+ assert status[:pleroma][:emoji_reactions] == [
+ %{name: "☕", count: 1, me: false}
+ ]
+
+ status = StatusView.render("show.json", activity: activity, for: user)
+
+ assert status[:pleroma][:emoji_reactions] == []
+
+ {:ok, _} = CommonAPI.react_with_emoji(activity.id, third_user, "☕")
+
+ status = StatusView.render("show.json", activity: activity)
+
+ assert status[:pleroma][:emoji_reactions] == [
+ %{name: "☕", count: 2, me: false}
+ ]
+
+ status = StatusView.render("show.json", activity: activity, for: user)
+
+ assert status[:pleroma][:emoji_reactions] == [
+ %{name: "☕", count: 1, me: false}
+ ]
+
+ status = StatusView.render("show.json", activity: activity, for: other_user)
+
+ assert status[:pleroma][:emoji_reactions] == [
+ %{name: "☕", count: 1, me: true}
+ ]
+ end
+
test "loads and returns the direct conversation id when given the `with_direct_conversation_id` option" do
user = insert(:user)
@@ -116,7 +160,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
{:ok, activity} = CommonAPI.post(user, %{status: "Hey @shp!", visibility: "direct"})
Repo.delete(user)
- Cachex.clear(:user_cache)
+ User.invalidate_cache(user)
finger_url =
"https://localhost/.well-known/webfinger?resource=acct:#{user.nickname}@localhost"
@@ -150,7 +194,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
|> Ecto.Changeset.change(%{ap_id: "#{user.ap_id}/extension/#{user.nickname}"})
|> Repo.update()
- Cachex.clear(:user_cache)
+ User.invalidate_cache(user)
result = StatusView.render("show.json", activity: activity)
@@ -160,7 +204,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
test "a note with null content" do
note = insert(:note_activity)
- note_object = Object.normalize(note)
+ note_object = Object.normalize(note, fetch: false)
data =
note_object.data
@@ -179,7 +223,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
test "a note activity" do
note = insert(:note_activity)
- object_data = Object.normalize(note).data
+ object_data = Object.normalize(note, fetch: false).data
user = User.get_cached_by_ap_id(note.data["actor"])
convo_id = Utils.context_to_conversation_id(object_data["context"])
@@ -218,14 +262,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
mentions: [],
tags: [
%{
- name: "#{object_data["tag"]}",
- url: "/tag/#{object_data["tag"]}"
+ name: "#{hd(object_data["tag"])}",
+ url: "http://localhost:4001/tag/#{hd(object_data["tag"])}"
}
],
- application: %{
- name: "Web",
- website: nil
- },
+ application: nil,
language: nil,
emojis: [
%{
@@ -245,7 +286,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
direct_conversation_id: nil,
thread_muted: false,
emoji_reactions: [],
- parent_visible: false
+ parent_visible: false,
+ pinned_at: nil
}
}
@@ -417,9 +459,12 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
"url" => [
%{
"mediaType" => "image/png",
- "href" => "someurl"
+ "href" => "someurl",
+ "width" => 200,
+ "height" => 100
}
],
+ "blurhash" => "UJJ8X[xYW,%Jtq%NNFbXB5j]IVM|9GV=WHRn",
"uuid" => 6
}
@@ -431,7 +476,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
preview_url: "someurl",
text_url: "someurl",
description: nil,
- pleroma: %{mime_type: "image/png"}
+ pleroma: %{mime_type: "image/png"},
+ meta: %{original: %{width: 200, height: 100, aspect: 2}},
+ blurhash: "UJJ8X[xYW,%Jtq%NNFbXB5j]IVM|9GV=WHRn"
}
api_spec = Pleroma.Web.ApiSpec.spec()
@@ -539,9 +586,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
]
assert StatusView.build_tags(object_tags) == [
- %{name: "fediverse", url: "/tag/fediverse"},
- %{name: "mastodon", url: "/tag/mastodon"},
- %{name: "nextcloud", url: "/tag/nextcloud"}
+ %{name: "fediverse", url: "http://localhost:4001/tag/fediverse"},
+ %{name: "mastodon", url: "http://localhost:4001/tag/mastodon"},
+ %{name: "nextcloud", url: "http://localhost:4001/tag/nextcloud"}
]
end
end
diff --git a/test/web/mastodon_api/views/subscription_view_test.exs b/test/pleroma/web/mastodon_api/views/subscription_view_test.exs
index 981524c0e..04b440389 100644
--- a/test/web/mastodon_api/views/subscription_view_test.exs
+++ b/test/pleroma/web/mastodon_api/views/subscription_view_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.SubscriptionViewTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
import Pleroma.Factory
alias Pleroma.Web.MastodonAPI.SubscriptionView, as: View
alias Pleroma.Web.Push
diff --git a/test/pleroma/web/mastodon_api/views/suggestion_view_test.exs b/test/pleroma/web/mastodon_api/views/suggestion_view_test.exs
new file mode 100644
index 000000000..5aae36ce9
--- /dev/null
+++ b/test/pleroma/web/mastodon_api/views/suggestion_view_test.exs
@@ -0,0 +1,34 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.MastodonAPI.SuggestionViewTest do
+ use Pleroma.DataCase, async: true
+ import Pleroma.Factory
+ alias Pleroma.Web.MastodonAPI.SuggestionView, as: View
+
+ test "show.json" do
+ user = insert(:user, is_suggested: true)
+ json = View.render("show.json", %{user: user, source: :staff, skip_visibility_check: true})
+
+ assert json.source == :staff
+ assert json.account.id == user.id
+ end
+
+ test "index.json" do
+ user1 = insert(:user, is_suggested: true)
+ user2 = insert(:user, is_suggested: true)
+ user3 = insert(:user, is_suggested: true)
+
+ [suggestion1, suggestion2, suggestion3] =
+ View.render("index.json", %{
+ users: [user1, user2, user3],
+ source: :staff,
+ skip_visibility_check: true
+ })
+
+ assert suggestion1.source == :staff
+ assert suggestion2.account.id == user2.id
+ assert suggestion3.account.url == user3.ap_id
+ end
+end
diff --git a/test/web/matrix_controller_test.exs b/test/pleroma/web/matrix_controller_test.exs
index c8273641b..c8273641b 100644
--- a/test/web/matrix_controller_test.exs
+++ b/test/pleroma/web/matrix_controller_test.exs
diff --git a/test/web/media_proxy/invalidations/http_test.exs b/test/pleroma/web/media_proxy/invalidation/http_test.exs
index a1bef5237..a15103c89 100644
--- a/test/web/media_proxy/invalidations/http_test.exs
+++ b/test/pleroma/web/media_proxy/invalidation/http_test.exs
@@ -1,3 +1,7 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.MediaProxy.Invalidation.HttpTest do
use ExUnit.Case
alias Pleroma.Web.MediaProxy.Invalidation
@@ -5,10 +9,6 @@ defmodule Pleroma.Web.MediaProxy.Invalidation.HttpTest do
import ExUnit.CaptureLog
import Tesla.Mock
- setup do
- on_exit(fn -> Cachex.clear(:banned_urls_cache) end)
- end
-
test "logs hasn't error message when request is valid" do
mock(fn
%{method: :purge, url: "http://example.com/media/example.jpg"} ->
diff --git a/test/pleroma/web/media_proxy/invalidation/script_test.exs b/test/pleroma/web/media_proxy/invalidation/script_test.exs
new file mode 100644
index 000000000..e9629b72b
--- /dev/null
+++ b/test/pleroma/web/media_proxy/invalidation/script_test.exs
@@ -0,0 +1,52 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.MediaProxy.Invalidation.ScriptTest do
+ use ExUnit.Case, async: true
+ alias Pleroma.Web.MediaProxy.Invalidation
+
+ import ExUnit.CaptureLog
+
+ test "it logs error when script is not found" do
+ assert capture_log(fn ->
+ assert Invalidation.Script.purge(
+ ["http://example.com/media/example.jpg"],
+ script_path: "./example"
+ ) == {:error, "%ErlangError{original: :enoent}"}
+ end) =~ "Error while cache purge: %ErlangError{original: :enoent}"
+
+ capture_log(fn ->
+ assert Invalidation.Script.purge(
+ ["http://example.com/media/example.jpg"],
+ []
+ ) == {:error, "\"not found script path\""}
+ end)
+ end
+
+ describe "url formatting" do
+ setup do
+ urls = [
+ "https://bikeshed.party/media/foo.png",
+ "http://safe.millennial.space/proxy/wheeeee.gif",
+ "https://lain.com/proxy/mediafile.mp4?foo&bar=true",
+ "http://localhost:4000/media/upload.jpeg"
+ ]
+
+ [urls: urls]
+ end
+
+ test "with invalid formatter", %{urls: urls} do
+ assert urls == Invalidation.Script.maybe_format_urls(urls, nil)
+ end
+
+ test "with :htcacheclean formatter", %{urls: urls} do
+ assert [
+ "https://bikeshed.party:443/media/foo.png?",
+ "http://safe.millennial.space:80/proxy/wheeeee.gif?",
+ "https://lain.com:443/proxy/mediafile.mp4?foo&bar=true",
+ "http://localhost:4000/media/upload.jpeg?"
+ ] == Invalidation.Script.maybe_format_urls(urls, :htcacheclean)
+ end
+ end
+end
diff --git a/test/web/media_proxy/invalidation_test.exs b/test/pleroma/web/media_proxy/invalidation_test.exs
index 926ae74ca..c77b8c94a 100644
--- a/test/web/media_proxy/invalidation_test.exs
+++ b/test/pleroma/web/media_proxy/invalidation_test.exs
@@ -1,8 +1,10 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.MediaProxy.InvalidationTest do
- use ExUnit.Case
- use Pleroma.Tests.Helpers
+ use Pleroma.DataCase
- alias Pleroma.Config
alias Pleroma.Web.MediaProxy.Invalidation
import ExUnit.CaptureLog
@@ -11,17 +13,13 @@ defmodule Pleroma.Web.MediaProxy.InvalidationTest do
setup do: clear_config([:media_proxy])
- setup do
- on_exit(fn -> Cachex.clear(:banned_urls_cache) end)
- end
-
describe "Invalidation.Http" do
test "perform request to clear cache" do
- Config.put([:media_proxy, :enabled], false)
- Config.put([:media_proxy, :invalidation, :enabled], true)
- Config.put([:media_proxy, :invalidation, :provider], Invalidation.Http)
+ clear_config([:media_proxy, :enabled], false)
+ clear_config([:media_proxy, :invalidation, :enabled], true)
+ clear_config([:media_proxy, :invalidation, :provider], Invalidation.Http)
- Config.put([Invalidation.Http], method: :purge, headers: [{"x-refresh", 1}])
+ clear_config([Invalidation.Http], method: :purge, headers: [{"x-refresh", 1}])
image_url = "http://example.com/media/example.jpg"
Pleroma.Web.MediaProxy.put_in_banned_urls(image_url)
@@ -44,10 +42,10 @@ defmodule Pleroma.Web.MediaProxy.InvalidationTest do
describe "Invalidation.Script" do
test "run script to clear cache" do
- Config.put([:media_proxy, :enabled], false)
- Config.put([:media_proxy, :invalidation, :enabled], true)
- Config.put([:media_proxy, :invalidation, :provider], Invalidation.Script)
- Config.put([Invalidation.Script], script_path: "purge-nginx")
+ clear_config([:media_proxy, :enabled], false)
+ clear_config([:media_proxy, :invalidation, :enabled], true)
+ clear_config([:media_proxy, :invalidation, :provider], Invalidation.Script)
+ clear_config([Invalidation.Script], script_path: "purge-nginx")
image_url = "http://example.com/media/example.jpg"
Pleroma.Web.MediaProxy.put_in_banned_urls(image_url)
diff --git a/test/pleroma/web/media_proxy/media_proxy_controller_test.exs b/test/pleroma/web/media_proxy/media_proxy_controller_test.exs
new file mode 100644
index 000000000..1f2e54194
--- /dev/null
+++ b/test/pleroma/web/media_proxy/media_proxy_controller_test.exs
@@ -0,0 +1,336 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do
+ use Pleroma.Web.ConnCase
+
+ import Mock
+
+ alias Pleroma.Web.MediaProxy
+ alias Plug.Conn
+
+ describe "Media Proxy" do
+ setup do
+ clear_config([:media_proxy, :enabled], true)
+ clear_config([Pleroma.Web.Endpoint, :secret_key_base], "00000000000")
+
+ [url: MediaProxy.encode_url("https://google.fn/test.png")]
+ end
+
+ test "it returns 404 when disabled", %{conn: conn} do
+ clear_config([:media_proxy, :enabled], false)
+
+ assert %Conn{
+ status: 404,
+ resp_body: "Not Found"
+ } = get(conn, "/proxy/hhgfh/eeeee")
+
+ assert %Conn{
+ status: 404,
+ resp_body: "Not Found"
+ } = get(conn, "/proxy/hhgfh/eeee/fff")
+ end
+
+ test "it returns 403 for invalid signature", %{conn: conn, url: url} do
+ clear_config([Pleroma.Web.Endpoint, :secret_key_base], "000")
+ %{path: path} = URI.parse(url)
+
+ assert %Conn{
+ status: 403,
+ resp_body: "Forbidden"
+ } = get(conn, path)
+
+ assert %Conn{
+ status: 403,
+ resp_body: "Forbidden"
+ } = get(conn, "/proxy/hhgfh/eeee")
+
+ assert %Conn{
+ status: 403,
+ resp_body: "Forbidden"
+ } = get(conn, "/proxy/hhgfh/eeee/fff")
+ end
+
+ test "redirects to valid url when filename is invalidated", %{conn: conn, url: url} do
+ invalid_url = String.replace(url, "test.png", "test-file.png")
+ response = get(conn, invalid_url)
+ assert response.status == 302
+ assert redirected_to(response) == url
+ end
+
+ test "it performs ReverseProxy.call with valid signature", %{conn: conn, url: url} do
+ with_mock Pleroma.ReverseProxy,
+ call: fn _conn, _url, _opts -> %Conn{status: :success} end do
+ assert %Conn{status: :success} = get(conn, url)
+ end
+ end
+
+ test "it returns 404 when url is in banned_urls cache", %{conn: conn, url: url} do
+ MediaProxy.put_in_banned_urls("https://google.fn/test.png")
+
+ with_mock Pleroma.ReverseProxy,
+ call: fn _conn, _url, _opts -> %Conn{status: :success} end do
+ assert %Conn{status: 404, resp_body: "Not Found"} = get(conn, url)
+ end
+ end
+ end
+
+ describe "Media Preview Proxy" do
+ def assert_dependencies_installed do
+ missing_dependencies = Pleroma.Helpers.MediaHelper.missing_dependencies()
+
+ assert missing_dependencies == [],
+ "Error: missing dependencies (please refer to `docs/installation`): #{inspect(missing_dependencies)}"
+ end
+
+ setup do
+ clear_config([:media_proxy, :enabled], true)
+ clear_config([:media_preview_proxy, :enabled], true)
+ clear_config([Pleroma.Web.Endpoint, :secret_key_base], "00000000000")
+
+ original_url = "https://google.fn/test.png"
+
+ [
+ url: MediaProxy.encode_preview_url(original_url),
+ media_proxy_url: MediaProxy.encode_url(original_url)
+ ]
+ end
+
+ test "returns 404 when media proxy is disabled", %{conn: conn} do
+ clear_config([:media_proxy, :enabled], false)
+
+ assert %Conn{
+ status: 404,
+ resp_body: "Not Found"
+ } = get(conn, "/proxy/preview/hhgfh/eeeee")
+
+ assert %Conn{
+ status: 404,
+ resp_body: "Not Found"
+ } = get(conn, "/proxy/preview/hhgfh/fff")
+ end
+
+ test "returns 404 when disabled", %{conn: conn} do
+ clear_config([:media_preview_proxy, :enabled], false)
+
+ assert %Conn{
+ status: 404,
+ resp_body: "Not Found"
+ } = get(conn, "/proxy/preview/hhgfh/eeeee")
+
+ assert %Conn{
+ status: 404,
+ resp_body: "Not Found"
+ } = get(conn, "/proxy/preview/hhgfh/fff")
+ end
+
+ test "it returns 403 for invalid signature", %{conn: conn, url: url} do
+ clear_config([Pleroma.Web.Endpoint, :secret_key_base], "000")
+ %{path: path} = URI.parse(url)
+
+ assert %Conn{
+ status: 403,
+ resp_body: "Forbidden"
+ } = get(conn, path)
+
+ assert %Conn{
+ status: 403,
+ resp_body: "Forbidden"
+ } = get(conn, "/proxy/preview/hhgfh/eeee")
+
+ assert %Conn{
+ status: 403,
+ resp_body: "Forbidden"
+ } = get(conn, "/proxy/preview/hhgfh/eeee/fff")
+ end
+
+ test "redirects to valid url when filename is invalidated", %{conn: conn, url: url} do
+ invalid_url = String.replace(url, "test.png", "test-file.png")
+ response = get(conn, invalid_url)
+ assert response.status == 302
+ assert redirected_to(response) == url
+ end
+
+ test "responds with 424 Failed Dependency if HEAD request to media proxy fails", %{
+ conn: conn,
+ url: url,
+ media_proxy_url: media_proxy_url
+ } do
+ Tesla.Mock.mock(fn
+ %{method: "head", url: ^media_proxy_url} ->
+ %Tesla.Env{status: 500, body: ""}
+ end)
+
+ response = get(conn, url)
+ assert response.status == 424
+ assert response.resp_body == "Can't fetch HTTP headers (HTTP 500)."
+ end
+
+ test "redirects to media proxy URI on unsupported content type", %{
+ conn: conn,
+ url: url,
+ media_proxy_url: media_proxy_url
+ } do
+ Tesla.Mock.mock(fn
+ %{method: "head", url: ^media_proxy_url} ->
+ %Tesla.Env{status: 200, body: "", headers: [{"content-type", "application/pdf"}]}
+ end)
+
+ response = get(conn, url)
+ assert response.status == 302
+ assert redirected_to(response) == media_proxy_url
+ end
+
+ test "with `static=true` and GIF image preview requested, responds with JPEG image", %{
+ conn: conn,
+ url: url,
+ media_proxy_url: media_proxy_url
+ } do
+ assert_dependencies_installed()
+
+ # Setting a high :min_content_length to ensure this scenario is not affected by its logic
+ clear_config([:media_preview_proxy, :min_content_length], 1_000_000_000)
+
+ Tesla.Mock.mock(fn
+ %{method: "head", url: ^media_proxy_url} ->
+ %Tesla.Env{
+ status: 200,
+ body: "",
+ headers: [{"content-type", "image/gif"}, {"content-length", "1001718"}]
+ }
+
+ %{method: :get, url: ^media_proxy_url} ->
+ %Tesla.Env{status: 200, body: File.read!("test/fixtures/image.gif")}
+ end)
+
+ response = get(conn, url <> "?static=true")
+
+ assert response.status == 200
+ assert Conn.get_resp_header(response, "content-type") == ["image/jpeg"]
+ assert response.resp_body != ""
+ end
+
+ test "with GIF image preview requested and no `static` param, redirects to media proxy URI",
+ %{
+ conn: conn,
+ url: url,
+ media_proxy_url: media_proxy_url
+ } do
+ Tesla.Mock.mock(fn
+ %{method: "head", url: ^media_proxy_url} ->
+ %Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/gif"}]}
+ end)
+
+ response = get(conn, url)
+
+ assert response.status == 302
+ assert redirected_to(response) == media_proxy_url
+ end
+
+ test "with `static` param and non-GIF image preview requested, " <>
+ "redirects to media preview proxy URI without `static` param",
+ %{
+ conn: conn,
+ url: url,
+ media_proxy_url: media_proxy_url
+ } do
+ Tesla.Mock.mock(fn
+ %{method: "head", url: ^media_proxy_url} ->
+ %Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/jpeg"}]}
+ end)
+
+ response = get(conn, url <> "?static=true")
+
+ assert response.status == 302
+ assert redirected_to(response) == url
+ end
+
+ test "with :min_content_length setting not matched by Content-Length header, " <>
+ "redirects to media proxy URI",
+ %{
+ conn: conn,
+ url: url,
+ media_proxy_url: media_proxy_url
+ } do
+ clear_config([:media_preview_proxy, :min_content_length], 100_000)
+
+ Tesla.Mock.mock(fn
+ %{method: "head", url: ^media_proxy_url} ->
+ %Tesla.Env{
+ status: 200,
+ body: "",
+ headers: [{"content-type", "image/gif"}, {"content-length", "5000"}]
+ }
+ end)
+
+ response = get(conn, url)
+
+ assert response.status == 302
+ assert redirected_to(response) == media_proxy_url
+ end
+
+ test "thumbnails PNG images into PNG", %{
+ conn: conn,
+ url: url,
+ media_proxy_url: media_proxy_url
+ } do
+ assert_dependencies_installed()
+
+ Tesla.Mock.mock(fn
+ %{method: "head", url: ^media_proxy_url} ->
+ %Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/png"}]}
+
+ %{method: :get, url: ^media_proxy_url} ->
+ %Tesla.Env{status: 200, body: File.read!("test/fixtures/image.png")}
+ end)
+
+ response = get(conn, url)
+
+ assert response.status == 200
+ assert Conn.get_resp_header(response, "content-type") == ["image/png"]
+ assert response.resp_body != ""
+ end
+
+ test "thumbnails JPEG images into JPEG", %{
+ conn: conn,
+ url: url,
+ media_proxy_url: media_proxy_url
+ } do
+ assert_dependencies_installed()
+
+ Tesla.Mock.mock(fn
+ %{method: "head", url: ^media_proxy_url} ->
+ %Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/jpeg"}]}
+
+ %{method: :get, url: ^media_proxy_url} ->
+ %Tesla.Env{status: 200, body: File.read!("test/fixtures/image.jpg")}
+ end)
+
+ response = get(conn, url)
+
+ assert response.status == 200
+ assert Conn.get_resp_header(response, "content-type") == ["image/jpeg"]
+ assert response.resp_body != ""
+ end
+
+ test "redirects to media proxy URI in case of thumbnailing error", %{
+ conn: conn,
+ url: url,
+ media_proxy_url: media_proxy_url
+ } do
+ Tesla.Mock.mock(fn
+ %{method: "head", url: ^media_proxy_url} ->
+ %Tesla.Env{status: 200, body: "", headers: [{"content-type", "image/jpeg"}]}
+
+ %{method: :get, url: ^media_proxy_url} ->
+ %Tesla.Env{status: 200, body: "<html><body>error</body></html>"}
+ end)
+
+ response = get(conn, url)
+
+ assert response.status == 302
+ assert redirected_to(response) == media_proxy_url
+ end
+ end
+end
diff --git a/test/web/media_proxy/media_proxy_test.exs b/test/pleroma/web/media_proxy_test.exs
index 72885cfdd..d97874f3a 100644
--- a/test/web/media_proxy/media_proxy_test.exs
+++ b/test/pleroma/web/media_proxy_test.exs
@@ -1,14 +1,20 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MediaProxyTest do
use ExUnit.Case
use Pleroma.Tests.Helpers
+ alias Pleroma.Config
alias Pleroma.Web.Endpoint
alias Pleroma.Web.MediaProxy
+ defp decode_result(encoded) do
+ {:ok, decoded} = MediaProxy.decode_url(encoded)
+ decoded
+ end
+
describe "when enabled" do
setup do: clear_config([:media_proxy, :enabled], true)
@@ -35,7 +41,7 @@ defmodule Pleroma.Web.MediaProxyTest do
assert String.starts_with?(
encoded,
- Pleroma.Config.get([:media_proxy, :base_url], Pleroma.Web.base_url())
+ Config.get([:media_proxy, :base_url], Pleroma.Web.Endpoint.url())
)
assert String.ends_with?(encoded, "/logo.png")
@@ -75,6 +81,64 @@ defmodule Pleroma.Web.MediaProxyTest do
assert MediaProxy.decode_url(sig, base64) == {:error, :invalid_signature}
end
+ def test_verify_request_path_and_url(request_path, url, expected_result) do
+ assert MediaProxy.verify_request_path_and_url(request_path, url) == expected_result
+
+ assert MediaProxy.verify_request_path_and_url(
+ %Plug.Conn{
+ params: %{"filename" => Path.basename(request_path)},
+ request_path: request_path
+ },
+ url
+ ) == expected_result
+ end
+
+ test "if first arg of `verify_request_path_and_url/2` is a Plug.Conn without \"filename\" " <>
+ "parameter, `verify_request_path_and_url/2` returns :ok " do
+ assert MediaProxy.verify_request_path_and_url(
+ %Plug.Conn{params: %{}, request_path: "/some/path"},
+ "https://instance.com/file.jpg"
+ ) == :ok
+
+ assert MediaProxy.verify_request_path_and_url(
+ %Plug.Conn{params: %{}, request_path: "/path/to/file.jpg"},
+ "https://instance.com/file.jpg"
+ ) == :ok
+ end
+
+ test "`verify_request_path_and_url/2` preserves the encoded or decoded path" do
+ test_verify_request_path_and_url(
+ "/Hello world.jpg",
+ "http://pleroma.social/Hello world.jpg",
+ :ok
+ )
+
+ test_verify_request_path_and_url(
+ "/Hello%20world.jpg",
+ "http://pleroma.social/Hello%20world.jpg",
+ :ok
+ )
+
+ test_verify_request_path_and_url(
+ "/my%2Flong%2Furl%2F2019%2F07%2FS.jpg",
+ "http://pleroma.social/my%2Flong%2Furl%2F2019%2F07%2FS.jpg",
+ :ok
+ )
+
+ test_verify_request_path_and_url(
+ # Note: `conn.request_path` returns encoded url
+ "/ANALYSE-DAI-_-LE-STABLECOIN-100-D%C3%89CENTRALIS%C3%89-BQ.jpg",
+ "https://mydomain.com/uploads/2019/07/ANALYSE-DAI-_-LE-STABLECOIN-100-DÉCENTRALISÉ-BQ.jpg",
+ :ok
+ )
+
+ test_verify_request_path_and_url(
+ "/my%2Flong%2Furl%2F2019%2F07%2FS",
+ "http://pleroma.social/my%2Flong%2Furl%2F2019%2F07%2FS.jpg",
+ {:wrong_filename, "my%2Flong%2Furl%2F2019%2F07%2FS.jpg"}
+ )
+ end
+
test "uses the configured base_url" do
base_url = "https://cache.pleroma.social"
clear_config([:media_proxy, :base_url], base_url)
@@ -124,12 +188,6 @@ defmodule Pleroma.Web.MediaProxyTest do
end
end
- defp decode_result(encoded) do
- [_, "proxy", sig, base64 | _] = URI.parse(encoded).path |> String.split("/")
- {:ok, decoded} = MediaProxy.decode_url(sig, base64)
- decoded
- end
-
describe "whitelist" do
setup do: clear_config([:media_proxy, :enabled], true)
diff --git a/test/web/metadata/player_view_test.exs b/test/pleroma/web/metadata/player_view_test.exs
index e6c990242..58caf6efd 100644
--- a/test/web/metadata/player_view_test.exs
+++ b/test/pleroma/web/metadata/player_view_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Metadata.PlayerViewTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Web.Metadata.PlayerView
diff --git a/test/web/metadata/feed_test.exs b/test/pleroma/web/metadata/providers/feed_test.exs
index e6e5cc5ed..013d42498 100644
--- a/test/web/metadata/feed_test.exs
+++ b/test/pleroma/web/metadata/providers/feed_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Metadata.Providers.FeedTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
import Pleroma.Factory
alias Pleroma.Web.Metadata.Providers.Feed
diff --git a/test/pleroma/web/metadata/providers/open_graph_test.exs b/test/pleroma/web/metadata/providers/open_graph_test.exs
new file mode 100644
index 000000000..28ca8839c
--- /dev/null
+++ b/test/pleroma/web/metadata/providers/open_graph_test.exs
@@ -0,0 +1,190 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Metadata.Providers.OpenGraphTest do
+ use Pleroma.DataCase
+ import Pleroma.Factory
+ alias Pleroma.Web.Metadata.Providers.OpenGraph
+
+ setup do: clear_config([Pleroma.Web.Metadata, :unfurl_nsfw])
+
+ test "it renders all supported types of attachments and skips unknown types" do
+ user = insert(:user)
+
+ note =
+ insert(:note, %{
+ data: %{
+ "actor" => user.ap_id,
+ "tag" => [],
+ "id" => "https://pleroma.gov/objects/whatever",
+ "content" => "pleroma in a nutshell",
+ "attachment" => [
+ %{
+ "url" => [
+ %{
+ "mediaType" => "image/png",
+ "href" => "https://pleroma.gov/tenshi.png",
+ "height" => 1024,
+ "width" => 1280
+ }
+ ]
+ },
+ %{
+ "url" => [
+ %{
+ "mediaType" => "application/octet-stream",
+ "href" => "https://pleroma.gov/fqa/badapple.sfc"
+ }
+ ]
+ },
+ %{
+ "url" => [
+ %{
+ "mediaType" => "video/webm",
+ "href" => "https://pleroma.gov/about/juche.webm",
+ "height" => 600,
+ "width" => 800
+ }
+ ]
+ },
+ %{
+ "url" => [
+ %{
+ "mediaType" => "audio/basic",
+ "href" => "http://www.gnu.org/music/free-software-song.au"
+ }
+ ]
+ }
+ ]
+ }
+ })
+
+ result = OpenGraph.build_tags(%{object: note, url: note.data["id"], user: user})
+
+ assert Enum.all?(
+ [
+ {:meta, [property: "og:image", content: "https://pleroma.gov/tenshi.png"], []},
+ {:meta, [property: "og:image:width", content: "1280"], []},
+ {:meta, [property: "og:image:height", content: "1024"], []},
+ {:meta,
+ [property: "og:audio", content: "http://www.gnu.org/music/free-software-song.au"],
+ []},
+ {:meta, [property: "og:video", content: "https://pleroma.gov/about/juche.webm"],
+ []},
+ {:meta, [property: "og:video:width", content: "800"], []},
+ {:meta, [property: "og:video:height", content: "600"], []}
+ ],
+ fn element -> element in result end
+ )
+ end
+
+ test "it does not render attachments if post is nsfw" do
+ clear_config([Pleroma.Web.Metadata, :unfurl_nsfw], false)
+ user = insert(:user, avatar: %{"url" => [%{"href" => "https://pleroma.gov/tenshi.png"}]})
+
+ note =
+ insert(:note, %{
+ data: %{
+ "actor" => user.ap_id,
+ "id" => "https://pleroma.gov/objects/whatever",
+ "content" => "#cuteposting #nsfw #hambaga",
+ "tag" => ["cuteposting", "nsfw", "hambaga"],
+ "sensitive" => true,
+ "attachment" => [
+ %{
+ "url" => [
+ %{"mediaType" => "image/png", "href" => "https://misskey.microsoft/corndog.png"}
+ ]
+ }
+ ]
+ }
+ })
+
+ result = OpenGraph.build_tags(%{object: note, url: note.data["id"], user: user})
+
+ assert {:meta, [property: "og:image", content: "https://pleroma.gov/tenshi.png"], []} in result
+
+ refute {:meta, [property: "og:image", content: "https://misskey.microsoft/corndog.png"], []} in result
+ end
+
+ test "video attachments have image thumbnail with WxH metadata with Preview Proxy enabled" do
+ clear_config([:media_proxy, :enabled], true)
+ clear_config([:media_preview_proxy, :enabled], true)
+ user = insert(:user)
+
+ note =
+ insert(:note, %{
+ data: %{
+ "actor" => user.ap_id,
+ "id" => "https://pleroma.gov/objects/whatever",
+ "content" => "test video post",
+ "sensitive" => false,
+ "attachment" => [
+ %{
+ "url" => [
+ %{
+ "mediaType" => "video/webm",
+ "href" => "https://pleroma.gov/about/juche.webm",
+ "height" => 600,
+ "width" => 800
+ }
+ ]
+ }
+ ]
+ }
+ })
+
+ result = OpenGraph.build_tags(%{object: note, url: note.data["id"], user: user})
+
+ assert {:meta, [property: "og:image:width", content: "800"], []} in result
+ assert {:meta, [property: "og:image:height", content: "600"], []} in result
+
+ assert {:meta,
+ [
+ property: "og:image",
+ content:
+ "http://localhost:4001/proxy/preview/LzAnlke-l5oZbNzWsrHfprX1rGw/aHR0cHM6Ly9wbGVyb21hLmdvdi9hYm91dC9qdWNoZS53ZWJt/juche.webm"
+ ], []} in result
+ end
+
+ test "video attachments have no image thumbnail with Preview Proxy disabled" do
+ clear_config([:media_proxy, :enabled], true)
+ clear_config([:media_preview_proxy, :enabled], false)
+ user = insert(:user)
+
+ note =
+ insert(:note, %{
+ data: %{
+ "actor" => user.ap_id,
+ "id" => "https://pleroma.gov/objects/whatever",
+ "content" => "test video post",
+ "sensitive" => false,
+ "attachment" => [
+ %{
+ "url" => [
+ %{
+ "mediaType" => "video/webm",
+ "href" => "https://pleroma.gov/about/juche.webm",
+ "height" => 600,
+ "width" => 800
+ }
+ ]
+ }
+ ]
+ }
+ })
+
+ result = OpenGraph.build_tags(%{object: note, url: note.data["id"], user: user})
+
+ refute {:meta, [property: "og:image:width", content: "800"], []} in result
+ refute {:meta, [property: "og:image:height", content: "600"], []} in result
+
+ refute {:meta,
+ [
+ property: "og:image",
+ content:
+ "http://localhost:4001/proxy/preview/LzAnlke-l5oZbNzWsrHfprX1rGw/aHR0cHM6Ly9wbGVyb21hLmdvdi9hYm91dC9qdWNoZS53ZWJt/juche.webm"
+ ], []} in result
+ end
+end
diff --git a/test/web/metadata/rel_me_test.exs b/test/pleroma/web/metadata/providers/rel_me_test.exs
index 2293d6e13..0db6e7d22 100644
--- a/test/web/metadata/rel_me_test.exs
+++ b/test/pleroma/web/metadata/providers/rel_me_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Metadata.Providers.RelMeTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
import Pleroma.Factory
alias Pleroma.Web.Metadata.Providers.RelMe
diff --git a/test/web/metadata/restrict_indexing_test.exs b/test/pleroma/web/metadata/providers/restrict_indexing_test.exs
index aad0bac42..aa253e5e2 100644
--- a/test/web/metadata/restrict_indexing_test.exs
+++ b/test/pleroma/web/metadata/providers/restrict_indexing_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Metadata.Providers.RestrictIndexingTest do
@@ -14,8 +14,14 @@ defmodule Pleroma.Web.Metadata.Providers.RestrictIndexingTest do
test "for local user" do
assert Pleroma.Web.Metadata.Providers.RestrictIndexing.build_tags(%{
- user: %Pleroma.User{local: true}
+ user: %Pleroma.User{local: true, is_discoverable: true}
}) == []
end
+
+ test "for local user when `is_discoverable` is false" do
+ assert Pleroma.Web.Metadata.Providers.RestrictIndexing.build_tags(%{
+ user: %Pleroma.User{local: true, is_discoverable: false}
+ }) == [{:meta, [name: "robots", content: "noindex, noarchive"], []}]
+ end
end
end
diff --git a/test/web/metadata/twitter_card_test.exs b/test/pleroma/web/metadata/providers/twitter_card_test.exs
index 10931b5ba..1b8d27cda 100644
--- a/test/web/metadata/twitter_card_test.exs
+++ b/test/pleroma/web/metadata/providers/twitter_card_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do
@@ -9,6 +9,7 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do
alias Pleroma.User
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.Endpoint
+ alias Pleroma.Web.MediaProxy
alias Pleroma.Web.Metadata.Providers.TwitterCard
alias Pleroma.Web.Metadata.Utils
alias Pleroma.Web.Router
@@ -17,7 +18,7 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do
test "it renders twitter card for user info" do
user = insert(:user, name: "Jimmy Hendriks", bio: "born 19 March 1994")
- avatar_url = Utils.attachment_url(User.avatar_url(user))
+ avatar_url = MediaProxy.preview_url(User.avatar_url(user))
res = TwitterCard.build_tags(%{user: user})
assert res == [
@@ -46,7 +47,7 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do
assert [
{:meta, [property: "twitter:title", content: Utils.user_name_string(user)], []},
- {:meta, [property: "twitter:description", content: "“pleroma in a nutshell”"], []},
+ {:meta, [property: "twitter:description", content: "pleroma in a nutshell"], []},
{:meta, [property: "twitter:image", content: "http://localhost:4001/images/avi.png"],
[]},
{:meta, [property: "twitter:card", content: "summary"], []}
@@ -54,7 +55,7 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do
end
test "it renders avatar not attachment if post is nsfw and unfurl_nsfw is disabled" do
- Pleroma.Config.put([Pleroma.Web.Metadata, :unfurl_nsfw], false)
+ clear_config([Pleroma.Web.Metadata, :unfurl_nsfw], false)
user = insert(:user, name: "Jimmy Hendriks", bio: "born 19 March 1994")
{:ok, activity} = CommonAPI.post(user, %{status: "HI"})
@@ -91,7 +92,7 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do
assert [
{:meta, [property: "twitter:title", content: Utils.user_name_string(user)], []},
- {:meta, [property: "twitter:description", content: "“pleroma in a nutshell”"], []},
+ {:meta, [property: "twitter:description", content: "pleroma in a nutshell"], []},
{:meta, [property: "twitter:image", content: "http://localhost:4001/images/avi.png"],
[]},
{:meta, [property: "twitter:card", content: "summary"], []}
@@ -111,7 +112,14 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do
"content" => "pleroma in a nutshell",
"attachment" => [
%{
- "url" => [%{"mediaType" => "image/png", "href" => "https://pleroma.gov/tenshi.png"}]
+ "url" => [
+ %{
+ "mediaType" => "image/png",
+ "href" => "https://pleroma.gov/tenshi.png",
+ "height" => 1024,
+ "width" => 1280
+ }
+ ]
},
%{
"url" => [
@@ -123,7 +131,12 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do
},
%{
"url" => [
- %{"mediaType" => "video/webm", "href" => "https://pleroma.gov/about/juche.webm"}
+ %{
+ "mediaType" => "video/webm",
+ "href" => "https://pleroma.gov/about/juche.webm",
+ "height" => 600,
+ "width" => 800
+ }
]
}
]
@@ -134,17 +147,25 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCardTest do
assert [
{:meta, [property: "twitter:title", content: Utils.user_name_string(user)], []},
- {:meta, [property: "twitter:description", content: "“pleroma in a nutshell”"], []},
+ {:meta, [property: "twitter:description", content: "pleroma in a nutshell"], []},
{:meta, [property: "twitter:card", content: "summary_large_image"], []},
{:meta, [property: "twitter:player", content: "https://pleroma.gov/tenshi.png"], []},
+ {:meta, [property: "twitter:player:width", content: "1280"], []},
+ {:meta, [property: "twitter:player:height", content: "1024"], []},
{:meta, [property: "twitter:card", content: "player"], []},
{:meta,
[
property: "twitter:player",
content: Router.Helpers.o_status_url(Endpoint, :notice_player, activity.id)
], []},
- {:meta, [property: "twitter:player:width", content: "480"], []},
- {:meta, [property: "twitter:player:height", content: "480"], []}
+ {:meta, [property: "twitter:player:width", content: "800"], []},
+ {:meta, [property: "twitter:player:height", content: "600"], []},
+ {:meta,
+ [
+ property: "twitter:player:stream",
+ content: "https://pleroma.gov/about/juche.webm"
+ ], []},
+ {:meta, [property: "twitter:player:stream:content_type", content: "video/webm"], []}
] == result
end
end
diff --git a/test/web/metadata/utils_test.exs b/test/pleroma/web/metadata/utils_test.exs
index 8183256d8..074bd2e2f 100644
--- a/test/web/metadata/utils_test.exs
+++ b/test/pleroma/web/metadata/utils_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Metadata.UtilsTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
import Pleroma.Factory
alias Pleroma.Web.Metadata.Utils
diff --git a/test/web/mongooseim/mongoose_im_controller_test.exs b/test/pleroma/web/mongoose_im_controller_test.exs
index 5176cde84..43c4dfa33 100644
--- a/test/web/mongooseim/mongoose_im_controller_test.exs
+++ b/test/pleroma/web/mongoose_im_controller_test.exs
@@ -1,15 +1,15 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Web.MongooseIMController do
- use Pleroma.Web.ConnCase
+defmodule Pleroma.Web.MongooseIMControllerTest do
+ use Pleroma.Web.ConnCase, async: true
import Pleroma.Factory
test "/user_exists", %{conn: conn} do
_user = insert(:user, nickname: "lain")
_remote_user = insert(:user, nickname: "alice", local: false)
- _deactivated_user = insert(:user, nickname: "konata", deactivated: true)
+ _deactivated_user = insert(:user, nickname: "konata", is_active: false)
res =
conn
@@ -41,13 +41,13 @@ defmodule Pleroma.Web.MongooseIMController do
end
test "/check_password", %{conn: conn} do
- user = insert(:user, password_hash: Pbkdf2.hash_pwd_salt("cool"))
+ user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("cool"))
_deactivated_user =
insert(:user,
nickname: "konata",
- deactivated: true,
- password_hash: Pbkdf2.hash_pwd_salt("cool")
+ is_active: false,
+ password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("cool")
)
res =
diff --git a/test/web/node_info_test.exs b/test/pleroma/web/node_info_test.exs
index 06b33607f..9deceb1b5 100644
--- a/test/web/node_info_test.exs
+++ b/test/pleroma/web/node_info_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.NodeInfoTest do
@@ -7,8 +7,6 @@ defmodule Pleroma.Web.NodeInfoTest do
import Pleroma.Factory
- alias Pleroma.Config
-
setup do: clear_config([:mrf_simple])
setup do: clear_config(:instance)
@@ -93,7 +91,7 @@ defmodule Pleroma.Web.NodeInfoTest do
assert "safe_dm_mentions" in response["metadata"]["features"]
- Config.put([:instance, :safe_dm_mentions], false)
+ clear_config([:instance, :safe_dm_mentions], false)
response =
conn
@@ -107,7 +105,7 @@ defmodule Pleroma.Web.NodeInfoTest do
setup do: clear_config([:instance, :federating])
test "it shows if federation is enabled/disabled", %{conn: conn} do
- Config.put([:instance, :federating], true)
+ clear_config([:instance, :federating], true)
response =
conn
@@ -116,7 +114,7 @@ defmodule Pleroma.Web.NodeInfoTest do
assert response["metadata"]["federation"]["enabled"] == true
- Config.put([:instance, :federating], false)
+ clear_config([:instance, :federating], false)
response =
conn
@@ -152,37 +150,127 @@ defmodule Pleroma.Web.NodeInfoTest do
)
end
- test "it shows MRF transparency data if enabled", %{conn: conn} do
- clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.SimplePolicy])
- clear_config([:mrf, :transparency], true)
+ describe "Quarantined instances" do
+ setup do
+ clear_config([:mrf, :transparency], true)
+ quarantined_instances = [{"example.com", "reason to quarantine"}]
+ clear_config([:instance, :quarantined_instances], quarantined_instances)
+ end
- simple_config = %{"reject" => ["example.com"]}
- clear_config(:mrf_simple, simple_config)
+ test "shows quarantined instances data if enabled", %{conn: conn} do
+ expected_config = ["example.com"]
- response =
- conn
- |> get("/nodeinfo/2.1.json")
- |> json_response(:ok)
+ response =
+ conn
+ |> get("/nodeinfo/2.1.json")
+ |> json_response(:ok)
+
+ assert response["metadata"]["federation"]["quarantined_instances"] == expected_config
+ end
- assert response["metadata"]["federation"]["mrf_simple"] == simple_config
+ test "shows extra information in the quarantined_info field for relevant entries", %{
+ conn: conn
+ } do
+ clear_config([:mrf, :transparency], true)
+
+ expected_config = %{
+ "quarantined_instances" => %{
+ "example.com" => %{"reason" => "reason to quarantine"}
+ }
+ }
+
+ response =
+ conn
+ |> get("/nodeinfo/2.1.json")
+ |> json_response(:ok)
+
+ assert response["metadata"]["federation"]["quarantined_instances_info"] == expected_config
+ end
end
- test "it performs exclusions from MRF transparency data if configured", %{conn: conn} do
- clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.SimplePolicy])
- clear_config([:mrf, :transparency], true)
- clear_config([:mrf, :transparency_exclusions], ["other.site"])
+ describe "MRF SimplePolicy" do
+ setup do
+ clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.SimplePolicy])
+ clear_config([:mrf, :transparency], true)
+ end
- simple_config = %{"reject" => ["example.com", "other.site"]}
- clear_config(:mrf_simple, simple_config)
+ test "shows MRF transparency data if enabled", %{conn: conn} do
+ simple_config = %{"reject" => [{"example.com", ""}]}
+ clear_config(:mrf_simple, simple_config)
- expected_config = %{"reject" => ["example.com"]}
+ expected_config = %{"reject" => ["example.com"]}
- response =
- conn
- |> get("/nodeinfo/2.1.json")
- |> json_response(:ok)
+ response =
+ conn
+ |> get("/nodeinfo/2.1.json")
+ |> json_response(:ok)
+
+ assert response["metadata"]["federation"]["mrf_simple"] == expected_config
+ end
+
+ test "performs exclusions from MRF transparency data if configured", %{conn: conn} do
+ clear_config([:mrf, :transparency_exclusions], [
+ {"other.site", "We don't want them to know"}
+ ])
+
+ simple_config = %{"reject" => [{"example.com", ""}, {"other.site", ""}]}
+ clear_config(:mrf_simple, simple_config)
+
+ expected_config = %{"reject" => ["example.com"]}
+
+ response =
+ conn
+ |> get("/nodeinfo/2.1.json")
+ |> json_response(:ok)
+
+ assert response["metadata"]["federation"]["mrf_simple"] == expected_config
+ assert response["metadata"]["federation"]["exclusions"] == true
+ end
+
+ test "shows extra information in the mrf_simple_info field for relevant entries", %{
+ conn: conn
+ } do
+ simple_config = %{
+ media_removal: [{"no.media", "LEEWWWDD >//<"}],
+ media_nsfw: [],
+ federated_timeline_removal: [{"no.ftl", ""}],
+ report_removal: [],
+ reject: [
+ {"example.instance", "Some reason"},
+ {"uwu.owo", "awoo to much"},
+ {"no.reason", ""}
+ ],
+ followers_only: [],
+ accept: [],
+ avatar_removal: [],
+ banner_removal: [],
+ reject_deletes: [
+ {"peak.me", "I want to peak at what they don't want me to see, eheh"}
+ ]
+ }
+
+ clear_config(:mrf_simple, simple_config)
+
+ clear_config([:mrf, :transparency_exclusions], [
+ {"peak.me", "I don't want them to know"}
+ ])
+
+ expected_config = %{
+ "media_removal" => %{
+ "no.media" => %{"reason" => "LEEWWWDD >//<"}
+ },
+ "reject" => %{
+ "example.instance" => %{"reason" => "Some reason"},
+ "uwu.owo" => %{"reason" => "awoo to much"}
+ }
+ }
- assert response["metadata"]["federation"]["mrf_simple"] == expected_config
- assert response["metadata"]["federation"]["exclusions"] == true
+ response =
+ conn
+ |> get("/nodeinfo/2.1.json")
+ |> json_response(:ok)
+
+ assert response["metadata"]["federation"]["mrf_simple_info"] == expected_config
+ end
end
end
diff --git a/test/web/oauth/app_test.exs b/test/pleroma/web/o_auth/app_test.exs
index 993a490e0..a5223b0a5 100644
--- a/test/web/oauth/app_test.exs
+++ b/test/pleroma/web/o_auth/app_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OAuth.AppTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Web.OAuth.App
import Pleroma.Factory
@@ -41,4 +41,16 @@ defmodule Pleroma.Web.OAuth.AppTest do
assert error.type == :unique
end
end
+
+ test "get_user_apps/1" do
+ user = insert(:user)
+
+ apps = [
+ insert(:oauth_app, user_id: user.id),
+ insert(:oauth_app, user_id: user.id),
+ insert(:oauth_app, user_id: user.id)
+ ]
+
+ assert App.get_user_apps(user) == apps
+ end
end
diff --git a/test/web/oauth/authorization_test.exs b/test/pleroma/web/o_auth/authorization_test.exs
index d74b26cf8..fc1c04c4c 100644
--- a/test/web/oauth/authorization_test.exs
+++ b/test/pleroma/web/o_auth/authorization_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OAuth.AuthorizationTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Web.OAuth.App
alias Pleroma.Web.OAuth.Authorization
import Pleroma.Factory
diff --git a/test/web/oauth/ldap_authorization_test.exs b/test/pleroma/web/o_auth/ldap_authorization_test.exs
index 63b1c0eb8..61b9ce6b7 100644
--- a/test/web/oauth/ldap_authorization_test.exs
+++ b/test/pleroma/web/o_auth/ldap_authorization_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OAuth.LDAPAuthorizationTest do
@@ -18,7 +18,7 @@ defmodule Pleroma.Web.OAuth.LDAPAuthorizationTest do
@tag @skip
test "authorizes the existing user using LDAP credentials" do
password = "testpassword"
- user = insert(:user, password_hash: Pbkdf2.hash_pwd_salt(password))
+ user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password))
app = insert(:oauth_app, scopes: ["read", "write"])
host = Pleroma.Config.get([:ldap, :host]) |> to_charlist
@@ -101,7 +101,7 @@ defmodule Pleroma.Web.OAuth.LDAPAuthorizationTest do
@tag @skip
test "disallow authorization for wrong LDAP credentials" do
password = "testpassword"
- user = insert(:user, password_hash: Pbkdf2.hash_pwd_salt(password))
+ user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password))
app = insert(:oauth_app, scopes: ["read", "write"])
host = Pleroma.Config.get([:ldap, :host]) |> to_charlist
diff --git a/test/web/oauth/mfa_controller_test.exs b/test/pleroma/web/o_auth/mfa_controller_test.exs
index 3c341facd..17bbde85b 100644
--- a/test/web/oauth/mfa_controller_test.exs
+++ b/test/pleroma/web/o_auth/mfa_controller_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OAuth.MFAControllerTest do
- use Pleroma.Web.ConnCase
+ use Pleroma.Web.ConnCase, async: true
import Pleroma.Factory
alias Pleroma.MFA
@@ -20,7 +20,7 @@ defmodule Pleroma.Web.OAuth.MFAControllerTest do
insert(:user,
multi_factor_authentication_settings: %MFA.Settings{
enabled: true,
- backup_codes: [Pbkdf2.hash_pwd_salt("test-code")],
+ backup_codes: [Pleroma.Password.Pbkdf2.hash_pwd_salt("test-code")],
totp: %MFA.Settings.TOTP{secret: otp_secret, confirmed: true}
}
)
@@ -171,7 +171,6 @@ defmodule Pleroma.Web.OAuth.MFAControllerTest do
assert match?(
%{
"access_token" => _,
- "expires_in" => 600,
"me" => ^ap_id,
"refresh_token" => _,
"scope" => "write",
@@ -247,7 +246,7 @@ defmodule Pleroma.Web.OAuth.MFAControllerTest do
hashed_codes =
backup_codes
- |> Enum.map(&Pbkdf2.hash_pwd_salt(&1))
+ |> Enum.map(&Pleroma.Password.Pbkdf2.hash_pwd_salt(&1))
user =
insert(:user,
@@ -280,7 +279,6 @@ defmodule Pleroma.Web.OAuth.MFAControllerTest do
assert match?(
%{
"access_token" => _,
- "expires_in" => 600,
"me" => ^ap_id,
"refresh_token" => _,
"scope" => "write",
diff --git a/test/web/oauth/oauth_controller_test.exs b/test/pleroma/web/o_auth/o_auth_controller_test.exs
index 1200126b8..0fdd5b8e9 100644
--- a/test/web/oauth/oauth_controller_test.exs
+++ b/test/pleroma/web/o_auth/o_auth_controller_test.exs
@@ -1,11 +1,13 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OAuth.OAuthControllerTest do
use Pleroma.Web.ConnCase
+
import Pleroma.Factory
+ alias Pleroma.Helpers.AuthHelper
alias Pleroma.MFA
alias Pleroma.MFA.TOTP
alias Pleroma.Repo
@@ -77,11 +79,11 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
}
)
- assert response = html_response(conn, 302)
+ assert html_response(conn, 302)
redirect_query = URI.parse(redirected_to(conn)).query
assert %{"state" => state_param} = URI.decode_query(redirect_query)
- assert {:ok, state_components} = Poison.decode(state_param)
+ assert {:ok, state_components} = Jason.decode(state_param)
expected_client_id = app.client_id
expected_redirect_uri = app.redirect_uris
@@ -115,11 +117,11 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
"oauth_token" => "G-5a3AAAAAAAwMH9AAABaektfSM",
"oauth_verifier" => "QZl8vUqNvXMTKpdmUnGejJxuHG75WWWs",
"provider" => "twitter",
- "state" => Poison.encode!(state_params)
+ "state" => Jason.encode!(state_params)
}
)
- assert response = html_response(conn, 302)
+ assert html_response(conn, 302)
assert redirected_to(conn) =~ ~r/#{redirect_uri}\?code=.+/
end
@@ -147,7 +149,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
"oauth_token" => "G-5a3AAAAAAAwMH9AAABaektfSM",
"oauth_verifier" => "QZl8vUqNvXMTKpdmUnGejJxuHG75WWWs",
"provider" => "twitter",
- "state" => Poison.encode!(state_params)
+ "state" => Jason.encode!(state_params)
}
)
@@ -178,11 +180,11 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
"oauth_token" => "G-5a3AAAAAAAwMH9AAABaektfSM",
"oauth_verifier" => "QZl8vUqNvXMTKpdmUnGejJxuHG75WWWs",
"provider" => "twitter",
- "state" => Poison.encode!(state_params)
+ "state" => Jason.encode!(state_params)
}
)
- assert response = html_response(conn, 302)
+ assert html_response(conn, 302)
assert redirected_to(conn) == app.redirect_uris
assert get_flash(conn, :error) == "Failed to authenticate: (error description)."
end
@@ -238,7 +240,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
}
)
- assert response = html_response(conn, 302)
+ assert html_response(conn, 302)
assert redirected_to(conn) =~ ~r/#{redirect_uri}\?code=.+/
end
@@ -268,7 +270,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
}
)
- assert response = html_response(conn, 401)
+ assert html_response(conn, 401)
end
test "with invalid params, POST /oauth/register?op=register renders registration_details page",
@@ -314,7 +316,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
app: app,
conn: conn
} do
- user = insert(:user, password_hash: Pbkdf2.hash_pwd_salt("testpassword"))
+ user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("testpassword"))
registration = insert(:registration, user: nil)
redirect_uri = OAuthController.default_redirect_uri(app)
@@ -336,7 +338,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
}
)
- assert response = html_response(conn, 302)
+ assert html_response(conn, 302)
assert redirected_to(conn) =~ ~r/#{redirect_uri}\?code=.+/
end
@@ -345,7 +347,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
app: app,
conn: conn
} do
- user = insert(:user, password_hash: Pbkdf2.hash_pwd_salt("testpassword"))
+ user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("testpassword"))
registration = insert(:registration, user: nil)
unlisted_redirect_uri = "http://cross-site-request.com"
@@ -367,7 +369,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
}
)
- assert response = html_response(conn, 401)
+ assert html_response(conn, 401)
end
test "with invalid params, POST /oauth/register?op=connect renders registration_details page",
@@ -454,7 +456,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
conn =
conn
- |> put_session(:oauth_token, token.token)
+ |> AuthHelper.put_session_token(token.token)
|> get(
"/oauth/authorize",
%{
@@ -478,7 +480,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
conn =
conn
- |> put_session(:oauth_token, token.token)
+ |> AuthHelper.put_session_token(token.token)
|> get(
"/oauth/authorize",
%{
@@ -501,7 +503,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
conn =
conn
- |> put_session(:oauth_token, token.token)
+ |> AuthHelper.put_session_token(token.token)
|> get(
"/oauth/authorize",
%{
@@ -527,7 +529,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
conn =
conn
- |> put_session(:oauth_token, token.token)
+ |> AuthHelper.put_session_token(token.token)
|> get(
"/oauth/authorize",
%{
@@ -551,7 +553,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
conn =
conn
- |> put_session(:oauth_token, token.token)
+ |> AuthHelper.put_session_token(token.token)
|> get(
"/oauth/authorize",
%{
@@ -609,6 +611,41 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
end
end
+ test "authorize from cookie" do
+ user = insert(:user)
+ app = insert(:oauth_app)
+ oauth_token = insert(:oauth_token, user: user, app: app)
+ redirect_uri = OAuthController.default_redirect_uri(app)
+
+ conn =
+ build_conn()
+ |> Plug.Session.call(Plug.Session.init(@session_opts))
+ |> fetch_session()
+ |> AuthHelper.put_session_token(oauth_token.token)
+ |> post(
+ "/oauth/authorize",
+ %{
+ "authorization" => %{
+ "name" => user.nickname,
+ "client_id" => app.client_id,
+ "redirect_uri" => redirect_uri,
+ "scope" => app.scopes,
+ "state" => "statepassed"
+ }
+ }
+ )
+
+ target = redirected_to(conn)
+ assert target =~ redirect_uri
+
+ query = URI.parse(target).query |> URI.query_decoder() |> Map.new()
+
+ assert %{"state" => "statepassed", "code" => code} = query
+ auth = Repo.get_by(Authorization, token: code)
+ assert auth
+ assert auth.scopes == app.scopes
+ end
+
test "redirect to on two-factor auth page" do
otp_secret = TOTP.generate_secret()
@@ -753,7 +790,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
test "issues a token for `password` grant_type with valid credentials, with full permissions by default" do
password = "testpassword"
- user = insert(:user, password_hash: Pbkdf2.hash_pwd_salt(password))
+ user = insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password))
app = insert(:oauth_app, scopes: ["read", "write"])
@@ -768,10 +805,12 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
"client_secret" => app.client_secret
})
- assert %{"access_token" => token} = json_response(conn, 200)
+ assert %{"id" => id, "access_token" => access_token} = json_response(conn, 200)
- token = Repo.get_by(Token, token: token)
+ token = Repo.get_by(Token, token: access_token)
assert token
+ assert token.id == id
+ assert token.token == access_token
assert token.scopes == app.scopes
end
@@ -781,7 +820,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
user =
insert(:user,
- password_hash: Pbkdf2.hash_pwd_salt(password),
+ password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password),
multi_factor_authentication_settings: %MFA.Settings{
enabled: true,
totp: %MFA.Settings.TOTP{secret: otp_secret, confirmed: true}
@@ -886,12 +925,12 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
end
test "rejects token exchange for valid credentials belonging to unconfirmed user and confirmation is required" do
- Pleroma.Config.put([:instance, :account_activation_required], true)
+ clear_config([:instance, :account_activation_required], true)
password = "testpassword"
{:ok, user} =
- insert(:user, password_hash: Pbkdf2.hash_pwd_salt(password))
- |> User.confirmation_changeset(need_confirmation: true)
+ insert(:user, password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password))
+ |> User.confirmation_changeset(set_confirmation: false)
|> User.update_and_set_cache()
refute Pleroma.User.account_status(user) == :active
@@ -918,8 +957,8 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
user =
insert(:user,
- password_hash: Pbkdf2.hash_pwd_salt(password),
- deactivated: true
+ password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password),
+ is_active: false
)
app = insert(:oauth_app)
@@ -946,7 +985,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
user =
insert(:user,
- password_hash: Pbkdf2.hash_pwd_salt(password),
+ password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password),
password_reset_pending: true
)
@@ -970,13 +1009,13 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
end
test "rejects token exchange for user with confirmation_pending set to true" do
- Pleroma.Config.put([:instance, :account_activation_required], true)
+ clear_config([:instance, :account_activation_required], true)
password = "testpassword"
user =
insert(:user,
- password_hash: Pbkdf2.hash_pwd_salt(password),
- confirmation_pending: true
+ password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password),
+ is_confirmed: false
)
app = insert(:oauth_app, scopes: ["read", "write"])
@@ -1001,7 +1040,11 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
test "rejects token exchange for valid credentials belonging to an unapproved user" do
password = "testpassword"
- user = insert(:user, password_hash: Pbkdf2.hash_pwd_salt(password), approval_pending: true)
+ user =
+ insert(:user,
+ password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt(password),
+ is_approved: false
+ )
refute Pleroma.User.account_status(user) == :active
@@ -1045,7 +1088,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
setup do: clear_config([:oauth2, :issue_new_refresh_token])
test "issues a new access token with keep fresh token" do
- Pleroma.Config.put([:oauth2, :issue_new_refresh_token], true)
+ clear_config([:oauth2, :issue_new_refresh_token], true)
user = insert(:user)
app = insert(:oauth_app, scopes: ["read", "write"])
@@ -1068,7 +1111,6 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
%{
"scope" => "write",
"token_type" => "Bearer",
- "expires_in" => 600,
"access_token" => _,
"refresh_token" => _,
"me" => ^ap_id
@@ -1085,7 +1127,7 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
end
test "issues a new access token with new fresh token" do
- Pleroma.Config.put([:oauth2, :issue_new_refresh_token], false)
+ clear_config([:oauth2, :issue_new_refresh_token], false)
user = insert(:user)
app = insert(:oauth_app, scopes: ["read", "write"])
@@ -1108,7 +1150,6 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
%{
"scope" => "write",
"token_type" => "Bearer",
- "expires_in" => 600,
"access_token" => _,
"refresh_token" => _,
"me" => ^ap_id
@@ -1191,7 +1232,6 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
%{
"scope" => "write",
"token_type" => "Bearer",
- "expires_in" => 600,
"access_token" => _,
"refresh_token" => _,
"me" => ^ap_id
@@ -1219,8 +1259,43 @@ defmodule Pleroma.Web.OAuth.OAuthControllerTest do
end
end
- describe "POST /oauth/revoke - bad request" do
- test "returns 500" do
+ describe "POST /oauth/revoke" do
+ test "when authenticated with request token, revokes it and clears it from session" do
+ oauth_token = insert(:oauth_token)
+
+ conn =
+ build_conn()
+ |> Plug.Session.call(Plug.Session.init(@session_opts))
+ |> fetch_session()
+ |> AuthHelper.put_session_token(oauth_token.token)
+ |> post("/oauth/revoke", %{"token" => oauth_token.token})
+
+ assert json_response(conn, 200)
+
+ refute AuthHelper.get_session_token(conn)
+ assert Token.get_by_token(oauth_token.token) == {:error, :not_found}
+ end
+
+ test "if request is authenticated with a different token, " <>
+ "revokes requested token but keeps session token" do
+ user = insert(:user)
+ oauth_token = insert(:oauth_token, user: user)
+ other_app_oauth_token = insert(:oauth_token, user: user)
+
+ conn =
+ build_conn()
+ |> Plug.Session.call(Plug.Session.init(@session_opts))
+ |> fetch_session()
+ |> AuthHelper.put_session_token(oauth_token.token)
+ |> post("/oauth/revoke", %{"token" => other_app_oauth_token.token})
+
+ assert json_response(conn, 200)
+
+ assert AuthHelper.get_session_token(conn) == oauth_token.token
+ assert Token.get_by_token(other_app_oauth_token.token) == {:error, :not_found}
+ end
+
+ test "returns 500 on bad request" do
response =
build_conn()
|> post("/oauth/revoke", %{})
diff --git a/test/web/oauth/token/utils_test.exs b/test/pleroma/web/o_auth/token/utils_test.exs
index a610d92f8..d2e7a0904 100644
--- a/test/web/oauth/token/utils_test.exs
+++ b/test/pleroma/web/o_auth/token/utils_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OAuth.Token.UtilsTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Web.OAuth.Token.Utils
import Pleroma.Factory
diff --git a/test/web/oauth/token_test.exs b/test/pleroma/web/o_auth/token_test.exs
index 40d71eb59..8c0858ebc 100644
--- a/test/web/oauth/token_test.exs
+++ b/test/pleroma/web/o_auth/token_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OAuth.TokenTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Repo
alias Pleroma.Web.OAuth.App
alias Pleroma.Web.OAuth.Authorization
@@ -69,17 +69,4 @@ defmodule Pleroma.Web.OAuth.TokenTest do
assert tokens == 2
end
-
- test "deletes expired tokens" do
- insert(:oauth_token, valid_until: Timex.shift(Timex.now(), days: -3))
- insert(:oauth_token, valid_until: Timex.shift(Timex.now(), days: -3))
- t3 = insert(:oauth_token)
- t4 = insert(:oauth_token, valid_until: Timex.shift(Timex.now(), minutes: 10))
- {tokens, _} = Token.delete_expired_tokens()
- assert tokens == 2
- available_tokens = Pleroma.Repo.all(Token)
-
- token_ids = available_tokens |> Enum.map(& &1.id)
- assert token_ids == [t3.id, t4.id]
- end
end
diff --git a/test/web/ostatus/ostatus_controller_test.exs b/test/pleroma/web/o_status/o_status_controller_test.exs
index ee498f4b5..41aef98b1 100644
--- a/test/web/ostatus/ostatus_controller_test.exs
+++ b/test/pleroma/web/o_status/o_status_controller_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OStatus.OStatusControllerTest do
@@ -7,7 +7,6 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
import Pleroma.Factory
- alias Pleroma.Config
alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
@@ -21,7 +20,7 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
:ok
end
- setup do: clear_config([:instance, :federating], true)
+ setup do: clear_config([:static_fe, :enabled], false)
describe "Mastodon compatibility routes" do
setup %{conn: conn} do
@@ -73,7 +72,7 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
test "redirects to /notice/id for html format", %{conn: conn} do
note_activity = insert(:note_activity)
- object = Object.normalize(note_activity)
+ object = Object.normalize(note_activity, fetch: false)
[_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"]))
url = "/objects/#{uuid}"
@@ -83,7 +82,7 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
test "404s on private objects", %{conn: conn} do
note_activity = insert(:direct_note_activity)
- object = Object.normalize(note_activity)
+ object = Object.normalize(note_activity, fetch: false)
[_, uuid] = hd(Regex.scan(~r/.+\/([\w-]+)$/, object.data["id"]))
conn
@@ -134,7 +133,7 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
conn: conn
} do
note_activity = insert(:note_activity)
- expected_redirect_url = Object.normalize(note_activity).data["id"]
+ expected_redirect_url = Object.normalize(note_activity, fetch: false).data["id"]
redirect_url =
conn
@@ -145,13 +144,19 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
assert redirect_url == expected_redirect_url
end
- test "returns a 404 on remote notice when json requested", %{conn: conn} do
+ test "redirects to a proper object URL when json requested and the object is remote", %{
+ conn: conn
+ } do
note_activity = insert(:note_activity, local: false)
+ expected_redirect_url = Object.normalize(note_activity, fetch: false).data["id"]
- conn
- |> put_req_header("accept", "application/activity+json")
- |> get("/notice/#{note_activity.id}")
- |> response(404)
+ redirect_url =
+ conn
+ |> put_req_header("accept", "application/activity+json")
+ |> get("/notice/#{note_activity.id}")
+ |> redirected_to()
+
+ assert redirect_url == expected_redirect_url
end
test "500s when actor not found", %{conn: conn} do
@@ -177,7 +182,7 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
|> response(200)
assert resp =~
- "<meta content=\"#{Pleroma.Web.base_url()}/notice/#{note_activity.id}\" property=\"og:url\">"
+ "<meta content=\"#{Pleroma.Web.Endpoint.url()}/notice/#{note_activity.id}\" property=\"og:url\">"
user = insert(:user)
@@ -215,22 +220,23 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
assert response(conn, 404)
end
- test "it requires authentication if instance is NOT federating", %{
+ test "does not require authentication on non-federating instances", %{
conn: conn
} do
- user = insert(:user)
+ clear_config([:instance, :federating], false)
note_activity = insert(:note_activity)
- conn = put_req_header(conn, "accept", "text/html")
-
- ensure_federating_or_authenticated(conn, "/notice/#{note_activity.id}", user)
+ conn
+ |> put_req_header("accept", "text/html")
+ |> get("/notice/#{note_activity.id}")
+ |> response(200)
end
end
describe "GET /notice/:id/embed_player" do
setup do
note_activity = insert(:note_activity)
- object = Pleroma.Object.normalize(note_activity)
+ object = Pleroma.Object.normalize(note_activity, fetch: false)
object_data =
Map.put(object.data, "attachment", [
@@ -287,7 +293,7 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
test "404s when attachment is empty", %{conn: conn} do
note_activity = insert(:note_activity)
- object = Pleroma.Object.normalize(note_activity)
+ object = Pleroma.Object.normalize(note_activity, fetch: false)
object_data = Map.put(object.data, "attachment", [])
object
@@ -301,7 +307,7 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
test "404s when attachment isn't audio or video", %{conn: conn} do
note_activity = insert(:note_activity)
- object = Pleroma.Object.normalize(note_activity)
+ object = Pleroma.Object.normalize(note_activity, fetch: false)
object_data =
Map.put(object.data, "attachment", [
@@ -325,14 +331,66 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
|> response(404)
end
- test "it requires authentication if instance is NOT federating", %{
+ test "does not require authentication on non-federating instances", %{
conn: conn,
note_activity: note_activity
} do
+ clear_config([:instance, :federating], false)
+
+ conn
+ |> put_req_header("accept", "text/html")
+ |> get("/notice/#{note_activity.id}/embed_player")
+ |> response(200)
+ end
+ end
+
+ describe "notice compatibility routes" do
+ test "Soapbox FE", %{conn: conn} do
user = insert(:user)
- conn = put_req_header(conn, "accept", "text/html")
+ note_activity = insert(:note_activity, user: user)
+
+ resp =
+ conn
+ |> put_req_header("accept", "text/html")
+ |> get("/@#{user.nickname}/posts/#{note_activity.id}")
+ |> response(200)
+
+ expected =
+ "<meta content=\"#{Endpoint.url()}/notice/#{note_activity.id}\" property=\"og:url\">"
+
+ assert resp =~ expected
+ end
+
+ test "Mastodon", %{conn: conn} do
+ user = insert(:user)
+ note_activity = insert(:note_activity, user: user)
+
+ resp =
+ conn
+ |> put_req_header("accept", "text/html")
+ |> get("/@#{user.nickname}/#{note_activity.id}")
+ |> response(200)
+
+ expected =
+ "<meta content=\"#{Endpoint.url()}/notice/#{note_activity.id}\" property=\"og:url\">"
+
+ assert resp =~ expected
+ end
+
+ test "Twitter", %{conn: conn} do
+ user = insert(:user)
+ note_activity = insert(:note_activity, user: user)
+
+ resp =
+ conn
+ |> put_req_header("accept", "text/html")
+ |> get("/#{user.nickname}/status/#{note_activity.id}")
+ |> response(200)
+
+ expected =
+ "<meta content=\"#{Endpoint.url()}/notice/#{note_activity.id}\" property=\"og:url\">"
- ensure_federating_or_authenticated(conn, "/notice/#{note_activity.id}/embed_player", user)
+ assert resp =~ expected
end
end
end
diff --git a/test/web/pleroma_api/controllers/account_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/account_controller_test.exs
index 07909d48b..ad271c31b 100644
--- a/test/web/pleroma_api/controllers/account_controller_test.exs
+++ b/test/pleroma/web/pleroma_api/controllers/account_controller_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do
@@ -17,10 +17,10 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do
setup do
{:ok, user} =
insert(:user)
- |> User.confirmation_changeset(need_confirmation: true)
+ |> User.confirmation_changeset(set_confirmation: false)
|> User.update_and_set_cache()
- assert user.confirmation_pending
+ refute user.is_confirmed
[user: user]
end
@@ -174,9 +174,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do
response =
conn
|> get(
- "/api/v1/pleroma/accounts/#{user.id}/favourites?since_id=#{third_activity.id}&max_id=#{
- seventh_activity.id
- }"
+ "/api/v1/pleroma/accounts/#{user.id}/favourites?since_id=#{third_activity.id}&max_id=#{seventh_activity.id}"
)
|> json_response_and_validate_schema(:ok)
diff --git a/test/pleroma/web/pleroma_api/controllers/app_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/app_controller_test.exs
new file mode 100644
index 000000000..5e24e18a8
--- /dev/null
+++ b/test/pleroma/web/pleroma_api/controllers/app_controller_test.exs
@@ -0,0 +1,53 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PleromaAPI.AppControllerTest do
+ use Pleroma.Web.ConnCase, async: true
+
+ alias Pleroma.Web.OAuth.App
+ alias Pleroma.Web.Push
+
+ import Pleroma.Factory
+
+ test "apps", %{conn: conn} do
+ user = insert(:user)
+ app_attrs = build(:oauth_app)
+
+ creation =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> assign(:user, user)
+ |> post("/api/v1/apps", %{
+ client_name: app_attrs.client_name,
+ redirect_uris: app_attrs.redirect_uris
+ })
+
+ [app] = App.get_user_apps(user)
+
+ expected = %{
+ "name" => app.client_name,
+ "website" => app.website,
+ "client_id" => app.client_id,
+ "client_secret" => app.client_secret,
+ "id" => app.id |> to_string(),
+ "redirect_uri" => app.redirect_uris,
+ "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
+ }
+
+ assert expected == json_response_and_validate_schema(creation, 200)
+
+ response =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> assign(:user, user)
+ |> assign(:token, insert(:oauth_token, user: user, scopes: ["read", "follow"]))
+ |> get("/api/v1/pleroma/apps")
+ |> json_response_and_validate_schema(200)
+
+ [apps] = response
+
+ assert length(response) == 1
+ assert apps["client_id"] == app.client_id
+ end
+end
diff --git a/test/pleroma/web/pleroma_api/controllers/backup_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/backup_controller_test.exs
new file mode 100644
index 000000000..3ee660a05
--- /dev/null
+++ b/test/pleroma/web/pleroma_api/controllers/backup_controller_test.exs
@@ -0,0 +1,85 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PleromaAPI.BackupControllerTest do
+ use Pleroma.Web.ConnCase
+
+ alias Pleroma.User.Backup
+ alias Pleroma.Web.PleromaAPI.BackupView
+
+ setup do
+ clear_config([Pleroma.Upload, :uploader])
+ clear_config([Backup, :limit_days])
+ oauth_access(["read:accounts"])
+ end
+
+ test "GET /api/v1/pleroma/backups", %{user: user, conn: conn} do
+ assert {:ok, %Oban.Job{args: %{"backup_id" => backup_id}}} = Backup.create(user)
+
+ backup = Backup.get(backup_id)
+
+ response =
+ conn
+ |> get("/api/v1/pleroma/backups")
+ |> json_response_and_validate_schema(:ok)
+
+ assert [
+ %{
+ "content_type" => "application/zip",
+ "url" => url,
+ "file_size" => 0,
+ "processed" => false,
+ "inserted_at" => _
+ }
+ ] = response
+
+ assert url == BackupView.download_url(backup)
+
+ Pleroma.Tests.ObanHelpers.perform_all()
+
+ assert [
+ %{
+ "url" => ^url,
+ "processed" => true
+ }
+ ] =
+ conn
+ |> get("/api/v1/pleroma/backups")
+ |> json_response_and_validate_schema(:ok)
+ end
+
+ test "POST /api/v1/pleroma/backups", %{user: _user, conn: conn} do
+ assert [
+ %{
+ "content_type" => "application/zip",
+ "url" => url,
+ "file_size" => 0,
+ "processed" => false,
+ "inserted_at" => _
+ }
+ ] =
+ conn
+ |> post("/api/v1/pleroma/backups")
+ |> json_response_and_validate_schema(:ok)
+
+ Pleroma.Tests.ObanHelpers.perform_all()
+
+ assert [
+ %{
+ "url" => ^url,
+ "processed" => true
+ }
+ ] =
+ conn
+ |> get("/api/v1/pleroma/backups")
+ |> json_response_and_validate_schema(:ok)
+
+ days = Pleroma.Config.get([Backup, :limit_days])
+
+ assert %{"error" => "Last export was less than #{days} days ago"} ==
+ conn
+ |> post("/api/v1/pleroma/backups")
+ |> json_response_and_validate_schema(400)
+ end
+end
diff --git a/test/web/pleroma_api/controllers/chat_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/chat_controller_test.exs
index 7be5fe09c..99b0d43a7 100644
--- a/test/web/pleroma_api/controllers/chat_controller_test.exs
+++ b/test/pleroma/web/pleroma_api/controllers/chat_controller_test.exs
@@ -1,8 +1,8 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do
- use Pleroma.Web.ConnCase, async: true
+ use Pleroma.Web.ConnCase
alias Pleroma.Chat
alias Pleroma.Chat.MessageReference
@@ -22,7 +22,7 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do
{:ok, create} = CommonAPI.post_chat_message(other_user, user, "sup")
{:ok, _create} = CommonAPI.post_chat_message(other_user, user, "sup part 2")
{:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id)
- object = Object.normalize(create, false)
+ object = Object.normalize(create, fetch: false)
cm_ref = MessageReference.for_chat_and_object(chat, object)
assert cm_ref.unread == true
@@ -52,7 +52,7 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do
{:ok, create} = CommonAPI.post_chat_message(other_user, user, "sup")
{:ok, _create} = CommonAPI.post_chat_message(other_user, user, "sup part 2")
{:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id)
- object = Object.normalize(create, false)
+ object = Object.normalize(create, fetch: false)
cm_ref = MessageReference.for_chat_and_object(chat, object)
assert cm_ref.unread == true
@@ -82,11 +82,13 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do
result =
conn
|> put_req_header("content-type", "application/json")
+ |> put_req_header("idempotency-key", "123")
|> post("/api/v1/pleroma/chats/#{chat.id}/messages", %{"content" => "Hallo!!"})
|> json_response_and_validate_schema(200)
assert result["content"] == "Hallo!!"
assert result["chat_id"] == chat.id |> to_string()
+ assert result["idempotency_key"] == "123"
end
test "it fails if there is no content", %{conn: conn, user: user} do
@@ -100,12 +102,12 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do
|> post("/api/v1/pleroma/chats/#{chat.id}/messages")
|> json_response_and_validate_schema(400)
- assert result
+ assert %{"error" => "no_content"} == result
end
test "it works with an attachment", %{conn: conn, user: user} do
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}
@@ -126,6 +128,23 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do
assert result["attachment"]
end
+
+ test "gets MRF reason when rejected", %{conn: conn, user: user} do
+ clear_config([:mrf_keyword, :reject], ["GNO"])
+ clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.KeywordPolicy])
+
+ other_user = insert(:user)
+
+ {:ok, chat} = Chat.get_or_create(user.id, other_user.ap_id)
+
+ result =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/v1/pleroma/chats/#{chat.id}/messages", %{"content" => "GNO/Linux"})
+ |> json_response_and_validate_schema(422)
+
+ assert %{"error" => "[KeywordPolicy] Matches with rejected keyword"} == result
+ end
end
describe "DELETE /api/v1/pleroma/chats/:id/messages/:message_id" do
@@ -139,7 +158,7 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do
{:ok, other_message} = CommonAPI.post_chat_message(recipient, user, "nico nico ni")
- object = Object.normalize(message, false)
+ object = Object.normalize(message, fetch: false)
chat = Chat.get(user.id, recipient.ap_id)
@@ -157,7 +176,7 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do
assert %{data: %{"type" => "Tombstone"}} = Object.get_by_id(object.id)
# Deleting other people's messages just removes the reference
- object = Object.normalize(other_message, false)
+ object = Object.normalize(other_message, fetch: false)
cm_ref = MessageReference.for_chat_and_object(chat, object)
result =
@@ -184,17 +203,39 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do
chat = Chat.get(user.id, recipient.ap_id)
- result =
- conn
- |> get("/api/v1/pleroma/chats/#{chat.id}/messages")
- |> json_response_and_validate_schema(200)
+ response = get(conn, "/api/v1/pleroma/chats/#{chat.id}/messages")
+ result = json_response_and_validate_schema(response, 200)
+
+ [next, prev] = get_resp_header(response, "link") |> hd() |> String.split(", ")
+ api_endpoint = "/api/v1/pleroma/chats/"
+
+ assert String.match?(
+ next,
+ ~r(#{api_endpoint}.*/messages\?limit=\d+&max_id=.*; rel=\"next\"$)
+ )
+
+ assert String.match?(
+ prev,
+ ~r(#{api_endpoint}.*/messages\?limit=\d+&min_id=.*; rel=\"prev\"$)
+ )
assert length(result) == 20
- result =
- conn
- |> get("/api/v1/pleroma/chats/#{chat.id}/messages?max_id=#{List.last(result)["id"]}")
- |> json_response_and_validate_schema(200)
+ response =
+ get(conn, "/api/v1/pleroma/chats/#{chat.id}/messages?max_id=#{List.last(result)["id"]}")
+
+ result = json_response_and_validate_schema(response, 200)
+ [next, prev] = get_resp_header(response, "link") |> hd() |> String.split(", ")
+
+ assert String.match?(
+ next,
+ ~r(#{api_endpoint}.*/messages\?limit=\d+&max_id=.*; rel=\"next\"$)
+ )
+
+ assert String.match?(
+ prev,
+ ~r(#{api_endpoint}.*/messages\?limit=\d+&max_id=.*&min_id=.*; rel=\"prev\"$)
+ )
assert length(result) == 10
end
@@ -223,12 +264,11 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do
assert length(result) == 3
# Trying to get the chat of a different user
- result =
- conn
- |> assign(:user, other_user)
- |> get("/api/v1/pleroma/chats/#{chat.id}/messages")
+ other_user_chat = Chat.get(other_user.id, user.ap_id)
- assert result |> json_response(404)
+ conn
+ |> get("/api/v1/pleroma/chats/#{other_user_chat.id}/messages")
+ |> json_response_and_validate_schema(404)
end
end
@@ -264,110 +304,165 @@ defmodule Pleroma.Web.PleromaAPI.ChatControllerTest do
end
end
- describe "GET /api/v1/pleroma/chats" do
- setup do: oauth_access(["read:chats"])
-
- test "it does not return chats with deleted users", %{conn: conn, user: user} do
- recipient = insert(:user)
- {:ok, _} = Chat.get_or_create(user.id, recipient.ap_id)
-
- Pleroma.Repo.delete(recipient)
- User.invalidate_cache(recipient)
-
- result =
- conn
- |> get("/api/v1/pleroma/chats")
- |> json_response_and_validate_schema(200)
-
- assert length(result) == 0
- end
-
- test "it does not return chats with users you blocked", %{conn: conn, user: user} do
- recipient = insert(:user)
-
- {:ok, _} = Chat.get_or_create(user.id, recipient.ap_id)
-
- result =
- conn
- |> get("/api/v1/pleroma/chats")
- |> json_response_and_validate_schema(200)
-
- assert length(result) == 1
+ for tested_endpoint <- ["/api/v1/pleroma/chats", "/api/v2/pleroma/chats"] do
+ describe "GET #{tested_endpoint}" do
+ setup do: oauth_access(["read:chats"])
- User.block(user, recipient)
-
- result =
- conn
- |> get("/api/v1/pleroma/chats")
- |> json_response_and_validate_schema(200)
-
- assert length(result) == 0
- end
-
- test "it returns all chats", %{conn: conn, user: user} do
- Enum.each(1..30, fn _ ->
+ test "it does not return chats with deleted users", %{conn: conn, user: user} do
recipient = insert(:user)
{:ok, _} = Chat.get_or_create(user.id, recipient.ap_id)
- end)
- result =
- conn
- |> get("/api/v1/pleroma/chats")
- |> json_response_and_validate_schema(200)
+ Pleroma.Repo.delete(recipient)
+ User.invalidate_cache(recipient)
- assert length(result) == 30
- end
+ result =
+ conn
+ |> get(unquote(tested_endpoint))
+ |> json_response_and_validate_schema(200)
- test "it return a list of chats the current user is participating in, in descending order of updates",
- %{conn: conn, user: user} do
- har = insert(:user)
- jafnhar = insert(:user)
- tridi = insert(:user)
+ assert length(result) == 0
+ end
- {:ok, chat_1} = Chat.get_or_create(user.id, har.ap_id)
- :timer.sleep(1000)
- {:ok, _chat_2} = Chat.get_or_create(user.id, jafnhar.ap_id)
- :timer.sleep(1000)
- {:ok, chat_3} = Chat.get_or_create(user.id, tridi.ap_id)
- :timer.sleep(1000)
+ test "it does not return chats with users you blocked", %{conn: conn, user: user} do
+ recipient = insert(:user)
- # bump the second one
- {:ok, chat_2} = Chat.bump_or_create(user.id, jafnhar.ap_id)
+ {:ok, _} = Chat.get_or_create(user.id, recipient.ap_id)
- result =
- conn
- |> get("/api/v1/pleroma/chats")
- |> json_response_and_validate_schema(200)
+ result =
+ conn
+ |> get(unquote(tested_endpoint))
+ |> json_response_and_validate_schema(200)
- ids = Enum.map(result, & &1["id"])
+ assert length(result) == 1
- assert ids == [
- chat_2.id |> to_string(),
- chat_3.id |> to_string(),
- chat_1.id |> to_string()
- ]
- end
+ User.block(user, recipient)
- test "it is not affected by :restrict_unauthenticated setting (issue #1973)", %{
- conn: conn,
- user: user
- } do
- clear_config([:restrict_unauthenticated, :profiles, :local], true)
- clear_config([:restrict_unauthenticated, :profiles, :remote], true)
+ result =
+ conn
+ |> get(unquote(tested_endpoint))
+ |> json_response_and_validate_schema(200)
- user2 = insert(:user)
- user3 = insert(:user, local: false)
+ assert length(result) == 0
+ end
- {:ok, _chat_12} = Chat.get_or_create(user.id, user2.ap_id)
- {:ok, _chat_13} = Chat.get_or_create(user.id, user3.ap_id)
+ test "it does not return chats with users you muted", %{conn: conn, user: user} do
+ recipient = insert(:user)
- result =
- conn
- |> get("/api/v1/pleroma/chats")
- |> json_response_and_validate_schema(200)
+ {:ok, _} = Chat.get_or_create(user.id, recipient.ap_id)
- account_ids = Enum.map(result, &get_in(&1, ["account", "id"]))
- assert Enum.sort(account_ids) == Enum.sort([user2.id, user3.id])
+ result =
+ conn
+ |> get(unquote(tested_endpoint))
+ |> json_response_and_validate_schema(200)
+
+ assert length(result) == 1
+
+ User.mute(user, recipient)
+
+ result =
+ conn
+ |> get(unquote(tested_endpoint))
+ |> json_response_and_validate_schema(200)
+
+ assert length(result) == 0
+
+ result =
+ conn
+ |> get("#{unquote(tested_endpoint)}?with_muted=true")
+ |> json_response_and_validate_schema(200)
+
+ assert length(result) == 1
+ end
+
+ if tested_endpoint == "/api/v1/pleroma/chats" do
+ test "it returns all chats", %{conn: conn, user: user} do
+ Enum.each(1..30, fn _ ->
+ recipient = insert(:user)
+ {:ok, _} = Chat.get_or_create(user.id, recipient.ap_id)
+ end)
+
+ result =
+ conn
+ |> get(unquote(tested_endpoint))
+ |> json_response_and_validate_schema(200)
+
+ assert length(result) == 30
+ end
+ else
+ test "it paginates chats", %{conn: conn, user: user} do
+ Enum.each(1..30, fn _ ->
+ recipient = insert(:user)
+ {:ok, _} = Chat.get_or_create(user.id, recipient.ap_id)
+ end)
+
+ result =
+ conn
+ |> get(unquote(tested_endpoint))
+ |> json_response_and_validate_schema(200)
+
+ assert length(result) == 20
+ last_id = List.last(result)["id"]
+
+ result =
+ conn
+ |> get(unquote(tested_endpoint) <> "?max_id=#{last_id}")
+ |> json_response_and_validate_schema(200)
+
+ assert length(result) == 10
+ end
+ end
+
+ test "it return a list of chats the current user is participating in, in descending order of updates",
+ %{conn: conn, user: user} do
+ har = insert(:user)
+ jafnhar = insert(:user)
+ tridi = insert(:user)
+
+ {:ok, chat_1} = Chat.get_or_create(user.id, har.ap_id)
+ {:ok, chat_1} = time_travel(chat_1, -3)
+ {:ok, chat_2} = Chat.get_or_create(user.id, jafnhar.ap_id)
+ {:ok, _chat_2} = time_travel(chat_2, -2)
+ {:ok, chat_3} = Chat.get_or_create(user.id, tridi.ap_id)
+ {:ok, chat_3} = time_travel(chat_3, -1)
+
+ # bump the second one
+ {:ok, chat_2} = Chat.bump_or_create(user.id, jafnhar.ap_id)
+
+ result =
+ conn
+ |> get(unquote(tested_endpoint))
+ |> json_response_and_validate_schema(200)
+
+ ids = Enum.map(result, & &1["id"])
+
+ assert ids == [
+ chat_2.id |> to_string(),
+ chat_3.id |> to_string(),
+ chat_1.id |> to_string()
+ ]
+ end
+
+ test "it is not affected by :restrict_unauthenticated setting (issue #1973)", %{
+ conn: conn,
+ user: user
+ } do
+ clear_config([:restrict_unauthenticated, :profiles, :local], true)
+ clear_config([:restrict_unauthenticated, :profiles, :remote], true)
+
+ user2 = insert(:user)
+ user3 = insert(:user, local: false)
+
+ {:ok, _chat_12} = Chat.get_or_create(user.id, user2.ap_id)
+ {:ok, _chat_13} = Chat.get_or_create(user.id, user3.ap_id)
+
+ result =
+ conn
+ |> get(unquote(tested_endpoint))
+ |> json_response_and_validate_schema(200)
+
+ account_ids = Enum.map(result, &get_in(&1, ["account", "id"]))
+ assert Enum.sort(account_ids) == Enum.sort([user2.id, user3.id])
+ end
end
end
end
diff --git a/test/web/pleroma_api/controllers/conversation_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/conversation_controller_test.exs
index e6d0b3e37..54f2c5a58 100644
--- a/test/web/pleroma_api/controllers/conversation_controller_test.exs
+++ b/test/pleroma/web/pleroma_api/controllers/conversation_controller_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.PleromaAPI.ConversationControllerTest do
- use Pleroma.Web.ConnCase
+ use Pleroma.Web.ConnCase, async: true
alias Pleroma.Conversation.Participation
alias Pleroma.Repo
@@ -104,7 +104,7 @@ defmodule Pleroma.Web.PleromaAPI.ConversationControllerTest do
[participation] = Participation.for_user(user)
participation = Repo.preload(participation, :recipients)
- assert user in participation.recipients
+ assert refresh_record(user) in participation.recipients
assert other_user in participation.recipients
end
@@ -121,7 +121,7 @@ defmodule Pleroma.Web.PleromaAPI.ConversationControllerTest do
[participation2, participation1] = Participation.for_user(other_user)
assert Participation.get(participation2.id).read == false
assert Participation.get(participation1.id).read == false
- assert User.get_cached_by_id(other_user.id).unread_conversation_count == 2
+ assert Participation.unread_count(other_user) == 2
[%{"unread" => false}, %{"unread" => false}] =
conn
@@ -131,6 +131,6 @@ defmodule Pleroma.Web.PleromaAPI.ConversationControllerTest do
[participation2, participation1] = Participation.for_user(other_user)
assert Participation.get(participation2.id).read == true
assert Participation.get(participation1.id).read == true
- assert User.get_cached_by_id(other_user.id).unread_conversation_count == 0
+ assert Participation.unread_count(other_user) == 0
end
end
diff --git a/test/pleroma/web/pleroma_api/controllers/emoji_file_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/emoji_file_controller_test.exs
new file mode 100644
index 000000000..547391249
--- /dev/null
+++ b/test/pleroma/web/pleroma_api/controllers/emoji_file_controller_test.exs
@@ -0,0 +1,381 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PleromaAPI.EmojiFileControllerTest do
+ use Pleroma.Web.ConnCase
+
+ import Mock
+ import Tesla.Mock
+ import Pleroma.Factory
+
+ @emoji_path Path.join(
+ Pleroma.Config.get!([:instance, :static_dir]),
+ "emoji"
+ )
+ setup do: clear_config([:instance, :public], true)
+
+ setup do
+ admin = insert(:user, is_admin: true)
+ token = insert(:oauth_admin_token, user: admin)
+
+ admin_conn =
+ build_conn()
+ |> assign(:user, admin)
+ |> assign(:token, token)
+
+ Pleroma.Emoji.reload()
+ {:ok, %{admin_conn: admin_conn}}
+ end
+
+ describe "POST/PATCH/DELETE /api/pleroma/emoji/packs/files?name=:name" do
+ setup do
+ pack_file = "#{@emoji_path}/test_pack/pack.json"
+ original_content = File.read!(pack_file)
+
+ on_exit(fn ->
+ File.write!(pack_file, original_content)
+ end)
+
+ :ok
+ end
+
+ test "upload zip file with emojies", %{admin_conn: admin_conn} do
+ on_exit(fn ->
+ [
+ "128px/a_trusted_friend-128.png",
+ "auroraborealis.png",
+ "1000px/baby_in_a_box.png",
+ "1000px/bear.png",
+ "128px/bear-128.png"
+ ]
+ |> Enum.each(fn path -> File.rm_rf!("#{@emoji_path}/test_pack/#{path}") end)
+ end)
+
+ resp =
+ admin_conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> post("/api/pleroma/emoji/packs/files?name=test_pack", %{
+ file: %Plug.Upload{
+ content_type: "application/zip",
+ filename: "emojis.zip",
+ path: Path.absname("test/fixtures/emojis.zip")
+ }
+ })
+ |> json_response_and_validate_schema(200)
+
+ assert resp == %{
+ "a_trusted_friend-128" => "128px/a_trusted_friend-128.png",
+ "auroraborealis" => "auroraborealis.png",
+ "baby_in_a_box" => "1000px/baby_in_a_box.png",
+ "bear" => "1000px/bear.png",
+ "bear-128" => "128px/bear-128.png",
+ "blank" => "blank.png",
+ "blank2" => "blank2.png"
+ }
+
+ Enum.each(Map.values(resp), fn path ->
+ assert File.exists?("#{@emoji_path}/test_pack/#{path}")
+ end)
+ end
+
+ test "create shortcode exists", %{admin_conn: admin_conn} do
+ assert admin_conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> post("/api/pleroma/emoji/packs/files?name=test_pack", %{
+ shortcode: "blank",
+ filename: "dir/blank.png",
+ file: %Plug.Upload{
+ filename: "blank.png",
+ path: "#{@emoji_path}/test_pack/blank.png"
+ }
+ })
+ |> json_response_and_validate_schema(:conflict) == %{
+ "error" => "An emoji with the \"blank\" shortcode already exists"
+ }
+ end
+
+ test "don't rewrite old emoji", %{admin_conn: admin_conn} do
+ on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir/") end)
+
+ assert admin_conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> post("/api/pleroma/emoji/packs/files?name=test_pack", %{
+ shortcode: "blank3",
+ filename: "dir/blank.png",
+ file: %Plug.Upload{
+ filename: "blank.png",
+ path: "#{@emoji_path}/test_pack/blank.png"
+ }
+ })
+ |> json_response_and_validate_schema(200) == %{
+ "blank" => "blank.png",
+ "blank2" => "blank2.png",
+ "blank3" => "dir/blank.png"
+ }
+
+ assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png")
+
+ assert admin_conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> patch("/api/pleroma/emoji/packs/files?name=test_pack", %{
+ shortcode: "blank",
+ new_shortcode: "blank2",
+ new_filename: "dir_2/blank_3.png"
+ })
+ |> json_response_and_validate_schema(:conflict) == %{
+ "error" =>
+ "New shortcode \"blank2\" is already used. If you want to override emoji use 'force' option"
+ }
+ end
+
+ test "rewrite old emoji with force option", %{admin_conn: admin_conn} do
+ on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir_2/") end)
+
+ assert admin_conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> post("/api/pleroma/emoji/packs/files?name=test_pack", %{
+ shortcode: "blank3",
+ filename: "dir/blank.png",
+ file: %Plug.Upload{
+ filename: "blank.png",
+ path: "#{@emoji_path}/test_pack/blank.png"
+ }
+ })
+ |> json_response_and_validate_schema(200) == %{
+ "blank" => "blank.png",
+ "blank2" => "blank2.png",
+ "blank3" => "dir/blank.png"
+ }
+
+ assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png")
+
+ assert admin_conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> patch("/api/pleroma/emoji/packs/files?name=test_pack", %{
+ shortcode: "blank3",
+ new_shortcode: "blank4",
+ new_filename: "dir_2/blank_3.png",
+ force: true
+ })
+ |> json_response_and_validate_schema(200) == %{
+ "blank" => "blank.png",
+ "blank2" => "blank2.png",
+ "blank4" => "dir_2/blank_3.png"
+ }
+
+ assert File.exists?("#{@emoji_path}/test_pack/dir_2/blank_3.png")
+ end
+
+ test "with empty filename", %{admin_conn: admin_conn} do
+ assert admin_conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> post("/api/pleroma/emoji/packs/files?name=test_pack", %{
+ shortcode: "blank2",
+ filename: "",
+ file: %Plug.Upload{
+ filename: "blank.png",
+ path: "#{@emoji_path}/test_pack/blank.png"
+ }
+ })
+ |> json_response_and_validate_schema(422) == %{
+ "error" => "pack name, shortcode or filename cannot be empty"
+ }
+ end
+
+ test "add file with not loaded pack", %{admin_conn: admin_conn} do
+ assert admin_conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> post("/api/pleroma/emoji/packs/files?name=not_loaded", %{
+ shortcode: "blank3",
+ filename: "dir/blank.png",
+ file: %Plug.Upload{
+ filename: "blank.png",
+ path: "#{@emoji_path}/test_pack/blank.png"
+ }
+ })
+ |> json_response_and_validate_schema(:not_found) == %{
+ "error" => "pack \"not_loaded\" is not found"
+ }
+ end
+
+ test "returns an error on add file when file system is not writable", %{
+ admin_conn: admin_conn
+ } do
+ pack_file = Path.join([@emoji_path, "not_loaded", "pack.json"])
+
+ with_mocks([
+ {File, [:passthrough], [stat: fn ^pack_file -> {:error, :eacces} end]}
+ ]) do
+ assert admin_conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> post("/api/pleroma/emoji/packs/files?name=not_loaded", %{
+ shortcode: "blank3",
+ filename: "dir/blank.png",
+ file: %Plug.Upload{
+ filename: "blank.png",
+ path: "#{@emoji_path}/test_pack/blank.png"
+ }
+ })
+ |> json_response_and_validate_schema(500) == %{
+ "error" =>
+ "Unexpected error occurred while adding file to pack. (POSIX error: Permission denied)"
+ }
+ end
+ end
+
+ test "remove file with not loaded pack", %{admin_conn: admin_conn} do
+ assert admin_conn
+ |> delete("/api/pleroma/emoji/packs/files?name=not_loaded&shortcode=blank3")
+ |> json_response_and_validate_schema(:not_found) == %{
+ "error" => "pack \"not_loaded\" is not found"
+ }
+ end
+
+ test "remove file with empty shortcode", %{admin_conn: admin_conn} do
+ assert admin_conn
+ |> delete("/api/pleroma/emoji/packs/files?name=not_loaded&shortcode=")
+ |> json_response_and_validate_schema(:not_found) == %{
+ "error" => "pack \"not_loaded\" is not found"
+ }
+ end
+
+ test "update file with not loaded pack", %{admin_conn: admin_conn} do
+ assert admin_conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> patch("/api/pleroma/emoji/packs/files?name=not_loaded", %{
+ shortcode: "blank4",
+ new_shortcode: "blank3",
+ new_filename: "dir_2/blank_3.png"
+ })
+ |> json_response_and_validate_schema(:not_found) == %{
+ "error" => "pack \"not_loaded\" is not found"
+ }
+ end
+
+ test "new with shortcode as file with update", %{admin_conn: admin_conn} do
+ assert admin_conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> post("/api/pleroma/emoji/packs/files?name=test_pack", %{
+ shortcode: "blank4",
+ filename: "dir/blank.png",
+ file: %Plug.Upload{
+ filename: "blank.png",
+ path: "#{@emoji_path}/test_pack/blank.png"
+ }
+ })
+ |> json_response_and_validate_schema(200) == %{
+ "blank" => "blank.png",
+ "blank4" => "dir/blank.png",
+ "blank2" => "blank2.png"
+ }
+
+ assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png")
+
+ assert admin_conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> patch("/api/pleroma/emoji/packs/files?name=test_pack", %{
+ shortcode: "blank4",
+ new_shortcode: "blank3",
+ new_filename: "dir_2/blank_3.png"
+ })
+ |> json_response_and_validate_schema(200) == %{
+ "blank3" => "dir_2/blank_3.png",
+ "blank" => "blank.png",
+ "blank2" => "blank2.png"
+ }
+
+ refute File.exists?("#{@emoji_path}/test_pack/dir/")
+ assert File.exists?("#{@emoji_path}/test_pack/dir_2/blank_3.png")
+
+ assert admin_conn
+ |> delete("/api/pleroma/emoji/packs/files?name=test_pack&shortcode=blank3")
+ |> json_response_and_validate_schema(200) == %{
+ "blank" => "blank.png",
+ "blank2" => "blank2.png"
+ }
+
+ refute File.exists?("#{@emoji_path}/test_pack/dir_2/")
+
+ on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir") end)
+ end
+
+ test "new with shortcode from url", %{admin_conn: admin_conn} do
+ mock(fn
+ %{
+ method: :get,
+ url: "https://test-blank/blank_url.png"
+ } ->
+ text(File.read!("#{@emoji_path}/test_pack/blank.png"))
+ end)
+
+ assert admin_conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> post("/api/pleroma/emoji/packs/files?name=test_pack", %{
+ shortcode: "blank_url",
+ file: "https://test-blank/blank_url.png"
+ })
+ |> json_response_and_validate_schema(200) == %{
+ "blank_url" => "blank_url.png",
+ "blank" => "blank.png",
+ "blank2" => "blank2.png"
+ }
+
+ assert File.exists?("#{@emoji_path}/test_pack/blank_url.png")
+
+ on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/blank_url.png") end)
+ end
+
+ test "new without shortcode", %{admin_conn: admin_conn} do
+ on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/shortcode.png") end)
+
+ assert admin_conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> post("/api/pleroma/emoji/packs/files?name=test_pack", %{
+ file: %Plug.Upload{
+ filename: "shortcode.png",
+ path: "#{Pleroma.Config.get([:instance, :static_dir])}/add/shortcode.png"
+ }
+ })
+ |> json_response_and_validate_schema(200) == %{
+ "shortcode" => "shortcode.png",
+ "blank" => "blank.png",
+ "blank2" => "blank2.png"
+ }
+ end
+
+ test "remove non existing shortcode in pack.json", %{admin_conn: admin_conn} do
+ assert admin_conn
+ |> delete("/api/pleroma/emoji/packs/files?name=test_pack&shortcode=blank3")
+ |> json_response_and_validate_schema(:bad_request) == %{
+ "error" => "Emoji \"blank3\" does not exist"
+ }
+ end
+
+ test "update non existing emoji", %{admin_conn: admin_conn} do
+ assert admin_conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> patch("/api/pleroma/emoji/packs/files?name=test_pack", %{
+ shortcode: "blank3",
+ new_shortcode: "blank4",
+ new_filename: "dir_2/blank_3.png"
+ })
+ |> json_response_and_validate_schema(:bad_request) == %{
+ "error" => "Emoji \"blank3\" does not exist"
+ }
+ end
+
+ test "update with empty shortcode", %{admin_conn: admin_conn} do
+ assert %{
+ "error" => "Missing field: new_shortcode."
+ } =
+ admin_conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> patch("/api/pleroma/emoji/packs/files?name=test_pack", %{
+ shortcode: "blank",
+ new_filename: "dir_2/blank_3.png"
+ })
+ |> json_response_and_validate_schema(:bad_request)
+ end
+ end
+end
diff --git a/test/web/pleroma_api/controllers/emoji_pack_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/emoji_pack_controller_test.exs
index e113bb15f..d1ba067b8 100644
--- a/test/web/pleroma_api/controllers/emoji_pack_controller_test.exs
+++ b/test/pleroma/web/pleroma_api/controllers/emoji_pack_controller_test.exs
@@ -1,10 +1,11 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
- use Pleroma.Web.ConnCase
+ use Pleroma.Web.ConnCase, async: false
+ import Mock
import Tesla.Mock
import Pleroma.Factory
@@ -12,7 +13,6 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
Pleroma.Config.get!([:instance, :static_dir]),
"emoji"
)
- setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], false)
setup do: clear_config([:instance, :public], true)
@@ -30,18 +30,18 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
end
test "GET /api/pleroma/emoji/packs when :public: false", %{conn: conn} do
- Config.put([:instance, :public], false)
+ clear_config([:instance, :public], false)
conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200)
end
test "GET /api/pleroma/emoji/packs", %{conn: conn} do
resp = conn |> get("/api/pleroma/emoji/packs") |> json_response_and_validate_schema(200)
- assert resp["count"] == 3
+ assert resp["count"] == 4
assert resp["packs"]
|> Map.keys()
- |> length() == 3
+ |> length() == 4
shared = resp["packs"]["test_pack"]
assert shared["files"] == %{"blank" => "blank.png", "blank2" => "blank2.png"}
@@ -58,7 +58,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
|> get("/api/pleroma/emoji/packs?page_size=1")
|> json_response_and_validate_schema(200)
- assert resp["count"] == 3
+ assert resp["count"] == 4
packs = Map.keys(resp["packs"])
@@ -71,7 +71,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
|> get("/api/pleroma/emoji/packs?page_size=1&page=2")
|> json_response_and_validate_schema(200)
- assert resp["count"] == 3
+ assert resp["count"] == 4
packs = Map.keys(resp["packs"])
assert length(packs) == 1
[pack2] = packs
@@ -81,18 +81,28 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
|> get("/api/pleroma/emoji/packs?page_size=1&page=3")
|> json_response_and_validate_schema(200)
- assert resp["count"] == 3
+ assert resp["count"] == 4
packs = Map.keys(resp["packs"])
assert length(packs) == 1
[pack3] = packs
- assert [pack1, pack2, pack3] |> Enum.uniq() |> length() == 3
+
+ resp =
+ conn
+ |> get("/api/pleroma/emoji/packs?page_size=1&page=4")
+ |> json_response_and_validate_schema(200)
+
+ assert resp["count"] == 4
+ packs = Map.keys(resp["packs"])
+ assert length(packs) == 1
+ [pack4] = packs
+ assert [pack1, pack2, pack3, pack4] |> Enum.uniq() |> length() == 4
end
describe "GET /api/pleroma/emoji/packs/remote" do
test "shareable instance", %{admin_conn: admin_conn, conn: conn} do
resp =
conn
- |> get("/api/pleroma/emoji/packs")
+ |> get("/api/pleroma/emoji/packs?page=2&page_size=1")
|> json_response_and_validate_schema(200)
mock(fn
@@ -102,12 +112,12 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
%{method: :get, url: "https://example.com/nodeinfo/2.1.json"} ->
json(%{metadata: %{features: ["shareable_emoji_packs"]}})
- %{method: :get, url: "https://example.com/api/pleroma/emoji/packs"} ->
+ %{method: :get, url: "https://example.com/api/pleroma/emoji/packs?page=2&page_size=1"} ->
json(resp)
end)
assert admin_conn
- |> get("/api/pleroma/emoji/packs/remote?url=https://example.com")
+ |> get("/api/pleroma/emoji/packs/remote?url=https://example.com&page=2&page_size=1")
|> json_response_and_validate_schema(200) == resp
end
@@ -128,11 +138,11 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
end
end
- describe "GET /api/pleroma/emoji/packs/:name/archive" do
+ describe "GET /api/pleroma/emoji/packs/archive?name=:name" do
test "download shared pack", %{conn: conn} do
resp =
conn
- |> get("/api/pleroma/emoji/packs/test_pack/archive")
+ |> get("/api/pleroma/emoji/packs/archive?name=test_pack")
|> response(200)
{:ok, arch} = :zip.unzip(resp, [:memory])
@@ -143,7 +153,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
test "non existing pack", %{conn: conn} do
assert conn
- |> get("/api/pleroma/emoji/packs/test_pack_for_import/archive")
+ |> get("/api/pleroma/emoji/packs/archive?name=test_pack_for_import")
|> json_response_and_validate_schema(:not_found) == %{
"error" => "Pack test_pack_for_import does not exist"
}
@@ -151,7 +161,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
test "non downloadable pack", %{conn: conn} do
assert conn
- |> get("/api/pleroma/emoji/packs/test_pack_nonshared/archive")
+ |> get("/api/pleroma/emoji/packs/archive?name=test_pack_nonshared")
|> json_response_and_validate_schema(:forbidden) == %{
"error" =>
"Pack test_pack_nonshared cannot be downloaded from this instance, either pack sharing was disabled for this pack or some files are missing"
@@ -173,28 +183,28 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
%{
method: :get,
- url: "https://example.com/api/pleroma/emoji/packs/test_pack"
+ url: "https://example.com/api/pleroma/emoji/pack?name=test_pack"
} ->
conn
- |> get("/api/pleroma/emoji/packs/test_pack")
+ |> get("/api/pleroma/emoji/pack?name=test_pack")
|> json_response_and_validate_schema(200)
|> json()
%{
method: :get,
- url: "https://example.com/api/pleroma/emoji/packs/test_pack/archive"
+ url: "https://example.com/api/pleroma/emoji/packs/archive?name=test_pack"
} ->
conn
- |> get("/api/pleroma/emoji/packs/test_pack/archive")
+ |> get("/api/pleroma/emoji/packs/archive?name=test_pack")
|> response(200)
|> text()
%{
method: :get,
- url: "https://example.com/api/pleroma/emoji/packs/test_pack_nonshared"
+ url: "https://example.com/api/pleroma/emoji/pack?name=test_pack_nonshared"
} ->
conn
- |> get("/api/pleroma/emoji/packs/test_pack_nonshared")
+ |> get("/api/pleroma/emoji/pack?name=test_pack_nonshared")
|> json_response_and_validate_schema(200)
|> json()
@@ -218,7 +228,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
assert File.exists?("#{@emoji_path}/test_pack2/blank.png")
assert admin_conn
- |> delete("/api/pleroma/emoji/packs/test_pack2")
+ |> delete("/api/pleroma/emoji/pack?name=test_pack2")
|> json_response_and_validate_schema(200) == "ok"
refute File.exists?("#{@emoji_path}/test_pack2")
@@ -239,7 +249,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
assert File.exists?("#{@emoji_path}/test_pack_nonshared2/blank.png")
assert admin_conn
- |> delete("/api/pleroma/emoji/packs/test_pack_nonshared2")
+ |> delete("/api/pleroma/emoji/pack?name=test_pack_nonshared2")
|> json_response_and_validate_schema(200) == "ok"
refute File.exists?("#{@emoji_path}/test_pack_nonshared2")
@@ -279,14 +289,14 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
%{
method: :get,
- url: "https://example.com/api/pleroma/emoji/packs/pack_bad_sha"
+ url: "https://example.com/api/pleroma/emoji/pack?name=pack_bad_sha"
} ->
{:ok, pack} = Pleroma.Emoji.Pack.load_pack("pack_bad_sha")
%Tesla.Env{status: 200, body: Jason.encode!(pack)}
%{
method: :get,
- url: "https://example.com/api/pleroma/emoji/packs/pack_bad_sha/archive"
+ url: "https://example.com/api/pleroma/emoji/packs/archive?name=pack_bad_sha"
} ->
%Tesla.Env{
status: 200,
@@ -316,7 +326,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
%{
method: :get,
- url: "https://example.com/api/pleroma/emoji/packs/test_pack"
+ url: "https://example.com/api/pleroma/emoji/pack?name=test_pack"
} ->
{:ok, pack} = Pleroma.Emoji.Pack.load_pack("test_pack")
%Tesla.Env{status: 200, body: Jason.encode!(pack)}
@@ -336,7 +346,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
end
end
- describe "PATCH /api/pleroma/emoji/packs/:name" do
+ describe "PATCH/update /api/pleroma/emoji/pack?name=:name" do
setup do
pack_file = "#{@emoji_path}/test_pack/pack.json"
original_content = File.read!(pack_file)
@@ -355,10 +365,26 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
}}
end
+ test "returns error when file system not writable", %{admin_conn: conn} = ctx do
+ with_mocks([
+ {File, [:passthrough], [stat: fn _ -> {:error, :eacces} end]}
+ ]) do
+ assert conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> patch(
+ "/api/pleroma/emoji/pack?name=test_pack",
+ %{"metadata" => ctx[:new_data]}
+ )
+ |> json_response_and_validate_schema(500)
+ end
+ end
+
test "for a pack without a fallback source", ctx do
assert ctx[:admin_conn]
|> put_req_header("content-type", "multipart/form-data")
- |> patch("/api/pleroma/emoji/packs/test_pack", %{"metadata" => ctx[:new_data]})
+ |> patch("/api/pleroma/emoji/pack?name=test_pack", %{
+ "metadata" => ctx[:new_data]
+ })
|> json_response_and_validate_schema(200) == ctx[:new_data]
assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == ctx[:new_data]
@@ -384,7 +410,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
assert ctx[:admin_conn]
|> put_req_header("content-type", "multipart/form-data")
- |> patch("/api/pleroma/emoji/packs/test_pack", %{metadata: new_data})
+ |> patch("/api/pleroma/emoji/pack?name=test_pack", %{metadata: new_data})
|> json_response_and_validate_schema(200) == new_data_with_sha
assert Jason.decode!(File.read!(ctx[:pack_file]))["pack"] == new_data_with_sha
@@ -404,304 +430,57 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
assert ctx[:admin_conn]
|> put_req_header("content-type", "multipart/form-data")
- |> patch("/api/pleroma/emoji/packs/test_pack", %{metadata: new_data})
+ |> patch("/api/pleroma/emoji/pack?name=test_pack", %{metadata: new_data})
|> json_response_and_validate_schema(:bad_request) == %{
"error" => "The fallback archive does not have all files specified in pack.json"
}
end
end
- describe "POST/PATCH/DELETE /api/pleroma/emoji/packs/:name/files" do
- setup do
- pack_file = "#{@emoji_path}/test_pack/pack.json"
- original_content = File.read!(pack_file)
-
- on_exit(fn ->
- File.write!(pack_file, original_content)
- end)
-
- :ok
- end
-
- test "create shortcode exists", %{admin_conn: admin_conn} do
- assert admin_conn
- |> put_req_header("content-type", "multipart/form-data")
- |> post("/api/pleroma/emoji/packs/test_pack/files", %{
- shortcode: "blank",
- filename: "dir/blank.png",
- file: %Plug.Upload{
- filename: "blank.png",
- path: "#{@emoji_path}/test_pack/blank.png"
- }
- })
- |> json_response_and_validate_schema(:conflict) == %{
- "error" => "An emoji with the \"blank\" shortcode already exists"
- }
- end
-
- test "don't rewrite old emoji", %{admin_conn: admin_conn} do
- on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir/") end)
-
- assert admin_conn
- |> put_req_header("content-type", "multipart/form-data")
- |> post("/api/pleroma/emoji/packs/test_pack/files", %{
- shortcode: "blank3",
- filename: "dir/blank.png",
- file: %Plug.Upload{
- filename: "blank.png",
- path: "#{@emoji_path}/test_pack/blank.png"
- }
- })
- |> json_response_and_validate_schema(200) == %{
- "blank" => "blank.png",
- "blank2" => "blank2.png",
- "blank3" => "dir/blank.png"
- }
-
- assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png")
-
- assert admin_conn
- |> put_req_header("content-type", "multipart/form-data")
- |> patch("/api/pleroma/emoji/packs/test_pack/files", %{
- shortcode: "blank",
- new_shortcode: "blank2",
- new_filename: "dir_2/blank_3.png"
- })
- |> json_response_and_validate_schema(:conflict) == %{
- "error" =>
- "New shortcode \"blank2\" is already used. If you want to override emoji use 'force' option"
- }
- end
-
- test "rewrite old emoji with force option", %{admin_conn: admin_conn} do
- on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir_2/") end)
-
- assert admin_conn
- |> put_req_header("content-type", "multipart/form-data")
- |> post("/api/pleroma/emoji/packs/test_pack/files", %{
- shortcode: "blank3",
- filename: "dir/blank.png",
- file: %Plug.Upload{
- filename: "blank.png",
- path: "#{@emoji_path}/test_pack/blank.png"
- }
- })
- |> json_response_and_validate_schema(200) == %{
- "blank" => "blank.png",
- "blank2" => "blank2.png",
- "blank3" => "dir/blank.png"
- }
-
- assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png")
-
- assert admin_conn
- |> put_req_header("content-type", "multipart/form-data")
- |> patch("/api/pleroma/emoji/packs/test_pack/files", %{
- shortcode: "blank3",
- new_shortcode: "blank4",
- new_filename: "dir_2/blank_3.png",
- force: true
- })
- |> json_response_and_validate_schema(200) == %{
- "blank" => "blank.png",
- "blank2" => "blank2.png",
- "blank4" => "dir_2/blank_3.png"
- }
-
- assert File.exists?("#{@emoji_path}/test_pack/dir_2/blank_3.png")
- end
-
- test "with empty filename", %{admin_conn: admin_conn} do
- assert admin_conn
- |> put_req_header("content-type", "multipart/form-data")
- |> post("/api/pleroma/emoji/packs/test_pack/files", %{
- shortcode: "blank2",
- filename: "",
- file: %Plug.Upload{
- filename: "blank.png",
- path: "#{@emoji_path}/test_pack/blank.png"
- }
- })
- |> json_response_and_validate_schema(:bad_request) == %{
- "error" => "pack name, shortcode or filename cannot be empty"
- }
- end
-
- test "add file with not loaded pack", %{admin_conn: admin_conn} do
- assert admin_conn
- |> put_req_header("content-type", "multipart/form-data")
- |> post("/api/pleroma/emoji/packs/not_loaded/files", %{
- shortcode: "blank3",
- filename: "dir/blank.png",
- file: %Plug.Upload{
- filename: "blank.png",
- path: "#{@emoji_path}/test_pack/blank.png"
- }
- })
- |> json_response_and_validate_schema(:bad_request) == %{
- "error" => "pack \"not_loaded\" is not found"
- }
- end
-
- test "remove file with not loaded pack", %{admin_conn: admin_conn} do
- assert admin_conn
- |> delete("/api/pleroma/emoji/packs/not_loaded/files?shortcode=blank3")
- |> json_response_and_validate_schema(:bad_request) == %{
- "error" => "pack \"not_loaded\" is not found"
- }
- end
-
- test "remove file with empty shortcode", %{admin_conn: admin_conn} do
- assert admin_conn
- |> delete("/api/pleroma/emoji/packs/not_loaded/files?shortcode=")
- |> json_response_and_validate_schema(:bad_request) == %{
- "error" => "pack name or shortcode cannot be empty"
- }
- end
-
- test "update file with not loaded pack", %{admin_conn: admin_conn} do
- assert admin_conn
- |> put_req_header("content-type", "multipart/form-data")
- |> patch("/api/pleroma/emoji/packs/not_loaded/files", %{
- shortcode: "blank4",
- new_shortcode: "blank3",
- new_filename: "dir_2/blank_3.png"
- })
- |> json_response_and_validate_schema(:bad_request) == %{
- "error" => "pack \"not_loaded\" is not found"
- }
- end
-
- test "new with shortcode as file with update", %{admin_conn: admin_conn} do
- assert admin_conn
- |> put_req_header("content-type", "multipart/form-data")
- |> post("/api/pleroma/emoji/packs/test_pack/files", %{
- shortcode: "blank4",
- filename: "dir/blank.png",
- file: %Plug.Upload{
- filename: "blank.png",
- path: "#{@emoji_path}/test_pack/blank.png"
- }
- })
- |> json_response_and_validate_schema(200) == %{
- "blank" => "blank.png",
- "blank4" => "dir/blank.png",
- "blank2" => "blank2.png"
- }
-
- assert File.exists?("#{@emoji_path}/test_pack/dir/blank.png")
-
- assert admin_conn
- |> put_req_header("content-type", "multipart/form-data")
- |> patch("/api/pleroma/emoji/packs/test_pack/files", %{
- shortcode: "blank4",
- new_shortcode: "blank3",
- new_filename: "dir_2/blank_3.png"
- })
- |> json_response_and_validate_schema(200) == %{
- "blank3" => "dir_2/blank_3.png",
- "blank" => "blank.png",
- "blank2" => "blank2.png"
- }
-
- refute File.exists?("#{@emoji_path}/test_pack/dir/")
- assert File.exists?("#{@emoji_path}/test_pack/dir_2/blank_3.png")
-
- assert admin_conn
- |> delete("/api/pleroma/emoji/packs/test_pack/files?shortcode=blank3")
- |> json_response_and_validate_schema(200) == %{
- "blank" => "blank.png",
- "blank2" => "blank2.png"
- }
-
- refute File.exists?("#{@emoji_path}/test_pack/dir_2/")
-
- on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/dir") end)
- end
-
- test "new with shortcode from url", %{admin_conn: admin_conn} do
- mock(fn
- %{
- method: :get,
- url: "https://test-blank/blank_url.png"
- } ->
- text(File.read!("#{@emoji_path}/test_pack/blank.png"))
- end)
-
- assert admin_conn
- |> put_req_header("content-type", "multipart/form-data")
- |> post("/api/pleroma/emoji/packs/test_pack/files", %{
- shortcode: "blank_url",
- file: "https://test-blank/blank_url.png"
- })
- |> json_response_and_validate_schema(200) == %{
- "blank_url" => "blank_url.png",
- "blank" => "blank.png",
- "blank2" => "blank2.png"
- }
-
- assert File.exists?("#{@emoji_path}/test_pack/blank_url.png")
-
- on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/blank_url.png") end)
- end
-
- test "new without shortcode", %{admin_conn: admin_conn} do
- on_exit(fn -> File.rm_rf!("#{@emoji_path}/test_pack/shortcode.png") end)
-
- assert admin_conn
- |> put_req_header("content-type", "multipart/form-data")
- |> post("/api/pleroma/emoji/packs/test_pack/files", %{
- file: %Plug.Upload{
- filename: "shortcode.png",
- path: "#{Pleroma.Config.get([:instance, :static_dir])}/add/shortcode.png"
+ describe "POST/DELETE /api/pleroma/emoji/pack?name=:name" do
+ test "returns an error on creates pack when file system not writable", %{
+ admin_conn: admin_conn
+ } do
+ path_pack = Path.join(@emoji_path, "test_pack")
+
+ with_mocks([
+ {File, [:passthrough], [mkdir: fn ^path_pack -> {:error, :eacces} end]}
+ ]) do
+ assert admin_conn
+ |> post("/api/pleroma/emoji/pack?name=test_pack")
+ |> json_response_and_validate_schema(500) == %{
+ "error" =>
+ "Unexpected error occurred while creating pack. (POSIX error: Permission denied)"
}
- })
- |> json_response_and_validate_schema(200) == %{
- "shortcode" => "shortcode.png",
- "blank" => "blank.png",
- "blank2" => "blank2.png"
- }
+ end
end
- test "remove non existing shortcode in pack.json", %{admin_conn: admin_conn} do
- assert admin_conn
- |> delete("/api/pleroma/emoji/packs/test_pack/files?shortcode=blank3")
- |> json_response_and_validate_schema(:bad_request) == %{
- "error" => "Emoji \"blank3\" does not exist"
- }
- end
-
- test "update non existing emoji", %{admin_conn: admin_conn} do
- assert admin_conn
- |> put_req_header("content-type", "multipart/form-data")
- |> patch("/api/pleroma/emoji/packs/test_pack/files", %{
- shortcode: "blank3",
- new_shortcode: "blank4",
- new_filename: "dir_2/blank_3.png"
- })
- |> json_response_and_validate_schema(:bad_request) == %{
- "error" => "Emoji \"blank3\" does not exist"
- }
- end
-
- test "update with empty shortcode", %{admin_conn: admin_conn} do
- assert %{
- "error" => "Missing field: new_shortcode."
- } =
- admin_conn
- |> put_req_header("content-type", "multipart/form-data")
- |> patch("/api/pleroma/emoji/packs/test_pack/files", %{
- shortcode: "blank",
- new_filename: "dir_2/blank_3.png"
- })
- |> json_response_and_validate_schema(:bad_request)
+ test "returns an error on deletes pack when the file system is not writable", %{
+ admin_conn: admin_conn
+ } do
+ path_pack = Path.join(@emoji_path, "test_emoji_pack")
+
+ try do
+ {:ok, _pack} = Pleroma.Emoji.Pack.create("test_emoji_pack")
+
+ with_mocks([
+ {File, [:passthrough], [rm_rf: fn ^path_pack -> {:error, :eacces, path_pack} end]}
+ ]) do
+ assert admin_conn
+ |> delete("/api/pleroma/emoji/pack?name=test_emoji_pack")
+ |> json_response_and_validate_schema(500) == %{
+ "error" =>
+ "Couldn't delete the `test_emoji_pack` pack (POSIX error: Permission denied)"
+ }
+ end
+ after
+ File.rm_rf(path_pack)
+ end
end
- end
- describe "POST/DELETE /api/pleroma/emoji/packs/:name" do
test "creating and deleting a pack", %{admin_conn: admin_conn} do
assert admin_conn
- |> post("/api/pleroma/emoji/packs/test_created")
+ |> post("/api/pleroma/emoji/pack?name=test_created")
|> json_response_and_validate_schema(200) == "ok"
assert File.exists?("#{@emoji_path}/test_created/pack.json")
@@ -713,7 +492,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
}
assert admin_conn
- |> delete("/api/pleroma/emoji/packs/test_created")
+ |> delete("/api/pleroma/emoji/pack?name=test_created")
|> json_response_and_validate_schema(200) == "ok"
refute File.exists?("#{@emoji_path}/test_created/pack.json")
@@ -726,7 +505,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
File.write!(Path.join(path, "pack.json"), pack_file)
assert admin_conn
- |> post("/api/pleroma/emoji/packs/test_created")
+ |> post("/api/pleroma/emoji/pack?name=test_created")
|> json_response_and_validate_schema(:conflict) == %{
"error" => "A pack named \"test_created\" already exists"
}
@@ -736,7 +515,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
test "with empty name", %{admin_conn: admin_conn} do
assert admin_conn
- |> post("/api/pleroma/emoji/packs/ ")
+ |> post("/api/pleroma/emoji/pack?name= ")
|> json_response_and_validate_schema(:bad_request) == %{
"error" => "pack name cannot be empty"
}
@@ -745,7 +524,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
test "deleting nonexisting pack", %{admin_conn: admin_conn} do
assert admin_conn
- |> delete("/api/pleroma/emoji/packs/non_existing")
+ |> delete("/api/pleroma/emoji/pack?name=non_existing")
|> json_response_and_validate_schema(:not_found) == %{
"error" => "Pack non_existing does not exist"
}
@@ -753,7 +532,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
test "deleting with empty name", %{admin_conn: admin_conn} do
assert admin_conn
- |> delete("/api/pleroma/emoji/packs/ ")
+ |> delete("/api/pleroma/emoji/pack?name= ")
|> json_response_and_validate_schema(:bad_request) == %{
"error" => "pack name cannot be empty"
}
@@ -801,7 +580,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
}
end
- describe "GET /api/pleroma/emoji/packs/:name" do
+ describe "GET /api/pleroma/emoji/pack?name=:name" do
test "shows pack.json", %{conn: conn} do
assert %{
"files" => files,
@@ -816,7 +595,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
}
} =
conn
- |> get("/api/pleroma/emoji/packs/test_pack")
+ |> get("/api/pleroma/emoji/pack?name=test_pack")
|> json_response_and_validate_schema(200)
assert files == %{"blank" => "blank.png", "blank2" => "blank2.png"}
@@ -826,7 +605,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
"files_count" => 2
} =
conn
- |> get("/api/pleroma/emoji/packs/test_pack?page_size=1")
+ |> get("/api/pleroma/emoji/pack?name=test_pack&page_size=1")
|> json_response_and_validate_schema(200)
assert files |> Map.keys() |> length() == 1
@@ -836,15 +615,33 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
"files_count" => 2
} =
conn
- |> get("/api/pleroma/emoji/packs/test_pack?page_size=1&page=2")
+ |> get("/api/pleroma/emoji/pack?name=test_pack&page_size=1&page=2")
|> json_response_and_validate_schema(200)
assert files |> Map.keys() |> length() == 1
end
+ test "for pack name with special chars", %{conn: conn} do
+ assert %{
+ "files" => _files,
+ "files_count" => 1,
+ "pack" => %{
+ "can-download" => true,
+ "description" => "Test description",
+ "download-sha256" => _,
+ "homepage" => "https://pleroma.social",
+ "license" => "Test license",
+ "share-files" => true
+ }
+ } =
+ conn
+ |> get("/api/pleroma/emoji/pack?name=blobs.gg")
+ |> json_response_and_validate_schema(200)
+ end
+
test "non existing pack", %{conn: conn} do
assert conn
- |> get("/api/pleroma/emoji/packs/non_existing")
+ |> get("/api/pleroma/emoji/pack?name=non_existing")
|> json_response_and_validate_schema(:not_found) == %{
"error" => "Pack non_existing does not exist"
}
@@ -852,7 +649,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do
test "error name", %{conn: conn} do
assert conn
- |> get("/api/pleroma/emoji/packs/ ")
+ |> get("/api/pleroma/emoji/pack?name= ")
|> json_response_and_validate_schema(:bad_request) == %{
"error" => "pack name cannot be empty"
}
diff --git a/test/web/pleroma_api/controllers/emoji_reaction_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/emoji_reaction_controller_test.exs
index 3deab30d1..28483985c 100644
--- a/test/web/pleroma_api/controllers/emoji_reaction_controller_test.exs
+++ b/test/pleroma/web/pleroma_api/controllers/emoji_reaction_controller_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.PleromaAPI.EmojiReactionControllerTest do
@@ -106,6 +106,48 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionControllerTest do
result
end
+ test "GET /api/v1/pleroma/statuses/:id/reactions?with_muted=true", %{conn: conn} do
+ user = insert(:user)
+ user2 = insert(:user)
+ user3 = insert(:user)
+
+ token = insert(:oauth_token, user: user, scopes: ["read:statuses"])
+
+ {:ok, activity} = CommonAPI.post(user, %{status: "#cofe"})
+
+ {:ok, _} = CommonAPI.react_with_emoji(activity.id, user2, "🎅")
+ {:ok, _} = CommonAPI.react_with_emoji(activity.id, user3, "🎅")
+
+ result =
+ conn
+ |> assign(:user, user)
+ |> assign(:token, token)
+ |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions")
+ |> json_response_and_validate_schema(200)
+
+ assert [%{"name" => "🎅", "count" => 2}] = result
+
+ User.mute(user, user3)
+
+ result =
+ conn
+ |> assign(:user, user)
+ |> assign(:token, token)
+ |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions")
+ |> json_response_and_validate_schema(200)
+
+ assert [%{"name" => "🎅", "count" => 1}] = result
+
+ result =
+ conn
+ |> assign(:user, user)
+ |> assign(:token, token)
+ |> get("/api/v1/pleroma/statuses/#{activity.id}/reactions?with_muted=true")
+ |> json_response_and_validate_schema(200)
+
+ assert [%{"name" => "🎅", "count" => 2}] = result
+ end
+
test "GET /api/v1/pleroma/statuses/:id/reactions with :show_reactions disabled", %{conn: conn} do
clear_config([:instance, :show_reactions], false)
diff --git a/test/pleroma/web/pleroma_api/controllers/instances_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/instances_controller_test.exs
new file mode 100644
index 000000000..54cf9d083
--- /dev/null
+++ b/test/pleroma/web/pleroma_api/controllers/instances_controller_test.exs
@@ -0,0 +1,38 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PleromaApi.InstancesControllerTest do
+ use Pleroma.Web.ConnCase
+
+ alias Pleroma.Instances
+
+ setup_all do: clear_config([:instance, :federation_reachability_timeout_days], 1)
+
+ setup do
+ constant = "http://consistently-unreachable.name/"
+ eventual = "http://eventually-unreachable.com/path"
+
+ {:ok, %Pleroma.Instances.Instance{unreachable_since: constant_unreachable}} =
+ Instances.set_consistently_unreachable(constant)
+
+ _eventual_unrechable = Instances.set_unreachable(eventual)
+
+ %{constant_unreachable: constant_unreachable, constant: constant}
+ end
+
+ test "GET /api/v1/pleroma/federation_status", %{
+ conn: conn,
+ constant_unreachable: constant_unreachable,
+ constant: constant
+ } do
+ constant_host = URI.parse(constant).host
+
+ assert conn
+ |> put_req_header("content-type", "application/json")
+ |> get("/api/v1/pleroma/federation_status")
+ |> json_response_and_validate_schema(200) == %{
+ "unreachable" => %{constant_host => to_string(constant_unreachable)}
+ }
+ end
+end
diff --git a/test/web/pleroma_api/controllers/mascot_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/mascot_controller_test.exs
index e2ead6e15..0011ddd54 100644
--- a/test/web/pleroma_api/controllers/mascot_controller_test.exs
+++ b/test/pleroma/web/pleroma_api/controllers/mascot_controller_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.PleromaAPI.MascotControllerTest do
- use Pleroma.Web.ConnCase
+ use Pleroma.Web.ConnCase, async: true
alias Pleroma.User
@@ -24,7 +24,7 @@ defmodule Pleroma.Web.PleromaAPI.MascotControllerTest do
assert json_response_and_validate_schema(ret_conn, 415)
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}
@@ -34,7 +34,7 @@ defmodule Pleroma.Web.PleromaAPI.MascotControllerTest do
|> put_req_header("content-type", "multipart/form-data")
|> put("/api/v1/pleroma/mascot", %{"file" => file})
- assert %{"id" => _, "type" => image} = json_response_and_validate_schema(conn, 200)
+ assert %{"id" => _, "type" => _image} = json_response_and_validate_schema(conn, 200)
end
test "mascot retrieving" do
@@ -48,7 +48,7 @@ defmodule Pleroma.Web.PleromaAPI.MascotControllerTest do
# When a user sets their mascot, we should get that back
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}
diff --git a/test/web/pleroma_api/controllers/notification_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/notification_controller_test.exs
index bb4fe6c49..08f374908 100644
--- a/test/web/pleroma_api/controllers/notification_controller_test.exs
+++ b/test/pleroma/web/pleroma_api/controllers/notification_controller_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.PleromaAPI.NotificationControllerTest do
- use Pleroma.Web.ConnCase
+ use Pleroma.Web.ConnCase, async: true
alias Pleroma.Notification
alias Pleroma.Repo
diff --git a/test/pleroma/web/pleroma_api/controllers/report_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/report_controller_test.exs
new file mode 100644
index 000000000..c507aeca0
--- /dev/null
+++ b/test/pleroma/web/pleroma_api/controllers/report_controller_test.exs
@@ -0,0 +1,80 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PleromaAPI.ReportControllerTest do
+ use Pleroma.Web.ConnCase, async: true
+
+ import Pleroma.Factory
+
+ alias Pleroma.Web.CommonAPI
+
+ describe "GET /api/v0/pleroma/reports" do
+ test "returns list of own reports" do
+ %{conn: reporter_conn, user: reporter} = oauth_access(["read:reports"])
+ %{conn: reported_conn, user: reported} = oauth_access(["read:reports"])
+ activity = insert(:note_activity, user: reported)
+
+ {:ok, %{id: report_id}} =
+ CommonAPI.report(reporter, %{
+ account_id: reported.id,
+ comment: "You stole my sandwich!",
+ status_ids: [activity.id]
+ })
+
+ assert reported_response =
+ reported_conn
+ |> get("/api/v0/pleroma/reports")
+ |> json_response_and_validate_schema(:ok)
+
+ assert reported_response == %{"reports" => [], "total" => 0}
+
+ assert reporter_response =
+ reporter_conn
+ |> get("/api/v0/pleroma/reports")
+ |> json_response_and_validate_schema(:ok)
+
+ assert %{"reports" => [report], "total" => 1} = reporter_response
+ assert report["id"] == report_id
+ refute report["notes"]
+ end
+ end
+
+ describe "GET /api/v0/pleroma/reports/:id" do
+ test "returns report by its id" do
+ %{conn: reporter_conn, user: reporter} = oauth_access(["read:reports"])
+ %{conn: reported_conn, user: reported} = oauth_access(["read:reports"])
+ activity = insert(:note_activity, user: reported)
+
+ {:ok, %{id: report_id}} =
+ CommonAPI.report(reporter, %{
+ account_id: reported.id,
+ comment: "You stole my sandwich!",
+ status_ids: [activity.id]
+ })
+
+ assert reported_conn
+ |> get("/api/v0/pleroma/reports/#{report_id}")
+ |> json_response_and_validate_schema(:not_found)
+
+ assert response =
+ reporter_conn
+ |> get("/api/v0/pleroma/reports/#{report_id}")
+ |> json_response_and_validate_schema(:ok)
+
+ assert response["id"] == report_id
+ refute response["notes"]
+ end
+
+ test "returns 404 when report id is invalid" do
+ %{conn: conn, user: _user} = oauth_access(["read:reports"])
+
+ assert response =
+ conn
+ |> get("/api/v0/pleroma/reports/0")
+ |> json_response_and_validate_schema(:not_found)
+
+ assert response == %{"error" => "Record not found"}
+ end
+ end
+end
diff --git a/test/web/pleroma_api/controllers/scrobble_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/scrobble_controller_test.exs
index f39c07ac6..d4546f442 100644
--- a/test/web/pleroma_api/controllers/scrobble_controller_test.exs
+++ b/test/pleroma/web/pleroma_api/controllers/scrobble_controller_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.PleromaAPI.ScrobbleControllerTest do
- use Pleroma.Web.ConnCase
+ use Pleroma.Web.ConnCase, async: true
alias Pleroma.Web.CommonAPI
diff --git a/test/web/pleroma_api/controllers/two_factor_authentication_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/two_factor_authentication_controller_test.exs
index d23d08a00..24074f4e5 100644
--- a/test/web/pleroma_api/controllers/two_factor_authentication_controller_test.exs
+++ b/test/pleroma/web/pleroma_api/controllers/two_factor_authentication_controller_test.exs
@@ -1,5 +1,9 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.PleromaAPI.TwoFactorAuthenticationControllerTest do
- use Pleroma.Web.ConnCase
+ use Pleroma.Web.ConnCase, async: true
import Pleroma.Factory
alias Pleroma.MFA.Settings
diff --git a/test/pleroma/web/pleroma_api/controllers/user_import_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/user_import_controller_test.exs
new file mode 100644
index 000000000..d977bc3a2
--- /dev/null
+++ b/test/pleroma/web/pleroma_api/controllers/user_import_controller_test.exs
@@ -0,0 +1,235 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PleromaAPI.UserImportControllerTest do
+ use Pleroma.Web.ConnCase
+ use Oban.Testing, repo: Pleroma.Repo
+
+ alias Pleroma.Tests.ObanHelpers
+
+ import Pleroma.Factory
+ import Mock
+
+ setup do
+ Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
+ :ok
+ end
+
+ describe "POST /api/pleroma/follow_import" do
+ setup do: oauth_access(["follow"])
+
+ test "it returns HTTP 200", %{conn: conn} do
+ user2 = insert(:user)
+
+ assert "job started" ==
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/pleroma/follow_import", %{"list" => "#{user2.ap_id}"})
+ |> json_response_and_validate_schema(200)
+ end
+
+ test "it imports follow lists from file", %{conn: conn} do
+ user2 = insert(:user)
+
+ with_mocks([
+ {File, [],
+ read!: fn "follow_list.txt" ->
+ "Account address,Show boosts\n#{user2.ap_id},true"
+ end}
+ ]) do
+ assert "job started" ==
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/pleroma/follow_import", %{
+ "list" => %Plug.Upload{path: "follow_list.txt"}
+ })
+ |> json_response_and_validate_schema(200)
+
+ assert [{:ok, job_result}] = ObanHelpers.perform_all()
+ assert job_result == [refresh_record(user2)]
+ assert [%Pleroma.User{follower_count: 1}] = job_result
+ end
+ end
+
+ test "it imports new-style mastodon follow lists", %{conn: conn} do
+ user2 = insert(:user)
+
+ response =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/pleroma/follow_import", %{
+ "list" => "Account address,Show boosts\n#{user2.ap_id},true"
+ })
+ |> json_response_and_validate_schema(200)
+
+ assert response == "job started"
+ end
+
+ test "requires 'follow' or 'write:follows' permissions" do
+ token1 = insert(:oauth_token, scopes: ["read", "write"])
+ token2 = insert(:oauth_token, scopes: ["follow"])
+ token3 = insert(:oauth_token, scopes: ["something"])
+ another_user = insert(:user)
+
+ for token <- [token1, token2, token3] do
+ conn =
+ build_conn()
+ |> put_req_header("authorization", "Bearer #{token.token}")
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/pleroma/follow_import", %{"list" => "#{another_user.ap_id}"})
+
+ if token == token3 do
+ assert %{"error" => "Insufficient permissions: follow | write:follows."} ==
+ json_response(conn, 403)
+ else
+ assert json_response_and_validate_schema(conn, 200)
+ end
+ end
+ end
+
+ test "it imports follows with different nickname variations", %{conn: conn} do
+ users = [user2, user3, user4, user5, user6] = insert_list(5, :user)
+
+ identifiers =
+ [
+ user2.ap_id,
+ user3.nickname,
+ " ",
+ "@" <> user4.nickname,
+ user5.nickname <> "@localhost",
+ "@" <> user6.nickname <> "@localhost"
+ ]
+ |> Enum.join("\n")
+
+ assert "job started" ==
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/pleroma/follow_import", %{"list" => identifiers})
+ |> json_response_and_validate_schema(200)
+
+ assert [{:ok, job_result}] = ObanHelpers.perform_all()
+ assert job_result == Enum.map(users, &refresh_record/1)
+ end
+ end
+
+ describe "POST /api/pleroma/blocks_import" do
+ # Note: "follow" or "write:blocks" permission is required
+ setup do: oauth_access(["write:blocks"])
+
+ test "it returns HTTP 200", %{conn: conn} do
+ user2 = insert(:user)
+
+ assert "job started" ==
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/pleroma/blocks_import", %{"list" => "#{user2.ap_id}"})
+ |> json_response_and_validate_schema(200)
+ end
+
+ test "it imports blocks users from file", %{conn: conn} do
+ users = [user2, user3] = insert_list(2, :user)
+
+ with_mocks([
+ {File, [], read!: fn "blocks_list.txt" -> "#{user2.ap_id} #{user3.ap_id}" end}
+ ]) do
+ assert "job started" ==
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/pleroma/blocks_import", %{
+ "list" => %Plug.Upload{path: "blocks_list.txt"}
+ })
+ |> json_response_and_validate_schema(200)
+
+ assert [{:ok, job_result}] = ObanHelpers.perform_all()
+ assert job_result == users
+ end
+ end
+
+ test "it imports blocks with different nickname variations", %{conn: conn} do
+ users = [user2, user3, user4, user5, user6] = insert_list(5, :user)
+
+ identifiers =
+ [
+ user2.ap_id,
+ user3.nickname,
+ "@" <> user4.nickname,
+ user5.nickname <> "@localhost",
+ "@" <> user6.nickname <> "@localhost"
+ ]
+ |> Enum.join(" ")
+
+ assert "job started" ==
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/pleroma/blocks_import", %{"list" => identifiers})
+ |> json_response_and_validate_schema(200)
+
+ assert [{:ok, job_result}] = ObanHelpers.perform_all()
+ assert job_result == users
+ end
+ end
+
+ describe "POST /api/pleroma/mutes_import" do
+ # Note: "follow" or "write:mutes" permission is required
+ setup do: oauth_access(["write:mutes"])
+
+ test "it returns HTTP 200", %{user: user, conn: conn} do
+ user2 = insert(:user)
+
+ assert "job started" ==
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/pleroma/mutes_import", %{"list" => "#{user2.ap_id}"})
+ |> json_response_and_validate_schema(200)
+
+ assert [{:ok, job_result}] = ObanHelpers.perform_all()
+ assert job_result == [user2]
+ assert Pleroma.User.mutes?(user, user2)
+ end
+
+ test "it imports mutes users from file", %{user: user, conn: conn} do
+ users = [user2, user3] = insert_list(2, :user)
+
+ with_mocks([
+ {File, [], read!: fn "mutes_list.txt" -> "#{user2.ap_id} #{user3.ap_id}" end}
+ ]) do
+ assert "job started" ==
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/pleroma/mutes_import", %{
+ "list" => %Plug.Upload{path: "mutes_list.txt"}
+ })
+ |> json_response_and_validate_schema(200)
+
+ assert [{:ok, job_result}] = ObanHelpers.perform_all()
+ assert job_result == users
+ assert Enum.all?(users, &Pleroma.User.mutes?(user, &1))
+ end
+ end
+
+ test "it imports mutes with different nickname variations", %{user: user, conn: conn} do
+ users = [user2, user3, user4, user5, user6] = insert_list(5, :user)
+
+ identifiers =
+ [
+ user2.ap_id,
+ user3.nickname,
+ "@" <> user4.nickname,
+ user5.nickname <> "@localhost",
+ "@" <> user6.nickname <> "@localhost"
+ ]
+ |> Enum.join(" ")
+
+ assert "job started" ==
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/pleroma/mutes_import", %{"list" => identifiers})
+ |> json_response_and_validate_schema(200)
+
+ assert [{:ok, job_result}] = ObanHelpers.perform_all()
+ assert job_result == users
+ assert Enum.all?(users, &Pleroma.User.mutes?(user, &1))
+ end
+ end
+end
diff --git a/test/pleroma/web/pleroma_api/views/app_view_test.exs b/test/pleroma/web/pleroma_api/views/app_view_test.exs
new file mode 100644
index 000000000..f0aee6987
--- /dev/null
+++ b/test/pleroma/web/pleroma_api/views/app_view_test.exs
@@ -0,0 +1,21 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PleromaAPI.AppViewTest do
+ use Pleroma.DataCase, async: true
+ alias Pleroma.Web.PleromaAPI.AppView
+ import Pleroma.Factory
+
+ test "index.json" do
+ apps = [
+ insert(:oauth_app),
+ insert(:oauth_app),
+ insert(:oauth_app)
+ ]
+
+ results = AppView.render("index.json", %{apps: apps})
+
+ assert [%{client_id: _, client_secret: _}, _, _] = results
+ end
+end
diff --git a/test/pleroma/web/pleroma_api/views/backup_view_test.exs b/test/pleroma/web/pleroma_api/views/backup_view_test.exs
new file mode 100644
index 000000000..9b4298dd1
--- /dev/null
+++ b/test/pleroma/web/pleroma_api/views/backup_view_test.exs
@@ -0,0 +1,18 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.PleromaAPI.BackupViewTest do
+ use Pleroma.DataCase, async: true
+ alias Pleroma.User.Backup
+ alias Pleroma.Web.PleromaAPI.BackupView
+ import Pleroma.Factory
+
+ test "it renders the ID" do
+ user = insert(:user)
+ backup = Backup.new(user)
+
+ result = BackupView.render("show.json", backup: backup)
+ assert result.id == backup.id
+ end
+end
diff --git a/test/web/pleroma_api/views/chat/message_reference_view_test.exs b/test/pleroma/web/pleroma_api/views/chat_message_reference_view_test.exs
index 40dbae3cd..6deaa2102 100644
--- a/test/web/pleroma_api/views/chat/message_reference_view_test.exs
+++ b/test/pleroma/web/pleroma_api/views/chat_message_reference_view_test.exs
@@ -1,8 +1,8 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Web.PleromaAPI.Chat.MessageReferenceViewTest do
+defmodule Pleroma.Web.PleromaAPI.ChatMessageReferenceViewTest do
use Pleroma.DataCase
alias Pleroma.Chat
@@ -19,17 +19,19 @@ defmodule Pleroma.Web.PleromaAPI.Chat.MessageReferenceViewTest do
recipient = insert(:user)
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}
{:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
- {:ok, activity} = CommonAPI.post_chat_message(user, recipient, "kippis :firefox:")
+
+ {:ok, activity} =
+ CommonAPI.post_chat_message(user, recipient, "kippis :firefox:", idempotency_key: "123")
chat = Chat.get(user.id, recipient.ap_id)
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
cm_ref = MessageReference.for_chat_and_object(chat, object)
@@ -42,10 +44,11 @@ defmodule Pleroma.Web.PleromaAPI.Chat.MessageReferenceViewTest do
assert chat_message[:created_at]
assert chat_message[:unread] == false
assert match?([%{shortcode: "firefox"}], chat_message[:emojis])
+ assert chat_message[:idempotency_key] == "123"
clear_config([:rich_media, :enabled], true)
- Tesla.Mock.mock(fn
+ Tesla.Mock.mock_global(fn
%{url: "https://example.com/ogp"} ->
%Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/ogp.html")}
end)
@@ -55,7 +58,7 @@ defmodule Pleroma.Web.PleromaAPI.Chat.MessageReferenceViewTest do
media_id: upload.id
)
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
cm_ref = MessageReference.for_chat_and_object(chat, object)
diff --git a/test/web/pleroma_api/views/chat_view_test.exs b/test/pleroma/web/pleroma_api/views/chat_view_test.exs
index 02484b705..5456c2de0 100644
--- a/test/web/pleroma_api/views/chat_view_test.exs
+++ b/test/pleroma/web/pleroma_api/views/chat_view_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.PleromaAPI.ChatViewTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Chat
alias Pleroma.Chat.MessageReference
@@ -35,7 +35,7 @@ defmodule Pleroma.Web.PleromaAPI.ChatViewTest do
{:ok, chat_message_creation} = CommonAPI.post_chat_message(user, recipient, "hello")
- chat_message = Object.normalize(chat_message_creation, false)
+ chat_message = Object.normalize(chat_message_creation, fetch: false)
{:ok, chat} = Chat.get_or_create(user.id, recipient.ap_id)
diff --git a/test/web/pleroma_api/views/scrobble_view_test.exs b/test/pleroma/web/pleroma_api/views/scrobble_view_test.exs
index 6bdb56509..382051f6f 100644
--- a/test/web/pleroma_api/views/scrobble_view_test.exs
+++ b/test/pleroma/web/pleroma_api/views/scrobble_view_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Web.PleromaAPI.StatusViewTest do
- use Pleroma.DataCase
+defmodule Pleroma.Web.PleromaAPI.ScrobbleViewTest do
+ use Pleroma.DataCase, async: true
alias Pleroma.Web.PleromaAPI.ScrobbleView
diff --git a/test/plugs/admin_secret_authentication_plug_test.exs b/test/pleroma/web/plugs/admin_secret_authentication_plug_test.exs
index 89df03c4b..79561afb7 100644
--- a/test/plugs/admin_secret_authentication_plug_test.exs
+++ b/test/pleroma/web/plugs/admin_secret_authentication_plug_test.exs
@@ -1,17 +1,17 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Plugs.AdminSecretAuthenticationPlugTest do
- use Pleroma.Web.ConnCase, async: true
+defmodule Pleroma.Web.Plugs.AdminSecretAuthenticationPlugTest do
+ use Pleroma.Web.ConnCase
import Mock
import Pleroma.Factory
- alias Pleroma.Plugs.AdminSecretAuthenticationPlug
- alias Pleroma.Plugs.OAuthScopesPlug
- alias Pleroma.Plugs.PlugHelper
- alias Pleroma.Plugs.RateLimiter
+ alias Pleroma.Web.Plugs.AdminSecretAuthenticationPlug
+ alias Pleroma.Web.Plugs.OAuthScopesPlug
+ alias Pleroma.Web.Plugs.PlugHelper
+ alias Pleroma.Web.Plugs.RateLimiter
test "does nothing if a user is assigned", %{conn: conn} do
user = insert(:user)
@@ -35,7 +35,7 @@ defmodule Pleroma.Plugs.AdminSecretAuthenticationPlugTest do
end
test "with `admin_token` query parameter", %{conn: conn} do
- Pleroma.Config.put(:admin_token, "password123")
+ clear_config(:admin_token, "password123")
conn =
%{conn | params: %{"admin_token" => "wrong_password"}}
@@ -49,11 +49,12 @@ defmodule Pleroma.Plugs.AdminSecretAuthenticationPlugTest do
|> AdminSecretAuthenticationPlug.call(%{})
assert conn.assigns[:user].is_admin
+ assert conn.assigns[:token] == nil
assert PlugHelper.plug_skipped?(conn, OAuthScopesPlug)
end
test "with `x-admin-token` HTTP header", %{conn: conn} do
- Pleroma.Config.put(:admin_token, "☕️")
+ clear_config(:admin_token, "☕️")
conn =
conn
@@ -69,6 +70,7 @@ defmodule Pleroma.Plugs.AdminSecretAuthenticationPlugTest do
|> AdminSecretAuthenticationPlug.call(%{})
assert conn.assigns[:user].is_admin
+ assert conn.assigns[:token] == nil
assert PlugHelper.plug_skipped?(conn, OAuthScopesPlug)
end
end
diff --git a/test/plugs/authentication_plug_test.exs b/test/pleroma/web/plugs/authentication_plug_test.exs
index 777ae15ae..118ab302a 100644
--- a/test/plugs/authentication_plug_test.exs
+++ b/test/pleroma/web/plugs/authentication_plug_test.exs
@@ -1,14 +1,14 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Plugs.AuthenticationPlugTest do
+defmodule Pleroma.Web.Plugs.AuthenticationPlugTest do
use Pleroma.Web.ConnCase, async: true
- alias Pleroma.Plugs.AuthenticationPlug
- alias Pleroma.Plugs.OAuthScopesPlug
- alias Pleroma.Plugs.PlugHelper
alias Pleroma.User
+ alias Pleroma.Web.Plugs.AuthenticationPlug
+ alias Pleroma.Web.Plugs.OAuthScopesPlug
+ alias Pleroma.Web.Plugs.PlugHelper
import ExUnit.CaptureLog
import Pleroma.Factory
@@ -17,7 +17,7 @@ defmodule Pleroma.Plugs.AuthenticationPlugTest do
user = %User{
id: 1,
name: "dude",
- password_hash: Pbkdf2.hash_pwd_salt("guy")
+ password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("guy")
}
conn =
@@ -48,6 +48,7 @@ defmodule Pleroma.Plugs.AuthenticationPlugTest do
|> AuthenticationPlug.call(%{})
assert conn.assigns.user == conn.assigns.auth_user
+ assert conn.assigns.token == nil
assert PlugHelper.plug_skipped?(conn, OAuthScopesPlug)
end
@@ -62,6 +63,7 @@ defmodule Pleroma.Plugs.AuthenticationPlugTest do
|> AuthenticationPlug.call(%{})
assert conn.assigns.user.id == conn.assigns.auth_user.id
+ assert conn.assigns.token == nil
assert PlugHelper.plug_skipped?(conn, OAuthScopesPlug)
user = User.get_by_id(user.id)
@@ -83,6 +85,7 @@ defmodule Pleroma.Plugs.AuthenticationPlugTest do
|> AuthenticationPlug.call(%{})
assert conn.assigns.user.id == conn.assigns.auth_user.id
+ assert conn.assigns.token == nil
assert PlugHelper.plug_skipped?(conn, OAuthScopesPlug)
user = User.get_by_id(user.id)
@@ -118,7 +121,7 @@ defmodule Pleroma.Plugs.AuthenticationPlugTest do
"psBWV8gxkGOZWBz$PmfCycChoxeJ3GgGzwvhlgacb9mUoZ.KUXNCssekER4SJ7bOK53uXrHNb2e4i8yPFgSKyzaW9CcmrDXWIEMtD1"
assert capture_log(fn ->
- refute Pleroma.Plugs.AuthenticationPlug.checkpw("password", hash)
+ refute AuthenticationPlug.checkpw("password", hash)
end) =~ "[error] Password hash not recognized"
end
end
diff --git a/test/plugs/basic_auth_decoder_plug_test.exs b/test/pleroma/web/plugs/basic_auth_decoder_plug_test.exs
index a6063d4f6..e90078eb5 100644
--- a/test/plugs/basic_auth_decoder_plug_test.exs
+++ b/test/pleroma/web/plugs/basic_auth_decoder_plug_test.exs
@@ -1,11 +1,11 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Plugs.BasicAuthDecoderPlugTest do
+defmodule Pleroma.Web.Plugs.BasicAuthDecoderPlugTest do
use Pleroma.Web.ConnCase, async: true
- alias Pleroma.Plugs.BasicAuthDecoderPlug
+ alias Pleroma.Web.Plugs.BasicAuthDecoderPlug
defp basic_auth_enc(username, password) do
"Basic " <> Base.encode64("#{username}:#{password}")
diff --git a/test/plugs/cache_control_test.exs b/test/pleroma/web/plugs/cache_control_test.exs
index 6b567e81d..263961897 100644
--- a/test/plugs/cache_control_test.exs
+++ b/test/pleroma/web/plugs/cache_control_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Web.CacheControlTest do
- use Pleroma.Web.ConnCase
+defmodule Pleroma.Web.Plugs.CacheControlTest do
+ use Pleroma.Web.ConnCase, async: true
alias Plug.Conn
test "Verify Cache-Control header on static assets", %{conn: conn} do
diff --git a/test/plugs/cache_test.exs b/test/pleroma/web/plugs/cache_test.exs
index 8b231c881..0ceab6cab 100644
--- a/test/plugs/cache_test.exs
+++ b/test/pleroma/web/plugs/cache_test.exs
@@ -1,12 +1,13 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Plugs.CacheTest do
- use ExUnit.Case, async: true
+defmodule Pleroma.Web.Plugs.CacheTest do
+ # Relies on Cachex, has to stay synchronous
+ use Pleroma.DataCase
use Plug.Test
- alias Pleroma.Plugs.Cache
+ alias Pleroma.Web.Plugs.Cache
@miss_resp {200,
[
@@ -24,11 +25,6 @@ defmodule Pleroma.Plugs.CacheTest do
@ttl 5
- setup do
- Cachex.clear(:web_resp_cache)
- :ok
- end
-
test "caches a response" do
assert @miss_resp ==
conn(:get, "/")
diff --git a/test/pleroma/web/plugs/digest_plug_test.exs b/test/pleroma/web/plugs/digest_plug_test.exs
new file mode 100644
index 000000000..629c28c93
--- /dev/null
+++ b/test/pleroma/web/plugs/digest_plug_test.exs
@@ -0,0 +1,48 @@
+defmodule Pleroma.Web.Plugs.DigestPlugTest do
+ use ExUnit.Case, async: true
+ use Plug.Test
+
+ test "digest algorithm is taken from digest header" do
+ body = "{\"hello\": \"world\"}"
+ digest = "X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE="
+
+ {:ok, ^body, conn} =
+ :get
+ |> conn("/", body)
+ |> put_req_header("content-type", "application/json")
+ |> put_req_header("digest", "sha-256=" <> digest)
+ |> Pleroma.Web.Plugs.DigestPlug.read_body([])
+
+ assert conn.assigns[:digest] == "sha-256=" <> digest
+
+ {:ok, ^body, conn} =
+ :get
+ |> conn("/", body)
+ |> put_req_header("content-type", "application/json")
+ |> put_req_header("digest", "SHA-256=" <> digest)
+ |> Pleroma.Web.Plugs.DigestPlug.read_body([])
+
+ assert conn.assigns[:digest] == "SHA-256=" <> digest
+ end
+
+ test "error if digest algorithm is invalid" do
+ body = "{\"hello\": \"world\"}"
+ digest = "X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE="
+
+ assert_raise ArgumentError, "invalid value for digest algorithm, got: MD5", fn ->
+ :get
+ |> conn("/", body)
+ |> put_req_header("content-type", "application/json")
+ |> put_req_header("digest", "MD5=" <> digest)
+ |> Pleroma.Web.Plugs.DigestPlug.read_body([])
+ end
+
+ assert_raise ArgumentError, "invalid value for digest algorithm, got: md5", fn ->
+ :get
+ |> conn("/", body)
+ |> put_req_header("content-type", "application/json")
+ |> put_req_header("digest", "md5=" <> digest)
+ |> Pleroma.Web.Plugs.DigestPlug.read_body([])
+ end
+ end
+end
diff --git a/test/plugs/ensure_authenticated_plug_test.exs b/test/pleroma/web/plugs/ensure_authenticated_plug_test.exs
index a0667c5e0..6b3ee3d87 100644
--- a/test/plugs/ensure_authenticated_plug_test.exs
+++ b/test/pleroma/web/plugs/ensure_authenticated_plug_test.exs
@@ -1,12 +1,12 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Plugs.EnsureAuthenticatedPlugTest do
+defmodule Pleroma.Web.Plugs.EnsureAuthenticatedPlugTest do
use Pleroma.Web.ConnCase, async: true
- alias Pleroma.Plugs.EnsureAuthenticatedPlug
alias Pleroma.User
+ alias Pleroma.Web.Plugs.EnsureAuthenticatedPlug
describe "without :if_func / :unless_func options" do
test "it halts if user is NOT assigned", %{conn: conn} do
diff --git a/test/plugs/ensure_public_or_authenticated_plug_test.exs b/test/pleroma/web/plugs/ensure_public_or_authenticated_plug_test.exs
index fc2934369..75c3b5784 100644
--- a/test/plugs/ensure_public_or_authenticated_plug_test.exs
+++ b/test/pleroma/web/plugs/ensure_public_or_authenticated_plug_test.exs
@@ -1,18 +1,17 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Plugs.EnsurePublicOrAuthenticatedPlugTest do
- use Pleroma.Web.ConnCase, async: true
+defmodule Pleroma.Web.Plugs.EnsurePublicOrAuthenticatedPlugTest do
+ use Pleroma.Web.ConnCase
- alias Pleroma.Config
- alias Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug
alias Pleroma.User
+ alias Pleroma.Web.Plugs.EnsurePublicOrAuthenticatedPlug
setup do: clear_config([:instance, :public])
test "it halts if not public and no user is assigned", %{conn: conn} do
- Config.put([:instance, :public], false)
+ clear_config([:instance, :public], false)
conn =
conn
@@ -23,7 +22,7 @@ defmodule Pleroma.Plugs.EnsurePublicOrAuthenticatedPlugTest do
end
test "it continues if public", %{conn: conn} do
- Config.put([:instance, :public], true)
+ clear_config([:instance, :public], true)
ret_conn =
conn
@@ -33,7 +32,7 @@ defmodule Pleroma.Plugs.EnsurePublicOrAuthenticatedPlugTest do
end
test "it continues if a user is assigned, even if not public", %{conn: conn} do
- Config.put([:instance, :public], false)
+ clear_config([:instance, :public], false)
conn =
conn
diff --git a/test/pleroma/web/plugs/ensure_staff_privileged_plug_test.exs b/test/pleroma/web/plugs/ensure_staff_privileged_plug_test.exs
new file mode 100644
index 000000000..74f4ae504
--- /dev/null
+++ b/test/pleroma/web/plugs/ensure_staff_privileged_plug_test.exs
@@ -0,0 +1,60 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Plugs.EnsureStaffPrivilegedPlugTest do
+ use Pleroma.Web.ConnCase, async: true
+
+ alias Pleroma.Web.Plugs.EnsureStaffPrivilegedPlug
+ import Pleroma.Factory
+
+ test "accepts a user that is an admin" do
+ user = insert(:user, is_admin: true)
+
+ conn = assign(build_conn(), :user, user)
+
+ ret_conn = EnsureStaffPrivilegedPlug.call(conn, %{})
+
+ assert conn == ret_conn
+ end
+
+ test "accepts a user that is a moderator when :privileged_staff is enabled" do
+ clear_config([:instance, :privileged_staff], true)
+ user = insert(:user, is_moderator: true)
+
+ conn = assign(build_conn(), :user, user)
+
+ ret_conn = EnsureStaffPrivilegedPlug.call(conn, %{})
+
+ assert conn == ret_conn
+ end
+
+ test "denies a user that is a moderator when :privileged_staff is disabled" do
+ clear_config([:instance, :privileged_staff], false)
+ user = insert(:user, is_moderator: true)
+
+ conn =
+ build_conn()
+ |> assign(:user, user)
+ |> EnsureStaffPrivilegedPlug.call(%{})
+
+ assert conn.status == 403
+ end
+
+ test "denies a user that isn't a staff member" do
+ user = insert(:user)
+
+ conn =
+ build_conn()
+ |> assign(:user, user)
+ |> EnsureStaffPrivilegedPlug.call(%{})
+
+ assert conn.status == 403
+ end
+
+ test "denies when a user isn't set" do
+ conn = EnsureStaffPrivilegedPlug.call(build_conn(), %{})
+
+ assert conn.status == 403
+ end
+end
diff --git a/test/pleroma/web/plugs/ensure_user_token_assigns_plug_test.exs b/test/pleroma/web/plugs/ensure_user_token_assigns_plug_test.exs
new file mode 100644
index 000000000..28ec67158
--- /dev/null
+++ b/test/pleroma/web/plugs/ensure_user_token_assigns_plug_test.exs
@@ -0,0 +1,69 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Plugs.EnsureUserTokenAssignsPlugTest do
+ use Pleroma.Web.ConnCase, async: true
+
+ import Pleroma.Factory
+
+ alias Pleroma.Web.Plugs.EnsureUserTokenAssignsPlug
+
+ test "with :user assign set to a User record " <>
+ "and :token assign set to a Token belonging to this user, " <>
+ "it does nothing" do
+ %{conn: conn} = oauth_access(["read"])
+
+ ret_conn = EnsureUserTokenAssignsPlug.call(conn, %{})
+
+ assert conn == ret_conn
+ end
+
+ test "with :user assign set to a User record " <>
+ "but :token assign not set or not a Token, " <>
+ "it assigns :token to `nil`",
+ %{conn: conn} do
+ user = insert(:user)
+ conn = assign(conn, :user, user)
+
+ ret_conn = EnsureUserTokenAssignsPlug.call(conn, %{})
+
+ assert %{token: nil} = ret_conn.assigns
+
+ ret_conn2 =
+ conn
+ |> assign(:token, 1)
+ |> EnsureUserTokenAssignsPlug.call(%{})
+
+ assert %{token: nil} = ret_conn2.assigns
+ end
+
+ # Abnormal (unexpected) scenario
+ test "with :user assign set to a User record " <>
+ "but :token assign set to a Token NOT belonging to :user, " <>
+ "it drops auth info" do
+ %{conn: conn} = oauth_access(["read"])
+ other_user = insert(:user)
+
+ conn = assign(conn, :user, other_user)
+
+ ret_conn = EnsureUserTokenAssignsPlug.call(conn, %{})
+
+ assert %{user: nil, token: nil} = ret_conn.assigns
+ end
+
+ test "if :user assign is not set to a User record, it sets :user and :token to nil", %{
+ conn: conn
+ } do
+ ret_conn = EnsureUserTokenAssignsPlug.call(conn, %{})
+
+ assert %{user: nil, token: nil} = ret_conn.assigns
+
+ ret_conn2 =
+ conn
+ |> assign(:user, 1)
+ |> EnsureUserTokenAssignsPlug.call(%{})
+
+ assert %{user: nil, token: nil} = ret_conn2.assigns
+ end
+end
diff --git a/test/web/plugs/federating_plug_test.exs b/test/pleroma/web/plugs/federating_plug_test.exs
index 2f8aadadc..01ecd2a1e 100644
--- a/test/web/plugs/federating_plug_test.exs
+++ b/test/pleroma/web/plugs/federating_plug_test.exs
@@ -1,29 +1,29 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Web.FederatingPlugTest do
+defmodule Pleroma.Web.Plugs.FederatingPlugTest do
use Pleroma.Web.ConnCase
setup do: clear_config([:instance, :federating])
test "returns and halt the conn when federating is disabled" do
- Pleroma.Config.put([:instance, :federating], false)
+ clear_config([:instance, :federating], false)
conn =
build_conn()
- |> Pleroma.Web.FederatingPlug.call(%{})
+ |> Pleroma.Web.Plugs.FederatingPlug.call(%{})
assert conn.status == 404
assert conn.halted
end
test "does nothing when federating is enabled" do
- Pleroma.Config.put([:instance, :federating], true)
+ clear_config([:instance, :federating], true)
conn =
build_conn()
- |> Pleroma.Web.FederatingPlug.call(%{})
+ |> Pleroma.Web.Plugs.FederatingPlug.call(%{})
refute conn.status
refute conn.halted
diff --git a/test/pleroma/web/plugs/frontend_static_plug_test.exs b/test/pleroma/web/plugs/frontend_static_plug_test.exs
new file mode 100644
index 000000000..4b3925ad2
--- /dev/null
+++ b/test/pleroma/web/plugs/frontend_static_plug_test.exs
@@ -0,0 +1,110 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Plugs.FrontendStaticPlugTest do
+ use Pleroma.Web.ConnCase
+ import Mock
+
+ @dir "test/tmp/instance_static"
+
+ setup do
+ File.mkdir_p!(@dir)
+ on_exit(fn -> File.rm_rf(@dir) end)
+ end
+
+ setup do: clear_config([:instance, :static_dir], @dir)
+
+ test "init will give a static plug config + the frontend type" do
+ opts =
+ [
+ at: "/admin",
+ frontend_type: :admin
+ ]
+ |> Pleroma.Web.Plugs.FrontendStatic.init()
+
+ assert opts[:at] == ["admin"]
+ assert opts[:frontend_type] == :admin
+ end
+
+ test "overrides existing static files", %{conn: conn} do
+ name = "pelmora"
+ ref = "uguu"
+
+ clear_config([:frontends, :primary], %{"name" => name, "ref" => ref})
+ path = "#{@dir}/frontends/#{name}/#{ref}"
+
+ File.mkdir_p!(path)
+ File.write!("#{path}/index.html", "from frontend plug")
+
+ index = get(conn, "/")
+ assert html_response(index, 200) == "from frontend plug"
+ end
+
+ test "overrides existing static files for the `pleroma/admin` path", %{conn: conn} do
+ name = "pelmora"
+ ref = "uguu"
+
+ clear_config([:frontends, :admin], %{"name" => name, "ref" => ref})
+ path = "#{@dir}/frontends/#{name}/#{ref}"
+
+ File.mkdir_p!(path)
+ File.write!("#{path}/index.html", "from frontend plug")
+
+ index = get(conn, "/pleroma/admin/")
+ assert html_response(index, 200) == "from frontend plug"
+ end
+
+ test "exclude invalid path", %{conn: conn} do
+ name = "pleroma-fe"
+ ref = "dist"
+ clear_config([:media_proxy, :enabled], true)
+ clear_config([Pleroma.Web.Endpoint, :secret_key_base], "00000000000")
+ clear_config([:frontends, :primary], %{"name" => name, "ref" => ref})
+ path = "#{@dir}/frontends/#{name}/#{ref}"
+
+ File.mkdir_p!("#{path}/proxy/rr/ss")
+ File.write!("#{path}/proxy/rr/ss/Ek7w8WPVcAApOvN.jpg:large", "FB image")
+
+ url =
+ Pleroma.Web.MediaProxy.encode_url("https://pbs.twimg.com/media/Ek7w8WPVcAApOvN.jpg:large")
+
+ with_mock Pleroma.ReverseProxy,
+ call: fn _conn, _url, _opts -> %Plug.Conn{status: :success} end do
+ assert %Plug.Conn{status: :success} = get(conn, url)
+ end
+ end
+
+ test "api routes are detected correctly" do
+ # If this test fails we have probably added something
+ # new that should be in /api/ instead
+ expected_routes = [
+ "api",
+ "main",
+ "ostatus_subscribe",
+ "oauth",
+ "objects",
+ "activities",
+ "notice",
+ "@:nickname",
+ ":nickname",
+ "users",
+ "tags",
+ "mailer",
+ "inbox",
+ "relay",
+ "internal",
+ ".well-known",
+ "nodeinfo",
+ "manifest.json",
+ "auth",
+ "proxy",
+ "phoenix",
+ "test",
+ "user_exists",
+ "check_password"
+ ]
+
+ assert expected_routes == Pleroma.Web.Router.get_api_routes()
+ end
+end
diff --git a/test/plugs/http_security_plug_test.exs b/test/pleroma/web/plugs/http_security_plug_test.exs
index 2297e3dac..4e7befdd5 100644
--- a/test/plugs/http_security_plug_test.exs
+++ b/test/pleroma/web/plugs/http_security_plug_test.exs
@@ -1,11 +1,10 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest do
use Pleroma.Web.ConnCase
- alias Pleroma.Config
alias Plug.Conn
describe "http security enabled" do
@@ -73,6 +72,21 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest do
assert csp =~ "media-src 'self' https:;"
assert csp =~ "img-src 'self' data: blob: https:;"
end
+
+ test "it sets the Service-Worker-Allowed header", %{conn: conn} do
+ clear_config([:http_security, :enabled], true)
+ clear_config([:frontends, :primary], %{"name" => "fedi-fe", "ref" => "develop"})
+
+ clear_config([:frontends, :available], %{
+ "fedi-fe" => %{
+ "name" => "fedi-fe",
+ "custom-http-headers" => [{"service-worker-allowed", "/"}]
+ }
+ })
+
+ conn = get(conn, "/api/v1/instance")
+ assert Conn.get_resp_header(conn, "service-worker-allowed") == ["/"]
+ end
end
describe "img-src and media-src" do
diff --git a/test/plugs/http_signature_plug_test.exs b/test/pleroma/web/plugs/http_signature_plug_test.exs
index e6cbde803..56ef6b06f 100644
--- a/test/plugs/http_signature_plug_test.exs
+++ b/test/pleroma/web/plugs/http_signature_plug_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Plugs.HTTPSignaturePlugTest do
@@ -32,11 +32,7 @@ defmodule Pleroma.Web.Plugs.HTTPSignaturePlugTest do
describe "requires a signature when `authorized_fetch_mode` is enabled" do
setup do
- Pleroma.Config.put([:activitypub, :authorized_fetch_mode], true)
-
- on_exit(fn ->
- Pleroma.Config.put([:activitypub, :authorized_fetch_mode], false)
- end)
+ clear_config([:activitypub, :authorized_fetch_mode], true)
params = %{"actor" => "http://mastodon.example.org/users/admin"}
conn = build_conn(:get, "/doesntmattter", params) |> put_format("activity+json")
diff --git a/test/plugs/idempotency_plug_test.exs b/test/pleroma/web/plugs/idempotency_plug_test.exs
index 21fa0fbcf..dd8cda664 100644
--- a/test/plugs/idempotency_plug_test.exs
+++ b/test/pleroma/web/plugs/idempotency_plug_test.exs
@@ -1,12 +1,13 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Plugs.IdempotencyPlugTest do
- use ExUnit.Case, async: true
+defmodule Pleroma.Web.Plugs.IdempotencyPlugTest do
+ # Relies on Cachex, has to stay synchronous
+ use Pleroma.DataCase
use Plug.Test
- alias Pleroma.Plugs.IdempotencyPlug
+ alias Pleroma.Web.Plugs.IdempotencyPlug
alias Plug.Conn
test "returns result from cache" do
diff --git a/test/plugs/instance_static_test.exs b/test/pleroma/web/plugs/instance_static_test.exs
index d42ba817e..46f2ca6b1 100644
--- a/test/plugs/instance_static_test.exs
+++ b/test/pleroma/web/plugs/instance_static_test.exs
@@ -1,8 +1,8 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Web.InstanceStaticPlugTest do
+defmodule Pleroma.Web.Plugs.InstanceStaticTest do
use Pleroma.Web.ConnCase
@dir "test/tmp/instance_static"
diff --git a/test/plugs/mapped_identity_to_signature_plug_test.exs b/test/pleroma/web/plugs/mapped_signature_to_identity_plug_test.exs
index 0ad3c2929..00ce6492d 100644
--- a/test/plugs/mapped_identity_to_signature_plug_test.exs
+++ b/test/pleroma/web/plugs/mapped_signature_to_identity_plug_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Plugs.MappedSignatureToIdentityPlugTest do
diff --git a/test/pleroma/web/plugs/o_auth_plug_test.exs b/test/pleroma/web/plugs/o_auth_plug_test.exs
new file mode 100644
index 000000000..9e4be5559
--- /dev/null
+++ b/test/pleroma/web/plugs/o_auth_plug_test.exs
@@ -0,0 +1,128 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Plugs.OAuthPlugTest do
+ use Pleroma.Web.ConnCase, async: true
+
+ alias Pleroma.Helpers.AuthHelper
+ alias Pleroma.Web.OAuth.Token
+ alias Pleroma.Web.OAuth.Token.Strategy.Revoke
+ alias Pleroma.Web.Plugs.OAuthPlug
+ alias Plug.Session
+
+ import Pleroma.Factory
+
+ setup %{conn: conn} do
+ user = insert(:user)
+ {:ok, oauth_token} = Token.create(insert(:oauth_app), user)
+ %{user: user, token: oauth_token, conn: conn}
+ end
+
+ test "it does nothing if a user is assigned", %{conn: conn} do
+ conn = assign(conn, :user, %Pleroma.User{})
+ ret_conn = OAuthPlug.call(conn, %{})
+
+ assert ret_conn == conn
+ end
+
+ test "with valid token (uppercase) in auth header, it assigns the user", %{conn: conn} = opts do
+ conn =
+ conn
+ |> put_req_header("authorization", "BEARER #{opts[:token].token}")
+ |> OAuthPlug.call(%{})
+
+ assert conn.assigns[:user] == opts[:user]
+ end
+
+ test "with valid token (downcase) in auth header, it assigns the user", %{conn: conn} = opts do
+ conn =
+ conn
+ |> put_req_header("authorization", "bearer #{opts[:token].token}")
+ |> OAuthPlug.call(%{})
+
+ assert conn.assigns[:user] == opts[:user]
+ end
+
+ test "with valid token (downcase) in url parameters, it assigns the user", opts do
+ conn =
+ :get
+ |> build_conn("/?access_token=#{opts[:token].token}")
+ |> put_req_header("content-type", "application/json")
+ |> fetch_query_params()
+ |> OAuthPlug.call(%{})
+
+ assert conn.assigns[:user] == opts[:user]
+ end
+
+ test "with valid token (downcase) in body parameters, it assigns the user", opts do
+ conn =
+ :post
+ |> build_conn("/api/v1/statuses", access_token: opts[:token].token, status: "test")
+ |> OAuthPlug.call(%{})
+
+ assert conn.assigns[:user] == opts[:user]
+ end
+
+ test "with invalid token, it does not assign the user", %{conn: conn} do
+ conn =
+ conn
+ |> put_req_header("authorization", "bearer TTTTT")
+ |> OAuthPlug.call(%{})
+
+ refute conn.assigns[:user]
+ end
+
+ describe "with :oauth_token in session, " do
+ setup %{token: oauth_token, conn: conn} do
+ session_opts = [
+ store: :cookie,
+ key: "_test",
+ signing_salt: "cooldude"
+ ]
+
+ conn =
+ conn
+ |> Session.call(Session.init(session_opts))
+ |> fetch_session()
+ |> AuthHelper.put_session_token(oauth_token.token)
+
+ %{conn: conn}
+ end
+
+ test "if session-stored token matches a valid OAuth token, assigns :user and :token", %{
+ conn: conn,
+ user: user,
+ token: oauth_token
+ } do
+ conn = OAuthPlug.call(conn, %{})
+
+ assert conn.assigns.user && conn.assigns.user.id == user.id
+ assert conn.assigns.token && conn.assigns.token.id == oauth_token.id
+ end
+
+ test "if session-stored token matches an expired OAuth token, does nothing", %{
+ conn: conn,
+ token: oauth_token
+ } do
+ expired_valid_until = NaiveDateTime.add(NaiveDateTime.utc_now(), -3600 * 24, :second)
+
+ oauth_token
+ |> Ecto.Changeset.change(valid_until: expired_valid_until)
+ |> Pleroma.Repo.update()
+
+ ret_conn = OAuthPlug.call(conn, %{})
+ assert ret_conn == conn
+ end
+
+ test "if session-stored token matches a revoked OAuth token, does nothing", %{
+ conn: conn,
+ token: oauth_token
+ } do
+ Revoke.revoke(oauth_token)
+
+ ret_conn = OAuthPlug.call(conn, %{})
+ assert ret_conn == conn
+ end
+ end
+end
diff --git a/test/plugs/oauth_scopes_plug_test.exs b/test/pleroma/web/plugs/o_auth_scopes_plug_test.exs
index 884de7b4d..9f6d3dc71 100644
--- a/test/plugs/oauth_scopes_plug_test.exs
+++ b/test/pleroma/web/plugs/o_auth_scopes_plug_test.exs
@@ -1,12 +1,12 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Plugs.OAuthScopesPlugTest do
- use Pleroma.Web.ConnCase, async: true
+defmodule Pleroma.Web.Plugs.OAuthScopesPlugTest do
+ use Pleroma.Web.ConnCase
- alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.Repo
+ alias Pleroma.Web.Plugs.OAuthScopesPlug
import Mock
import Pleroma.Factory
@@ -169,42 +169,4 @@ defmodule Pleroma.Plugs.OAuthScopesPlugTest do
assert f.(["admin:read"], ["write", "admin"]) == ["admin:read"]
end
end
-
- describe "transform_scopes/2" do
- setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage])
-
- setup do
- {:ok, %{f: &OAuthScopesPlug.transform_scopes/2}}
- end
-
- test "with :admin option, prefixes all requested scopes with `admin:` " <>
- "and [optionally] keeps only prefixed scopes, " <>
- "depending on `[:auth, :enforce_oauth_admin_scope_usage]` setting",
- %{f: f} do
- Pleroma.Config.put([:auth, :enforce_oauth_admin_scope_usage], false)
-
- assert f.(["read"], %{admin: true}) == ["admin:read", "read"]
-
- assert f.(["read", "write"], %{admin: true}) == [
- "admin:read",
- "read",
- "admin:write",
- "write"
- ]
-
- Pleroma.Config.put([:auth, :enforce_oauth_admin_scope_usage], true)
-
- assert f.(["read:accounts"], %{admin: true}) == ["admin:read:accounts"]
-
- assert f.(["read", "write:reports"], %{admin: true}) == [
- "admin:read",
- "admin:write:reports"
- ]
- end
-
- test "with no supported options, returns unmodified scopes", %{f: f} do
- assert f.(["read"], %{}) == ["read"]
- assert f.(["read", "write"], %{}) == ["read", "write"]
- end
- end
end
diff --git a/test/web/plugs/plug_test.exs b/test/pleroma/web/plugs/plug_helper_test.exs
index 943e484e7..346113628 100644
--- a/test/web/plugs/plug_test.exs
+++ b/test/pleroma/web/plugs/plug_helper_test.exs
@@ -1,13 +1,13 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Web.PlugTest do
+defmodule Pleroma.Web.Plugs.PlugHelperTest do
@moduledoc "Tests for the functionality added via `use Pleroma.Web, :plug`"
- alias Pleroma.Plugs.ExpectAuthenticatedCheckPlug
- alias Pleroma.Plugs.ExpectPublicOrAuthenticatedCheckPlug
- alias Pleroma.Plugs.PlugHelper
+ alias Pleroma.Web.Plugs.ExpectAuthenticatedCheckPlug
+ alias Pleroma.Web.Plugs.ExpectPublicOrAuthenticatedCheckPlug
+ alias Pleroma.Web.Plugs.PlugHelper
import Mock
diff --git a/test/plugs/rate_limiter_test.exs b/test/pleroma/web/plugs/rate_limiter_test.exs
index 4d3d694f4..b7cfde1f7 100644
--- a/test/plugs/rate_limiter_test.exs
+++ b/test/pleroma/web/plugs/rate_limiter_test.exs
@@ -1,13 +1,12 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Plugs.RateLimiterTest do
+defmodule Pleroma.Web.Plugs.RateLimiterTest do
use Pleroma.Web.ConnCase
alias Phoenix.ConnTest
- alias Pleroma.Config
- alias Pleroma.Plugs.RateLimiter
+ alias Pleroma.Web.Plugs.RateLimiter
alias Plug.Conn
import Pleroma.Factory
@@ -19,11 +18,11 @@ defmodule Pleroma.Plugs.RateLimiterTest do
describe "config" do
@limiter_name :test_init
- setup do: clear_config([Pleroma.Plugs.RemoteIp, :enabled])
+ setup do: clear_config([Pleroma.Web.Plugs.RemoteIp, :enabled])
test "config is required for plug to work" do
- Config.put([:rate_limit, @limiter_name], {1, 1})
- Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
+ clear_config([:rate_limit, @limiter_name], {1, 1})
+ clear_config([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
assert %{limits: {1, 1}, name: :test_init, opts: [name: :test_init]} ==
[name: @limiter_name]
@@ -49,13 +48,14 @@ defmodule Pleroma.Plugs.RateLimiterTest do
refute RateLimiter.disabled?(build_conn())
end
+ @tag :erratic
test "it restricts based on config values" do
limiter_name = :test_plug_opts
scale = 80
limit = 5
- Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
- Config.put([:rate_limit, limiter_name], {scale, limit})
+ clear_config([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
+ clear_config([:rate_limit, limiter_name], {scale, limit})
plug_opts = RateLimiter.init(name: limiter_name)
conn = build_conn(:get, "/")
@@ -86,8 +86,8 @@ defmodule Pleroma.Plugs.RateLimiterTest do
test "`bucket_name` option overrides default bucket name" do
limiter_name = :test_bucket_name
- Config.put([:rate_limit, limiter_name], {1000, 5})
- Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
+ clear_config([:rate_limit, limiter_name], {1000, 5})
+ clear_config([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
base_bucket_name = "#{limiter_name}:group1"
plug_opts = RateLimiter.init(name: limiter_name, bucket_name: base_bucket_name)
@@ -101,8 +101,8 @@ defmodule Pleroma.Plugs.RateLimiterTest do
test "`params` option allows different queries to be tracked independently" do
limiter_name = :test_params
- Config.put([:rate_limit, limiter_name], {1000, 5})
- Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
+ clear_config([:rate_limit, limiter_name], {1000, 5})
+ clear_config([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
plug_opts = RateLimiter.init(name: limiter_name, params: ["id"])
@@ -117,8 +117,8 @@ defmodule Pleroma.Plugs.RateLimiterTest do
test "it supports combination of options modifying bucket name" do
limiter_name = :test_options_combo
- Config.put([:rate_limit, limiter_name], {1000, 5})
- Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
+ clear_config([:rate_limit, limiter_name], {1000, 5})
+ clear_config([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
base_bucket_name = "#{limiter_name}:group1"
@@ -138,10 +138,11 @@ defmodule Pleroma.Plugs.RateLimiterTest do
end
describe "unauthenticated users" do
+ @tag :erratic
test "are restricted based on remote IP" do
limiter_name = :test_unauthenticated
- Config.put([:rate_limit, limiter_name], [{1000, 5}, {1, 10}])
- Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
+ clear_config([:rate_limit, limiter_name], [{1000, 5}, {1, 10}])
+ clear_config([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
plug_opts = RateLimiter.init(name: limiter_name)
@@ -175,13 +176,14 @@ defmodule Pleroma.Plugs.RateLimiterTest do
:ok
end
+ @tag :erratic
test "can have limits separate from unauthenticated connections" do
limiter_name = :test_authenticated1
scale = 50
limit = 5
- Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
- Config.put([:rate_limit, limiter_name], [{1000, 1}, {scale, limit}])
+ clear_config([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
+ clear_config([:rate_limit, limiter_name], [{1000, 1}, {scale, limit}])
plug_opts = RateLimiter.init(name: limiter_name)
@@ -200,10 +202,11 @@ defmodule Pleroma.Plugs.RateLimiterTest do
assert conn.halted
end
+ @tag :erratic
test "different users are counted independently" do
limiter_name = :test_authenticated2
- Config.put([:rate_limit, limiter_name], [{1, 10}, {1000, 5}])
- Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
+ clear_config([:rate_limit, limiter_name], [{1, 10}, {1000, 5}])
+ clear_config([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
plug_opts = RateLimiter.init(name: limiter_name)
@@ -232,8 +235,8 @@ defmodule Pleroma.Plugs.RateLimiterTest do
test "doesn't crash due to a race condition when multiple requests are made at the same time and the bucket is not yet initialized" do
limiter_name = :test_race_condition
- Pleroma.Config.put([:rate_limit, limiter_name], {1000, 5})
- Pleroma.Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
+ clear_config([:rate_limit, limiter_name], {1000, 5})
+ clear_config([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8})
opts = RateLimiter.init(name: limiter_name)
diff --git a/test/pleroma/web/plugs/remote_ip_test.exs b/test/pleroma/web/plugs/remote_ip_test.exs
new file mode 100644
index 000000000..4d98de2bd
--- /dev/null
+++ b/test/pleroma/web/plugs/remote_ip_test.exs
@@ -0,0 +1,108 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Plugs.RemoteIpTest do
+ use ExUnit.Case
+ use Plug.Test
+
+ alias Pleroma.Web.Plugs.RemoteIp
+
+ import Pleroma.Tests.Helpers, only: [clear_config: 2]
+
+ setup do:
+ clear_config(RemoteIp,
+ enabled: true,
+ headers: ["x-forwarded-for"],
+ proxies: [],
+ reserved: [
+ "127.0.0.0/8",
+ "::1/128",
+ "fc00::/7",
+ "10.0.0.0/8",
+ "172.16.0.0/12",
+ "192.168.0.0/16"
+ ]
+ )
+
+ test "disabled" do
+ clear_config(RemoteIp, enabled: false)
+
+ %{remote_ip: remote_ip} = conn(:get, "/")
+
+ conn =
+ conn(:get, "/")
+ |> put_req_header("x-forwarded-for", "1.1.1.1")
+ |> RemoteIp.call(nil)
+
+ assert conn.remote_ip == remote_ip
+ end
+
+ test "enabled" do
+ conn =
+ conn(:get, "/")
+ |> put_req_header("x-forwarded-for", "1.1.1.1")
+ |> RemoteIp.call(nil)
+
+ assert conn.remote_ip == {1, 1, 1, 1}
+ end
+
+ test "custom headers" do
+ clear_config(RemoteIp, enabled: true, headers: ["cf-connecting-ip"])
+
+ conn =
+ conn(:get, "/")
+ |> put_req_header("x-forwarded-for", "1.1.1.1")
+ |> RemoteIp.call(nil)
+
+ refute conn.remote_ip == {1, 1, 1, 1}
+
+ conn =
+ conn(:get, "/")
+ |> put_req_header("cf-connecting-ip", "1.1.1.1")
+ |> RemoteIp.call(nil)
+
+ assert conn.remote_ip == {1, 1, 1, 1}
+ end
+
+ test "custom proxies" do
+ conn =
+ conn(:get, "/")
+ |> put_req_header("x-forwarded-for", "173.245.48.1, 1.1.1.1, 173.245.48.2")
+ |> RemoteIp.call(nil)
+
+ refute conn.remote_ip == {1, 1, 1, 1}
+
+ clear_config([RemoteIp, :proxies], ["173.245.48.0/20"])
+
+ conn =
+ conn(:get, "/")
+ |> put_req_header("x-forwarded-for", "173.245.48.1, 1.1.1.1, 173.245.48.2")
+ |> RemoteIp.call(nil)
+
+ assert conn.remote_ip == {1, 1, 1, 1}
+ end
+
+ test "proxies set without CIDR format" do
+ clear_config([RemoteIp, :proxies], ["173.245.48.1"])
+
+ conn =
+ conn(:get, "/")
+ |> put_req_header("x-forwarded-for", "173.245.48.1, 1.1.1.1")
+ |> RemoteIp.call(nil)
+
+ assert conn.remote_ip == {1, 1, 1, 1}
+ end
+
+ test "proxies set `nonsensical` CIDR" do
+ clear_config([RemoteIp, :reserved], ["127.0.0.0/8"])
+ clear_config([RemoteIp, :proxies], ["10.0.0.3/24"])
+
+ conn =
+ conn(:get, "/")
+ |> put_req_header("x-forwarded-for", "10.0.0.3, 1.1.1.1")
+ |> RemoteIp.call(nil)
+
+ assert conn.remote_ip == {1, 1, 1, 1}
+ end
+end
diff --git a/test/plugs/set_format_plug_test.exs b/test/pleroma/web/plugs/set_format_plug_test.exs
index 7a1dfe9bf..21043f698 100644
--- a/test/plugs/set_format_plug_test.exs
+++ b/test/pleroma/web/plugs/set_format_plug_test.exs
@@ -1,12 +1,12 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Plugs.SetFormatPlugTest do
+defmodule Pleroma.Web.Plugs.SetFormatPlugTest do
use ExUnit.Case, async: true
use Plug.Test
- alias Pleroma.Plugs.SetFormatPlug
+ alias Pleroma.Web.Plugs.SetFormatPlug
test "set format from params" do
conn =
diff --git a/test/plugs/set_locale_plug_test.exs b/test/pleroma/web/plugs/set_locale_plug_test.exs
index 7114b1557..5261e67ae 100644
--- a/test/plugs/set_locale_plug_test.exs
+++ b/test/pleroma/web/plugs/set_locale_plug_test.exs
@@ -1,12 +1,12 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Plugs.SetLocalePlugTest do
+defmodule Pleroma.Web.Plugs.SetLocalePlugTest do
use ExUnit.Case, async: true
use Plug.Test
- alias Pleroma.Plugs.SetLocalePlug
+ alias Pleroma.Web.Plugs.SetLocalePlug
alias Plug.Conn
test "default locale is `en`" do
diff --git a/test/plugs/set_user_session_id_plug_test.exs b/test/pleroma/web/plugs/set_user_session_id_plug_test.exs
index 7f1a1e98b..9814c80d8 100644
--- a/test/plugs/set_user_session_id_plug_test.exs
+++ b/test/pleroma/web/plugs/set_user_session_id_plug_test.exs
@@ -1,12 +1,12 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Plugs.SetUserSessionIdPlugTest do
+defmodule Pleroma.Web.Plugs.SetUserSessionIdPlugTest do
use Pleroma.Web.ConnCase, async: true
- alias Pleroma.Plugs.SetUserSessionIdPlug
- alias Pleroma.User
+ alias Pleroma.Helpers.AuthHelper
+ alias Pleroma.Web.Plugs.SetUserSessionIdPlug
setup %{conn: conn} do
session_opts = [
@@ -18,28 +18,26 @@ defmodule Pleroma.Plugs.SetUserSessionIdPlugTest do
conn =
conn
|> Plug.Session.call(Plug.Session.init(session_opts))
- |> fetch_session
+ |> fetch_session()
%{conn: conn}
end
test "doesn't do anything if the user isn't set", %{conn: conn} do
- ret_conn =
- conn
- |> SetUserSessionIdPlug.call(%{})
+ ret_conn = SetUserSessionIdPlug.call(conn, %{})
assert ret_conn == conn
end
- test "sets the user_id in the session to the user id of the user assign", %{conn: conn} do
- Code.ensure_compiled(Pleroma.User)
+ test "sets session token basing on :token assign", %{conn: conn} do
+ %{user: user, token: oauth_token} = oauth_access(["read"])
- conn =
+ ret_conn =
conn
- |> assign(:user, %User{id: 1})
+ |> assign(:user, user)
+ |> assign(:token, oauth_token)
|> SetUserSessionIdPlug.call(%{})
- id = get_session(conn, :user_id)
- assert id == 1
+ assert AuthHelper.get_session_token(ret_conn) == oauth_token.token
end
end
diff --git a/test/plugs/uploaded_media_plug_test.exs b/test/pleroma/web/plugs/uploaded_media_plug_test.exs
index 20b13dfac..75f313282 100644
--- a/test/plugs/uploaded_media_plug_test.exs
+++ b/test/pleroma/web/plugs/uploaded_media_plug_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Web.UploadedMediaPlugTest do
- use Pleroma.Web.ConnCase
+defmodule Pleroma.Web.Plugs.UploadedMediaPlugTest do
+ use Pleroma.Web.ConnCase, async: true
alias Pleroma.Upload
defp upload_file(context) do
@@ -11,7 +11,7 @@ defmodule Pleroma.Web.UploadedMediaPlugTest do
File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image_tmp.jpg"),
filename: "nice_tf.jpg"
}
diff --git a/test/plugs/user_enabled_plug_test.exs b/test/pleroma/web/plugs/user_enabled_plug_test.exs
index b219d8abf..999c6c49c 100644
--- a/test/plugs/user_enabled_plug_test.exs
+++ b/test/pleroma/web/plugs/user_enabled_plug_test.exs
@@ -1,11 +1,11 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Plugs.UserEnabledPlugTest do
- use Pleroma.Web.ConnCase, async: true
+defmodule Pleroma.Web.Plugs.UserEnabledPlugTest do
+ use Pleroma.Web.ConnCase
- alias Pleroma.Plugs.UserEnabledPlug
+ alias Pleroma.Web.Plugs.UserEnabledPlug
import Pleroma.Factory
setup do: clear_config([:instance, :account_activation_required])
@@ -20,9 +20,9 @@ defmodule Pleroma.Plugs.UserEnabledPlugTest do
test "with a user that's not confirmed and a config requiring confirmation, it removes that user",
%{conn: conn} do
- Pleroma.Config.put([:instance, :account_activation_required], true)
+ clear_config([:instance, :account_activation_required], true)
- user = insert(:user, confirmation_pending: true)
+ user = insert(:user, is_confirmed: false)
conn =
conn
@@ -33,7 +33,7 @@ defmodule Pleroma.Plugs.UserEnabledPlugTest do
end
test "with a user that is deactivated, it removes that user", %{conn: conn} do
- user = insert(:user, deactivated: true)
+ user = insert(:user, is_active: false)
conn =
conn
diff --git a/test/plugs/user_fetcher_plug_test.exs b/test/pleroma/web/plugs/user_fetcher_plug_test.exs
index 0496f14dd..902bee642 100644
--- a/test/plugs/user_fetcher_plug_test.exs
+++ b/test/pleroma/web/plugs/user_fetcher_plug_test.exs
@@ -1,11 +1,11 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Plugs.UserFetcherPlugTest do
+defmodule Pleroma.Web.Plugs.UserFetcherPlugTest do
use Pleroma.Web.ConnCase, async: true
- alias Pleroma.Plugs.UserFetcherPlug
+ alias Pleroma.Web.Plugs.UserFetcherPlug
import Pleroma.Factory
setup do
diff --git a/test/plugs/user_is_admin_plug_test.exs b/test/pleroma/web/plugs/user_is_admin_plug_test.exs
index 8bc00e444..58996d5a4 100644
--- a/test/plugs/user_is_admin_plug_test.exs
+++ b/test/pleroma/web/plugs/user_is_admin_plug_test.exs
@@ -1,11 +1,11 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Plugs.UserIsAdminPlugTest do
+defmodule Pleroma.Web.Plugs.UserIsAdminPlugTest do
use Pleroma.Web.ConnCase, async: true
- alias Pleroma.Plugs.UserIsAdminPlug
+ alias Pleroma.Web.Plugs.UserIsAdminPlug
import Pleroma.Factory
test "accepts a user that is an admin" do
diff --git a/test/pleroma/web/plugs/user_is_staff_plug_test.exs b/test/pleroma/web/plugs/user_is_staff_plug_test.exs
new file mode 100644
index 000000000..a0c4061db
--- /dev/null
+++ b/test/pleroma/web/plugs/user_is_staff_plug_test.exs
@@ -0,0 +1,47 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Plugs.UserIsStaffPlugTest do
+ use Pleroma.Web.ConnCase, async: true
+
+ alias Pleroma.Web.Plugs.UserIsStaffPlug
+ import Pleroma.Factory
+
+ test "accepts a user that is an admin" do
+ user = insert(:user, is_admin: true)
+
+ conn = assign(build_conn(), :user, user)
+
+ ret_conn = UserIsStaffPlug.call(conn, %{})
+
+ assert conn == ret_conn
+ end
+
+ test "accepts a user that is a moderator" do
+ user = insert(:user, is_moderator: true)
+
+ conn = assign(build_conn(), :user, user)
+
+ ret_conn = UserIsStaffPlug.call(conn, %{})
+
+ assert conn == ret_conn
+ end
+
+ test "denies a user that isn't a staff member" do
+ user = insert(:user)
+
+ conn =
+ build_conn()
+ |> assign(:user, user)
+ |> UserIsStaffPlug.call(%{})
+
+ assert conn.status == 403
+ end
+
+ test "denies when a user isn't set" do
+ conn = UserIsStaffPlug.call(build_conn(), %{})
+
+ assert conn.status == 403
+ end
+end
diff --git a/test/pleroma/web/plugs/user_tracking_plug_test.exs b/test/pleroma/web/plugs/user_tracking_plug_test.exs
new file mode 100644
index 000000000..8e9d59b99
--- /dev/null
+++ b/test/pleroma/web/plugs/user_tracking_plug_test.exs
@@ -0,0 +1,58 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Plugs.UserTrackingPlugTest do
+ use Pleroma.Web.ConnCase, async: true
+
+ import Pleroma.Factory
+
+ alias Pleroma.Web.Plugs.UserTrackingPlug
+
+ test "updates last_active_at for a new user", %{conn: conn} do
+ user = insert(:user)
+
+ assert is_nil(user.last_active_at)
+
+ test_started_at = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second)
+
+ %{assigns: %{user: user}} =
+ conn
+ |> assign(:user, user)
+ |> UserTrackingPlug.call(%{})
+
+ assert user.last_active_at >= test_started_at
+ assert user.last_active_at <= NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second)
+ end
+
+ test "doesn't update last_active_at if it was updated recently", %{conn: conn} do
+ last_active_at =
+ NaiveDateTime.utc_now()
+ |> NaiveDateTime.add(-:timer.hours(1), :millisecond)
+ |> NaiveDateTime.truncate(:second)
+
+ user = insert(:user, %{last_active_at: last_active_at})
+
+ %{assigns: %{user: user}} =
+ conn
+ |> assign(:user, user)
+ |> UserTrackingPlug.call(%{})
+
+ assert user.last_active_at == last_active_at
+ end
+
+ test "skips updating last_active_at if user ID is nil", %{conn: conn} do
+ %{assigns: %{user: user}} =
+ conn
+ |> assign(:user, %Pleroma.User{})
+ |> UserTrackingPlug.call(%{})
+
+ assert is_nil(user.last_active_at)
+ end
+
+ test "does nothing if user is not present", %{conn: conn} do
+ %{assigns: assigns} = UserTrackingPlug.call(conn, %{})
+
+ refute Map.has_key?(assigns, :user)
+ end
+end
diff --git a/test/web/preload/instance_test.exs b/test/pleroma/web/preload/providers/instance_test.exs
index a46f28312..a401475ee 100644
--- a/test/web/preload/instance_test.exs
+++ b/test/pleroma/web/preload/providers/instance_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Preload.Providers.InstanceTest do
@@ -45,4 +45,12 @@ defmodule Pleroma.Web.Preload.Providers.InstanceTest do
assert metadata.private == false
assert metadata.suggestions == %{enabled: false}
end
+
+ test "it renders the frontend configurations", %{
+ "/api/pleroma/frontend_configurations" => fe_configs
+ } do
+ assert %{
+ pleroma_fe: %{background: "/images/city.jpg", logo: "/static/logo.svg"}
+ } = fe_configs
+ end
end
diff --git a/test/web/preload/timeline_test.exs b/test/pleroma/web/preload/providers/timeline_test.exs
index 3b1f2f1aa..2ae2ca5fb 100644
--- a/test/web/preload/timeline_test.exs
+++ b/test/pleroma/web/preload/providers/timeline_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Preload.Providers.TimelineTest do
diff --git a/test/web/preload/user_test.exs b/test/pleroma/web/preload/providers/user_test.exs
index 83f065e27..b7017ac20 100644
--- a/test/web/preload/user_test.exs
+++ b/test/pleroma/web/preload/providers/user_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Preload.Providers.UserTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
import Pleroma.Factory
alias Pleroma.Web.Preload.Providers.User
diff --git a/test/web/push/impl_test.exs b/test/pleroma/web/push/impl_test.exs
index aeb5c1fbd..b3ca1a337 100644
--- a/test/web/push/impl_test.exs
+++ b/test/pleroma/web/push/impl_test.exs
@@ -1,9 +1,11 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Push.ImplTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
+
+ import Pleroma.Factory
alias Pleroma.Notification
alias Pleroma.Object
@@ -13,8 +15,6 @@ defmodule Pleroma.Web.Push.ImplTest do
alias Pleroma.Web.Push.Impl
alias Pleroma.Web.Push.Subscription
- import Pleroma.Factory
-
setup do
Tesla.Mock.mock(fn
%{method: :post, url: "https://example.com/example/1234"} ->
@@ -118,7 +118,7 @@ defmodule Pleroma.Web.Push.ImplTest do
"<span>Lorem ipsum dolor sit amet</span>, consectetur :firefox: adipiscing elit. Fusce sagittis finibus turpis."
})
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
assert Impl.format_body(
%{
@@ -137,7 +137,7 @@ defmodule Pleroma.Web.Push.ImplTest do
user = insert(:user, nickname: "Bob")
other_user = insert(:user)
{:ok, _, _, activity} = CommonAPI.follow(user, other_user)
- object = Object.normalize(activity, false)
+ object = Object.normalize(activity, fetch: false)
assert Impl.format_body(%{activity: activity, type: "follow"}, user, object) ==
"@Bob has followed you"
@@ -156,7 +156,7 @@ defmodule Pleroma.Web.Push.ImplTest do
})
{:ok, announce_activity} = CommonAPI.repeat(activity.id, user)
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
assert Impl.format_body(%{activity: announce_activity}, user, object) ==
"@#{user.nickname} repeated: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce sagittis fini..."
@@ -175,7 +175,7 @@ defmodule Pleroma.Web.Push.ImplTest do
})
{:ok, activity} = CommonAPI.favorite(user, activity.id)
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
assert Impl.format_body(%{activity: activity, type: "favourite"}, user, object) ==
"@Bob has favorited your post"
@@ -184,6 +184,24 @@ defmodule Pleroma.Web.Push.ImplTest do
"New Favorite"
end
+ test "renders title and body for pleroma:emoji_reaction activity" do
+ user = insert(:user, nickname: "Bob")
+
+ {:ok, activity} =
+ CommonAPI.post(user, %{
+ status: "This post is a really good post!"
+ })
+
+ {:ok, activity} = CommonAPI.react_with_emoji(activity.id, user, "👍")
+ object = Object.normalize(activity, fetch: false)
+
+ assert Impl.format_body(%{activity: activity, type: "pleroma:emoji_reaction"}, user, object) ==
+ "@Bob reacted with 👍"
+
+ assert Impl.format_title(%{activity: activity, type: "pleroma:emoji_reaction"}) ==
+ "New Reaction"
+ end
+
test "renders title for create activity with direct visibility" do
user = insert(:user, nickname: "Bob")
@@ -203,7 +221,7 @@ defmodule Pleroma.Web.Push.ImplTest do
recipient = insert(:user)
{:ok, chat} = CommonAPI.post_chat_message(user, recipient, "hey")
- object = Object.normalize(chat, false)
+ object = Object.normalize(chat, fetch: false)
[notification] = Notification.for_user(recipient)
res = Impl.build_content(notification, user, object)
@@ -219,7 +237,7 @@ defmodule Pleroma.Web.Push.ImplTest do
recipient = insert(:user)
file = %Plug.Upload{
- content_type: "image/jpg",
+ content_type: "image/jpeg",
path: Path.absname("test/fixtures/image.jpg"),
filename: "an_image.jpg"
}
@@ -227,7 +245,7 @@ defmodule Pleroma.Web.Push.ImplTest do
{:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
{:ok, chat} = CommonAPI.post_chat_message(user, recipient, nil, media_id: upload.id)
- object = Object.normalize(chat, false)
+ object = Object.normalize(chat, fetch: false)
[notification] = Notification.for_user(recipient)
res = Impl.build_content(notification, user, object)
@@ -253,7 +271,7 @@ defmodule Pleroma.Web.Push.ImplTest do
notif = insert(:notification, user: user2, activity: activity)
actor = User.get_cached_by_ap_id(notif.activity.data["actor"])
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
assert Impl.build_content(notif, actor, object) == %{
body: "New Direct Message"
@@ -268,7 +286,7 @@ defmodule Pleroma.Web.Push.ImplTest do
notif = insert(:notification, user: user2, activity: activity, type: "mention")
actor = User.get_cached_by_ap_id(notif.activity.data["actor"])
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
assert Impl.build_content(notif, actor, object) == %{
body: "New Mention"
@@ -279,7 +297,7 @@ defmodule Pleroma.Web.Push.ImplTest do
notif = insert(:notification, user: user2, activity: activity, type: "favourite")
actor = User.get_cached_by_ap_id(notif.activity.data["actor"])
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
assert Impl.build_content(notif, actor, object) == %{
body: "New Favorite"
@@ -302,7 +320,7 @@ defmodule Pleroma.Web.Push.ImplTest do
notif = insert(:notification, user: user2, activity: activity)
actor = User.get_cached_by_ap_id(notif.activity.data["actor"])
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
assert Impl.build_content(notif, actor, object) == %{
body:
@@ -320,7 +338,7 @@ defmodule Pleroma.Web.Push.ImplTest do
notif = insert(:notification, user: user2, activity: activity, type: "mention")
actor = User.get_cached_by_ap_id(notif.activity.data["actor"])
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
assert Impl.build_content(notif, actor, object) == %{
body:
@@ -333,7 +351,7 @@ defmodule Pleroma.Web.Push.ImplTest do
notif = insert(:notification, user: user2, activity: activity, type: "favourite")
actor = User.get_cached_by_ap_id(notif.activity.data["actor"])
- object = Object.normalize(activity)
+ object = Object.normalize(activity, fetch: false)
assert Impl.build_content(notif, actor, object) == %{
body: "@Bob has favorited your post",
diff --git a/test/web/rel_me_test.exs b/test/pleroma/web/rel_me_test.exs
index 65255916d..313b163b5 100644
--- a/test/web/rel_me_test.exs
+++ b/test/pleroma/web/rel_me_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.RelMeTest do
- use ExUnit.Case
+ use Pleroma.DataCase
setup_all do
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
diff --git a/test/web/rich_media/helpers_test.exs b/test/pleroma/web/rich_media/helpers_test.exs
index 8264a9c41..689854fb6 100644
--- a/test/web/rich_media/helpers_test.exs
+++ b/test/pleroma/web/rich_media/helpers_test.exs
@@ -1,12 +1,10 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.RichMedia.HelpersTest do
use Pleroma.DataCase
- alias Pleroma.Config
- alias Pleroma.Object
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.RichMedia.Helpers
@@ -30,7 +28,7 @@ defmodule Pleroma.Web.RichMedia.HelpersTest do
content_type: "text/markdown"
})
- Config.put([:rich_media, :enabled], true)
+ clear_config([:rich_media, :enabled], true)
assert %{} == Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
end
@@ -44,7 +42,7 @@ defmodule Pleroma.Web.RichMedia.HelpersTest do
content_type: "text/markdown"
})
- Config.put([:rich_media, :enabled], true)
+ clear_config([:rich_media, :enabled], true)
assert %{} == Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
end
@@ -58,47 +56,12 @@ defmodule Pleroma.Web.RichMedia.HelpersTest do
content_type: "text/markdown"
})
- Config.put([:rich_media, :enabled], true)
+ clear_config([:rich_media, :enabled], true)
assert %{page_url: "https://example.com/ogp", rich_media: _} =
Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
end
- test "refuses to crawl URLs from posts marked sensitive" do
- user = insert(:user)
-
- {:ok, activity} =
- CommonAPI.post(user, %{
- status: "http://example.com/ogp",
- sensitive: true
- })
-
- %Object{} = object = Object.normalize(activity)
-
- assert object.data["sensitive"]
-
- Config.put([:rich_media, :enabled], true)
-
- assert %{} = Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
- end
-
- test "refuses to crawl URLs from posts tagged NSFW" do
- user = insert(:user)
-
- {:ok, activity} =
- CommonAPI.post(user, %{
- status: "http://example.com/ogp #nsfw"
- })
-
- %Object{} = object = Object.normalize(activity)
-
- assert object.data["sensitive"]
-
- Config.put([:rich_media, :enabled], true)
-
- assert %{} = Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
- end
-
test "refuses to crawl URLs of private network from posts" do
user = insert(:user)
@@ -110,7 +73,7 @@ defmodule Pleroma.Web.RichMedia.HelpersTest do
{:ok, activity4} = CommonAPI.post(user, %{status: "https://192.168.10.40/notice/9kCP7V"})
{:ok, activity5} = CommonAPI.post(user, %{status: "https://pleroma.local/notice/9kCP7V"})
- Config.put([:rich_media, :enabled], true)
+ clear_config([:rich_media, :enabled], true)
assert %{} = Helpers.fetch_data_for_activity(activity)
assert %{} = Helpers.fetch_data_for_activity(activity2)
diff --git a/test/web/rich_media/aws_signed_url_test.exs b/test/pleroma/web/rich_media/parser/ttl/aws_signed_url_test.exs
index 1ceae1a31..0c8203417 100644
--- a/test/web/rich_media/aws_signed_url_test.exs
+++ b/test/pleroma/web/rich_media/parser/ttl/aws_signed_url_test.exs
@@ -1,9 +1,10 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Web.RichMedia.TTL.AwsSignedUrlTest do
- use ExUnit.Case, async: true
+defmodule Pleroma.Web.RichMedia.Parser.TTL.AwsSignedUrlTest do
+ # Relies on Cachex, needs to be synchronous
+ use Pleroma.DataCase
test "s3 signed url is parsed correct for expiration time" do
url = "https://pleroma.social/amz"
@@ -65,9 +66,7 @@ defmodule Pleroma.Web.RichMedia.TTL.AwsSignedUrlTest do
end
defp construct_s3_url(timestamp, valid_till) do
- "https://pleroma.s3.ap-southeast-1.amazonaws.com/sachin%20%281%29%20_a%20-%25%2Aasdasd%20BNN%20bnnn%20.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIBLWWK6RGDQXDLJQ%2F20190716%2Fap-southeast-1%2Fs3%2Faws4_request&X-Amz-Date=#{
- timestamp
- }&X-Amz-Expires=#{valid_till}&X-Amz-Signature=04ffd6b98634f4b1bbabc62e0fac4879093cd54a6eed24fe8eb38e8369526bbf&X-Amz-SignedHeaders=host"
+ "https://pleroma.s3.ap-southeast-1.amazonaws.com/sachin%20%281%29%20_a%20-%25%2Aasdasd%20BNN%20bnnn%20.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIBLWWK6RGDQXDLJQ%2F20190716%2Fap-southeast-1%2Fs3%2Faws4_request&X-Amz-Date=#{timestamp}&X-Amz-Expires=#{valid_till}&X-Amz-Signature=04ffd6b98634f4b1bbabc62e0fac4879093cd54a6eed24fe8eb38e8369526bbf&X-Amz-SignedHeaders=host"
end
defp construct_metadata(timestamp, valid_till, url) do
diff --git a/test/web/rich_media/parser_test.exs b/test/pleroma/web/rich_media/parser_test.exs
index 21ae35f8b..2f363b012 100644
--- a/test/web/rich_media/parser_test.exs
+++ b/test/pleroma/web/rich_media/parser_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.RichMedia.ParserTest do
@@ -56,6 +56,27 @@ defmodule Pleroma.Web.RichMedia.ParserTest do
%{method: :get, url: "http://example.com/error"} ->
{:error, :overload}
+
+ %{
+ method: :head,
+ url: "http://example.com/huge-page"
+ } ->
+ %Tesla.Env{
+ status: 200,
+ headers: [{"content-length", "2000001"}, {"content-type", "text/html"}]
+ }
+
+ %{
+ method: :head,
+ url: "http://example.com/pdf-file"
+ } ->
+ %Tesla.Env{
+ status: 200,
+ headers: [{"content-length", "1000000"}, {"content-type", "application/pdf"}]
+ }
+
+ %{method: :head} ->
+ %Tesla.Env{status: 404, body: "", headers: []}
end)
:ok
@@ -144,4 +165,12 @@ defmodule Pleroma.Web.RichMedia.ParserTest do
test "returns error if getting page was not successful" do
assert {:error, :overload} = Parser.parse("http://example.com/error")
end
+
+ test "does a HEAD request to check if the body is too large" do
+ assert {:error, :body_too_large} = Parser.parse("http://example.com/huge-page")
+ end
+
+ test "does a HEAD request to check if the body is html" do
+ assert {:error, {:content_type, _}} = Parser.parse("http://example.com/pdf-file")
+ end
end
diff --git a/test/web/rich_media/parsers/twitter_card_test.exs b/test/pleroma/web/rich_media/parsers/twitter_card_test.exs
index 219f005a2..2aacd29a3 100644
--- a/test/web/rich_media/parsers/twitter_card_test.exs
+++ b/test/pleroma/web/rich_media/parsers/twitter_card_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.RichMedia.Parsers.TwitterCardTest do
diff --git a/test/web/chat_channel_test.exs b/test/pleroma/web/shout_channel_test.exs
index f18f3a212..5c86efe9f 100644
--- a/test/web/chat_channel_test.exs
+++ b/test/pleroma/web/shout_channel_test.exs
@@ -1,6 +1,10 @@
-defmodule Pleroma.Web.ChatChannelTest do
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ShoutChannelTest do
use Pleroma.Web.ChannelCase
- alias Pleroma.Web.ChatChannel
+ alias Pleroma.Web.ShoutChannel
alias Pleroma.Web.UserSocket
import Pleroma.Factory
@@ -10,7 +14,7 @@ defmodule Pleroma.Web.ChatChannelTest do
{:ok, _, socket} =
socket(UserSocket, "", %{user_name: user.nickname})
- |> subscribe_and_join(ChatChannel, "chat:public")
+ |> subscribe_and_join(ShoutChannel, "chat:public")
{:ok, socket: socket}
end
@@ -21,7 +25,7 @@ defmodule Pleroma.Web.ChatChannelTest do
end
describe "message lengths" do
- setup do: clear_config([:instance, :chat_limit])
+ setup do: clear_config([:shout, :limit])
test "it ignores messages of length zero", %{socket: socket} do
push(socket, "new_msg", %{"text" => ""})
@@ -29,7 +33,7 @@ defmodule Pleroma.Web.ChatChannelTest do
end
test "it ignores messages above a certain length", %{socket: socket} do
- Pleroma.Config.put([:instance, :chat_limit], 2)
+ clear_config([:shout, :limit], 2)
push(socket, "new_msg", %{"text" => "123"})
refute_broadcast("new_msg", %{text: "123"})
end
diff --git a/test/web/static_fe/static_fe_controller_test.exs b/test/pleroma/web/static_fe/static_fe_controller_test.exs
index 1598bf675..5752cffda 100644
--- a/test/web/static_fe/static_fe_controller_test.exs
+++ b/test/pleroma/web/static_fe/static_fe_controller_test.exs
@@ -1,15 +1,18 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
defmodule Pleroma.Web.StaticFE.StaticFEControllerTest do
use Pleroma.Web.ConnCase
alias Pleroma.Activity
- alias Pleroma.Config
alias Pleroma.Web.ActivityPub.Transmogrifier
+ alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.CommonAPI
import Pleroma.Factory
setup_all do: clear_config([:static_fe, :enabled], true)
- setup do: clear_config([:instance, :federating], true)
setup %{conn: conn} do
conn = put_req_header(conn, "accept", "text/html")
@@ -70,8 +73,27 @@ defmodule Pleroma.Web.StaticFE.StaticFEControllerTest do
refute html =~ ">test29<"
end
- test "it requires authentication if instance is NOT federating", %{conn: conn, user: user} do
- ensure_federating_or_authenticated(conn, "/users/#{user.nickname}", user)
+ test "does not require authentication on non-federating instances", %{
+ conn: conn,
+ user: user
+ } do
+ clear_config([:instance, :federating], false)
+
+ conn = get(conn, "/users/#{user.nickname}")
+
+ assert html_response(conn, 200) =~ user.nickname
+ end
+
+ test "returns 404 for local user with `restrict_unauthenticated/profiles/local` setting", %{
+ conn: conn
+ } do
+ clear_config([:restrict_unauthenticated, :profiles, :local], true)
+
+ local_user = insert(:user, local: true)
+
+ conn
+ |> get("/users/#{local_user.nickname}")
+ |> html_response(404)
end
end
@@ -164,16 +186,16 @@ defmodule Pleroma.Web.StaticFE.StaticFEControllerTest do
test "302 for remote cached status", %{conn: conn, user: user} do
message = %{
"@context" => "https://www.w3.org/ns/activitystreams",
- "to" => user.follower_address,
- "cc" => "https://www.w3.org/ns/activitystreams#Public",
"type" => "Create",
+ "actor" => user.ap_id,
"object" => %{
+ "to" => user.follower_address,
+ "cc" => "https://www.w3.org/ns/activitystreams#Public",
+ "id" => Utils.generate_object_id(),
"content" => "blah blah blah",
"type" => "Note",
- "attributedTo" => user.ap_id,
- "inReplyTo" => nil
- },
- "actor" => user.ap_id
+ "attributedTo" => user.ap_id
+ }
}
assert {:ok, activity} = Transmogrifier.handle_incoming(message)
@@ -183,10 +205,28 @@ defmodule Pleroma.Web.StaticFE.StaticFEControllerTest do
assert html_response(conn, 302) =~ "redirected"
end
- test "it requires authentication if instance is NOT federating", %{conn: conn, user: user} do
+ test "does not require authentication on non-federating instances", %{
+ conn: conn,
+ user: user
+ } do
+ clear_config([:instance, :federating], false)
+
+ {:ok, activity} = CommonAPI.post(user, %{status: "testing a thing!"})
+
+ conn = get(conn, "/notice/#{activity.id}")
+
+ assert html_response(conn, 200) =~ "testing a thing!"
+ end
+
+ test "returns 404 for local public activity with `restrict_unauthenticated/activities/local` setting",
+ %{conn: conn, user: user} do
+ clear_config([:restrict_unauthenticated, :activities, :local], true)
+
{:ok, activity} = CommonAPI.post(user, %{status: "testing a thing!"})
- ensure_federating_or_authenticated(conn, "/notice/#{activity.id}", user)
+ conn
+ |> get("/notice/#{activity.id}")
+ |> html_response(404)
end
end
end
diff --git a/test/web/streamer/streamer_test.exs b/test/pleroma/web/streamer_test.exs
index d56d74464..b2941a62c 100644
--- a/test/web/streamer/streamer_test.exs
+++ b/test/pleroma/web/streamer_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.StreamerTest do
@@ -21,92 +21,156 @@ defmodule Pleroma.Web.StreamerTest do
setup do: clear_config([:instance, :skip_thread_containment])
- describe "get_topic without an user" do
+ describe "get_topic/_ (unauthenticated)" do
test "allows public" do
- assert {:ok, "public"} = Streamer.get_topic("public", nil)
- assert {:ok, "public:local"} = Streamer.get_topic("public:local", nil)
- assert {:ok, "public:media"} = Streamer.get_topic("public:media", nil)
- assert {:ok, "public:local:media"} = Streamer.get_topic("public:local:media", nil)
+ assert {:ok, "public"} = Streamer.get_topic("public", nil, nil)
+ assert {:ok, "public:local"} = Streamer.get_topic("public:local", nil, nil)
+ assert {:ok, "public:media"} = Streamer.get_topic("public:media", nil, nil)
+ assert {:ok, "public:local:media"} = Streamer.get_topic("public:local:media", nil, nil)
+ end
+
+ test "allows instance streams" do
+ assert {:ok, "public:remote:lain.com"} =
+ Streamer.get_topic("public:remote", nil, nil, %{"instance" => "lain.com"})
+
+ assert {:ok, "public:remote:media:lain.com"} =
+ Streamer.get_topic("public:remote:media", nil, nil, %{"instance" => "lain.com"})
end
test "allows hashtag streams" do
- assert {:ok, "hashtag:cofe"} = Streamer.get_topic("hashtag", nil, %{"tag" => "cofe"})
+ assert {:ok, "hashtag:cofe"} = Streamer.get_topic("hashtag", nil, nil, %{"tag" => "cofe"})
end
test "disallows user streams" do
- assert {:error, _} = Streamer.get_topic("user", nil)
- assert {:error, _} = Streamer.get_topic("user:notification", nil)
- assert {:error, _} = Streamer.get_topic("direct", nil)
+ assert {:error, _} = Streamer.get_topic("user", nil, nil)
+ assert {:error, _} = Streamer.get_topic("user:notification", nil, nil)
+ assert {:error, _} = Streamer.get_topic("direct", nil, nil)
end
test "disallows list streams" do
- assert {:error, _} = Streamer.get_topic("list", nil, %{"list" => 42})
+ assert {:error, _} = Streamer.get_topic("list", nil, nil, %{"list" => 42})
end
end
- describe "get_topic with an user" do
- setup do
- user = insert(:user)
- {:ok, %{user: user}}
- end
+ describe "get_topic/_ (authenticated)" do
+ setup do: oauth_access(["read"])
+
+ test "allows public streams (regardless of OAuth token scopes)", %{
+ user: user,
+ token: read_oauth_token
+ } do
+ with oauth_token <- [nil, read_oauth_token] do
+ assert {:ok, "public"} = Streamer.get_topic("public", user, oauth_token)
+ assert {:ok, "public:local"} = Streamer.get_topic("public:local", user, oauth_token)
+ assert {:ok, "public:media"} = Streamer.get_topic("public:media", user, oauth_token)
- test "allows public streams", %{user: user} do
- assert {:ok, "public"} = Streamer.get_topic("public", user)
- assert {:ok, "public:local"} = Streamer.get_topic("public:local", user)
- assert {:ok, "public:media"} = Streamer.get_topic("public:media", user)
- assert {:ok, "public:local:media"} = Streamer.get_topic("public:local:media", user)
+ assert {:ok, "public:local:media"} =
+ Streamer.get_topic("public:local:media", user, oauth_token)
+ end
end
- test "allows user streams", %{user: user} do
+ test "allows user streams (with proper OAuth token scopes)", %{
+ user: user,
+ token: read_oauth_token
+ } do
+ %{token: read_notifications_token} = oauth_access(["read:notifications"], user: user)
+ %{token: read_statuses_token} = oauth_access(["read:statuses"], user: user)
+ %{token: badly_scoped_token} = oauth_access(["irrelevant:scope"], user: user)
+
expected_user_topic = "user:#{user.id}"
- expected_notif_topic = "user:notification:#{user.id}"
+ expected_notification_topic = "user:notification:#{user.id}"
expected_direct_topic = "direct:#{user.id}"
- assert {:ok, ^expected_user_topic} = Streamer.get_topic("user", user)
- assert {:ok, ^expected_notif_topic} = Streamer.get_topic("user:notification", user)
- assert {:ok, ^expected_direct_topic} = Streamer.get_topic("direct", user)
+ expected_pleroma_chat_topic = "user:pleroma_chat:#{user.id}"
+
+ for valid_user_token <- [read_oauth_token, read_statuses_token] do
+ assert {:ok, ^expected_user_topic} = Streamer.get_topic("user", user, valid_user_token)
+
+ assert {:ok, ^expected_direct_topic} =
+ Streamer.get_topic("direct", user, valid_user_token)
+
+ assert {:ok, ^expected_pleroma_chat_topic} =
+ Streamer.get_topic("user:pleroma_chat", user, valid_user_token)
+ end
+
+ for invalid_user_token <- [read_notifications_token, badly_scoped_token],
+ user_topic <- ["user", "direct", "user:pleroma_chat"] do
+ assert {:error, :unauthorized} = Streamer.get_topic(user_topic, user, invalid_user_token)
+ end
+
+ for valid_notification_token <- [read_oauth_token, read_notifications_token] do
+ assert {:ok, ^expected_notification_topic} =
+ Streamer.get_topic("user:notification", user, valid_notification_token)
+ end
+
+ for invalid_notification_token <- [read_statuses_token, badly_scoped_token] do
+ assert {:error, :unauthorized} =
+ Streamer.get_topic("user:notification", user, invalid_notification_token)
+ end
end
- test "allows hashtag streams", %{user: user} do
- assert {:ok, "hashtag:cofe"} = Streamer.get_topic("hashtag", user, %{"tag" => "cofe"})
+ test "allows hashtag streams (regardless of OAuth token scopes)", %{
+ user: user,
+ token: read_oauth_token
+ } do
+ for oauth_token <- [nil, read_oauth_token] do
+ assert {:ok, "hashtag:cofe"} =
+ Streamer.get_topic("hashtag", user, oauth_token, %{"tag" => "cofe"})
+ end
end
- test "disallows registering to an user stream", %{user: user} do
+ test "disallows registering to another user's stream", %{user: user, token: read_oauth_token} do
another_user = insert(:user)
- assert {:error, _} = Streamer.get_topic("user:#{another_user.id}", user)
- assert {:error, _} = Streamer.get_topic("user:notification:#{another_user.id}", user)
- assert {:error, _} = Streamer.get_topic("direct:#{another_user.id}", user)
+ assert {:error, _} = Streamer.get_topic("user:#{another_user.id}", user, read_oauth_token)
+
+ assert {:error, _} =
+ Streamer.get_topic("user:notification:#{another_user.id}", user, read_oauth_token)
+
+ assert {:error, _} = Streamer.get_topic("direct:#{another_user.id}", user, read_oauth_token)
end
- test "allows list stream that are owned by the user", %{user: user} do
+ test "allows list stream that are owned by the user (with `read` or `read:lists` scopes)", %{
+ user: user,
+ token: read_oauth_token
+ } do
+ %{token: read_lists_token} = oauth_access(["read:lists"], user: user)
+ %{token: invalid_token} = oauth_access(["irrelevant:scope"], user: user)
{:ok, list} = List.create("Test", user)
- assert {:error, _} = Streamer.get_topic("list:#{list.id}", user)
- assert {:ok, _} = Streamer.get_topic("list", user, %{"list" => list.id})
+
+ assert {:error, _} = Streamer.get_topic("list:#{list.id}", user, read_oauth_token)
+
+ for valid_token <- [read_oauth_token, read_lists_token] do
+ assert {:ok, _} = Streamer.get_topic("list", user, valid_token, %{"list" => list.id})
+ end
+
+ assert {:error, _} = Streamer.get_topic("list", user, invalid_token, %{"list" => list.id})
end
- test "disallows list stream that are not owned by the user", %{user: user} do
+ test "disallows list stream that are not owned by the user", %{user: user, token: oauth_token} do
another_user = insert(:user)
{:ok, list} = List.create("Test", another_user)
- assert {:error, _} = Streamer.get_topic("list:#{list.id}", user)
- assert {:error, _} = Streamer.get_topic("list", user, %{"list" => list.id})
+
+ assert {:error, _} = Streamer.get_topic("list:#{list.id}", user, oauth_token)
+ assert {:error, _} = Streamer.get_topic("list", user, oauth_token, %{"list" => list.id})
end
end
describe "user streams" do
setup do
- user = insert(:user)
+ %{user: user, token: token} = oauth_access(["read"])
notify = insert(:notification, user: user, activity: build(:note_activity))
- {:ok, %{user: user, notify: notify}}
+ {:ok, %{user: user, notify: notify, token: token}}
end
- test "it streams the user's post in the 'user' stream", %{user: user} do
- Streamer.get_topic_and_add_socket("user", user)
+ test "it streams the user's post in the 'user' stream", %{user: user, token: oauth_token} do
+ Streamer.get_topic_and_add_socket("user", user, oauth_token)
{:ok, activity} = CommonAPI.post(user, %{status: "hey"})
+
assert_receive {:render_with_user, _, _, ^activity}
refute Streamer.filtered_by_user?(user, activity)
end
- test "it streams boosts of the user in the 'user' stream", %{user: user} do
- Streamer.get_topic_and_add_socket("user", user)
+ test "it streams boosts of the user in the 'user' stream", %{user: user, token: oauth_token} do
+ Streamer.get_topic_and_add_socket("user", user, oauth_token)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(other_user, %{status: "hey"})
@@ -117,9 +181,10 @@ defmodule Pleroma.Web.StreamerTest do
end
test "it does not stream announces of the user's own posts in the 'user' stream", %{
- user: user
+ user: user,
+ token: oauth_token
} do
- Streamer.get_topic_and_add_socket("user", user)
+ Streamer.get_topic_and_add_socket("user", user, oauth_token)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey"})
@@ -129,9 +194,10 @@ defmodule Pleroma.Web.StreamerTest do
end
test "it does stream notifications announces of the user's own posts in the 'user' stream", %{
- user: user
+ user: user,
+ token: oauth_token
} do
- Streamer.get_topic_and_add_socket("user", user)
+ Streamer.get_topic_and_add_socket("user", user, oauth_token)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "hey"})
@@ -145,15 +211,18 @@ defmodule Pleroma.Web.StreamerTest do
refute Streamer.filtered_by_user?(user, notification)
end
- test "it streams boosts of mastodon user in the 'user' stream", %{user: user} do
- Streamer.get_topic_and_add_socket("user", user)
+ test "it streams boosts of mastodon user in the 'user' stream", %{
+ user: user,
+ token: oauth_token
+ } do
+ Streamer.get_topic_and_add_socket("user", user, oauth_token)
other_user = insert(:user)
{:ok, activity} = CommonAPI.post(other_user, %{status: "hey"})
data =
File.read!("test/fixtures/mastodon-announce.json")
- |> Poison.decode!()
+ |> Jason.decode!()
|> Map.put("object", activity.data["object"])
|> Map.put("actor", user.ap_id)
@@ -164,30 +233,45 @@ defmodule Pleroma.Web.StreamerTest do
refute Streamer.filtered_by_user?(user, announce)
end
- test "it sends notify to in the 'user' stream", %{user: user, notify: notify} do
- Streamer.get_topic_and_add_socket("user", user)
+ test "it sends notify to in the 'user' stream", %{
+ user: user,
+ token: oauth_token,
+ notify: notify
+ } do
+ Streamer.get_topic_and_add_socket("user", user, oauth_token)
Streamer.stream("user", notify)
+
assert_receive {:render_with_user, _, _, ^notify}
refute Streamer.filtered_by_user?(user, notify)
end
- test "it sends notify to in the 'user:notification' stream", %{user: user, notify: notify} do
- Streamer.get_topic_and_add_socket("user:notification", user)
+ test "it sends notify to in the 'user:notification' stream", %{
+ user: user,
+ token: oauth_token,
+ notify: notify
+ } do
+ Streamer.get_topic_and_add_socket("user:notification", user, oauth_token)
Streamer.stream("user:notification", notify)
+
assert_receive {:render_with_user, _, _, ^notify}
refute Streamer.filtered_by_user?(user, notify)
end
- test "it sends chat messages to the 'user:pleroma_chat' stream", %{user: user} do
+ test "it sends chat messages to the 'user:pleroma_chat' stream", %{
+ user: user,
+ token: oauth_token
+ } do
other_user = insert(:user)
- {:ok, create_activity} = CommonAPI.post_chat_message(other_user, user, "hey cirno")
- object = Object.normalize(create_activity, false)
+ {:ok, create_activity} =
+ CommonAPI.post_chat_message(other_user, user, "hey cirno", idempotency_key: "123")
+
+ object = Object.normalize(create_activity, fetch: false)
chat = Chat.get(user.id, other_user.ap_id)
cm_ref = MessageReference.for_chat_and_object(chat, object)
cm_ref = %{cm_ref | chat: chat, object: object}
- Streamer.get_topic_and_add_socket("user:pleroma_chat", user)
+ Streamer.get_topic_and_add_socket("user:pleroma_chat", user, oauth_token)
Streamer.stream("user:pleroma_chat", {user, cm_ref})
text = StreamerView.render("chat_update.json", %{chat_message_reference: cm_ref})
@@ -196,16 +280,16 @@ defmodule Pleroma.Web.StreamerTest do
assert_receive {:text, ^text}
end
- test "it sends chat messages to the 'user' stream", %{user: user} do
+ test "it sends chat messages to the 'user' stream", %{user: user, token: oauth_token} do
other_user = insert(:user)
{:ok, create_activity} = CommonAPI.post_chat_message(other_user, user, "hey cirno")
- object = Object.normalize(create_activity, false)
+ object = Object.normalize(create_activity, fetch: false)
chat = Chat.get(user.id, other_user.ap_id)
cm_ref = MessageReference.for_chat_and_object(chat, object)
cm_ref = %{cm_ref | chat: chat, object: object}
- Streamer.get_topic_and_add_socket("user", user)
+ Streamer.get_topic_and_add_socket("user", user, oauth_token)
Streamer.stream("user", {user, cm_ref})
text = StreamerView.render("chat_update.json", %{chat_message_reference: cm_ref})
@@ -214,7 +298,10 @@ defmodule Pleroma.Web.StreamerTest do
assert_receive {:text, ^text}
end
- test "it sends chat message notifications to the 'user:notification' stream", %{user: user} do
+ test "it sends chat message notifications to the 'user:notification' stream", %{
+ user: user,
+ token: oauth_token
+ } do
other_user = insert(:user)
{:ok, create_activity} = CommonAPI.post_chat_message(other_user, user, "hey")
@@ -223,19 +310,21 @@ defmodule Pleroma.Web.StreamerTest do
Repo.get_by(Pleroma.Notification, user_id: user.id, activity_id: create_activity.id)
|> Repo.preload(:activity)
- Streamer.get_topic_and_add_socket("user:notification", user)
+ Streamer.get_topic_and_add_socket("user:notification", user, oauth_token)
Streamer.stream("user:notification", notify)
+
assert_receive {:render_with_user, _, _, ^notify}
refute Streamer.filtered_by_user?(user, notify)
end
test "it doesn't send notify to the 'user:notification' stream when a user is blocked", %{
- user: user
+ user: user,
+ token: oauth_token
} do
blocked = insert(:user)
{:ok, _user_relationship} = User.block(user, blocked)
- Streamer.get_topic_and_add_socket("user:notification", user)
+ Streamer.get_topic_and_add_socket("user:notification", user, oauth_token)
{:ok, activity} = CommonAPI.post(user, %{status: ":("})
{:ok, _} = CommonAPI.favorite(blocked, activity.id)
@@ -244,14 +333,15 @@ defmodule Pleroma.Web.StreamerTest do
end
test "it doesn't send notify to the 'user:notification' stream when a thread is muted", %{
- user: user
+ user: user,
+ token: oauth_token
} do
user2 = insert(:user)
{:ok, activity} = CommonAPI.post(user, %{status: "super hot take"})
{:ok, _} = CommonAPI.add_mute(user, activity)
- Streamer.get_topic_and_add_socket("user:notification", user)
+ Streamer.get_topic_and_add_socket("user:notification", user, oauth_token)
{:ok, favorite_activity} = CommonAPI.favorite(user2, activity.id)
@@ -260,12 +350,13 @@ defmodule Pleroma.Web.StreamerTest do
end
test "it sends favorite to 'user:notification' stream'", %{
- user: user
+ user: user,
+ token: oauth_token
} do
user2 = insert(:user, %{ap_id: "https://hecking-lewd-place.com/user/meanie"})
{:ok, activity} = CommonAPI.post(user, %{status: "super hot take"})
- Streamer.get_topic_and_add_socket("user:notification", user)
+ Streamer.get_topic_and_add_socket("user:notification", user, oauth_token)
{:ok, favorite_activity} = CommonAPI.favorite(user2, activity.id)
assert_receive {:render_with_user, _, "notification.json", notif}
@@ -274,13 +365,14 @@ defmodule Pleroma.Web.StreamerTest do
end
test "it doesn't send the 'user:notification' stream' when a domain is blocked", %{
- user: user
+ user: user,
+ token: oauth_token
} do
user2 = insert(:user, %{ap_id: "https://hecking-lewd-place.com/user/meanie"})
{:ok, user} = User.block_domain(user, "hecking-lewd-place.com")
{:ok, activity} = CommonAPI.post(user, %{status: "super hot take"})
- Streamer.get_topic_and_add_socket("user:notification", user)
+ Streamer.get_topic_and_add_socket("user:notification", user, oauth_token)
{:ok, favorite_activity} = CommonAPI.favorite(user2, activity.id)
refute_receive _
@@ -288,75 +380,117 @@ defmodule Pleroma.Web.StreamerTest do
end
test "it sends follow activities to the 'user:notification' stream", %{
- user: user
+ user: user,
+ token: oauth_token
} do
- user_url = user.ap_id
user2 = insert(:user)
- body =
- File.read!("test/fixtures/users_mock/localhost.json")
- |> String.replace("{{nickname}}", user.nickname)
- |> Jason.encode!()
-
- Tesla.Mock.mock_global(fn
- %{method: :get, url: ^user_url} ->
- %Tesla.Env{status: 200, body: body}
- end)
-
- Streamer.get_topic_and_add_socket("user:notification", user)
+ Streamer.get_topic_and_add_socket("user:notification", user, oauth_token)
{:ok, _follower, _followed, follow_activity} = CommonAPI.follow(user2, user)
assert_receive {:render_with_user, _, "notification.json", notif}
assert notif.activity.id == follow_activity.id
refute Streamer.filtered_by_user?(user, notif)
end
+
+ test "it sends follow relationships updates to the 'user' stream", %{
+ user: user,
+ token: oauth_token
+ } do
+ user_id = user.id
+ other_user = insert(:user)
+ other_user_id = other_user.id
+
+ Streamer.get_topic_and_add_socket("user", user, oauth_token)
+ {:ok, _follower, _followed, _follow_activity} = CommonAPI.follow(user, other_user)
+
+ assert_receive {:text, event}
+
+ assert %{"event" => "pleroma:follow_relationships_update", "payload" => payload} =
+ Jason.decode!(event)
+
+ assert %{
+ "follower" => %{
+ "follower_count" => 0,
+ "following_count" => 0,
+ "id" => ^user_id
+ },
+ "following" => %{
+ "follower_count" => 0,
+ "following_count" => 0,
+ "id" => ^other_user_id
+ },
+ "state" => "follow_pending"
+ } = Jason.decode!(payload)
+
+ assert_receive {:text, event}
+
+ assert %{"event" => "pleroma:follow_relationships_update", "payload" => payload} =
+ Jason.decode!(event)
+
+ assert %{
+ "follower" => %{
+ "follower_count" => 0,
+ "following_count" => 1,
+ "id" => ^user_id
+ },
+ "following" => %{
+ "follower_count" => 1,
+ "following_count" => 0,
+ "id" => ^other_user_id
+ },
+ "state" => "follow_accept"
+ } = Jason.decode!(payload)
+ end
end
- test "it sends to public authenticated" do
- user = insert(:user)
- other_user = insert(:user)
+ describe "public streams" do
+ test "it sends to public (authenticated)" do
+ %{user: user, token: oauth_token} = oauth_access(["read"])
+ other_user = insert(:user)
- Streamer.get_topic_and_add_socket("public", other_user)
+ Streamer.get_topic_and_add_socket("public", user, oauth_token)
- {:ok, activity} = CommonAPI.post(user, %{status: "Test"})
- assert_receive {:render_with_user, _, _, ^activity}
- refute Streamer.filtered_by_user?(user, activity)
- end
+ {:ok, activity} = CommonAPI.post(other_user, %{status: "Test"})
+ assert_receive {:render_with_user, _, _, ^activity}
+ refute Streamer.filtered_by_user?(other_user, activity)
+ end
- test "works for deletions" do
- user = insert(:user)
- other_user = insert(:user)
- {:ok, activity} = CommonAPI.post(other_user, %{status: "Test"})
+ test "it sends to public (unauthenticated)" do
+ user = insert(:user)
- Streamer.get_topic_and_add_socket("public", user)
+ Streamer.get_topic_and_add_socket("public", nil, nil)
- {:ok, _} = CommonAPI.delete(activity.id, other_user)
- activity_id = activity.id
- assert_receive {:text, event}
- assert %{"event" => "delete", "payload" => ^activity_id} = Jason.decode!(event)
- end
+ {:ok, activity} = CommonAPI.post(user, %{status: "Test"})
+ activity_id = activity.id
+ assert_receive {:text, event}
+ assert %{"event" => "update", "payload" => payload} = Jason.decode!(event)
+ assert %{"id" => ^activity_id} = Jason.decode!(payload)
- test "it sends to public unauthenticated" do
- user = insert(:user)
+ {:ok, _} = CommonAPI.delete(activity.id, user)
+ assert_receive {:text, event}
+ assert %{"event" => "delete", "payload" => ^activity_id} = Jason.decode!(event)
+ end
- Streamer.get_topic_and_add_socket("public", nil)
+ test "handles deletions" do
+ %{user: user, token: oauth_token} = oauth_access(["read"])
+ other_user = insert(:user)
+ {:ok, activity} = CommonAPI.post(other_user, %{status: "Test"})
- {:ok, activity} = CommonAPI.post(user, %{status: "Test"})
- activity_id = activity.id
- assert_receive {:text, event}
- assert %{"event" => "update", "payload" => payload} = Jason.decode!(event)
- assert %{"id" => ^activity_id} = Jason.decode!(payload)
+ Streamer.get_topic_and_add_socket("public", user, oauth_token)
- {:ok, _} = CommonAPI.delete(activity.id, user)
- assert_receive {:text, event}
- assert %{"event" => "delete", "payload" => ^activity_id} = Jason.decode!(event)
+ {:ok, _} = CommonAPI.delete(activity.id, other_user)
+ activity_id = activity.id
+ assert_receive {:text, event}
+ assert %{"event" => "delete", "payload" => ^activity_id} = Jason.decode!(event)
+ end
end
- describe "thread_containment" do
+ describe "thread_containment/2" do
test "it filters to user if recipients invalid and thread containment is enabled" do
- Pleroma.Config.put([:instance, :skip_thread_containment], false)
+ clear_config([:instance, :skip_thread_containment], false)
author = insert(:user)
- user = insert(:user)
+ %{user: user, token: oauth_token} = oauth_access(["read"])
User.follow(user, author, :follow_accept)
activity =
@@ -368,16 +502,16 @@ defmodule Pleroma.Web.StreamerTest do
)
)
- Streamer.get_topic_and_add_socket("public", user)
+ Streamer.get_topic_and_add_socket("public", user, oauth_token)
Streamer.stream("public", activity)
assert_receive {:render_with_user, _, _, ^activity}
assert Streamer.filtered_by_user?(user, activity)
end
test "it sends message if recipients invalid and thread containment is disabled" do
- Pleroma.Config.put([:instance, :skip_thread_containment], true)
+ clear_config([:instance, :skip_thread_containment], true)
author = insert(:user)
- user = insert(:user)
+ %{user: user, token: oauth_token} = oauth_access(["read"])
User.follow(user, author, :follow_accept)
activity =
@@ -389,7 +523,7 @@ defmodule Pleroma.Web.StreamerTest do
)
)
- Streamer.get_topic_and_add_socket("public", user)
+ Streamer.get_topic_and_add_socket("public", user, oauth_token)
Streamer.stream("public", activity)
assert_receive {:render_with_user, _, _, ^activity}
@@ -397,9 +531,10 @@ defmodule Pleroma.Web.StreamerTest do
end
test "it sends message if recipients invalid and thread containment is enabled but user's thread containment is disabled" do
- Pleroma.Config.put([:instance, :skip_thread_containment], false)
+ clear_config([:instance, :skip_thread_containment], false)
author = insert(:user)
user = insert(:user, skip_thread_containment: true)
+ %{token: oauth_token} = oauth_access(["read"], user: user)
User.follow(user, author, :follow_accept)
activity =
@@ -411,7 +546,7 @@ defmodule Pleroma.Web.StreamerTest do
)
)
- Streamer.get_topic_and_add_socket("public", user)
+ Streamer.get_topic_and_add_socket("public", user, oauth_token)
Streamer.stream("public", activity)
assert_receive {:render_with_user, _, _, ^activity}
@@ -420,23 +555,26 @@ defmodule Pleroma.Web.StreamerTest do
end
describe "blocks" do
- test "it filters messages involving blocked users" do
- user = insert(:user)
+ setup do: oauth_access(["read"])
+
+ test "it filters messages involving blocked users", %{user: user, token: oauth_token} do
blocked_user = insert(:user)
{:ok, _user_relationship} = User.block(user, blocked_user)
- Streamer.get_topic_and_add_socket("public", user)
+ Streamer.get_topic_and_add_socket("public", user, oauth_token)
{:ok, activity} = CommonAPI.post(blocked_user, %{status: "Test"})
assert_receive {:render_with_user, _, _, ^activity}
assert Streamer.filtered_by_user?(user, activity)
end
- test "it filters messages transitively involving blocked users" do
- blocker = insert(:user)
+ test "it filters messages transitively involving blocked users", %{
+ user: blocker,
+ token: blocker_token
+ } do
blockee = insert(:user)
friend = insert(:user)
- Streamer.get_topic_and_add_socket("public", blocker)
+ Streamer.get_topic_and_add_socket("public", blocker, blocker_token)
{:ok, _user_relationship} = User.block(blocker, blockee)
@@ -458,17 +596,18 @@ defmodule Pleroma.Web.StreamerTest do
end
describe "lists" do
- test "it doesn't send unwanted DMs to list" do
- user_a = insert(:user)
+ setup do: oauth_access(["read"])
+
+ test "it doesn't send unwanted DMs to list", %{user: user_a, token: user_a_token} do
user_b = insert(:user)
user_c = insert(:user)
- {:ok, user_a} = User.follow(user_a, user_b)
+ {:ok, user_a, user_b} = User.follow(user_a, user_b)
{:ok, list} = List.create("Test", user_a)
{:ok, list} = List.follow(list, user_b)
- Streamer.get_topic_and_add_socket("list", user_a, %{"list" => list.id})
+ Streamer.get_topic_and_add_socket("list", user_a, user_a_token, %{"list" => list.id})
{:ok, _activity} =
CommonAPI.post(user_b, %{
@@ -479,14 +618,13 @@ defmodule Pleroma.Web.StreamerTest do
refute_receive _
end
- test "it doesn't send unwanted private posts to list" do
- user_a = insert(:user)
+ test "it doesn't send unwanted private posts to list", %{user: user_a, token: user_a_token} do
user_b = insert(:user)
{:ok, list} = List.create("Test", user_a)
{:ok, list} = List.follow(list, user_b)
- Streamer.get_topic_and_add_socket("list", user_a, %{"list" => list.id})
+ Streamer.get_topic_and_add_socket("list", user_a, user_a_token, %{"list" => list.id})
{:ok, _activity} =
CommonAPI.post(user_b, %{
@@ -497,16 +635,15 @@ defmodule Pleroma.Web.StreamerTest do
refute_receive _
end
- test "it sends wanted private posts to list" do
- user_a = insert(:user)
+ test "it sends wanted private posts to list", %{user: user_a, token: user_a_token} do
user_b = insert(:user)
- {:ok, user_a} = User.follow(user_a, user_b)
+ {:ok, user_a, user_b} = User.follow(user_a, user_b)
{:ok, list} = List.create("Test", user_a)
{:ok, list} = List.follow(list, user_b)
- Streamer.get_topic_and_add_socket("list", user_a, %{"list" => list.id})
+ Streamer.get_topic_and_add_socket("list", user_a, user_a_token, %{"list" => list.id})
{:ok, activity} =
CommonAPI.post(user_b, %{
@@ -520,8 +657,9 @@ defmodule Pleroma.Web.StreamerTest do
end
describe "muted reblogs" do
- test "it filters muted reblogs" do
- user1 = insert(:user)
+ setup do: oauth_access(["read"])
+
+ test "it filters muted reblogs", %{user: user1, token: user1_token} do
user2 = insert(:user)
user3 = insert(:user)
CommonAPI.follow(user1, user2)
@@ -529,34 +667,38 @@ defmodule Pleroma.Web.StreamerTest do
{:ok, create_activity} = CommonAPI.post(user3, %{status: "I'm kawen"})
- Streamer.get_topic_and_add_socket("user", user1)
+ Streamer.get_topic_and_add_socket("user", user1, user1_token)
{:ok, announce_activity} = CommonAPI.repeat(create_activity.id, user2)
assert_receive {:render_with_user, _, _, ^announce_activity}
assert Streamer.filtered_by_user?(user1, announce_activity)
end
- test "it filters reblog notification for reblog-muted actors" do
- user1 = insert(:user)
+ test "it filters reblog notification for reblog-muted actors", %{
+ user: user1,
+ token: user1_token
+ } do
user2 = insert(:user)
CommonAPI.follow(user1, user2)
CommonAPI.hide_reblogs(user1, user2)
{:ok, create_activity} = CommonAPI.post(user1, %{status: "I'm kawen"})
- Streamer.get_topic_and_add_socket("user", user1)
+ Streamer.get_topic_and_add_socket("user", user1, user1_token)
{:ok, _announce_activity} = CommonAPI.repeat(create_activity.id, user2)
assert_receive {:render_with_user, _, "notification.json", notif}
assert Streamer.filtered_by_user?(user1, notif)
end
- test "it send non-reblog notification for reblog-muted actors" do
- user1 = insert(:user)
+ test "it send non-reblog notification for reblog-muted actors", %{
+ user: user1,
+ token: user1_token
+ } do
user2 = insert(:user)
CommonAPI.follow(user1, user2)
CommonAPI.hide_reblogs(user1, user2)
{:ok, create_activity} = CommonAPI.post(user1, %{status: "I'm kawen"})
- Streamer.get_topic_and_add_socket("user", user1)
+ Streamer.get_topic_and_add_socket("user", user1, user1_token)
{:ok, _favorite_activity} = CommonAPI.favorite(user2, create_activity.id)
assert_receive {:render_with_user, _, "notification.json", notif}
@@ -564,27 +706,28 @@ defmodule Pleroma.Web.StreamerTest do
end
end
- test "it filters posts from muted threads" do
- user = insert(:user)
- user2 = insert(:user)
- Streamer.get_topic_and_add_socket("user", user2)
- {:ok, user2, user, _activity} = CommonAPI.follow(user2, user)
- {:ok, activity} = CommonAPI.post(user, %{status: "super hot take"})
- {:ok, _} = CommonAPI.add_mute(user2, activity)
- assert_receive {:render_with_user, _, _, ^activity}
- assert Streamer.filtered_by_user?(user2, activity)
+ describe "muted threads" do
+ test "it filters posts from muted threads" do
+ user = insert(:user)
+ %{user: user2, token: user2_token} = oauth_access(["read"])
+ Streamer.get_topic_and_add_socket("user", user2, user2_token)
+
+ {:ok, user2, user, _activity} = CommonAPI.follow(user2, user)
+ {:ok, activity} = CommonAPI.post(user, %{status: "super hot take"})
+ {:ok, _} = CommonAPI.add_mute(user2, activity)
+
+ assert_receive {:render_with_user, _, _, ^activity}
+ assert Streamer.filtered_by_user?(user2, activity)
+ end
end
describe "direct streams" do
- setup do
- :ok
- end
+ setup do: oauth_access(["read"])
- test "it sends conversation update to the 'direct' stream", %{} do
- user = insert(:user)
+ test "it sends conversation update to the 'direct' stream", %{user: user, token: oauth_token} do
another_user = insert(:user)
- Streamer.get_topic_and_add_socket("direct", user)
+ Streamer.get_topic_and_add_socket("direct", user, oauth_token)
{:ok, _create_activity} =
CommonAPI.post(another_user, %{
@@ -602,11 +745,11 @@ defmodule Pleroma.Web.StreamerTest do
assert last_status["pleroma"]["direct_conversation_id"] == participation.id
end
- test "it doesn't send conversation update to the 'direct' stream when the last message in the conversation is deleted" do
- user = insert(:user)
+ test "it doesn't send conversation update to the 'direct' stream when the last message in the conversation is deleted",
+ %{user: user, token: oauth_token} do
another_user = insert(:user)
- Streamer.get_topic_and_add_socket("direct", user)
+ Streamer.get_topic_and_add_socket("direct", user, oauth_token)
{:ok, create_activity} =
CommonAPI.post(another_user, %{
@@ -629,10 +772,13 @@ defmodule Pleroma.Web.StreamerTest do
refute_receive _
end
- test "it sends conversation update to the 'direct' stream when a message is deleted" do
- user = insert(:user)
+ @tag :erratic
+ test "it sends conversation update to the 'direct' stream when a message is deleted", %{
+ user: user,
+ token: oauth_token
+ } do
another_user = insert(:user)
- Streamer.get_topic_and_add_socket("direct", user)
+ Streamer.get_topic_and_add_socket("direct", user, oauth_token)
{:ok, create_activity} =
CommonAPI.post(another_user, %{
diff --git a/test/web/twitter_api/twitter_api_controller_test.exs b/test/pleroma/web/twitter_api/controller_test.exs
index 464d0ea2e..bca9e2dad 100644
--- a/test/web/twitter_api/twitter_api_controller_test.exs
+++ b/test/pleroma/web/twitter_api/controller_test.exs
@@ -1,75 +1,24 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.TwitterAPI.ControllerTest do
- use Pleroma.Web.ConnCase
+ use Pleroma.Web.ConnCase, async: true
- alias Pleroma.Builders.ActivityBuilder
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.OAuth.Token
import Pleroma.Factory
- describe "POST /api/qvitter/statuses/notifications/read" do
- test "without valid credentials", %{conn: conn} do
- conn = post(conn, "/api/qvitter/statuses/notifications/read", %{"latest_id" => 1_234_567})
- assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
- end
-
- test "with credentials, without any params" do
- %{conn: conn} = oauth_access(["write:notifications"])
-
- conn = post(conn, "/api/qvitter/statuses/notifications/read")
-
- assert json_response(conn, 400) == %{
- "error" => "You need to specify latest_id",
- "request" => "/api/qvitter/statuses/notifications/read"
- }
- end
-
- test "with credentials, with params" do
- %{user: current_user, conn: conn} =
- oauth_access(["read:notifications", "write:notifications"])
-
- other_user = insert(:user)
-
- {:ok, _activity} =
- ActivityBuilder.insert(%{"to" => [current_user.ap_id]}, %{user: other_user})
-
- response_conn =
- conn
- |> assign(:user, current_user)
- |> get("/api/v1/notifications")
-
- [notification] = response = json_response(response_conn, 200)
-
- assert length(response) == 1
-
- assert notification["pleroma"]["is_seen"] == false
-
- response_conn =
- conn
- |> assign(:user, current_user)
- |> post("/api/qvitter/statuses/notifications/read", %{"latest_id" => notification["id"]})
-
- [notification] = response = json_response(response_conn, 200)
-
- assert length(response) == 1
-
- assert notification["pleroma"]["is_seen"] == true
- end
- end
-
describe "GET /api/account/confirm_email/:id/:token" do
setup do
{:ok, user} =
insert(:user)
- |> User.confirmation_changeset(need_confirmation: true)
+ |> User.confirmation_changeset(set_confirmation: false)
|> Repo.update()
- assert user.confirmation_pending
+ refute user.is_confirmed
[user: user]
end
@@ -85,7 +34,7 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
user = User.get_cached_by_id(user.id)
- refute user.confirmation_pending
+ assert user.is_confirmed
refute user.confirmation_token
end
diff --git a/test/pleroma/web/twitter_api/password_controller_test.exs b/test/pleroma/web/twitter_api/password_controller_test.exs
new file mode 100644
index 000000000..45ab10a8a
--- /dev/null
+++ b/test/pleroma/web/twitter_api/password_controller_test.exs
@@ -0,0 +1,213 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.TwitterAPI.PasswordControllerTest do
+ use Pleroma.Web.ConnCase
+
+ alias Pleroma.Config
+ alias Pleroma.PasswordResetToken
+ alias Pleroma.Repo
+ alias Pleroma.Tests.ObanHelpers
+ alias Pleroma.User
+ alias Pleroma.Web.OAuth.Token
+ import Pleroma.Factory
+ import Swoosh.TestAssertions
+
+ describe "GET /api/pleroma/password_reset/token" do
+ test "it returns error when token invalid", %{conn: conn} do
+ response =
+ conn
+ |> get("/api/pleroma/password_reset/token")
+ |> html_response(:ok)
+
+ assert response =~ "<h2>Invalid Token</h2>"
+ end
+
+ test "it shows password reset form", %{conn: conn} do
+ user = insert(:user)
+ {:ok, token} = PasswordResetToken.create_token(user)
+
+ response =
+ conn
+ |> get("/api/pleroma/password_reset/#{token.token}")
+ |> html_response(:ok)
+
+ assert response =~ "<h2>Password Reset for #{user.nickname}</h2>"
+ end
+
+ test "it returns an error when the token has expired", %{conn: conn} do
+ clear_config([:instance, :password_reset_token_validity], 0)
+
+ user = insert(:user)
+ {:ok, token} = PasswordResetToken.create_token(user)
+ {:ok, token} = time_travel(token, -2)
+
+ response =
+ conn
+ |> get("/api/pleroma/password_reset/#{token.token}")
+ |> html_response(:ok)
+
+ assert response =~ "<h2>Invalid Token</h2>"
+ end
+ end
+
+ describe "POST /api/pleroma/password_reset" do
+ test "it fails for an expired token", %{conn: conn} do
+ clear_config([:instance, :password_reset_token_validity], 0)
+
+ user = insert(:user)
+ {:ok, token} = PasswordResetToken.create_token(user)
+ {:ok, token} = time_travel(token, -2)
+ {:ok, _access_token} = Token.create(insert(:oauth_app), user, %{})
+
+ params = %{
+ "password" => "test",
+ password_confirmation: "test",
+ token: token.token
+ }
+
+ response =
+ conn
+ |> assign(:user, user)
+ |> post("/api/pleroma/password_reset", %{data: params})
+ |> html_response(:ok)
+
+ refute response =~ "<h2>Password changed!</h2>"
+ end
+
+ test "it returns HTTP 200", %{conn: conn} do
+ user = insert(:user)
+ {:ok, token} = PasswordResetToken.create_token(user)
+ {:ok, _access_token} = Token.create(insert(:oauth_app), user, %{})
+
+ params = %{
+ "password" => "test",
+ password_confirmation: "test",
+ token: token.token
+ }
+
+ response =
+ conn
+ |> assign(:user, user)
+ |> post("/api/pleroma/password_reset", %{data: params})
+ |> html_response(:ok)
+
+ assert response =~ "<h2>Password changed!</h2>"
+
+ user = refresh_record(user)
+ assert Pleroma.Password.Pbkdf2.verify_pass("test", user.password_hash)
+ assert Enum.empty?(Token.get_user_tokens(user))
+ end
+
+ test "it sets password_reset_pending to false", %{conn: conn} do
+ user = insert(:user, password_reset_pending: true)
+
+ {:ok, token} = PasswordResetToken.create_token(user)
+ {:ok, _access_token} = Token.create(insert(:oauth_app), user, %{})
+
+ params = %{
+ "password" => "test",
+ password_confirmation: "test",
+ token: token.token
+ }
+
+ conn
+ |> assign(:user, user)
+ |> post("/api/pleroma/password_reset", %{data: params})
+ |> html_response(:ok)
+
+ assert User.get_by_id(user.id).password_reset_pending == false
+ end
+ end
+
+ describe "POST /auth/password, with valid parameters" do
+ setup %{conn: conn} do
+ user = insert(:user)
+ conn = post(conn, "/auth/password?email=#{user.email}")
+ %{conn: conn, user: user}
+ end
+
+ test "it returns 204", %{conn: conn} do
+ assert empty_json_response(conn)
+ end
+
+ test "it creates a PasswordResetToken record for user", %{user: user} do
+ token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
+ assert token_record
+ end
+
+ test "it sends an email to user", %{user: user} do
+ ObanHelpers.perform_all()
+ token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
+
+ email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token)
+ notify_email = Config.get([:instance, :notify_email])
+ instance_name = Config.get([:instance, :name])
+
+ assert_email_sent(
+ from: {instance_name, notify_email},
+ to: {user.name, user.email},
+ html_body: email.html_body
+ )
+ end
+ end
+
+ describe "POST /auth/password, with nickname" do
+ test "it returns 204", %{conn: conn} do
+ user = insert(:user)
+
+ assert conn
+ |> post("/auth/password?nickname=#{user.nickname}")
+ |> empty_json_response()
+
+ ObanHelpers.perform_all()
+ token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
+
+ email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token)
+ notify_email = Config.get([:instance, :notify_email])
+ instance_name = Config.get([:instance, :name])
+
+ assert_email_sent(
+ from: {instance_name, notify_email},
+ to: {user.name, user.email},
+ html_body: email.html_body
+ )
+ end
+
+ test "it doesn't fail when a user has no email", %{conn: conn} do
+ user = insert(:user, %{email: nil})
+
+ assert conn
+ |> post("/auth/password?nickname=#{user.nickname}")
+ |> empty_json_response()
+ end
+ end
+
+ describe "POST /auth/password, with invalid parameters" do
+ setup do
+ user = insert(:user)
+ {:ok, user: user}
+ end
+
+ test "it returns 204 when user is not found", %{conn: conn, user: user} do
+ conn = post(conn, "/auth/password?email=nonexisting_#{user.email}")
+
+ assert empty_json_response(conn)
+ end
+
+ test "it returns 204 when user is not local", %{conn: conn, user: user} do
+ {:ok, user} = Repo.update(Ecto.Changeset.change(user, local: false))
+ conn = post(conn, "/auth/password?email=#{user.email}")
+
+ assert empty_json_response(conn)
+ end
+
+ test "it returns 204 when user is deactivated", %{conn: conn, user: user} do
+ {:ok, user} = Repo.update(Ecto.Changeset.change(user, is_active: false, local: true))
+ conn = post(conn, "/auth/password?email=#{user.email}")
+
+ assert empty_json_response(conn)
+ end
+ end
+end
diff --git a/test/web/twitter_api/remote_follow_controller_test.exs b/test/pleroma/web/twitter_api/remote_follow_controller_test.exs
index f7e54c26a..fa3b29006 100644
--- a/test/web/twitter_api/remote_follow_controller_test.exs
+++ b/test/pleroma/web/twitter_api/remote_follow_controller_test.exs
@@ -1,11 +1,10 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do
use Pleroma.Web.ConnCase
- alias Pleroma.Config
alias Pleroma.MFA
alias Pleroma.MFA.TOTP
alias Pleroma.User
@@ -15,18 +14,37 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do
import Pleroma.Factory
import Ecto.Query
- setup do
- Tesla.Mock.mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
- :ok
- end
-
setup_all do: clear_config([:instance, :federating], true)
- setup do: clear_config([:instance])
- setup do: clear_config([:frontend_configurations, :pleroma_fe])
setup do: clear_config([:user, :deny_follow_blocked])
describe "GET /ostatus_subscribe - remote_follow/2" do
test "adds status to pleroma instance if the `acct` is a status", %{conn: conn} do
+ Tesla.Mock.mock(fn
+ %{method: :get, url: "https://mastodon.social/users/emelie/statuses/101849165031453009"} ->
+ %Tesla.Env{
+ status: 200,
+ headers: [{"content-type", "application/activity+json"}],
+ body: File.read!("test/fixtures/tesla_mock/status.emelie.json")
+ }
+
+ %{method: :get, url: "https://mastodon.social/users/emelie/collections/featured"} ->
+ %Tesla.Env{
+ status: 200,
+ headers: [{"content-type", "application/activity+json"}],
+ body:
+ File.read!("test/fixtures/users_mock/masto_featured.json")
+ |> String.replace("{{domain}}", "mastodon.social")
+ |> String.replace("{{nickname}}", "emelie")
+ }
+
+ %{method: :get, url: "https://mastodon.social/users/emelie"} ->
+ %Tesla.Env{
+ status: 200,
+ headers: [{"content-type", "application/activity+json"}],
+ body: File.read!("test/fixtures/tesla_mock/emelie.json")
+ }
+ end)
+
assert conn
|> get(
remote_follow_path(conn, :follow, %{
@@ -37,6 +55,25 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do
end
test "show follow account page if the `acct` is a account link", %{conn: conn} do
+ Tesla.Mock.mock(fn
+ %{method: :get, url: "https://mastodon.social/users/emelie"} ->
+ %Tesla.Env{
+ status: 200,
+ headers: [{"content-type", "application/activity+json"}],
+ body: File.read!("test/fixtures/tesla_mock/emelie.json")
+ }
+
+ %{method: :get, url: "https://mastodon.social/users/emelie/collections/featured"} ->
+ %Tesla.Env{
+ status: 200,
+ headers: [{"content-type", "application/activity+json"}],
+ body:
+ File.read!("test/fixtures/users_mock/masto_featured.json")
+ |> String.replace("{{domain}}", "mastodon.social")
+ |> String.replace("{{nickname}}", "emelie")
+ }
+ end)
+
response =
conn
|> get(remote_follow_path(conn, :follow, %{acct: "https://mastodon.social/users/emelie"}))
@@ -46,6 +83,25 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do
end
test "show follow page if the `acct` is a account link", %{conn: conn} do
+ Tesla.Mock.mock(fn
+ %{method: :get, url: "https://mastodon.social/users/emelie"} ->
+ %Tesla.Env{
+ status: 200,
+ headers: [{"content-type", "application/activity+json"}],
+ body: File.read!("test/fixtures/tesla_mock/emelie.json")
+ }
+
+ %{method: :get, url: "https://mastodon.social/users/emelie/collections/featured"} ->
+ %Tesla.Env{
+ status: 200,
+ headers: [{"content-type", "application/activity+json"}],
+ body:
+ File.read!("test/fixtures/users_mock/masto_featured.json")
+ |> String.replace("{{domain}}", "mastodon.social")
+ |> String.replace("{{nickname}}", "emelie")
+ }
+ end)
+
user = insert(:user)
response =
@@ -57,7 +113,14 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do
assert response =~ "Remote follow"
end
- test "show follow page with error when user cannot fecth by `acct` link", %{conn: conn} do
+ test "show follow page with error when user can not be fetched by `acct` link", %{conn: conn} do
+ Tesla.Mock.mock(fn
+ %{method: :get, url: "https://mastodon.social/users/not_found"} ->
+ %Tesla.Env{
+ status: 404
+ }
+ end)
+
user = insert(:user)
assert capture_log(fn ->
@@ -108,7 +171,7 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do
end
test "returns error when user is deactivated", %{conn: conn} do
- user = insert(:user, deactivated: true)
+ user = insert(:user, is_active: false)
user2 = insert(:user)
response =
@@ -121,7 +184,7 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do
end
test "returns error when user is blocked", %{conn: conn} do
- Pleroma.Config.put([:user, :deny_follow_blocked], true)
+ clear_config([:user, :deny_follow_blocked], true)
user = insert(:user)
user2 = insert(:user)
@@ -227,7 +290,7 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do
}
)
- {:ok, %{token: token}} = MFA.Token.create_token(user)
+ {:ok, %{token: token}} = MFA.Token.create(user)
user2 = insert(:user)
otp_token = TOTP.generate_token(otp_secret)
@@ -256,7 +319,7 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do
}
)
- {:ok, %{token: token}} = MFA.Token.create_token(user)
+ {:ok, %{token: token}} = MFA.Token.create(user)
user2 = insert(:user)
otp_token = TOTP.generate_token(TOTP.generate_secret())
@@ -332,7 +395,7 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowControllerTest do
end
test "returns error when user is blocked", %{conn: conn} do
- Pleroma.Config.put([:user, :deny_follow_blocked], true)
+ clear_config([:user, :deny_follow_blocked], true)
user = insert(:user)
user2 = insert(:user)
{:ok, _user_block} = Pleroma.User.block(user2, user)
diff --git a/test/web/twitter_api/twitter_api_test.exs b/test/pleroma/web/twitter_api/twitter_api_test.exs
index 20a45cb6f..2b8a4c3f5 100644
--- a/test/web/twitter_api/twitter_api_test.exs
+++ b/test/pleroma/web/twitter_api/twitter_api_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
@@ -46,12 +46,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
end
test "it sends confirmation email if :account_activation_required is specified in instance config" do
- setting = Pleroma.Config.get([:instance, :account_activation_required])
-
- unless setting do
- Pleroma.Config.put([:instance, :account_activation_required], true)
- on_exit(fn -> Pleroma.Config.put([:instance, :account_activation_required], setting) end)
- end
+ clear_config([:instance, :account_activation_required], true)
data = %{
:username => "lain",
@@ -65,7 +60,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
{:ok, user} = TwitterAPI.register_user(data)
ObanHelpers.perform_all()
- assert user.confirmation_pending
+ refute user.is_confirmed
email = Pleroma.Emails.UserEmail.account_confirmation_email(user)
@@ -80,13 +75,9 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
end
test "it sends an admin email if :account_approval_required is specified in instance config" do
- admin = insert(:user, is_admin: true)
- setting = Pleroma.Config.get([:instance, :account_approval_required])
+ clear_config([:instance, :account_approval_required], true)
- unless setting do
- Pleroma.Config.put([:instance, :account_approval_required], true)
- on_exit(fn -> Pleroma.Config.put([:instance, :account_approval_required], setting) end)
- end
+ admin = insert(:user, is_admin: true)
data = %{
:username => "lain",
@@ -101,17 +92,26 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
{:ok, user} = TwitterAPI.register_user(data)
ObanHelpers.perform_all()
- assert user.approval_pending
+ refute user.is_approved
- email = Pleroma.Emails.AdminEmail.new_unapproved_registration(admin, user)
+ user_email = Pleroma.Emails.UserEmail.approval_pending_email(user)
+ admin_email = Pleroma.Emails.AdminEmail.new_unapproved_registration(admin, user)
notify_email = Pleroma.Config.get([:instance, :notify_email])
instance_name = Pleroma.Config.get([:instance, :name])
+ # User approval email
+ Swoosh.TestAssertions.assert_email_sent(
+ from: {instance_name, notify_email},
+ to: {user.name, user.email},
+ html_body: user_email.html_body
+ )
+
+ # Admin email
Swoosh.TestAssertions.assert_email_sent(
from: {instance_name, notify_email},
to: {admin.name, admin.email},
- html_body: email.html_body
+ html_body: admin_email.html_body
)
end
@@ -139,9 +139,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
{:ok, user2} = TwitterAPI.register_user(data2)
expected_text =
- ~s(<span class="h-card"><a class="u-url mention" data-user="#{user1.id}" href="#{
- user1.ap_id
- }" rel="ugc">@<span>john</span></a></span> test)
+ ~s(<span class="h-card"><a class="u-url mention" data-user="#{user1.id}" href="#{user1.ap_id}" rel="ugc">@<span>john</span></a></span> test)
assert user2.bio == expected_text
end
@@ -423,10 +421,4 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPITest do
assert is_binary(error)
refute User.get_cached_by_nickname("lain")
end
-
- setup do
- Supervisor.terminate_child(Pleroma.Supervisor, Cachex)
- Supervisor.restart_child(Pleroma.Supervisor, Cachex)
- :ok
- end
end
diff --git a/test/web/twitter_api/util_controller_test.exs b/test/pleroma/web/twitter_api/util_controller_test.exs
index d164127ee..ee658ddf6 100644
--- a/test/web/twitter_api/util_controller_test.exs
+++ b/test/pleroma/web/twitter_api/util_controller_test.exs
@@ -1,12 +1,11 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
use Pleroma.Web.ConnCase
use Oban.Testing, repo: Pleroma.Repo
- alias Pleroma.Config
alias Pleroma.Tests.ObanHelpers
alias Pleroma.User
@@ -21,180 +20,15 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
setup do: clear_config([:instance])
setup do: clear_config([:frontend_configurations, :pleroma_fe])
- describe "POST /api/pleroma/follow_import" do
- setup do: oauth_access(["follow"])
-
- test "it returns HTTP 200", %{conn: conn} do
- user2 = insert(:user)
-
- response =
- conn
- |> post("/api/pleroma/follow_import", %{"list" => "#{user2.ap_id}"})
- |> json_response(:ok)
-
- assert response == "job started"
- end
-
- test "it imports follow lists from file", %{user: user1, conn: conn} do
- user2 = insert(:user)
-
- with_mocks([
- {File, [],
- read!: fn "follow_list.txt" ->
- "Account address,Show boosts\n#{user2.ap_id},true"
- end}
- ]) do
- response =
- conn
- |> post("/api/pleroma/follow_import", %{"list" => %Plug.Upload{path: "follow_list.txt"}})
- |> json_response(:ok)
-
- assert response == "job started"
-
- assert ObanHelpers.member?(
- %{
- "op" => "follow_import",
- "follower_id" => user1.id,
- "followed_identifiers" => [user2.ap_id]
- },
- all_enqueued(worker: Pleroma.Workers.BackgroundWorker)
- )
- end
- end
-
- test "it imports new-style mastodon follow lists", %{conn: conn} do
- user2 = insert(:user)
-
- response =
- conn
- |> post("/api/pleroma/follow_import", %{
- "list" => "Account address,Show boosts\n#{user2.ap_id},true"
- })
- |> json_response(:ok)
-
- assert response == "job started"
- end
-
- test "requires 'follow' or 'write:follows' permissions" do
- token1 = insert(:oauth_token, scopes: ["read", "write"])
- token2 = insert(:oauth_token, scopes: ["follow"])
- token3 = insert(:oauth_token, scopes: ["something"])
- another_user = insert(:user)
-
- for token <- [token1, token2, token3] do
- conn =
- build_conn()
- |> put_req_header("authorization", "Bearer #{token.token}")
- |> post("/api/pleroma/follow_import", %{"list" => "#{another_user.ap_id}"})
-
- if token == token3 do
- assert %{"error" => "Insufficient permissions: follow | write:follows."} ==
- json_response(conn, 403)
- else
- assert json_response(conn, 200)
- end
- end
- end
-
- test "it imports follows with different nickname variations", %{conn: conn} do
- [user2, user3, user4, user5, user6] = insert_list(5, :user)
-
- identifiers =
- [
- user2.ap_id,
- user3.nickname,
- " ",
- "@" <> user4.nickname,
- user5.nickname <> "@localhost",
- "@" <> user6.nickname <> "@localhost"
- ]
- |> Enum.join("\n")
-
- response =
- conn
- |> post("/api/pleroma/follow_import", %{"list" => identifiers})
- |> json_response(:ok)
-
- assert response == "job started"
- assert [{:ok, job_result}] = ObanHelpers.perform_all()
- assert job_result == [user2, user3, user4, user5, user6]
- end
- end
-
- describe "POST /api/pleroma/blocks_import" do
- # Note: "follow" or "write:blocks" permission is required
- setup do: oauth_access(["write:blocks"])
-
- test "it returns HTTP 200", %{conn: conn} do
- user2 = insert(:user)
-
- response =
- conn
- |> post("/api/pleroma/blocks_import", %{"list" => "#{user2.ap_id}"})
- |> json_response(:ok)
-
- assert response == "job started"
- end
-
- test "it imports blocks users from file", %{user: user1, conn: conn} do
- user2 = insert(:user)
- user3 = insert(:user)
-
- with_mocks([
- {File, [], read!: fn "blocks_list.txt" -> "#{user2.ap_id} #{user3.ap_id}" end}
- ]) do
- response =
- conn
- |> post("/api/pleroma/blocks_import", %{"list" => %Plug.Upload{path: "blocks_list.txt"}})
- |> json_response(:ok)
-
- assert response == "job started"
-
- assert ObanHelpers.member?(
- %{
- "op" => "blocks_import",
- "blocker_id" => user1.id,
- "blocked_identifiers" => [user2.ap_id, user3.ap_id]
- },
- all_enqueued(worker: Pleroma.Workers.BackgroundWorker)
- )
- end
- end
-
- test "it imports blocks with different nickname variations", %{conn: conn} do
- [user2, user3, user4, user5, user6] = insert_list(5, :user)
-
- identifiers =
- [
- user2.ap_id,
- user3.nickname,
- "@" <> user4.nickname,
- user5.nickname <> "@localhost",
- "@" <> user6.nickname <> "@localhost"
- ]
- |> Enum.join(" ")
-
- response =
- conn
- |> post("/api/pleroma/blocks_import", %{"list" => identifiers})
- |> json_response(:ok)
-
- assert response == "job started"
- assert [{:ok, job_result}] = ObanHelpers.perform_all()
- assert job_result == [user2, user3, user4, user5, user6]
- end
- end
-
describe "PUT /api/pleroma/notification_settings" do
setup do: oauth_access(["write:accounts"])
test "it updates notification settings", %{user: user, conn: conn} do
conn
- |> put("/api/pleroma/notification_settings", %{
- "block_from_strangers" => true,
- "bar" => 1
- })
- |> json_response(:ok)
+ |> put(
+ "/api/pleroma/notification_settings?#{URI.encode_query(%{block_from_strangers: true})}"
+ )
+ |> json_response_and_validate_schema(:ok)
user = refresh_record(user)
@@ -206,8 +40,10 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
test "it updates notification settings to enable hiding contents", %{user: user, conn: conn} do
conn
- |> put("/api/pleroma/notification_settings", %{"hide_notification_contents" => "1"})
- |> json_response(:ok)
+ |> put(
+ "/api/pleroma/notification_settings?#{URI.encode_query(%{hide_notification_contents: 1})}"
+ )
+ |> json_response_and_validate_schema(:ok)
user = refresh_record(user)
@@ -230,12 +66,12 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
}
]
- Config.put(:frontend_configurations, config)
+ clear_config(:frontend_configurations, config)
response =
conn
|> get("/api/pleroma/frontend_configurations")
- |> json_response(:ok)
+ |> json_response_and_validate_schema(:ok)
assert response == Jason.encode!(config |> Enum.into(%{})) |> Jason.decode!()
end
@@ -246,7 +82,7 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
emoji =
conn
|> get("/api/pleroma/emoji")
- |> json_response(200)
+ |> json_response_and_validate_schema(200)
assert Enum.all?(emoji, fn
{_key,
@@ -263,25 +99,25 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
setup do: clear_config([:instance, :healthcheck])
test "returns 503 when healthcheck disabled", %{conn: conn} do
- Config.put([:instance, :healthcheck], false)
+ clear_config([:instance, :healthcheck], false)
response =
conn
|> get("/api/pleroma/healthcheck")
- |> json_response(503)
+ |> json_response_and_validate_schema(503)
assert response == %{}
end
test "returns 200 when healthcheck enabled and all ok", %{conn: conn} do
- Config.put([:instance, :healthcheck], true)
+ clear_config([:instance, :healthcheck], true)
with_mock Pleroma.Healthcheck,
system_info: fn -> %Pleroma.Healthcheck{healthy: true} end do
response =
conn
|> get("/api/pleroma/healthcheck")
- |> json_response(200)
+ |> json_response_and_validate_schema(200)
assert %{
"active" => _,
@@ -294,14 +130,14 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
end
test "returns 503 when healthcheck enabled and health is false", %{conn: conn} do
- Config.put([:instance, :healthcheck], true)
+ clear_config([:instance, :healthcheck], true)
with_mock Pleroma.Healthcheck,
system_info: fn -> %Pleroma.Healthcheck{healthy: false} end do
response =
conn
|> get("/api/pleroma/healthcheck")
- |> json_response(503)
+ |> json_response_and_validate_schema(503)
assert %{
"active" => _,
@@ -320,15 +156,15 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
test "with valid permissions and password, it disables the account", %{conn: conn, user: user} do
response =
conn
- |> post("/api/pleroma/disable_account", %{"password" => "test"})
- |> json_response(:ok)
+ |> post("/api/pleroma/disable_account?password=test")
+ |> json_response_and_validate_schema(:ok)
assert response == %{"status" => "success"}
ObanHelpers.perform_all()
user = User.get_cached_by_id(user.id)
- assert user.deactivated == true
+ refute user.is_active
end
test "with valid permissions and invalid password, it returns an error", %{conn: conn} do
@@ -336,13 +172,13 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
response =
conn
- |> post("/api/pleroma/disable_account", %{"password" => "test1"})
- |> json_response(:ok)
+ |> post("/api/pleroma/disable_account?password=test1")
+ |> json_response_and_validate_schema(:ok)
assert response == %{"error" => "Invalid password."}
user = User.get_cached_by_id(user.id)
- refute user.deactivated
+ assert user.is_active
end
end
@@ -417,54 +253,93 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
conn =
conn
|> assign(:token, nil)
- |> post("/api/pleroma/change_email")
+ |> put_req_header("content-type", "multipart/form-data")
+ |> post("/api/pleroma/change_email", %{password: "hi", email: "test@test.com"})
- assert json_response(conn, 403) == %{"error" => "Insufficient permissions: write:accounts."}
+ assert json_response_and_validate_schema(conn, 403) == %{
+ "error" => "Insufficient permissions: write:accounts."
+ }
end
test "with proper permissions and invalid password", %{conn: conn} do
conn =
- post(conn, "/api/pleroma/change_email", %{
- "password" => "hi",
- "email" => "test@test.com"
- })
+ conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> post("/api/pleroma/change_email", %{password: "hi", email: "test@test.com"})
- assert json_response(conn, 200) == %{"error" => "Invalid password."}
+ assert json_response_and_validate_schema(conn, 200) == %{"error" => "Invalid password."}
end
test "with proper permissions, valid password and invalid email", %{
conn: conn
} do
conn =
- post(conn, "/api/pleroma/change_email", %{
- "password" => "test",
- "email" => "foobar"
- })
+ conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> post("/api/pleroma/change_email", %{password: "test", email: "foobar"})
- assert json_response(conn, 200) == %{"error" => "Email has invalid format."}
+ assert json_response_and_validate_schema(conn, 200) == %{
+ "error" => "Email has invalid format."
+ }
end
test "with proper permissions, valid password and no email", %{
conn: conn
} do
conn =
- post(conn, "/api/pleroma/change_email", %{
- "password" => "test"
- })
+ conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> post("/api/pleroma/change_email", %{password: "test"})
- assert json_response(conn, 200) == %{"error" => "Email can't be blank."}
+ assert %{"error" => "Missing field: email."} = json_response_and_validate_schema(conn, 400)
end
- test "with proper permissions, valid password and blank email", %{
- conn: conn
- } do
+ test "with proper permissions, valid password and blank email, when instance requires user email",
+ %{
+ conn: conn
+ } do
+ orig_account_activation_required =
+ Pleroma.Config.get([:instance, :account_activation_required])
+
+ Pleroma.Config.put([:instance, :account_activation_required], true)
+
+ on_exit(fn ->
+ Pleroma.Config.put(
+ [:instance, :account_activation_required],
+ orig_account_activation_required
+ )
+ end)
+
conn =
- post(conn, "/api/pleroma/change_email", %{
- "password" => "test",
- "email" => ""
- })
+ conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> post("/api/pleroma/change_email", %{password: "test", email: ""})
+
+ assert json_response_and_validate_schema(conn, 200) == %{"error" => "Email can't be blank."}
+ end
+
+ test "with proper permissions, valid password and blank email, when instance does not require user email",
+ %{
+ conn: conn
+ } do
+ orig_account_activation_required =
+ Pleroma.Config.get([:instance, :account_activation_required])
+
+ Pleroma.Config.put([:instance, :account_activation_required], false)
+
+ on_exit(fn ->
+ Pleroma.Config.put(
+ [:instance, :account_activation_required],
+ orig_account_activation_required
+ )
+ end)
+
+ conn =
+ conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> post("/api/pleroma/change_email", %{password: "test", email: ""})
- assert json_response(conn, 200) == %{"error" => "Email can't be blank."}
+ assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"}
end
test "with proper permissions, valid password and non unique email", %{
@@ -473,24 +348,24 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
user = insert(:user)
conn =
- post(conn, "/api/pleroma/change_email", %{
- "password" => "test",
- "email" => user.email
- })
+ conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> post("/api/pleroma/change_email", %{password: "test", email: user.email})
- assert json_response(conn, 200) == %{"error" => "Email has already been taken."}
+ assert json_response_and_validate_schema(conn, 200) == %{
+ "error" => "Email has already been taken."
+ }
end
test "with proper permissions, valid password and valid email", %{
conn: conn
} do
conn =
- post(conn, "/api/pleroma/change_email", %{
- "password" => "test",
- "email" => "cofe@foobar.com"
- })
+ conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> post("/api/pleroma/change_email", %{password: "test", email: "cofe@foobar.com"})
- assert json_response(conn, 200) == %{"status" => "success"}
+ assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"}
end
end
@@ -501,20 +376,29 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
conn =
conn
|> assign(:token, nil)
- |> post("/api/pleroma/change_password")
+ |> put_req_header("content-type", "multipart/form-data")
+ |> post("/api/pleroma/change_password", %{
+ "password" => "hi",
+ "new_password" => "newpass",
+ "new_password_confirmation" => "newpass"
+ })
- assert json_response(conn, 403) == %{"error" => "Insufficient permissions: write:accounts."}
+ assert json_response_and_validate_schema(conn, 403) == %{
+ "error" => "Insufficient permissions: write:accounts."
+ }
end
test "with proper permissions and invalid password", %{conn: conn} do
conn =
- post(conn, "/api/pleroma/change_password", %{
+ conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> post("/api/pleroma/change_password", %{
"password" => "hi",
"new_password" => "newpass",
"new_password_confirmation" => "newpass"
})
- assert json_response(conn, 200) == %{"error" => "Invalid password."}
+ assert json_response_and_validate_schema(conn, 200) == %{"error" => "Invalid password."}
end
test "with proper permissions, valid password and new password and confirmation not matching",
@@ -522,13 +406,15 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
conn: conn
} do
conn =
- post(conn, "/api/pleroma/change_password", %{
+ conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> post("/api/pleroma/change_password", %{
"password" => "test",
"new_password" => "newpass",
"new_password_confirmation" => "notnewpass"
})
- assert json_response(conn, 200) == %{
+ assert json_response_and_validate_schema(conn, 200) == %{
"error" => "New password does not match confirmation."
}
end
@@ -537,13 +423,15 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
conn: conn
} do
conn =
- post(conn, "/api/pleroma/change_password", %{
- "password" => "test",
- "new_password" => "",
- "new_password_confirmation" => ""
+ conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> post("/api/pleroma/change_password", %{
+ password: "test",
+ new_password: "",
+ new_password_confirmation: ""
})
- assert json_response(conn, 200) == %{
+ assert json_response_and_validate_schema(conn, 200) == %{
"error" => "New password can't be blank."
}
end
@@ -553,15 +441,20 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
user: user
} do
conn =
- post(conn, "/api/pleroma/change_password", %{
- "password" => "test",
- "new_password" => "newpass",
- "new_password_confirmation" => "newpass"
- })
-
- assert json_response(conn, 200) == %{"status" => "success"}
+ conn
+ |> put_req_header("content-type", "multipart/form-data")
+ |> post(
+ "/api/pleroma/change_password",
+ %{
+ password: "test",
+ new_password: "newpass",
+ new_password_confirmation: "newpass"
+ }
+ )
+
+ assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"}
fetched_user = User.get_cached_by_id(user.id)
- assert Pbkdf2.verify_pass("newpass", fetched_user.password_hash) == true
+ assert Pleroma.Password.Pbkdf2.verify_pass("newpass", fetched_user.password_hash) == true
end
end
@@ -574,25 +467,50 @@ defmodule Pleroma.Web.TwitterAPI.UtilControllerTest do
|> assign(:token, nil)
|> post("/api/pleroma/delete_account")
- assert json_response(conn, 403) ==
+ assert json_response_and_validate_schema(conn, 403) ==
%{"error" => "Insufficient permissions: write:accounts."}
end
test "with proper permissions and wrong or missing password", %{conn: conn} do
for params <- [%{"password" => "hi"}, %{}] do
- ret_conn = post(conn, "/api/pleroma/delete_account", params)
+ ret_conn =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/pleroma/delete_account", params)
- assert json_response(ret_conn, 200) == %{"error" => "Invalid password."}
+ assert json_response_and_validate_schema(ret_conn, 200) == %{
+ "error" => "Invalid password."
+ }
end
end
- test "with proper permissions and valid password", %{conn: conn, user: user} do
- conn = post(conn, "/api/pleroma/delete_account", %{"password" => "test"})
+ test "with proper permissions and valid password (URL query)", %{conn: conn, user: user} do
+ conn =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/pleroma/delete_account?password=test")
+
+ ObanHelpers.perform_all()
+ assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"}
+
+ user = User.get_by_id(user.id)
+ refute user.is_active
+ assert user.name == nil
+ assert user.bio == ""
+ assert user.password_hash == nil
+ end
+
+ test "with proper permissions and valid password (JSON body)", %{conn: conn, user: user} do
+ conn =
+ conn
+ |> put_req_header("content-type", "application/json")
+ |> post("/api/pleroma/delete_account", %{password: "test"})
+
ObanHelpers.perform_all()
- assert json_response(conn, 200) == %{"status" => "success"}
+ assert json_response_and_validate_schema(conn, 200) == %{"status" => "success"}
user = User.get_by_id(user.id)
- assert user.deactivated == true
+ refute user.is_active
assert user.name == nil
assert user.bio == ""
assert user.password_hash == nil
diff --git a/test/web/uploader_controller_test.exs b/test/pleroma/web/uploader_controller_test.exs
index 21e518236..fc278004e 100644
--- a/test/web/uploader_controller_test.exs
+++ b/test/pleroma/web/uploader_controller_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.UploaderControllerTest do
- use Pleroma.Web.ConnCase
+ use Pleroma.Web.ConnCase, async: true
alias Pleroma.Uploaders.Uploader
describe "callback/2" do
diff --git a/test/web/views/error_view_test.exs b/test/pleroma/web/views/error_view_test.exs
index 8dbbd18b4..42da8f458 100644
--- a/test/web/views/error_view_test.exs
+++ b/test/pleroma/web/views/error_view_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ErrorViewTest do
diff --git a/test/web/web_finger/web_finger_controller_test.exs b/test/pleroma/web/web_finger/web_finger_controller_test.exs
index 0023f1e81..66d79320f 100644
--- a/test/web/web_finger/web_finger_controller_test.exs
+++ b/test/pleroma/web/web_finger/web_finger_controller_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.WebFinger.WebFingerControllerTest do
@@ -24,20 +24,28 @@ defmodule Pleroma.Web.WebFinger.WebFingerControllerTest do
assert response.status == 200
assert response.resp_body ==
- ~s(<?xml version="1.0" encoding="UTF-8"?><XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"><Link rel="lrdd" template="#{
- Pleroma.Web.base_url()
- }/.well-known/webfinger?resource={uri}" type="application/xrd+xml" /></XRD>)
+ ~s(<?xml version="1.0" encoding="UTF-8"?><XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"><Link rel="lrdd" template="#{Pleroma.Web.Endpoint.url()}/.well-known/webfinger?resource={uri}" type="application/xrd+xml" /></XRD>)
end
test "Webfinger JRD" do
- user = insert(:user)
+ user =
+ insert(:user,
+ ap_id: "https://hyrule.world/users/zelda",
+ also_known_as: ["https://mushroom.kingdom/users/toad"]
+ )
response =
build_conn()
|> put_req_header("accept", "application/jrd+json")
|> get("/.well-known/webfinger?resource=acct:#{user.nickname}@localhost")
+ |> json_response(200)
+
+ assert response["subject"] == "acct:#{user.nickname}@localhost"
- assert json_response(response, 200)["subject"] == "acct:#{user.nickname}@localhost"
+ assert response["aliases"] == [
+ "https://hyrule.world/users/zelda",
+ "https://mushroom.kingdom/users/toad"
+ ]
end
test "it returns 404 when user isn't found (JSON)" do
@@ -51,14 +59,20 @@ defmodule Pleroma.Web.WebFinger.WebFingerControllerTest do
end
test "Webfinger XML" do
- user = insert(:user)
+ user =
+ insert(:user,
+ ap_id: "https://hyrule.world/users/zelda",
+ also_known_as: ["https://mushroom.kingdom/users/toad"]
+ )
response =
build_conn()
|> put_req_header("accept", "application/xrd+xml")
|> get("/.well-known/webfinger?resource=acct:#{user.nickname}@localhost")
+ |> response(200)
- assert response(response, 200)
+ assert response =~ "<Alias>https://hyrule.world/users/zelda</Alias>"
+ assert response =~ "<Alias>https://mushroom.kingdom/users/toad</Alias>"
end
test "it returns 404 when user isn't found (XML)" do
diff --git a/test/web/web_finger/web_finger_test.exs b/test/pleroma/web/web_finger_test.exs
index 96fc0bbaa..0a36d57e6 100644
--- a/test/web/web_finger/web_finger_test.exs
+++ b/test/pleroma/web/web_finger_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.WebFingerTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.Web.WebFinger
import Pleroma.Factory
import Tesla.Mock
@@ -17,7 +17,7 @@ defmodule Pleroma.Web.WebFingerTest do
test "returns a link to the xml lrdd" do
host_info = WebFinger.host_meta()
- assert String.contains?(host_info, Pleroma.Web.base_url())
+ assert String.contains?(host_info, Pleroma.Web.Endpoint.url())
end
end
@@ -45,6 +45,26 @@ defmodule Pleroma.Web.WebFingerTest do
assert {:error, _} = WebFinger.finger("pleroma.social")
end
+ test "returns error when there is no content-type header" do
+ Tesla.Mock.mock(fn
+ %{url: "http://social.heldscal.la/.well-known/host-meta"} ->
+ {:ok,
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/tesla_mock/social.heldscal.la_host_meta")
+ }}
+
+ %{
+ url:
+ "https://social.heldscal.la/.well-known/webfinger?resource=acct:invalid_content@social.heldscal.la"
+ } ->
+ {:ok, %Tesla.Env{status: 200, body: ""}}
+ end)
+
+ user = "invalid_content@social.heldscal.la"
+ assert {:error, {:content_type, nil}} = WebFinger.finger(user)
+ end
+
test "returns error when fails parse xml or json" do
user = "invalid_content@social.heldscal.la"
assert {:error, %Jason.DecodeError{}} = WebFinger.finger(user)
@@ -56,12 +76,13 @@ defmodule Pleroma.Web.WebFingerTest do
{:ok, _data} = WebFinger.finger(user)
end
- test "returns the ActivityPub actor URI for an ActivityPub user with the ld+json mimetype" do
+ test "returns the ActivityPub actor URI and subscribe address for an ActivityPub user with the ld+json mimetype" do
user = "kaniini@gerzilla.de"
{:ok, data} = WebFinger.finger(user)
assert data["ap_id"] == "https://gerzilla.de/channel/kaniini"
+ assert data["subscribe_address"] == "https://gerzilla.de/follow?f=&url={uri}"
end
test "it work for AP-only user" do
@@ -112,5 +133,52 @@ defmodule Pleroma.Web.WebFingerTest do
ap_id = "https://" <> to_string(:idna.encode("zetsubou.みんな")) <> "/users/lain"
{:ok, _data} = WebFinger.finger(ap_id)
end
+
+ test "respects json content-type" do
+ Tesla.Mock.mock(fn
+ %{
+ url:
+ "https://mastodon.social/.well-known/webfinger?resource=acct:emelie@mastodon.social"
+ } ->
+ {:ok,
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/tesla_mock/webfinger_emelie.json"),
+ headers: [{"content-type", "application/jrd+json"}]
+ }}
+
+ %{url: "http://mastodon.social/.well-known/host-meta"} ->
+ {:ok,
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/tesla_mock/mastodon.social_host_meta")
+ }}
+ end)
+
+ {:ok, _data} = WebFinger.finger("emelie@mastodon.social")
+ end
+
+ test "respects xml content-type" do
+ Tesla.Mock.mock(fn
+ %{
+ url: "https://pawoo.net/.well-known/webfinger?resource=acct:pekorino@pawoo.net"
+ } ->
+ {:ok,
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/tesla_mock/https___pawoo.net_users_pekorino.xml"),
+ headers: [{"content-type", "application/xrd+xml"}]
+ }}
+
+ %{url: "http://pawoo.net/.well-known/host-meta"} ->
+ {:ok,
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/tesla_mock/pawoo.net_host_meta")
+ }}
+ end)
+
+ {:ok, _data} = WebFinger.finger("pekorino@pawoo.net")
+ end
end
end
diff --git a/test/workers/cron/digest_emails_worker_test.exs b/test/pleroma/workers/cron/digest_emails_worker_test.exs
index 65887192e..b3ca6235b 100644
--- a/test/workers/cron/digest_emails_worker_test.exs
+++ b/test/pleroma/workers/cron/digest_emails_worker_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Workers.Cron.DigestEmailsWorkerTest do
@@ -14,7 +14,7 @@ defmodule Pleroma.Workers.Cron.DigestEmailsWorkerTest do
setup do: clear_config([:email_notifications, :digest])
setup do
- Pleroma.Config.put([:email_notifications, :digest], %{
+ clear_config([:email_notifications, :digest], %{
active: true,
inactivity_threshold: 7,
interval: 7
diff --git a/test/workers/cron/new_users_digest_worker_test.exs b/test/pleroma/workers/cron/new_users_digest_worker_test.exs
index 129534cb1..f9ef265c2 100644
--- a/test/workers/cron/new_users_digest_worker_test.exs
+++ b/test/pleroma/workers/cron/new_users_digest_worker_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Workers.Cron.NewUsersDigestWorkerTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
import Pleroma.Factory
alias Pleroma.Tests.ObanHelpers
@@ -28,7 +28,7 @@ defmodule Pleroma.Workers.Cron.NewUsersDigestWorkerTest do
assert email.html_body =~ user.nickname
assert email.html_body =~ user2.nickname
assert email.html_body =~ "cofe"
- assert email.html_body =~ "#{Pleroma.Web.Endpoint.url()}/static/logo.png"
+ assert email.html_body =~ "#{Pleroma.Web.Endpoint.url()}/static/logo.svg"
end
test "it doesn't fail when admin has no email" do
diff --git a/test/pleroma/workers/purge_expired_activity_test.exs b/test/pleroma/workers/purge_expired_activity_test.exs
new file mode 100644
index 000000000..98f30f61f
--- /dev/null
+++ b/test/pleroma/workers/purge_expired_activity_test.exs
@@ -0,0 +1,59 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Workers.PurgeExpiredActivityTest do
+ use Pleroma.DataCase, async: true
+ use Oban.Testing, repo: Pleroma.Repo
+
+ import Pleroma.Factory
+
+ alias Pleroma.Workers.PurgeExpiredActivity
+
+ test "enqueue job" do
+ activity = insert(:note_activity)
+
+ assert {:ok, _} =
+ PurgeExpiredActivity.enqueue(%{
+ activity_id: activity.id,
+ expires_at: DateTime.add(DateTime.utc_now(), 3601)
+ })
+
+ assert_enqueued(
+ worker: Pleroma.Workers.PurgeExpiredActivity,
+ args: %{activity_id: activity.id}
+ )
+
+ assert {:ok, _} =
+ perform_job(Pleroma.Workers.PurgeExpiredActivity, %{activity_id: activity.id})
+
+ assert %Oban.Job{} = Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity.id)
+ end
+
+ test "error if user was not found" do
+ activity = insert(:note_activity)
+
+ assert {:ok, _} =
+ PurgeExpiredActivity.enqueue(%{
+ activity_id: activity.id,
+ expires_at: DateTime.add(DateTime.utc_now(), 3601)
+ })
+
+ user = Pleroma.User.get_by_ap_id(activity.actor)
+ Pleroma.Repo.delete(user)
+
+ assert {:error, :user_not_found} =
+ perform_job(Pleroma.Workers.PurgeExpiredActivity, %{activity_id: activity.id})
+ end
+
+ test "error if actiivity was not found" do
+ assert {:ok, _} =
+ PurgeExpiredActivity.enqueue(%{
+ activity_id: "some_id",
+ expires_at: DateTime.add(DateTime.utc_now(), 3601)
+ })
+
+ assert {:error, :activity_not_found} =
+ perform_job(Pleroma.Workers.PurgeExpiredActivity, %{activity_id: "some_if"})
+ end
+end
diff --git a/test/pleroma/workers/purge_expired_filter_test.exs b/test/pleroma/workers/purge_expired_filter_test.exs
new file mode 100644
index 000000000..d10586be9
--- /dev/null
+++ b/test/pleroma/workers/purge_expired_filter_test.exs
@@ -0,0 +1,30 @@
+defmodule Pleroma.Workers.PurgeExpiredFilterTest do
+ use Pleroma.DataCase, async: true
+ use Oban.Testing, repo: Repo
+
+ import Pleroma.Factory
+
+ test "purges expired filter" do
+ %{id: user_id} = insert(:user)
+
+ {:ok, %{id: id}} =
+ Pleroma.Filter.create(%{
+ user_id: user_id,
+ phrase: "cofe",
+ context: ["home"],
+ expires_in: 600
+ })
+
+ assert_enqueued(
+ worker: Pleroma.Workers.PurgeExpiredFilter,
+ args: %{filter_id: id}
+ )
+
+ assert {:ok, %{id: ^id}} =
+ perform_job(Pleroma.Workers.PurgeExpiredFilter, %{
+ filter_id: id
+ })
+
+ assert Repo.aggregate(Pleroma.Filter, :count, :id) == 0
+ end
+end
diff --git a/test/pleroma/workers/purge_expired_token_test.exs b/test/pleroma/workers/purge_expired_token_test.exs
new file mode 100644
index 000000000..00cbd40cd
--- /dev/null
+++ b/test/pleroma/workers/purge_expired_token_test.exs
@@ -0,0 +1,51 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Workers.PurgeExpiredTokenTest do
+ use Pleroma.DataCase, async: true
+ use Oban.Testing, repo: Pleroma.Repo
+
+ import Pleroma.Factory
+
+ setup do: clear_config([:oauth2, :clean_expired_tokens], true)
+
+ test "purges expired oauth token" do
+ user = insert(:user)
+ app = insert(:oauth_app)
+
+ {:ok, %{id: id}} = Pleroma.Web.OAuth.Token.create(app, user)
+
+ assert_enqueued(
+ worker: Pleroma.Workers.PurgeExpiredToken,
+ args: %{token_id: id, mod: Pleroma.Web.OAuth.Token}
+ )
+
+ assert {:ok, %{id: ^id}} =
+ perform_job(Pleroma.Workers.PurgeExpiredToken, %{
+ token_id: id,
+ mod: Pleroma.Web.OAuth.Token
+ })
+
+ assert Repo.aggregate(Pleroma.Web.OAuth.Token, :count, :id) == 0
+ end
+
+ test "purges expired mfa token" do
+ authorization = insert(:oauth_authorization)
+
+ {:ok, %{id: id}} = Pleroma.MFA.Token.create(authorization.user, authorization)
+
+ assert_enqueued(
+ worker: Pleroma.Workers.PurgeExpiredToken,
+ args: %{token_id: id, mod: Pleroma.MFA.Token}
+ )
+
+ assert {:ok, %{id: ^id}} =
+ perform_job(Pleroma.Workers.PurgeExpiredToken, %{
+ token_id: id,
+ mod: Pleroma.MFA.Token
+ })
+
+ assert Repo.aggregate(Pleroma.MFA.Token, :count, :id) == 0
+ end
+end
diff --git a/test/workers/scheduled_activity_worker_test.exs b/test/pleroma/workers/scheduled_activity_worker_test.exs
index f3eddf7b1..5558d5b5f 100644
--- a/test/workers/scheduled_activity_worker_test.exs
+++ b/test/pleroma/workers/scheduled_activity_worker_test.exs
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Workers.ScheduledActivityWorkerTest do
@@ -11,10 +11,9 @@ defmodule Pleroma.Workers.ScheduledActivityWorkerTest do
import Pleroma.Factory
import ExUnit.CaptureLog
- setup do: clear_config([ScheduledActivity, :enabled])
+ setup do: clear_config([ScheduledActivity, :enabled], true)
test "creates a status from the scheduled activity" do
- Pleroma.Config.put([ScheduledActivity, :enabled], true)
user = insert(:user)
naive_datetime =
@@ -32,18 +31,22 @@ defmodule Pleroma.Workers.ScheduledActivityWorkerTest do
params: %{status: "hi"}
)
- ScheduledActivityWorker.perform(%Oban.Job{args: %{"activity_id" => scheduled_activity.id}})
+ {:ok, %{id: activity_id}} =
+ ScheduledActivityWorker.perform(%Oban.Job{args: %{"activity_id" => scheduled_activity.id}})
refute Repo.get(ScheduledActivity, scheduled_activity.id)
- activity = Repo.all(Pleroma.Activity) |> Enum.find(&(&1.actor == user.ap_id))
- assert Pleroma.Object.normalize(activity).data["content"] == "hi"
- end
- test "adds log message if ScheduledActivity isn't find" do
- Pleroma.Config.put([ScheduledActivity, :enabled], true)
+ object =
+ Pleroma.Activity
+ |> Repo.get(activity_id)
+ |> Pleroma.Object.normalize()
+
+ assert object.data["content"] == "hi"
+ end
+ test "error message for non-existent scheduled activity" do
assert capture_log([level: :error], fn ->
ScheduledActivityWorker.perform(%Oban.Job{args: %{"activity_id" => 42}})
- end) =~ "Couldn't find scheduled activity"
+ end) =~ "Couldn't find scheduled activity: 42"
end
end
diff --git a/test/xml_builder_test.exs b/test/pleroma/xml_builder_test.exs
index 059384c34..9aae32cdc 100644
--- a/test/xml_builder_test.exs
+++ b/test/pleroma/xml_builder_test.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.XmlBuilderTest do
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
alias Pleroma.XmlBuilder
test "Build a basic xml string from a tuple" do
diff --git a/test/plugs/ensure_user_key_plug_test.exs b/test/plugs/ensure_user_key_plug_test.exs
deleted file mode 100644
index 633c05447..000000000
--- a/test/plugs/ensure_user_key_plug_test.exs
+++ /dev/null
@@ -1,29 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Plugs.EnsureUserKeyPlugTest do
- use Pleroma.Web.ConnCase, async: true
-
- alias Pleroma.Plugs.EnsureUserKeyPlug
-
- test "if the conn has a user key set, it does nothing", %{conn: conn} do
- conn =
- conn
- |> assign(:user, 1)
-
- ret_conn =
- conn
- |> EnsureUserKeyPlug.call(%{})
-
- assert conn == ret_conn
- end
-
- test "if the conn has no key set, it sets it to nil", %{conn: conn} do
- conn =
- conn
- |> EnsureUserKeyPlug.call(%{})
-
- assert Map.has_key?(conn.assigns, :user)
- end
-end
diff --git a/test/plugs/frontend_static_test.exs b/test/plugs/frontend_static_test.exs
deleted file mode 100644
index 6f4923048..000000000
--- a/test/plugs/frontend_static_test.exs
+++ /dev/null
@@ -1,57 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.FrontendStaticPlugTest do
- alias Pleroma.Plugs.FrontendStatic
- use Pleroma.Web.ConnCase
-
- @dir "test/tmp/instance_static"
-
- setup do
- File.mkdir_p!(@dir)
- on_exit(fn -> File.rm_rf(@dir) end)
- end
-
- setup do: clear_config([:instance, :static_dir], @dir)
-
- test "init will give a static plug config + the frontend type" do
- opts =
- [
- at: "/admin",
- frontend_type: :admin
- ]
- |> FrontendStatic.init()
-
- assert opts[:at] == ["admin"]
- assert opts[:frontend_type] == :admin
- end
-
- test "overrides existing static files", %{conn: conn} do
- name = "pelmora"
- ref = "uguu"
-
- clear_config([:frontends, :primary], %{"name" => name, "ref" => ref})
- path = "#{@dir}/frontends/#{name}/#{ref}"
-
- File.mkdir_p!(path)
- File.write!("#{path}/index.html", "from frontend plug")
-
- index = get(conn, "/")
- assert html_response(index, 200) == "from frontend plug"
- end
-
- test "overrides existing static files for the `pleroma/admin` path", %{conn: conn} do
- name = "pelmora"
- ref = "uguu"
-
- clear_config([:frontends, :admin], %{"name" => name, "ref" => ref})
- path = "#{@dir}/frontends/#{name}/#{ref}"
-
- File.mkdir_p!(path)
- File.write!("#{path}/index.html", "from frontend plug")
-
- index = get(conn, "/pleroma/admin/")
- assert html_response(index, 200) == "from frontend plug"
- end
-end
diff --git a/test/plugs/legacy_authentication_plug_test.exs b/test/plugs/legacy_authentication_plug_test.exs
deleted file mode 100644
index 3b8c07627..000000000
--- a/test/plugs/legacy_authentication_plug_test.exs
+++ /dev/null
@@ -1,82 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Plugs.LegacyAuthenticationPlugTest do
- use Pleroma.Web.ConnCase
-
- import Pleroma.Factory
-
- alias Pleroma.Plugs.LegacyAuthenticationPlug
- alias Pleroma.Plugs.OAuthScopesPlug
- alias Pleroma.Plugs.PlugHelper
- alias Pleroma.User
-
- setup do
- user =
- insert(:user,
- password: "password",
- password_hash:
- "$6$9psBWV8gxkGOZWBz$PmfCycChoxeJ3GgGzwvhlgacb9mUoZ.KUXNCssekER4SJ7bOK53uXrHNb2e4i8yPFgSKyzaW9CcmrDXWIEMtD1"
- )
-
- %{user: user}
- end
-
- test "it does nothing if a user is assigned", %{conn: conn, user: user} do
- conn =
- conn
- |> assign(:auth_credentials, %{username: "dude", password: "password"})
- |> assign(:auth_user, user)
- |> assign(:user, %User{})
-
- ret_conn =
- conn
- |> LegacyAuthenticationPlug.call(%{})
-
- assert ret_conn == conn
- end
-
- @tag :skip_on_mac
- test "if `auth_user` is present and password is correct, " <>
- "it authenticates the user, resets the password, marks OAuthScopesPlug as skipped",
- %{
- conn: conn,
- user: user
- } do
- conn =
- conn
- |> assign(:auth_credentials, %{username: "dude", password: "password"})
- |> assign(:auth_user, user)
-
- conn = LegacyAuthenticationPlug.call(conn, %{})
-
- assert conn.assigns.user.id == user.id
- assert PlugHelper.plug_skipped?(conn, OAuthScopesPlug)
- end
-
- @tag :skip_on_mac
- test "it does nothing if the password is wrong", %{
- conn: conn,
- user: user
- } do
- conn =
- conn
- |> assign(:auth_credentials, %{username: "dude", password: "wrong_password"})
- |> assign(:auth_user, user)
-
- ret_conn =
- conn
- |> LegacyAuthenticationPlug.call(%{})
-
- assert conn == ret_conn
- end
-
- test "with no credentials or user it does nothing", %{conn: conn} do
- ret_conn =
- conn
- |> LegacyAuthenticationPlug.call(%{})
-
- assert ret_conn == conn
- end
-end
diff --git a/test/plugs/oauth_plug_test.exs b/test/plugs/oauth_plug_test.exs
deleted file mode 100644
index f74c068cd..000000000
--- a/test/plugs/oauth_plug_test.exs
+++ /dev/null
@@ -1,80 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Plugs.OAuthPlugTest do
- use Pleroma.Web.ConnCase, async: true
-
- alias Pleroma.Plugs.OAuthPlug
- import Pleroma.Factory
-
- @session_opts [
- store: :cookie,
- key: "_test",
- signing_salt: "cooldude"
- ]
-
- setup %{conn: conn} do
- user = insert(:user)
- {:ok, %{token: token}} = Pleroma.Web.OAuth.Token.create_token(insert(:oauth_app), user)
- %{user: user, token: token, conn: conn}
- end
-
- test "with valid token(uppercase), it assigns the user", %{conn: conn} = opts do
- conn =
- conn
- |> put_req_header("authorization", "BEARER #{opts[:token]}")
- |> OAuthPlug.call(%{})
-
- assert conn.assigns[:user] == opts[:user]
- end
-
- test "with valid token(downcase), it assigns the user", %{conn: conn} = opts do
- conn =
- conn
- |> put_req_header("authorization", "bearer #{opts[:token]}")
- |> OAuthPlug.call(%{})
-
- assert conn.assigns[:user] == opts[:user]
- end
-
- test "with valid token(downcase) in url parameters, it assigns the user", opts do
- conn =
- :get
- |> build_conn("/?access_token=#{opts[:token]}")
- |> put_req_header("content-type", "application/json")
- |> fetch_query_params()
- |> OAuthPlug.call(%{})
-
- assert conn.assigns[:user] == opts[:user]
- end
-
- test "with valid token(downcase) in body parameters, it assigns the user", opts do
- conn =
- :post
- |> build_conn("/api/v1/statuses", access_token: opts[:token], status: "test")
- |> OAuthPlug.call(%{})
-
- assert conn.assigns[:user] == opts[:user]
- end
-
- test "with invalid token, it not assigns the user", %{conn: conn} do
- conn =
- conn
- |> put_req_header("authorization", "bearer TTTTT")
- |> OAuthPlug.call(%{})
-
- refute conn.assigns[:user]
- end
-
- test "when token is missed but token in session, it assigns the user", %{conn: conn} = opts do
- conn =
- conn
- |> Plug.Session.call(Plug.Session.init(@session_opts))
- |> fetch_session()
- |> put_session(:oauth_token, opts[:token])
- |> OAuthPlug.call(%{})
-
- assert conn.assigns[:user] == opts[:user]
- end
-end
diff --git a/test/plugs/remote_ip_test.exs b/test/plugs/remote_ip_test.exs
deleted file mode 100644
index 752ab32e7..000000000
--- a/test/plugs/remote_ip_test.exs
+++ /dev/null
@@ -1,75 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Plugs.RemoteIpTest do
- use ExUnit.Case, async: true
- use Plug.Test
-
- alias Pleroma.Plugs.RemoteIp
-
- import Pleroma.Tests.Helpers, only: [clear_config: 1, clear_config: 2]
- setup do: clear_config(RemoteIp)
-
- test "disabled" do
- Pleroma.Config.put(RemoteIp, enabled: false)
-
- %{remote_ip: remote_ip} = conn(:get, "/")
-
- conn =
- conn(:get, "/")
- |> put_req_header("x-forwarded-for", "1.1.1.1")
- |> RemoteIp.call(nil)
-
- assert conn.remote_ip == remote_ip
- end
-
- test "enabled" do
- Pleroma.Config.put(RemoteIp, enabled: true)
-
- conn =
- conn(:get, "/")
- |> put_req_header("x-forwarded-for", "1.1.1.1")
- |> RemoteIp.call(nil)
-
- assert conn.remote_ip == {1, 1, 1, 1}
- end
-
- test "custom headers" do
- Pleroma.Config.put(RemoteIp, enabled: true, headers: ["cf-connecting-ip"])
-
- conn =
- conn(:get, "/")
- |> put_req_header("x-forwarded-for", "1.1.1.1")
- |> RemoteIp.call(nil)
-
- refute conn.remote_ip == {1, 1, 1, 1}
-
- conn =
- conn(:get, "/")
- |> put_req_header("cf-connecting-ip", "1.1.1.1")
- |> RemoteIp.call(nil)
-
- assert conn.remote_ip == {1, 1, 1, 1}
- end
-
- test "custom proxies" do
- Pleroma.Config.put(RemoteIp, enabled: true)
-
- conn =
- conn(:get, "/")
- |> put_req_header("x-forwarded-for", "173.245.48.1, 1.1.1.1, 173.245.48.2")
- |> RemoteIp.call(nil)
-
- refute conn.remote_ip == {1, 1, 1, 1}
-
- Pleroma.Config.put([RemoteIp, :proxies], ["173.245.48.0/20"])
-
- conn =
- conn(:get, "/")
- |> put_req_header("x-forwarded-for", "173.245.48.1, 1.1.1.1, 173.245.48.2")
- |> RemoteIp.call(nil)
-
- assert conn.remote_ip == {1, 1, 1, 1}
- end
-end
diff --git a/test/plugs/session_authentication_plug_test.exs b/test/plugs/session_authentication_plug_test.exs
deleted file mode 100644
index 0949ecfed..000000000
--- a/test/plugs/session_authentication_plug_test.exs
+++ /dev/null
@@ -1,63 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Plugs.SessionAuthenticationPlugTest do
- use Pleroma.Web.ConnCase, async: true
-
- alias Pleroma.Plugs.SessionAuthenticationPlug
- alias Pleroma.User
-
- setup %{conn: conn} do
- session_opts = [
- store: :cookie,
- key: "_test",
- signing_salt: "cooldude"
- ]
-
- conn =
- conn
- |> Plug.Session.call(Plug.Session.init(session_opts))
- |> fetch_session
- |> assign(:auth_user, %User{id: 1})
-
- %{conn: conn}
- end
-
- test "it does nothing if a user is assigned", %{conn: conn} do
- conn =
- conn
- |> assign(:user, %User{})
-
- ret_conn =
- conn
- |> SessionAuthenticationPlug.call(%{})
-
- assert ret_conn == conn
- end
-
- test "if the auth_user has the same id as the user_id in the session, it assigns the user", %{
- conn: conn
- } do
- conn =
- conn
- |> put_session(:user_id, conn.assigns.auth_user.id)
- |> SessionAuthenticationPlug.call(%{})
-
- assert conn.assigns.user == conn.assigns.auth_user
- end
-
- test "if the auth_user has a different id as the user_id in the session, it does nothing", %{
- conn: conn
- } do
- conn =
- conn
- |> put_session(:user_id, -1)
-
- ret_conn =
- conn
- |> SessionAuthenticationPlug.call(%{})
-
- assert ret_conn == conn
- end
-end
diff --git a/test/support/api_spec_helpers.ex b/test/support/api_spec_helpers.ex
index 46388f92c..886e72d73 100644
--- a/test/support/api_spec_helpers.ex
+++ b/test/support/api_spec_helpers.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Tests.ApiSpecHelpers do
@@ -29,9 +29,7 @@ defmodule Pleroma.Tests.ApiSpecHelpers do
end)
flunk(
- "Value does not conform to schema #{schema.title}: #{Enum.join(errors, "\n")}\n#{
- inspect(value)
- }"
+ "Value does not conform to schema #{schema.title}: #{Enum.join(errors, "\n")}\n#{inspect(value)}"
)
end
end
diff --git a/test/support/builders/user_builder.ex b/test/support/builders/user_builder.ex
index 0c687c029..6bccbb35a 100644
--- a/test/support/builders/user_builder.ex
+++ b/test/support/builders/user_builder.ex
@@ -7,7 +7,7 @@ defmodule Pleroma.Builders.UserBuilder do
email: "test@example.org",
name: "Test Name",
nickname: "testname",
- password_hash: Pbkdf2.hash_pwd_salt("test"),
+ password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("test"),
bio: "A tester.",
ap_id: "some id",
last_digest_emailed_at: NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
diff --git a/test/support/cachex_proxy.ex b/test/support/cachex_proxy.ex
new file mode 100644
index 000000000..de1f1c766
--- /dev/null
+++ b/test/support/cachex_proxy.ex
@@ -0,0 +1,40 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.CachexProxy do
+ @behaviour Pleroma.Caching
+
+ @impl true
+ defdelegate get!(cache, key), to: Cachex
+
+ @impl true
+ defdelegate stream!(cache, key), to: Cachex
+
+ @impl true
+ defdelegate put(cache, key, value, options), to: Cachex
+
+ @impl true
+ defdelegate put(cache, key, value), to: Cachex
+
+ @impl true
+ defdelegate get_and_update(cache, key, func), to: Cachex
+
+ @impl true
+ defdelegate get(cache, key), to: Cachex
+
+ @impl true
+ defdelegate fetch!(cache, key, func), to: Cachex
+
+ @impl true
+ defdelegate expire_at(cache, str, num), to: Cachex
+
+ @impl true
+ defdelegate exists?(cache, key), to: Cachex
+
+ @impl true
+ defdelegate del(cache, key), to: Cachex
+
+ @impl true
+ defdelegate execute!(cache, func), to: Cachex
+end
diff --git a/test/support/captcha_mock.ex b/test/support/captcha/mock.ex
index 2ed2ba3b4..175ade131 100644
--- a/test/support/captcha_mock.ex
+++ b/test/support/captcha/mock.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Captcha.Mock do
diff --git a/test/support/channel_case.ex b/test/support/channel_case.ex
index d63a0f06b..1fbf6f100 100644
--- a/test/support/channel_case.ex
+++ b/test/support/channel_case.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ChannelCase do
@@ -22,7 +22,7 @@ defmodule Pleroma.Web.ChannelCase do
using do
quote do
# Import conveniences for testing with channels
- use Phoenix.ChannelTest
+ import Phoenix.ChannelTest
use Pleroma.Tests.Helpers
# The default endpoint for testing
@@ -30,13 +30,5 @@ defmodule Pleroma.Web.ChannelCase do
end
end
- setup tags do
- :ok = Ecto.Adapters.SQL.Sandbox.checkout(Pleroma.Repo)
-
- unless tags[:async] do
- Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, {:shared, self()})
- end
-
- :ok
- end
+ setup tags, do: Pleroma.DataCase.setup_multi_process_mode(tags)
end
diff --git a/test/support/conn_case.ex b/test/support/conn_case.ex
index 7ef681258..eab469833 100644
--- a/test/support/conn_case.ex
+++ b/test/support/conn_case.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ConnCase do
@@ -19,10 +19,13 @@ defmodule Pleroma.Web.ConnCase do
use ExUnit.CaseTemplate
+ alias Pleroma.DataCase
+
using do
quote do
# Import conveniences for testing with connections
- use Phoenix.ConnTest
+ import Plug.Conn
+ import Phoenix.ConnTest
use Pleroma.Tests.Helpers
import Pleroma.Web.Router.Helpers
@@ -64,13 +67,11 @@ defmodule Pleroma.Web.ConnCase do
end
defp json_response_and_validate_schema(
- %{
- private: %{
- open_api_spex: %{operation_id: op_id, operation_lookup: lookup, spec: spec}
- }
- } = conn,
+ %{private: %{operation_id: op_id}} = conn,
status
) do
+ {spec, lookup} = OpenApiSpex.Plug.PutApiSpec.get_spec_and_operation_lookup(conn)
+
content_type =
conn
|> Plug.Conn.get_resp_header("content-type")
@@ -101,9 +102,7 @@ defmodule Pleroma.Web.ConnCase do
end)
flunk(
- "Response does not conform to schema of #{op_id} operation: #{
- Enum.join(errors, "\n")
- }\n#{inspect(json)}"
+ "Response does not conform to schema of #{op_id} operation: #{Enum.join(errors, "\n")}\n#{inspect(json)}"
)
end
end
@@ -111,47 +110,15 @@ defmodule Pleroma.Web.ConnCase do
defp json_response_and_validate_schema(conn, _status) do
flunk("Response schema not found for #{conn.method} #{conn.request_path} #{conn.status}")
end
-
- defp ensure_federating_or_authenticated(conn, url, user) do
- initial_setting = Config.get([:instance, :federating])
- on_exit(fn -> Config.put([:instance, :federating], initial_setting) end)
-
- Config.put([:instance, :federating], false)
-
- conn
- |> get(url)
- |> response(403)
-
- conn
- |> assign(:user, user)
- |> get(url)
- |> response(200)
-
- Config.put([:instance, :federating], true)
-
- conn
- |> get(url)
- |> response(200)
- end
end
end
setup tags do
- Cachex.clear(:user_cache)
- Cachex.clear(:object_cache)
- :ok = Ecto.Adapters.SQL.Sandbox.checkout(Pleroma.Repo)
+ DataCase.setup_multi_process_mode(tags)
+ DataCase.setup_streamer(tags)
+ DataCase.stub_pipeline()
- unless tags[:async] do
- Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, {:shared, self()})
- end
-
- if tags[:needs_streamer] do
- start_supervised(%{
- id: Pleroma.Web.Streamer.registry(),
- start:
- {Registry, :start_link, [[keys: :duplicate, name: Pleroma.Web.Streamer.registry()]]}
- })
- end
+ Mox.verify_on_exit!()
{:ok, conn: Phoenix.ConnTest.build_conn()}
end
diff --git a/test/support/data_case.ex b/test/support/data_case.ex
index ba8848952..0ee2aa4a2 100644
--- a/test/support/data_case.ex
+++ b/test/support/data_case.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.DataCase do
@@ -18,6 +18,8 @@ defmodule Pleroma.DataCase do
use ExUnit.CaseTemplate
+ import Pleroma.Tests.Helpers, only: [clear_config: 2]
+
using do
quote do
alias Pleroma.Repo
@@ -27,18 +29,59 @@ defmodule Pleroma.DataCase do
import Ecto.Query
import Pleroma.DataCase
use Pleroma.Tests.Helpers
+
+ # Sets up OAuth access with specified scopes
+ defp oauth_access(scopes, opts \\ []) do
+ user =
+ Keyword.get_lazy(opts, :user, fn ->
+ Pleroma.Factory.insert(:user)
+ end)
+
+ token =
+ Keyword.get_lazy(opts, :oauth_token, fn ->
+ Pleroma.Factory.insert(:oauth_token, user: user, scopes: scopes)
+ end)
+
+ %{user: user, token: token}
+ end
end
end
- setup tags do
- Cachex.clear(:user_cache)
- Cachex.clear(:object_cache)
+ def clear_cachex do
+ Pleroma.Supervisor
+ |> Supervisor.which_children()
+ |> Enum.each(fn
+ {name, _, _, [Cachex]} ->
+ name
+ |> to_string
+ |> String.trim_leading("cachex_")
+ |> Kernel.<>("_cache")
+ |> String.to_existing_atom()
+ |> Cachex.clear()
+
+ _ ->
+ nil
+ end)
+ end
+
+ def setup_multi_process_mode(tags) do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(Pleroma.Repo)
- unless tags[:async] do
+ if tags[:async] do
+ Mox.stub_with(Pleroma.CachexMock, Pleroma.NullCache)
+ Mox.set_mox_private()
+ else
Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, {:shared, self()})
+
+ Mox.set_mox_global()
+ Mox.stub_with(Pleroma.CachexMock, Pleroma.CachexProxy)
+ clear_cachex()
end
+ :ok
+ end
+
+ def setup_streamer(tags) do
if tags[:needs_streamer] do
start_supervised(%{
id: Pleroma.Web.Streamer.registry(),
@@ -50,18 +93,35 @@ defmodule Pleroma.DataCase do
:ok
end
- def ensure_local_uploader(context) do
- test_uploader = Map.get(context, :uploader, Pleroma.Uploaders.Local)
- uploader = Pleroma.Config.get([Pleroma.Upload, :uploader])
- filters = Pleroma.Config.get([Pleroma.Upload, :filters])
+ setup tags do
+ setup_multi_process_mode(tags)
+ setup_streamer(tags)
+ stub_pipeline()
- Pleroma.Config.put([Pleroma.Upload, :uploader], test_uploader)
- Pleroma.Config.put([Pleroma.Upload, :filters], [])
+ Mox.verify_on_exit!()
- on_exit(fn ->
- Pleroma.Config.put([Pleroma.Upload, :uploader], uploader)
- Pleroma.Config.put([Pleroma.Upload, :filters], filters)
- end)
+ :ok
+ end
+
+ def stub_pipeline do
+ Mox.stub_with(Pleroma.Web.ActivityPub.SideEffectsMock, Pleroma.Web.ActivityPub.SideEffects)
+
+ Mox.stub_with(
+ Pleroma.Web.ActivityPub.ObjectValidatorMock,
+ Pleroma.Web.ActivityPub.ObjectValidator
+ )
+
+ Mox.stub_with(Pleroma.Web.ActivityPub.MRFMock, Pleroma.Web.ActivityPub.MRF)
+ Mox.stub_with(Pleroma.Web.ActivityPub.ActivityPubMock, Pleroma.Web.ActivityPub.ActivityPub)
+ Mox.stub_with(Pleroma.Web.FederatorMock, Pleroma.Web.Federator)
+ Mox.stub_with(Pleroma.ConfigMock, Pleroma.Config)
+ end
+
+ def ensure_local_uploader(context) do
+ test_uploader = Map.get(context, :uploader) || Pleroma.Uploaders.Local
+
+ clear_config([Pleroma.Upload, :uploader], test_uploader)
+ clear_config([Pleroma.Upload, :filters], [])
:ok
end
diff --git a/test/support/factory.ex b/test/support/factory.ex
index 486eda8da..4a78425ce 100644
--- a/test/support/factory.ex
+++ b/test/support/factory.ex
@@ -1,9 +1,12 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Factory do
use ExMachina.Ecto, repo: Pleroma.Repo
+
+ require Pleroma.Constants
+
alias Pleroma.Object
alias Pleroma.User
@@ -24,13 +27,14 @@ defmodule Pleroma.Factory do
}
end
- def user_factory do
+ def user_factory(attrs \\ %{}) do
user = %User{
name: sequence(:name, &"Test テスト User #{&1}"),
email: sequence(:email, &"user#{&1}@example.com"),
nickname: sequence(:nickname, &"nick#{&1}"),
- password_hash: Pbkdf2.hash_pwd_salt("test"),
+ password_hash: Pleroma.Password.Pbkdf2.hash_pwd_salt("test"),
bio: sequence(:bio, &"Tester Number #{&1}"),
+ is_discoverable: true,
last_digest_emailed_at: NaiveDateTime.utc_now(),
last_refreshed_at: NaiveDateTime.utc_now(),
notification_settings: %Pleroma.User.NotificationSetting{},
@@ -38,13 +42,33 @@ defmodule Pleroma.Factory do
ap_enabled: true
}
- %{
- user
- | ap_id: User.ap_id(user),
- follower_address: User.ap_followers(user),
- following_address: User.ap_following(user),
- raw_bio: user.bio
- }
+ urls =
+ if attrs[:local] == false do
+ base_domain = attrs[:domain] || Enum.random(["domain1.com", "domain2.com", "domain3.com"])
+
+ ap_id = "https://#{base_domain}/users/#{user.nickname}"
+
+ %{
+ ap_id: ap_id,
+ follower_address: ap_id <> "/followers",
+ following_address: ap_id <> "/following",
+ featured_address: ap_id <> "/collections/featured"
+ }
+ else
+ %{
+ ap_id: User.ap_id(user),
+ follower_address: User.ap_followers(user),
+ following_address: User.ap_following(user),
+ featured_address: User.ap_featured_collection(user)
+ }
+ end
+
+ attrs = Map.delete(attrs, :domain)
+
+ user
+ |> Map.put(:raw_bio, user.bio)
+ |> Map.merge(urls)
+ |> merge_attributes(attrs)
end
def user_relationship_factory(attrs \\ %{}) do
@@ -87,6 +111,42 @@ defmodule Pleroma.Factory do
}
end
+ def attachment_note_factory(attrs \\ %{}) do
+ user = attrs[:user] || insert(:user)
+ {length, attrs} = Map.pop(attrs, :length, 1)
+
+ data = %{
+ "attachment" =>
+ Stream.repeatedly(fn -> attachment_data(user.ap_id, attrs[:href]) end)
+ |> Enum.take(length)
+ }
+
+ build(:note, Map.put(attrs, :data, data))
+ end
+
+ defp attachment_data(ap_id, href) do
+ href = href || sequence(:href, &"#{Pleroma.Web.Endpoint.url()}/media/#{&1}.jpg")
+
+ %{
+ "url" => [
+ %{
+ "href" => href,
+ "type" => "Link",
+ "mediaType" => "image/jpeg"
+ }
+ ],
+ "name" => "some name",
+ "type" => "Document",
+ "actor" => ap_id,
+ "mediaType" => "image/jpeg"
+ }
+ end
+
+ def followers_only_note_factory(attrs \\ %{}) do
+ %Pleroma.Object{data: data} = note_factory(attrs)
+ %Pleroma.Object{data: Map.merge(data, %{"to" => [data["actor"] <> "/followers"]})}
+ end
+
def audio_factory(attrs \\ %{}) do
text = sequence(:text, &"lain radio episode #{&1}")
@@ -136,8 +196,8 @@ defmodule Pleroma.Factory do
end
def article_factory do
- note_factory()
- |> Map.put("type", "Article")
+ %Pleroma.Object{data: data} = note_factory()
+ %Pleroma.Object{data: Map.merge(data, %{"type" => "Article"})}
end
def tombstone_factory do
@@ -153,6 +213,38 @@ defmodule Pleroma.Factory do
}
end
+ def question_factory(attrs \\ %{}) do
+ user = attrs[:user] || insert(:user)
+
+ data = %{
+ "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id(),
+ "type" => "Question",
+ "actor" => user.ap_id,
+ "attributedTo" => user.ap_id,
+ "attachment" => [],
+ "to" => ["https://www.w3.org/ns/activitystreams#Public"],
+ "cc" => [user.follower_address],
+ "context" => Pleroma.Web.ActivityPub.Utils.generate_context_id(),
+ "closed" => DateTime.utc_now() |> DateTime.add(86_400) |> DateTime.to_iso8601(),
+ "oneOf" => [
+ %{
+ "type" => "Note",
+ "name" => "chocolate",
+ "replies" => %{"totalItems" => 0, "type" => "Collection"}
+ },
+ %{
+ "type" => "Note",
+ "name" => "vanilla",
+ "replies" => %{"totalItems" => 0, "type" => "Collection"}
+ }
+ ]
+ }
+
+ %Pleroma.Object{
+ data: merge_attributes(data, Map.get(attrs, :data, %{}))
+ }
+ end
+
def direct_note_activity_factory do
dm = insert(:direct_note)
@@ -173,10 +265,49 @@ defmodule Pleroma.Factory do
}
end
- def note_activity_factory(attrs \\ %{}) do
+ def add_activity_factory(attrs \\ %{}) do
+ featured_collection_activity(attrs, "Add")
+ end
+
+ def remove_activity_factor(attrs \\ %{}) do
+ featured_collection_activity(attrs, "Remove")
+ end
+
+ defp featured_collection_activity(attrs, type) do
user = attrs[:user] || insert(:user)
note = attrs[:note] || insert(:note, user: user)
+ data_attrs =
+ attrs
+ |> Map.get(:data_attrs, %{})
+ |> Map.put(:type, type)
+
+ attrs = Map.drop(attrs, [:user, :note, :data_attrs])
+
+ data =
+ %{
+ "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
+ "target" => user.featured_address,
+ "object" => note.data["object"],
+ "actor" => note.data["actor"],
+ "type" => "Add",
+ "to" => [Pleroma.Constants.as_public()],
+ "cc" => [user.follower_address]
+ }
+ |> Map.merge(data_attrs)
+
+ %Pleroma.Activity{
+ data: data,
+ actor: data["actor"],
+ recipients: data["to"]
+ }
+ |> Map.merge(attrs)
+ end
+
+ def followers_only_note_activity_factory(attrs \\ %{}) do
+ user = attrs[:user] || insert(:user)
+ note = insert(:followers_only_note, user: user)
+
data_attrs = attrs[:data_attrs] || %{}
attrs = Map.drop(attrs, [:user, :note, :data_attrs])
@@ -186,7 +317,7 @@ defmodule Pleroma.Factory do
"type" => "Create",
"actor" => note.data["actor"],
"to" => note.data["to"],
- "object" => note.data["id"],
+ "object" => note.data,
"published" => DateTime.utc_now() |> DateTime.to_iso8601(),
"context" => note.data["context"]
}
@@ -200,23 +331,31 @@ defmodule Pleroma.Factory do
|> Map.merge(attrs)
end
- defp expiration_offset_by_minutes(attrs, minutes) do
- scheduled_at =
- NaiveDateTime.utc_now()
- |> NaiveDateTime.add(:timer.minutes(minutes), :millisecond)
- |> NaiveDateTime.truncate(:second)
+ def note_activity_factory(attrs \\ %{}) do
+ user = attrs[:user] || insert(:user)
+ note = attrs[:note] || insert(:note, user: user)
- %Pleroma.ActivityExpiration{}
- |> Map.merge(attrs)
- |> Map.put(:scheduled_at, scheduled_at)
- end
+ data_attrs = attrs[:data_attrs] || %{}
+ attrs = Map.drop(attrs, [:user, :note, :data_attrs])
- def expiration_in_the_past_factory(attrs \\ %{}) do
- expiration_offset_by_minutes(attrs, -60)
- end
+ data =
+ %{
+ "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
+ "type" => "Create",
+ "actor" => note.data["actor"],
+ "to" => note.data["to"],
+ "object" => note.data["id"],
+ "published" => DateTime.utc_now() |> DateTime.to_iso8601(),
+ "context" => note.data["context"]
+ }
+ |> Map.merge(data_attrs)
- def expiration_in_the_future_factory(attrs \\ %{}) do
- expiration_offset_by_minutes(attrs, 61)
+ %Pleroma.Activity{
+ data: data,
+ actor: data["actor"],
+ recipients: data["to"]
+ }
+ |> Map.merge(attrs)
end
def article_activity_factory do
@@ -261,7 +400,7 @@ defmodule Pleroma.Factory do
def like_activity_factory(attrs \\ %{}) do
note_activity = attrs[:note_activity] || insert(:note_activity)
- object = Object.normalize(note_activity)
+ object = Object.normalize(note_activity, fetch: false)
user = insert(:user)
data =
@@ -321,6 +460,33 @@ defmodule Pleroma.Factory do
}
end
+ def question_activity_factory(attrs \\ %{}) do
+ user = attrs[:user] || insert(:user)
+ question = attrs[:question] || insert(:question, user: user)
+
+ data_attrs = attrs[:data_attrs] || %{}
+ attrs = Map.drop(attrs, [:user, :question, :data_attrs])
+
+ data =
+ %{
+ "id" => Pleroma.Web.ActivityPub.Utils.generate_activity_id(),
+ "type" => "Create",
+ "actor" => question.data["actor"],
+ "to" => question.data["to"],
+ "object" => question.data["id"],
+ "published" => DateTime.utc_now() |> DateTime.to_iso8601(),
+ "context" => question.data["context"]
+ }
+ |> Map.merge(data_attrs)
+
+ %Pleroma.Activity{
+ data: data,
+ actor: data["actor"],
+ recipients: data["to"]
+ }
+ |> Map.merge(attrs)
+ end
+
def oauth_app_factory do
%Pleroma.Web.OAuth.App{
client_name: sequence(:client_name, &"Some client #{&1}"),
@@ -457,7 +623,8 @@ defmodule Pleroma.Factory do
%Pleroma.Filter{
user: build(:user),
filter_id: sequence(:filter_id, & &1),
- phrase: "cofe"
+ phrase: "cofe",
+ context: ["home"]
}
end
end
diff --git a/test/support/helpers.ex b/test/support/helpers.ex
index ecd4b1e18..34f1505d0 100644
--- a/test/support/helpers.ex
+++ b/test/support/helpers.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Tests.Helpers do
@@ -8,6 +8,8 @@ defmodule Pleroma.Tests.Helpers do
"""
alias Pleroma.Config
+ require Logger
+
defmacro clear_config(config_path) do
quote do
clear_config(unquote(config_path)) do
@@ -18,6 +20,7 @@ defmodule Pleroma.Tests.Helpers do
defmacro clear_config(config_path, do: yield) do
quote do
initial_setting = Config.fetch(unquote(config_path))
+
unquote(yield)
on_exit(fn ->
@@ -35,6 +38,14 @@ defmodule Pleroma.Tests.Helpers do
end
defmacro clear_config(config_path, temp_setting) do
+ # NOTE: `clear_config([section, key], value)` != `clear_config([section], key: value)` (!)
+ # Displaying a warning to prevent unintentional clearing of all but one keys in section
+ if Keyword.keyword?(temp_setting) and length(temp_setting) == 1 do
+ Logger.warn(
+ "Please change `clear_config([section], key: value)` to `clear_config([section, key], value)`"
+ )
+ end
+
quote do
clear_config(unquote(config_path)) do
Config.put(unquote(config_path), unquote(temp_setting))
@@ -55,6 +66,14 @@ defmodule Pleroma.Tests.Helpers do
clear_config: 2
]
+ def time_travel(entity, seconds) do
+ new_time = NaiveDateTime.add(entity.inserted_at, seconds)
+
+ entity
+ |> Ecto.Changeset.change(%{inserted_at: new_time, updated_at: new_time})
+ |> Pleroma.Repo.update()
+ end
+
def to_datetime(%NaiveDateTime{} = naive_datetime) do
naive_datetime
|> DateTime.from_naive!("Etc/UTC")
@@ -85,8 +104,8 @@ defmodule Pleroma.Tests.Helpers do
assigns = Map.new(assigns)
view.render(template, assigns)
- |> Poison.encode!()
- |> Poison.decode!()
+ |> Jason.encode!()
+ |> Jason.decode!()
end
def stringify_keys(nil), do: nil
diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex
index a0ebf65d9..94900dc14 100644
--- a/test/support/http_request_mock.ex
+++ b/test/support/http_request_mock.ex
@@ -1,10 +1,12 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule HttpRequestMock do
require Logger
+ def activitypub_object_headers, do: [{"content-type", "application/activity+json"}]
+
def request(
%Tesla.Env{
url: url,
@@ -34,7 +36,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/https___osada.macgirvin.com_channel_mike.json")
+ body: File.read!("test/fixtures/tesla_mock/https___osada.macgirvin.com_channel_mike.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -42,7 +45,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/moonman@shitposter.club.json")
+ body: File.read!("test/fixtures/tesla_mock/moonman@shitposter.club.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -50,7 +54,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/status.emelie.json")
+ body: File.read!("test/fixtures/tesla_mock/status.emelie.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -66,7 +71,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/emelie.json")
+ body: File.read!("test/fixtures/tesla_mock/emelie.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -78,7 +84,20 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/rinpatch.json")
+ body: File.read!("test/fixtures/tesla_mock/rinpatch.json"),
+ headers: activitypub_object_headers()
+ }}
+ end
+
+ def get("https://mastodon.sdf.org/users/rinpatch/collections/featured", _, _, _) do
+ {:ok,
+ %Tesla.Env{
+ status: 200,
+ body:
+ File.read!("test/fixtures/users_mock/masto_featured.json")
+ |> String.replace("{{domain}}", "mastodon.sdf.org")
+ |> String.replace("{{nickname}}", "rinpatch"),
+ headers: [{"content-type", "application/activity+json"}]
}}
end
@@ -86,7 +105,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/poll_attachment.json")
+ body: File.read!("test/fixtures/tesla_mock/poll_attachment.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -99,15 +119,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/webfinger_emelie.json")
- }}
- end
-
- def get("https://mastodon.social/users/emelie.atom", _, _, _) do
- {:ok,
- %Tesla.Env{
- status: 200,
- body: File.read!("test/fixtures/tesla_mock/emelie.atom")
+ body: File.read!("test/fixtures/tesla_mock/webfinger_emelie.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -120,7 +133,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/mike@osada.macgirvin.com.json")
+ body: File.read!("test/fixtures/tesla_mock/mike@osada.macgirvin.com.json"),
+ headers: [{"content-type", "application/jrd+json"}]
}}
end
@@ -137,14 +151,6 @@ defmodule HttpRequestMock do
}}
end
- def get("https://pawoo.net/users/pekorino.atom", _, _, _) do
- {:ok,
- %Tesla.Env{
- status: 200,
- body: File.read!("test/fixtures/tesla_mock/https___pawoo.net_users_pekorino.atom")
- }}
- end
-
def get(
"https://pawoo.net/.well-known/webfinger?resource=acct:https://pawoo.net/users/pekorino",
_,
@@ -159,19 +165,6 @@ defmodule HttpRequestMock do
end
def get(
- "https://social.stopwatchingus-heidelberg.de/api/statuses/user_timeline/18330.atom",
- _,
- _,
- _
- ) do
- {:ok,
- %Tesla.Env{
- status: 200,
- body: File.read!("test/fixtures/tesla_mock/atarifrosch_feed.xml")
- }}
- end
-
- def get(
"https://social.stopwatchingus-heidelberg.de/.well-known/webfinger?resource=acct:https://social.stopwatchingus-heidelberg.de/user/18330",
_,
_,
@@ -184,27 +177,6 @@ defmodule HttpRequestMock do
}}
end
- def get("https://mamot.fr/users/Skruyb.atom", _, _, _) do
- {:ok,
- %Tesla.Env{
- status: 200,
- body: File.read!("test/fixtures/tesla_mock/https___mamot.fr_users_Skruyb.atom")
- }}
- end
-
- def get(
- "https://mamot.fr/.well-known/webfinger?resource=acct:https://mamot.fr/users/Skruyb",
- _,
- _,
- [{"accept", "application/xrd+xml,application/jrd+json"}]
- ) do
- {:ok,
- %Tesla.Env{
- status: 200,
- body: File.read!("test/fixtures/tesla_mock/skruyb@mamot.fr.atom")
- }}
- end
-
def get(
"https://social.heldscal.la/.well-known/webfinger?resource=nonexistant@social.heldscal.la",
_,
@@ -227,7 +199,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/lain_squeet.me_webfinger.xml")
+ body: File.read!("test/fixtures/tesla_mock/lain_squeet.me_webfinger.xml"),
+ headers: [{"content-type", "application/xrd+xml"}]
}}
end
@@ -240,7 +213,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/lucifermysticus.json")
+ body: File.read!("test/fixtures/tesla_mock/lucifermysticus.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -248,7 +222,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/https___prismo.news__mxb.json")
+ body: File.read!("test/fixtures/tesla_mock/https___prismo.news__mxb.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -261,7 +236,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/kaniini@hubzilla.example.org.json")
+ body: File.read!("test/fixtures/tesla_mock/kaniini@hubzilla.example.org.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -269,7 +245,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/rye.json")
+ body: File.read!("test/fixtures/tesla_mock/rye.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -277,7 +254,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/rye.json")
+ body: File.read!("test/fixtures/tesla_mock/rye.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -296,7 +274,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/puckipedia.com.json")
+ body: File.read!("test/fixtures/tesla_mock/puckipedia.com.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -304,7 +283,17 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/7even.json")
+ body: File.read!("test/fixtures/tesla_mock/7even.json"),
+ headers: activitypub_object_headers()
+ }}
+ end
+
+ def get("https://peertube.stream/accounts/createurs", _, _, _) do
+ {:ok,
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/peertube/actor-person.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -312,7 +301,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/peertube.moe-vid.json")
+ body: File.read!("test/fixtures/tesla_mock/peertube.moe-vid.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -320,7 +310,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/https___framatube.org_accounts_framasoft.json")
+ body: File.read!("test/fixtures/tesla_mock/https___framatube.org_accounts_framasoft.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -328,7 +319,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/framatube.org-video.json")
+ body: File.read!("test/fixtures/tesla_mock/framatube.org-video.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -336,7 +328,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/craigmaloney.json")
+ body: File.read!("test/fixtures/tesla_mock/craigmaloney.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -344,7 +337,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/peertube-social.json")
+ body: File.read!("test/fixtures/tesla_mock/peertube-social.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -354,7 +348,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/mobilizon.org-event.json")
+ body: File.read!("test/fixtures/tesla_mock/mobilizon.org-event.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -362,7 +357,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/mobilizon.org-user.json")
+ body: File.read!("test/fixtures/tesla_mock/mobilizon.org-user.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -370,7 +366,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/baptiste.gelex.xyz-user.json")
+ body: File.read!("test/fixtures/tesla_mock/baptiste.gelex.xyz-user.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -378,7 +375,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/baptiste.gelex.xyz-article.json")
+ body: File.read!("test/fixtures/tesla_mock/baptiste.gelex.xyz-article.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -386,7 +384,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/wedistribute-article.json")
+ body: File.read!("test/fixtures/tesla_mock/wedistribute-article.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -394,7 +393,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/wedistribute-user.json")
+ body: File.read!("test/fixtures/tesla_mock/wedistribute-user.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -402,7 +402,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/admin@mastdon.example.org.json")
+ body: File.read!("test/fixtures/tesla_mock/admin@mastdon.example.org.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -412,7 +413,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/relay@mastdon.example.org.json")
+ body: File.read!("test/fixtures/tesla_mock/relay@mastdon.example.org.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -507,19 +509,6 @@ defmodule HttpRequestMock do
}}
end
- def get(
- "https://mamot.fr/.well-known/webfinger?resource=https://mamot.fr/users/Skruyb",
- _,
- _,
- _
- ) do
- {:ok,
- %Tesla.Env{
- status: 200,
- body: File.read!("test/fixtures/tesla_mock/skruyb@mamot.fr.atom")
- }}
- end
-
def get("http://pawoo.net/.well-known/host-meta", _, _, _) do
{:ok,
%Tesla.Env{
@@ -545,23 +534,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/pekorino@pawoo.net_host_meta.json")
- }}
- end
-
- def get("http://zetsubou.xn--q9jyb4c/.well-known/host-meta", _, _, _) do
- {:ok,
- %Tesla.Env{
- status: 200,
- body: File.read!("test/fixtures/tesla_mock/xn--q9jyb4c_host_meta")
- }}
- end
-
- def get("https://zetsubou.xn--q9jyb4c/.well-known/host-meta", _, _, _) do
- {:ok,
- %Tesla.Env{
- status: 200,
- body: File.read!("test/fixtures/tesla_mock/xn--q9jyb4c_host_meta")
+ body: File.read!("test/fixtures/tesla_mock/pekorino@pawoo.net_host_meta.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -606,7 +580,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/mastodon-note-object.json")
+ body: File.read!("test/fixtures/mastodon-note-object.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -630,7 +605,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/mayumayu.json")
+ body: File.read!("test/fixtures/tesla_mock/mayumayu.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -643,18 +619,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/mayumayupost.json")
- }}
- end
-
- def get("https://pleroma.soykaf.com/users/lain/feed.atom", _, _, _) do
- {:ok,
- %Tesla.Env{
- status: 200,
- body:
- File.read!(
- "test/fixtures/tesla_mock/https___pleroma.soykaf.com_users_lain_feed.atom.xml"
- )
+ body: File.read!("test/fixtures/tesla_mock/mayumayupost.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -670,17 +636,6 @@ defmodule HttpRequestMock do
}}
end
- def get("https://shitposter.club/api/statuses/user_timeline/1.atom", _, _, _) do
- {:ok,
- %Tesla.Env{
- status: 200,
- body:
- File.read!(
- "test/fixtures/tesla_mock/https___shitposter.club_api_statuses_user_timeline_1.atom.xml"
- )
- }}
- end
-
def get(
"https://shitposter.club/.well-known/webfinger?resource=https://shitposter.club/user/1",
_,
@@ -694,37 +649,10 @@ defmodule HttpRequestMock do
}}
end
- def get("https://shitposter.club/notice/2827873", _, _, _) do
- {:ok,
- %Tesla.Env{
- status: 200,
- body: File.read!("test/fixtures/tesla_mock/https___shitposter.club_notice_2827873.json")
- }}
- end
-
- def get("https://shitposter.club/api/statuses/show/2827873.atom", _, _, _) do
- {:ok,
- %Tesla.Env{
- status: 200,
- body:
- File.read!(
- "test/fixtures/tesla_mock/https___shitposter.club_api_statuses_show_2827873.atom.xml"
- )
- }}
- end
-
def get("https://testing.pleroma.lol/objects/b319022a-4946-44c5-9de9-34801f95507b", _, _, _) do
{:ok, %Tesla.Env{status: 200}}
end
- def get("https://shitposter.club/api/statuses/user_timeline/5381.atom", _, _, _) do
- {:ok,
- %Tesla.Env{
- status: 200,
- body: File.read!("test/fixtures/tesla_mock/spc_5381.atom")
- }}
- end
-
def get(
"https://shitposter.club/.well-known/webfinger?resource=https://shitposter.club/user/5381",
_,
@@ -746,14 +674,6 @@ defmodule HttpRequestMock do
}}
end
- def get("https://shitposter.club/api/statuses/show/7369654.atom", _, _, _) do
- {:ok,
- %Tesla.Env{
- status: 200,
- body: File.read!("test/fixtures/tesla_mock/7369654.atom")
- }}
- end
-
def get("https://shitposter.club/notice/4027863", _, _, _) do
{:ok,
%Tesla.Env{
@@ -762,14 +682,6 @@ defmodule HttpRequestMock do
}}
end
- def get("https://social.sakamoto.gq/users/eal/feed.atom", _, _, _) do
- {:ok,
- %Tesla.Env{
- status: 200,
- body: File.read!("test/fixtures/tesla_mock/sakamoto_eal_feed.atom")
- }}
- end
-
def get("http://social.sakamoto.gq/.well-known/host-meta", _, _, _) do
{:ok,
%Tesla.Env{
@@ -791,15 +703,6 @@ defmodule HttpRequestMock do
}}
end
- def get(
- "https://social.sakamoto.gq/objects/0ccc1a2c-66b0-4305-b23a-7f7f2b040056",
- _,
- _,
- [{"accept", "application/atom+xml"}]
- ) do
- {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/sakamoto.atom")}}
- end
-
def get("http://mastodon.social/.well-known/host-meta", _, _, _) do
{:ok,
%Tesla.Env{
@@ -853,28 +756,6 @@ defmodule HttpRequestMock do
{:ok, %Tesla.Env{status: 406, body: ""}}
end
- def get("http://gs.example.org/index.php/api/statuses/user_timeline/1.atom", _, _, _) do
- {:ok,
- %Tesla.Env{
- status: 200,
- body:
- File.read!(
- "test/fixtures/tesla_mock/http__gs.example.org_index.php_api_statuses_user_timeline_1.atom.xml"
- )
- }}
- end
-
- def get("https://social.heldscal.la/api/statuses/user_timeline/29191.atom", _, _, _) do
- {:ok,
- %Tesla.Env{
- status: 200,
- body:
- File.read!(
- "test/fixtures/tesla_mock/https___social.heldscal.la_api_statuses_user_timeline_29191.atom.xml"
- )
- }}
- end
-
def get("http://squeet.me/.well-known/host-meta", _, _, _) do
{:ok,
%Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/squeet.me_host_meta")}}
@@ -902,7 +783,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/shp@social.heldscal.la.xml")
+ body: File.read!("test/fixtures/tesla_mock/shp@social.heldscal.la.xml"),
+ headers: [{"content-type", "application/xrd+xml"}]
}}
end
@@ -912,7 +794,7 @@ defmodule HttpRequestMock do
_,
[{"accept", "application/xrd+xml,application/jrd+json"}]
) do
- {:ok, %Tesla.Env{status: 200, body: ""}}
+ {:ok, %Tesla.Env{status: 200, body: "", headers: [{"content-type", "application/jrd+json"}]}}
end
def get("http://framatube.org/.well-known/host-meta", _, _, _) do
@@ -932,7 +814,7 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- headers: [{"content-type", "application/json"}],
+ headers: [{"content-type", "application/jrd+json"}],
body: File.read!("test/fixtures/tesla_mock/framasoft@framatube.org.json")
}}
end
@@ -954,7 +836,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/winterdienst_webfinger.json")
+ body: File.read!("test/fixtures/tesla_mock/winterdienst_webfinger.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -991,22 +874,11 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- headers: [{"content-type", "application/json"}],
+ headers: [{"content-type", "application/jrd+json"}],
body: File.read!("test/fixtures/tesla_mock/kaniini@gerzilla.de.json")
}}
end
- def get("https://social.heldscal.la/api/statuses/user_timeline/23211.atom", _, _, _) do
- {:ok,
- %Tesla.Env{
- status: 200,
- body:
- File.read!(
- "test/fixtures/tesla_mock/https___social.heldscal.la_api_statuses_user_timeline_23211.atom.xml"
- )
- }}
- end
-
def get(
"https://social.heldscal.la/.well-known/webfinger?resource=https://social.heldscal.la/user/23211",
_,
@@ -1036,17 +908,34 @@ defmodule HttpRequestMock do
}}
end
- def get("https://mastodon.social/users/lambadalambda.atom", _, _, _) do
- {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/lambadalambda.atom")}}
+ def get("https://mastodon.social/users/lambadalambda", _, _, _) do
+ {:ok,
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/lambadalambda.json"),
+ headers: activitypub_object_headers()
+ }}
end
- def get("https://mastodon.social/users/lambadalambda", _, _, _) do
- {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/lambadalambda.json")}}
+ def get("https://mastodon.social/users/lambadalambda/collections/featured", _, _, _) do
+ {:ok,
+ %Tesla.Env{
+ status: 200,
+ body:
+ File.read!("test/fixtures/users_mock/masto_featured.json")
+ |> String.replace("{{domain}}", "mastodon.social")
+ |> String.replace("{{nickname}}", "lambadalambda"),
+ headers: activitypub_object_headers()
+ }}
end
def get("https://apfed.club/channel/indio", _, _, _) do
{:ok,
- %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/osada-user-indio.json")}}
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/tesla_mock/osada-user-indio.json"),
+ headers: activitypub_object_headers()
+ }}
end
def get("https://social.heldscal.la/user/23211", _, _, [{"accept", "application/activity+json"}]) do
@@ -1069,7 +958,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/users_mock/masto_closed_followers.json")
+ body: File.read!("test/fixtures/users_mock/masto_closed_followers.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -1077,7 +967,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/users_mock/masto_closed_followers_page.json")
+ body: File.read!("test/fixtures/users_mock/masto_closed_followers_page.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -1085,7 +976,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/users_mock/masto_closed_following.json")
+ body: File.read!("test/fixtures/users_mock/masto_closed_following.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -1093,7 +985,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/users_mock/masto_closed_following_page.json")
+ body: File.read!("test/fixtures/users_mock/masto_closed_following_page.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -1101,7 +994,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/users_mock/friendica_followers.json")
+ body: File.read!("test/fixtures/users_mock/friendica_followers.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -1109,7 +1003,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/users_mock/friendica_following.json")
+ body: File.read!("test/fixtures/users_mock/friendica_following.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -1117,7 +1012,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/users_mock/pleroma_followers.json")
+ body: File.read!("test/fixtures/users_mock/pleroma_followers.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -1125,7 +1021,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/users_mock/pleroma_following.json")
+ body: File.read!("test/fixtures/users_mock/pleroma_following.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -1187,7 +1084,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/lain.xml")
+ body: File.read!("test/fixtures/lain.xml"),
+ headers: [{"content-type", "application/xrd+xml"}]
}}
end
@@ -1200,7 +1098,16 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/lain.xml")
+ body: File.read!("test/fixtures/lain.xml"),
+ headers: [{"content-type", "application/xrd+xml"}]
+ }}
+ end
+
+ def get("http://zetsubou.xn--q9jyb4c/.well-known/host-meta", _, _, _) do
+ {:ok,
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/host-meta-zetsubou.xn--q9jyb4c.xml")
}}
end
@@ -1223,7 +1130,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/https__info.pleroma.site_activity.json")
+ body: File.read!("test/fixtures/tesla_mock/https__info.pleroma.site_activity.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -1237,7 +1145,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/https__info.pleroma.site_activity2.json")
+ body: File.read!("test/fixtures/tesla_mock/https__info.pleroma.site_activity2.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -1251,7 +1160,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/https__info.pleroma.site_activity3.json")
+ body: File.read!("test/fixtures/tesla_mock/https__info.pleroma.site_activity3.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -1263,7 +1173,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/kpherox@mstdn.jp.xml")
+ body: File.read!("test/fixtures/tesla_mock/kpherox@mstdn.jp.xml"),
+ headers: [{"content-type", "application/xrd+xml"}]
}}
end
@@ -1284,7 +1195,12 @@ defmodule HttpRequestMock do
end
def get("http://mastodon.example.org/@admin/99541947525187367", _, _, _) do
- {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/mastodon-post-activity.json")}}
+ {:ok,
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/mastodon-post-activity.json"),
+ headers: activitypub_object_headers()
+ }}
end
def get("https://info.pleroma.site/activity4.json", _, _, _) do
@@ -1311,7 +1227,8 @@ defmodule HttpRequestMock do
{:ok,
%Tesla.Env{
status: 200,
- body: File.read!("test/fixtures/tesla_mock/misskey_poll_no_end_date.json")
+ body: File.read!("test/fixtures/tesla_mock/misskey_poll_no_end_date.json"),
+ headers: activitypub_object_headers()
}}
end
@@ -1320,11 +1237,21 @@ defmodule HttpRequestMock do
end
def get("https://skippers-bin.com/users/7v1w1r8ce6", _, _, _) do
- {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/sjw.json")}}
+ {:ok,
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/tesla_mock/sjw.json"),
+ headers: activitypub_object_headers()
+ }}
end
def get("https://patch.cx/users/rin", _, _, _) do
- {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/rin.json")}}
+ {:ok,
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/tesla_mock/rin.json"),
+ headers: activitypub_object_headers()
+ }}
end
def get(
@@ -1334,12 +1261,20 @@ defmodule HttpRequestMock do
_
) do
{:ok,
- %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/funkwhale_audio.json")}}
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/tesla_mock/funkwhale_audio.json"),
+ headers: activitypub_object_headers()
+ }}
end
def get("https://channels.tests.funkwhale.audio/federation/actors/compositions", _, _, _) do
{:ok,
- %Tesla.Env{status: 200, body: File.read!("test/fixtures/tesla_mock/funkwhale_channel.json")}}
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/tesla_mock/funkwhale_channel.json"),
+ headers: activitypub_object_headers()
+ }}
end
def get("http://example.com/rel_me/error", _, _, _) do
@@ -1347,7 +1282,12 @@ defmodule HttpRequestMock do
end
def get("https://relay.mastodon.host/actor", _, _, _) do
- {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/relay/relay.json")}}
+ {:ok,
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/relay/relay.json"),
+ headers: activitypub_object_headers()
+ }}
end
def get("http://localhost:4001/", _, "", [{"accept", "text/html"}]) do
@@ -1362,11 +1302,18 @@ defmodule HttpRequestMock do
}}
end
+ def get("https://patch.cx/objects/a399c28e-c821-4820-bc3e-4afeb044c16f", _, _, _) do
+ {:ok,
+ %Tesla.Env{
+ status: 200,
+ body: File.read!("test/fixtures/tesla_mock/emoji-in-summary.json"),
+ headers: activitypub_object_headers()
+ }}
+ end
+
def get(url, query, body, headers) do
{:error,
- "Mock response not implemented for GET #{inspect(url)}, #{query}, #{inspect(body)}, #{
- inspect(headers)
- }"}
+ "Mock response not implemented for GET #{inspect(url)}, #{query}, #{inspect(body)}, #{inspect(headers)}"}
end
# POST Requests
@@ -1432,8 +1379,21 @@ defmodule HttpRequestMock do
def post(url, query, body, headers) do
{:error,
- "Mock response not implemented for POST #{inspect(url)}, #{query}, #{inspect(body)}, #{
- inspect(headers)
- }"}
+ "Mock response not implemented for POST #{inspect(url)}, #{query}, #{inspect(body)}, #{inspect(headers)}"}
+ end
+
+ # Most of the rich media mocks are missing HEAD requests, so we just return 404.
+ @rich_media_mocks [
+ "https://example.com/ogp",
+ "https://example.com/ogp-missing-data",
+ "https://example.com/twitter-card"
+ ]
+ def head(url, _query, _body, _headers) when url in @rich_media_mocks do
+ {:ok, %Tesla.Env{status: 404, body: ""}}
+ end
+
+ def head(url, query, body, headers) do
+ {:error,
+ "Mock response not implemented for HEAD #{inspect(url)}, #{query}, #{inspect(body)}, #{inspect(headers)}"}
end
end
diff --git a/test/support/mocks.ex b/test/support/mocks.ex
new file mode 100644
index 000000000..fd8f825b3
--- /dev/null
+++ b/test/support/mocks.ex
@@ -0,0 +1,30 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+Mox.defmock(Pleroma.CachexMock, for: Pleroma.Caching)
+
+Mox.defmock(Pleroma.Web.ActivityPub.ObjectValidatorMock,
+ for: Pleroma.Web.ActivityPub.ObjectValidator.Validating
+)
+
+Mox.defmock(Pleroma.Web.ActivityPub.MRFMock,
+ for: Pleroma.Web.ActivityPub.MRF.PipelineFiltering
+)
+
+Mox.defmock(Pleroma.Web.ActivityPub.ActivityPubMock,
+ for: [
+ Pleroma.Web.ActivityPub.ActivityPub.Persisting,
+ Pleroma.Web.ActivityPub.ActivityPub.Streaming
+ ]
+)
+
+Mox.defmock(Pleroma.Web.ActivityPub.SideEffectsMock,
+ for: Pleroma.Web.ActivityPub.SideEffects.Handling
+)
+
+Mox.defmock(Pleroma.Web.FederatorMock, for: Pleroma.Web.Federator.Publishing)
+
+Mox.defmock(Pleroma.ConfigMock, for: Pleroma.Config.Getting)
+
+Mox.defmock(Pleroma.LoggerMock, for: Pleroma.Logging)
diff --git a/test/support/mrf_module_mock.ex b/test/support/mrf_module_mock.ex
index 028ea542a..4d21d7fe0 100644
--- a/test/support/mrf_module_mock.ex
+++ b/test/support/mrf_module_mock.ex
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule MRFModuleMock do
- @behaviour Pleroma.Web.ActivityPub.MRF
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
@impl true
def filter(message), do: {:ok, message}
diff --git a/test/support/null_cache.ex b/test/support/null_cache.ex
new file mode 100644
index 000000000..47c10ebb6
--- /dev/null
+++ b/test/support/null_cache.ex
@@ -0,0 +1,49 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.NullCache do
+ @moduledoc """
+ A module simulating a permanently empty cache.
+ """
+ @behaviour Pleroma.Caching
+
+ @impl true
+ def get!(_, _), do: nil
+
+ @impl true
+ def put(_, _, _, _ \\ nil), do: {:ok, true}
+
+ @impl true
+ def stream!(_, _), do: []
+
+ @impl true
+ def get(_, _), do: {:ok, nil}
+
+ @impl true
+ def fetch!(_, key, func) do
+ case func.(key) do
+ {_, res} -> res
+ res -> res
+ end
+ end
+
+ @impl true
+ def get_and_update(_, _, func) do
+ func.(nil)
+ end
+
+ @impl true
+ def expire_at(_, _, _), do: {:ok, true}
+
+ @impl true
+ def exists?(_, _), do: {:ok, false}
+
+ @impl true
+ def execute!(_, func) do
+ func.(:nothing)
+ end
+
+ @impl true
+ def del(_, _), do: {:ok, true}
+end
diff --git a/test/support/oban_helpers.ex b/test/support/oban_helpers.ex
index 9f90a821c..9b6e5256e 100644
--- a/test/support/oban_helpers.ex
+++ b/test/support/oban_helpers.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Tests.ObanHelpers do
@@ -7,6 +7,8 @@ defmodule Pleroma.Tests.ObanHelpers do
Oban test helpers.
"""
+ require Ecto.Query
+
alias Pleroma.Repo
def wipe_all do
@@ -15,6 +17,7 @@ defmodule Pleroma.Tests.ObanHelpers do
def perform_all do
Oban.Job
+ |> Ecto.Query.where(state: "available")
|> Repo.all()
|> perform()
end
diff --git a/test/support/web_push_http_client_mock.ex b/test/support/web_push_http_client_mock.ex
deleted file mode 100644
index 3cd12957d..000000000
--- a/test/support/web_push_http_client_mock.ex
+++ /dev/null
@@ -1,23 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.WebPushHttpClientMock do
- def get(url, headers \\ [], options \\ []) do
- {
- res,
- %Tesla.Env{status: status}
- } = Pleroma.HTTP.request(:get, url, "", headers, options)
-
- {res, %{status_code: status}}
- end
-
- def post(url, body, headers \\ [], options \\ []) do
- {
- res,
- %Tesla.Env{status: status}
- } = Pleroma.HTTP.request(:post, url, body, headers, options)
-
- {res, %{status_code: status}}
- end
-end
diff --git a/test/support/websocket_client.ex b/test/support/websocket_client.ex
index 8c9d4b2b4..34b955474 100644
--- a/test/support/websocket_client.ex
+++ b/test/support/websocket_client.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Integration.WebsocketClient do
diff --git a/test/tasks/config_test.exs b/test/tasks/config_test.exs
deleted file mode 100644
index fb12e7fb3..000000000
--- a/test/tasks/config_test.exs
+++ /dev/null
@@ -1,176 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Mix.Tasks.Pleroma.ConfigTest do
- use Pleroma.DataCase
-
- import Pleroma.Factory
-
- alias Pleroma.ConfigDB
- alias Pleroma.Repo
-
- setup_all do
- Mix.shell(Mix.Shell.Process)
-
- on_exit(fn ->
- Mix.shell(Mix.Shell.IO)
- Application.delete_env(:pleroma, :first_setting)
- Application.delete_env(:pleroma, :second_setting)
- end)
-
- :ok
- end
-
- setup_all do: clear_config(:configurable_from_database, true)
-
- test "error if file with custom settings doesn't exist" do
- Mix.Tasks.Pleroma.Config.migrate_to_db("config/not_existance_config_file.exs")
-
- assert_receive {:mix_shell, :info,
- [
- "To migrate settings, you must define custom settings in config/not_existance_config_file.exs."
- ]},
- 15
- end
-
- describe "migrate_to_db/1" do
- setup do
- initial = Application.get_env(:quack, :level)
- on_exit(fn -> Application.put_env(:quack, :level, initial) end)
- end
-
- test "filtered settings are migrated to db" do
- assert Repo.all(ConfigDB) == []
-
- Mix.Tasks.Pleroma.Config.migrate_to_db("test/fixtures/config/temp.secret.exs")
-
- config1 = ConfigDB.get_by_params(%{group: ":pleroma", key: ":first_setting"})
- config2 = ConfigDB.get_by_params(%{group: ":pleroma", key: ":second_setting"})
- config3 = ConfigDB.get_by_params(%{group: ":quack", key: ":level"})
- refute ConfigDB.get_by_params(%{group: ":pleroma", key: "Pleroma.Repo"})
- refute ConfigDB.get_by_params(%{group: ":postgrex", key: ":json_library"})
- refute ConfigDB.get_by_params(%{group: ":pleroma", key: ":database"})
-
- assert config1.value == [key: "value", key2: [Repo]]
- assert config2.value == [key: "value2", key2: ["Activity"]]
- assert config3.value == :info
- end
-
- test "config table is truncated before migration" do
- insert(:config, key: :first_setting, value: [key: "value", key2: ["Activity"]])
- assert Repo.aggregate(ConfigDB, :count, :id) == 1
-
- Mix.Tasks.Pleroma.Config.migrate_to_db("test/fixtures/config/temp.secret.exs")
-
- config = ConfigDB.get_by_params(%{group: ":pleroma", key: ":first_setting"})
- assert config.value == [key: "value", key2: [Repo]]
- end
- end
-
- describe "with deletion temp file" do
- setup do
- temp_file = "config/temp.exported_from_db.secret.exs"
-
- on_exit(fn ->
- :ok = File.rm(temp_file)
- end)
-
- {:ok, temp_file: temp_file}
- end
-
- test "settings are migrated to file and deleted from db", %{temp_file: temp_file} do
- insert(:config, key: :setting_first, value: [key: "value", key2: ["Activity"]])
- insert(:config, key: :setting_second, value: [key: "value2", key2: [Repo]])
- insert(:config, group: :quack, key: :level, value: :info)
-
- Mix.Tasks.Pleroma.Config.run(["migrate_from_db", "--env", "temp", "-d"])
-
- assert Repo.all(ConfigDB) == []
-
- file = File.read!(temp_file)
- assert file =~ "config :pleroma, :setting_first,"
- assert file =~ "config :pleroma, :setting_second,"
- assert file =~ "config :quack, :level, :info"
- end
-
- test "load a settings with large values and pass to file", %{temp_file: temp_file} do
- insert(:config,
- key: :instance,
- value: [
- name: "Pleroma",
- email: "example@example.com",
- notify_email: "noreply@example.com",
- description: "A Pleroma instance, an alternative fediverse server",
- limit: 5_000,
- chat_limit: 5_000,
- remote_limit: 100_000,
- upload_limit: 16_000_000,
- avatar_upload_limit: 2_000_000,
- background_upload_limit: 4_000_000,
- banner_upload_limit: 4_000_000,
- poll_limits: %{
- max_options: 20,
- max_option_chars: 200,
- min_expiration: 0,
- max_expiration: 365 * 24 * 60 * 60
- },
- registrations_open: true,
- federating: true,
- federation_incoming_replies_max_depth: 100,
- federation_reachability_timeout_days: 7,
- federation_publisher_modules: [Pleroma.Web.ActivityPub.Publisher],
- allow_relay: true,
- public: true,
- quarantined_instances: [],
- managed_config: true,
- static_dir: "instance/static/",
- allowed_post_formats: ["text/plain", "text/html", "text/markdown", "text/bbcode"],
- autofollowed_nicknames: [],
- max_pinned_statuses: 1,
- attachment_links: false,
- max_report_comment_size: 1000,
- safe_dm_mentions: false,
- healthcheck: false,
- remote_post_retention_days: 90,
- skip_thread_containment: true,
- limit_to_local_content: :unauthenticated,
- user_bio_length: 5000,
- user_name_length: 100,
- max_account_fields: 10,
- max_remote_account_fields: 20,
- account_field_name_length: 512,
- account_field_value_length: 2048,
- external_user_synchronization: true,
- extended_nickname_format: true,
- multi_factor_authentication: [
- totp: [
- digits: 6,
- period: 30
- ],
- backup_codes: [
- number: 2,
- length: 6
- ]
- ]
- ]
- )
-
- Mix.Tasks.Pleroma.Config.run(["migrate_from_db", "--env", "temp", "-d"])
-
- assert Repo.all(ConfigDB) == []
- assert File.exists?(temp_file)
- {:ok, file} = File.read(temp_file)
-
- header =
- if Code.ensure_loaded?(Config.Reader) do
- "import Config"
- else
- "use Mix.Config"
- end
-
- assert file ==
- "#{header}\n\nconfig :pleroma, :instance,\n name: \"Pleroma\",\n email: \"example@example.com\",\n notify_email: \"noreply@example.com\",\n description: \"A Pleroma instance, an alternative fediverse server\",\n limit: 5000,\n chat_limit: 5000,\n remote_limit: 100_000,\n upload_limit: 16_000_000,\n avatar_upload_limit: 2_000_000,\n background_upload_limit: 4_000_000,\n banner_upload_limit: 4_000_000,\n poll_limits: %{\n max_expiration: 31_536_000,\n max_option_chars: 200,\n max_options: 20,\n min_expiration: 0\n },\n registrations_open: true,\n federating: true,\n federation_incoming_replies_max_depth: 100,\n federation_reachability_timeout_days: 7,\n federation_publisher_modules: [Pleroma.Web.ActivityPub.Publisher],\n allow_relay: true,\n public: true,\n quarantined_instances: [],\n managed_config: true,\n static_dir: \"instance/static/\",\n allowed_post_formats: [\"text/plain\", \"text/html\", \"text/markdown\", \"text/bbcode\"],\n autofollowed_nicknames: [],\n max_pinned_statuses: 1,\n attachment_links: false,\n max_report_comment_size: 1000,\n safe_dm_mentions: false,\n healthcheck: false,\n remote_post_retention_days: 90,\n skip_thread_containment: true,\n limit_to_local_content: :unauthenticated,\n user_bio_length: 5000,\n user_name_length: 100,\n max_account_fields: 10,\n max_remote_account_fields: 20,\n account_field_name_length: 512,\n account_field_value_length: 2048,\n external_user_synchronization: true,\n extended_nickname_format: true,\n multi_factor_authentication: [\n totp: [digits: 6, period: 30],\n backup_codes: [number: 2, length: 6]\n ]\n"
- end
- end
-end
diff --git a/test/tasks/email_test.exs b/test/tasks/email_test.exs
deleted file mode 100644
index c3af7ef68..000000000
--- a/test/tasks/email_test.exs
+++ /dev/null
@@ -1,54 +0,0 @@
-defmodule Mix.Tasks.Pleroma.EmailTest do
- use Pleroma.DataCase
-
- import Swoosh.TestAssertions
-
- alias Pleroma.Config
- alias Pleroma.Tests.ObanHelpers
-
- setup_all do
- Mix.shell(Mix.Shell.Process)
-
- on_exit(fn ->
- Mix.shell(Mix.Shell.IO)
- end)
-
- :ok
- end
-
- setup do: clear_config([Pleroma.Emails.Mailer, :enabled], true)
-
- describe "pleroma.email test" do
- test "Sends test email with no given address" do
- mail_to = Config.get([:instance, :email])
-
- :ok = Mix.Tasks.Pleroma.Email.run(["test"])
-
- ObanHelpers.perform_all()
-
- assert_receive {:mix_shell, :info, [message]}
- assert message =~ "Test email has been sent"
-
- assert_email_sent(
- to: mail_to,
- html_body: ~r/a test email was requested./i
- )
- end
-
- test "Sends test email with given address" do
- mail_to = "hewwo@example.com"
-
- :ok = Mix.Tasks.Pleroma.Email.run(["test", "--to", mail_to])
-
- ObanHelpers.perform_all()
-
- assert_receive {:mix_shell, :info, [message]}
- assert message =~ "Test email has been sent"
-
- assert_email_sent(
- to: mail_to,
- html_body: ~r/a test email was requested./i
- )
- end
- end
-end
diff --git a/test/test_helper.exs b/test/test_helper.exs
index ee880e226..9fb41e985 100644
--- a/test/test_helper.exs
+++ b/test/test_helper.exs
@@ -1,9 +1,9 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
os_exclude = if :os.type() == {:unix, :darwin}, do: [skip_on_mac: true], else: []
-ExUnit.start(exclude: [:federated | os_exclude])
+ExUnit.start(exclude: [:federated, :erratic] ++ os_exclude)
Ecto.Adapters.SQL.Sandbox.mode(Pleroma.Repo, :manual)
diff --git a/test/web/activity_pub/mrf/steal_emoji_policy_test.exs b/test/web/activity_pub/mrf/steal_emoji_policy_test.exs
deleted file mode 100644
index 3f8222736..000000000
--- a/test/web/activity_pub/mrf/steal_emoji_policy_test.exs
+++ /dev/null
@@ -1,68 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicyTest do
- use Pleroma.DataCase
-
- alias Pleroma.Config
- alias Pleroma.Web.ActivityPub.MRF.StealEmojiPolicy
-
- setup_all do
- Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
- :ok
- end
-
- setup do
- emoji_path = Path.join(Config.get([:instance, :static_dir]), "emoji/stolen")
- File.rm_rf!(emoji_path)
- File.mkdir!(emoji_path)
-
- Pleroma.Emoji.reload()
-
- on_exit(fn ->
- File.rm_rf!(emoji_path)
- end)
-
- :ok
- end
-
- test "does nothing by default" do
- installed_emoji = Pleroma.Emoji.get_all() |> Enum.map(fn {k, _} -> k end)
- refute "firedfox" in installed_emoji
-
- message = %{
- "type" => "Create",
- "object" => %{
- "emoji" => [{"firedfox", "https://example.org/emoji/firedfox.png"}],
- "actor" => "https://example.org/users/admin"
- }
- }
-
- assert {:ok, message} == StealEmojiPolicy.filter(message)
-
- installed_emoji = Pleroma.Emoji.get_all() |> Enum.map(fn {k, _} -> k end)
- refute "firedfox" in installed_emoji
- end
-
- test "Steals emoji on unknown shortcode from allowed remote host" do
- installed_emoji = Pleroma.Emoji.get_all() |> Enum.map(fn {k, _} -> k end)
- refute "firedfox" in installed_emoji
-
- message = %{
- "type" => "Create",
- "object" => %{
- "emoji" => [{"firedfox", "https://example.org/emoji/firedfox.png"}],
- "actor" => "https://example.org/users/admin"
- }
- }
-
- clear_config([:mrf_steal_emoji, :hosts], ["example.org"])
- clear_config([:mrf_steal_emoji, :size_limit], 284_468)
-
- assert {:ok, message} == StealEmojiPolicy.filter(message)
-
- installed_emoji = Pleroma.Emoji.get_all() |> Enum.map(fn {k, _} -> k end)
- assert "firedfox" in installed_emoji
- end
-end
diff --git a/test/web/activity_pub/pipeline_test.exs b/test/web/activity_pub/pipeline_test.exs
deleted file mode 100644
index f2a231eaf..000000000
--- a/test/web/activity_pub/pipeline_test.exs
+++ /dev/null
@@ -1,179 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.ActivityPub.PipelineTest do
- use Pleroma.DataCase
-
- import Mock
- import Pleroma.Factory
-
- describe "common_pipeline/2" do
- setup do
- clear_config([:instance, :federating], true)
- :ok
- end
-
- test "when given an `object_data` in meta, Federation will receive a the original activity with the `object` field set to this embedded object" do
- activity = insert(:note_activity)
- object = %{"id" => "1", "type" => "Love"}
- meta = [local: true, object_data: object]
-
- activity_with_object = %{activity | data: Map.put(activity.data, "object", object)}
-
- with_mocks([
- {Pleroma.Web.ActivityPub.ObjectValidator, [], [validate: fn o, m -> {:ok, o, m} end]},
- {
- Pleroma.Web.ActivityPub.MRF,
- [],
- [filter: fn o -> {:ok, o} end]
- },
- {
- Pleroma.Web.ActivityPub.ActivityPub,
- [],
- [persist: fn o, m -> {:ok, o, m} end]
- },
- {
- Pleroma.Web.ActivityPub.SideEffects,
- [],
- [
- handle: fn o, m -> {:ok, o, m} end,
- handle_after_transaction: fn m -> m end
- ]
- },
- {
- Pleroma.Web.Federator,
- [],
- [publish: fn _o -> :ok end]
- }
- ]) do
- assert {:ok, ^activity, ^meta} =
- Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity, meta)
-
- assert_called(Pleroma.Web.ActivityPub.ObjectValidator.validate(activity, meta))
- assert_called(Pleroma.Web.ActivityPub.MRF.filter(activity))
- assert_called(Pleroma.Web.ActivityPub.ActivityPub.persist(activity, meta))
- assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta))
- refute called(Pleroma.Web.Federator.publish(activity))
- assert_called(Pleroma.Web.Federator.publish(activity_with_object))
- end
- end
-
- test "it goes through validation, filtering, persisting, side effects and federation for local activities" do
- activity = insert(:note_activity)
- meta = [local: true]
-
- with_mocks([
- {Pleroma.Web.ActivityPub.ObjectValidator, [], [validate: fn o, m -> {:ok, o, m} end]},
- {
- Pleroma.Web.ActivityPub.MRF,
- [],
- [filter: fn o -> {:ok, o} end]
- },
- {
- Pleroma.Web.ActivityPub.ActivityPub,
- [],
- [persist: fn o, m -> {:ok, o, m} end]
- },
- {
- Pleroma.Web.ActivityPub.SideEffects,
- [],
- [
- handle: fn o, m -> {:ok, o, m} end,
- handle_after_transaction: fn m -> m end
- ]
- },
- {
- Pleroma.Web.Federator,
- [],
- [publish: fn _o -> :ok end]
- }
- ]) do
- assert {:ok, ^activity, ^meta} =
- Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity, meta)
-
- assert_called(Pleroma.Web.ActivityPub.ObjectValidator.validate(activity, meta))
- assert_called(Pleroma.Web.ActivityPub.MRF.filter(activity))
- assert_called(Pleroma.Web.ActivityPub.ActivityPub.persist(activity, meta))
- assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta))
- assert_called(Pleroma.Web.Federator.publish(activity))
- end
- end
-
- test "it goes through validation, filtering, persisting, side effects without federation for remote activities" do
- activity = insert(:note_activity)
- meta = [local: false]
-
- with_mocks([
- {Pleroma.Web.ActivityPub.ObjectValidator, [], [validate: fn o, m -> {:ok, o, m} end]},
- {
- Pleroma.Web.ActivityPub.MRF,
- [],
- [filter: fn o -> {:ok, o} end]
- },
- {
- Pleroma.Web.ActivityPub.ActivityPub,
- [],
- [persist: fn o, m -> {:ok, o, m} end]
- },
- {
- Pleroma.Web.ActivityPub.SideEffects,
- [],
- [handle: fn o, m -> {:ok, o, m} end, handle_after_transaction: fn m -> m end]
- },
- {
- Pleroma.Web.Federator,
- [],
- []
- }
- ]) do
- assert {:ok, ^activity, ^meta} =
- Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity, meta)
-
- assert_called(Pleroma.Web.ActivityPub.ObjectValidator.validate(activity, meta))
- assert_called(Pleroma.Web.ActivityPub.MRF.filter(activity))
- assert_called(Pleroma.Web.ActivityPub.ActivityPub.persist(activity, meta))
- assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta))
- end
- end
-
- test "it goes through validation, filtering, persisting, side effects without federation for local activities if federation is deactivated" do
- clear_config([:instance, :federating], false)
-
- activity = insert(:note_activity)
- meta = [local: true]
-
- with_mocks([
- {Pleroma.Web.ActivityPub.ObjectValidator, [], [validate: fn o, m -> {:ok, o, m} end]},
- {
- Pleroma.Web.ActivityPub.MRF,
- [],
- [filter: fn o -> {:ok, o} end]
- },
- {
- Pleroma.Web.ActivityPub.ActivityPub,
- [],
- [persist: fn o, m -> {:ok, o, m} end]
- },
- {
- Pleroma.Web.ActivityPub.SideEffects,
- [],
- [handle: fn o, m -> {:ok, o, m} end, handle_after_transaction: fn m -> m end]
- },
- {
- Pleroma.Web.Federator,
- [],
- []
- }
- ]) do
- assert {:ok, ^activity, ^meta} =
- Pleroma.Web.ActivityPub.Pipeline.common_pipeline(activity, meta)
-
- assert_called(Pleroma.Web.ActivityPub.ObjectValidator.validate(activity, meta))
- assert_called(Pleroma.Web.ActivityPub.MRF.filter(activity))
- assert_called(Pleroma.Web.ActivityPub.ActivityPub.persist(activity, meta))
- assert_called(Pleroma.Web.ActivityPub.SideEffects.handle(activity, meta))
- end
- end
- end
-end
diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs
deleted file mode 100644
index 3fa41b0c7..000000000
--- a/test/web/activity_pub/transmogrifier_test.exs
+++ /dev/null
@@ -1,1379 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
- use Oban.Testing, repo: Pleroma.Repo
- use Pleroma.DataCase
-
- alias Pleroma.Activity
- alias Pleroma.Object
- alias Pleroma.Object.Fetcher
- alias Pleroma.Tests.ObanHelpers
- alias Pleroma.User
- alias Pleroma.Web.ActivityPub.Transmogrifier
- alias Pleroma.Web.AdminAPI.AccountView
- alias Pleroma.Web.CommonAPI
-
- import Mock
- import Pleroma.Factory
- import ExUnit.CaptureLog
-
- setup_all do
- Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
- :ok
- end
-
- setup do: clear_config([:instance, :max_remote_account_fields])
-
- describe "handle_incoming" do
- test "it works for incoming notices with tag not being an array (kroeg)" do
- data = File.read!("test/fixtures/kroeg-array-less-emoji.json") |> Poison.decode!()
-
- {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
- object = Object.normalize(data["object"])
-
- assert object.data["emoji"] == %{
- "icon_e_smile" => "https://puckipedia.com/forum/images/smilies/icon_e_smile.png"
- }
-
- data = File.read!("test/fixtures/kroeg-array-less-hashtag.json") |> Poison.decode!()
-
- {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
- object = Object.normalize(data["object"])
-
- assert "test" in object.data["tag"]
- end
-
- test "it works for incoming notices with url not being a string (prismo)" do
- data = File.read!("test/fixtures/prismo-url-map.json") |> Poison.decode!()
-
- {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
- object = Object.normalize(data["object"])
-
- assert object.data["url"] == "https://prismo.news/posts/83"
- end
-
- test "it cleans up incoming notices which are not really DMs" do
- user = insert(:user)
- other_user = insert(:user)
-
- to = [user.ap_id, other_user.ap_id]
-
- data =
- File.read!("test/fixtures/mastodon-post-activity.json")
- |> Poison.decode!()
- |> Map.put("to", to)
- |> Map.put("cc", [])
-
- object =
- data["object"]
- |> Map.put("to", to)
- |> Map.put("cc", [])
-
- data = Map.put(data, "object", object)
-
- {:ok, %Activity{data: data, local: false} = activity} = Transmogrifier.handle_incoming(data)
-
- assert data["to"] == []
- assert data["cc"] == to
-
- object_data = Object.normalize(activity).data
-
- assert object_data["to"] == []
- assert object_data["cc"] == to
- end
-
- test "it ignores an incoming notice if we already have it" do
- activity = insert(:note_activity)
-
- data =
- File.read!("test/fixtures/mastodon-post-activity.json")
- |> Poison.decode!()
- |> Map.put("object", Object.normalize(activity).data)
-
- {:ok, returned_activity} = Transmogrifier.handle_incoming(data)
-
- assert activity == returned_activity
- end
-
- @tag capture_log: true
- test "it fetches reply-to activities if we don't have them" do
- data =
- File.read!("test/fixtures/mastodon-post-activity.json")
- |> Poison.decode!()
-
- object =
- data["object"]
- |> Map.put("inReplyTo", "https://shitposter.club/notice/2827873")
-
- data = Map.put(data, "object", object)
- {:ok, returned_activity} = Transmogrifier.handle_incoming(data)
- returned_object = Object.normalize(returned_activity, false)
-
- assert activity =
- Activity.get_create_by_object_ap_id(
- "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
- )
-
- assert returned_object.data["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873"
- end
-
- test "it does not fetch reply-to activities beyond max replies depth limit" do
- data =
- File.read!("test/fixtures/mastodon-post-activity.json")
- |> Poison.decode!()
-
- object =
- data["object"]
- |> Map.put("inReplyTo", "https://shitposter.club/notice/2827873")
-
- data = Map.put(data, "object", object)
-
- with_mock Pleroma.Web.Federator,
- allowed_thread_distance?: fn _ -> false end do
- {:ok, returned_activity} = Transmogrifier.handle_incoming(data)
-
- returned_object = Object.normalize(returned_activity, false)
-
- refute Activity.get_create_by_object_ap_id(
- "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
- )
-
- assert returned_object.data["inReplyToAtomUri"] ==
- "https://shitposter.club/notice/2827873"
- end
- end
-
- test "it does not crash if the object in inReplyTo can't be fetched" do
- data =
- File.read!("test/fixtures/mastodon-post-activity.json")
- |> Poison.decode!()
-
- object =
- data["object"]
- |> Map.put("inReplyTo", "https://404.site/whatever")
-
- data =
- data
- |> Map.put("object", object)
-
- assert capture_log(fn ->
- {:ok, _returned_activity} = Transmogrifier.handle_incoming(data)
- end) =~ "[warn] Couldn't fetch \"https://404.site/whatever\", error: nil"
- end
-
- test "it does not work for deactivated users" do
- data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
-
- insert(:user, ap_id: data["actor"], deactivated: true)
-
- assert {:error, _} = Transmogrifier.handle_incoming(data)
- end
-
- test "it works for incoming notices" do
- data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
-
- {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
-
- assert data["id"] ==
- "http://mastodon.example.org/users/admin/statuses/99512778738411822/activity"
-
- assert data["context"] ==
- "tag:mastodon.example.org,2018-02-12:objectId=20:objectType=Conversation"
-
- assert data["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
-
- assert data["cc"] == [
- "http://mastodon.example.org/users/admin/followers",
- "http://localtesting.pleroma.lol/users/lain"
- ]
-
- assert data["actor"] == "http://mastodon.example.org/users/admin"
-
- object_data = Object.normalize(data["object"]).data
-
- assert object_data["id"] ==
- "http://mastodon.example.org/users/admin/statuses/99512778738411822"
-
- assert object_data["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
-
- assert object_data["cc"] == [
- "http://mastodon.example.org/users/admin/followers",
- "http://localtesting.pleroma.lol/users/lain"
- ]
-
- assert object_data["actor"] == "http://mastodon.example.org/users/admin"
- assert object_data["attributedTo"] == "http://mastodon.example.org/users/admin"
-
- assert object_data["context"] ==
- "tag:mastodon.example.org,2018-02-12:objectId=20:objectType=Conversation"
-
- assert object_data["sensitive"] == true
-
- user = User.get_cached_by_ap_id(object_data["actor"])
-
- assert user.note_count == 1
- end
-
- test "it works for incoming notices with hashtags" do
- data = File.read!("test/fixtures/mastodon-post-activity-hashtag.json") |> Poison.decode!()
-
- {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
- object = Object.normalize(data["object"])
-
- assert Enum.at(object.data["tag"], 2) == "moo"
- end
-
- test "it works for incoming notices with contentMap" do
- data =
- File.read!("test/fixtures/mastodon-post-activity-contentmap.json") |> Poison.decode!()
-
- {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
- object = Object.normalize(data["object"])
-
- assert object.data["content"] ==
- "<p><span class=\"h-card\"><a href=\"http://localtesting.pleroma.lol/users/lain\" class=\"u-url mention\">@<span>lain</span></a></span></p>"
- end
-
- test "it works for incoming notices with to/cc not being an array (kroeg)" do
- data = File.read!("test/fixtures/kroeg-post-activity.json") |> Poison.decode!()
-
- {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
- object = Object.normalize(data["object"])
-
- assert object.data["content"] ==
- "<p>henlo from my Psion netBook</p><p>message sent from my Psion netBook</p>"
- end
-
- test "it ensures that as:Public activities make it to their followers collection" do
- user = insert(:user)
-
- data =
- File.read!("test/fixtures/mastodon-post-activity.json")
- |> Poison.decode!()
- |> Map.put("actor", user.ap_id)
- |> Map.put("to", ["https://www.w3.org/ns/activitystreams#Public"])
- |> Map.put("cc", [])
-
- object =
- data["object"]
- |> Map.put("attributedTo", user.ap_id)
- |> Map.put("to", ["https://www.w3.org/ns/activitystreams#Public"])
- |> Map.put("cc", [])
- |> Map.put("id", user.ap_id <> "/activities/12345678")
-
- data = Map.put(data, "object", object)
-
- {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
-
- assert data["cc"] == [User.ap_followers(user)]
- end
-
- test "it ensures that address fields become lists" do
- user = insert(:user)
-
- data =
- File.read!("test/fixtures/mastodon-post-activity.json")
- |> Poison.decode!()
- |> Map.put("actor", user.ap_id)
- |> Map.put("to", nil)
- |> Map.put("cc", nil)
-
- object =
- data["object"]
- |> Map.put("attributedTo", user.ap_id)
- |> Map.put("to", nil)
- |> Map.put("cc", nil)
- |> Map.put("id", user.ap_id <> "/activities/12345678")
-
- data = Map.put(data, "object", object)
-
- {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
-
- assert !is_nil(data["to"])
- assert !is_nil(data["cc"])
- end
-
- test "it strips internal likes" do
- data =
- File.read!("test/fixtures/mastodon-post-activity.json")
- |> Poison.decode!()
-
- likes = %{
- "first" =>
- "http://mastodon.example.org/objects/dbdbc507-52c8-490d-9b7c-1e1d52e5c132/likes?page=1",
- "id" => "http://mastodon.example.org/objects/dbdbc507-52c8-490d-9b7c-1e1d52e5c132/likes",
- "totalItems" => 3,
- "type" => "OrderedCollection"
- }
-
- object = Map.put(data["object"], "likes", likes)
- data = Map.put(data, "object", object)
-
- {:ok, %Activity{object: object}} = Transmogrifier.handle_incoming(data)
-
- refute Map.has_key?(object.data, "likes")
- end
-
- test "it strips internal reactions" do
- user = insert(:user)
- {:ok, activity} = CommonAPI.post(user, %{status: "#cofe"})
- {:ok, _} = CommonAPI.react_with_emoji(activity.id, user, "📢")
-
- %{object: object} = Activity.get_by_id_with_object(activity.id)
- assert Map.has_key?(object.data, "reactions")
- assert Map.has_key?(object.data, "reaction_count")
-
- object_data = Transmogrifier.strip_internal_fields(object.data)
- refute Map.has_key?(object_data, "reactions")
- refute Map.has_key?(object_data, "reaction_count")
- end
-
- test "it works for incoming unfollows with an existing follow" do
- user = insert(:user)
-
- follow_data =
- File.read!("test/fixtures/mastodon-follow-activity.json")
- |> Poison.decode!()
- |> Map.put("object", user.ap_id)
-
- {:ok, %Activity{data: _, local: false}} = Transmogrifier.handle_incoming(follow_data)
-
- data =
- File.read!("test/fixtures/mastodon-unfollow-activity.json")
- |> Poison.decode!()
- |> Map.put("object", follow_data)
-
- {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
-
- assert data["type"] == "Undo"
- assert data["object"]["type"] == "Follow"
- assert data["object"]["object"] == user.ap_id
- assert data["actor"] == "http://mastodon.example.org/users/admin"
-
- refute User.following?(User.get_cached_by_ap_id(data["actor"]), user)
- end
-
- test "skip converting the content when it is nil" do
- object_id = "https://peertube.social/videos/watch/278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe"
-
- {:ok, object} = Fetcher.fetch_and_contain_remote_object_from_id(object_id)
-
- result =
- Pleroma.Web.ActivityPub.Transmogrifier.fix_object(Map.merge(object, %{"content" => nil}))
-
- assert result["content"] == nil
- end
-
- test "it converts content of object to html" do
- object_id = "https://peertube.social/videos/watch/278d2b7c-0f38-4aaa-afe6-9ecc0c4a34fe"
-
- {:ok, %{"content" => content_markdown}} =
- Fetcher.fetch_and_contain_remote_object_from_id(object_id)
-
- {:ok, %Pleroma.Object{data: %{"content" => content}} = object} =
- Fetcher.fetch_object_from_id(object_id)
-
- assert content_markdown ==
- "Support this and our other Michigan!/usr/group videos and meetings. Learn more at http://mug.org/membership\n\nTwenty Years in Jail: FreeBSD's Jails, Then and Now\n\nJails started as a limited virtualization system, but over the last two years they've..."
-
- assert content ==
- "<p>Support this and our other Michigan!/usr/group videos and meetings. Learn more at <a href=\"http://mug.org/membership\">http://mug.org/membership</a></p><p>Twenty Years in Jail: FreeBSD’s Jails, Then and Now</p><p>Jails started as a limited virtualization system, but over the last two years they’ve…</p>"
-
- assert object.data["mediaType"] == "text/html"
- end
-
- test "it remaps video URLs as attachments if necessary" do
- {:ok, object} =
- Fetcher.fetch_object_from_id(
- "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3"
- )
-
- assert object.data["url"] ==
- "https://peertube.moe/videos/watch/df5f464b-be8d-46fb-ad81-2d4c2d1630e3"
-
- assert object.data["attachment"] == [
- %{
- "type" => "Link",
- "mediaType" => "video/mp4",
- "url" => [
- %{
- "href" =>
- "https://peertube.moe/static/webseed/df5f464b-be8d-46fb-ad81-2d4c2d1630e3-480.mp4",
- "mediaType" => "video/mp4",
- "type" => "Link"
- }
- ]
- }
- ]
-
- {:ok, object} =
- Fetcher.fetch_object_from_id(
- "https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206"
- )
-
- assert object.data["attachment"] == [
- %{
- "type" => "Link",
- "mediaType" => "video/mp4",
- "url" => [
- %{
- "href" =>
- "https://framatube.org/static/webseed/6050732a-8a7a-43d4-a6cd-809525a1d206-1080.mp4",
- "mediaType" => "video/mp4",
- "type" => "Link"
- }
- ]
- }
- ]
-
- assert object.data["url"] ==
- "https://framatube.org/videos/watch/6050732a-8a7a-43d4-a6cd-809525a1d206"
- end
-
- test "it accepts Flag activities" do
- user = insert(:user)
- other_user = insert(:user)
-
- {:ok, activity} = CommonAPI.post(user, %{status: "test post"})
- object = Object.normalize(activity)
-
- note_obj = %{
- "type" => "Note",
- "id" => activity.data["id"],
- "content" => "test post",
- "published" => object.data["published"],
- "actor" => AccountView.render("show.json", %{user: user, skip_visibility_check: true})
- }
-
- message = %{
- "@context" => "https://www.w3.org/ns/activitystreams",
- "cc" => [user.ap_id],
- "object" => [user.ap_id, activity.data["id"]],
- "type" => "Flag",
- "content" => "blocked AND reported!!!",
- "actor" => other_user.ap_id
- }
-
- assert {:ok, activity} = Transmogrifier.handle_incoming(message)
-
- assert activity.data["object"] == [user.ap_id, note_obj]
- assert activity.data["content"] == "blocked AND reported!!!"
- assert activity.data["actor"] == other_user.ap_id
- assert activity.data["cc"] == [user.ap_id]
- end
-
- test "it correctly processes messages with non-array to field" do
- user = insert(:user)
-
- message = %{
- "@context" => "https://www.w3.org/ns/activitystreams",
- "to" => "https://www.w3.org/ns/activitystreams#Public",
- "type" => "Create",
- "object" => %{
- "content" => "blah blah blah",
- "type" => "Note",
- "attributedTo" => user.ap_id,
- "inReplyTo" => nil
- },
- "actor" => user.ap_id
- }
-
- assert {:ok, activity} = Transmogrifier.handle_incoming(message)
-
- assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["to"]
- end
-
- test "it correctly processes messages with non-array cc field" do
- user = insert(:user)
-
- message = %{
- "@context" => "https://www.w3.org/ns/activitystreams",
- "to" => user.follower_address,
- "cc" => "https://www.w3.org/ns/activitystreams#Public",
- "type" => "Create",
- "object" => %{
- "content" => "blah blah blah",
- "type" => "Note",
- "attributedTo" => user.ap_id,
- "inReplyTo" => nil
- },
- "actor" => user.ap_id
- }
-
- assert {:ok, activity} = Transmogrifier.handle_incoming(message)
-
- assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["cc"]
- assert [user.follower_address] == activity.data["to"]
- end
-
- test "it correctly processes messages with weirdness in address fields" do
- user = insert(:user)
-
- message = %{
- "@context" => "https://www.w3.org/ns/activitystreams",
- "to" => [nil, user.follower_address],
- "cc" => ["https://www.w3.org/ns/activitystreams#Public", ["¿"]],
- "type" => "Create",
- "object" => %{
- "content" => "…",
- "type" => "Note",
- "attributedTo" => user.ap_id,
- "inReplyTo" => nil
- },
- "actor" => user.ap_id
- }
-
- assert {:ok, activity} = Transmogrifier.handle_incoming(message)
-
- assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["cc"]
- assert [user.follower_address] == activity.data["to"]
- end
-
- test "it accepts Move activities" do
- old_user = insert(:user)
- new_user = insert(:user)
-
- message = %{
- "@context" => "https://www.w3.org/ns/activitystreams",
- "type" => "Move",
- "actor" => old_user.ap_id,
- "object" => old_user.ap_id,
- "target" => new_user.ap_id
- }
-
- assert :error = Transmogrifier.handle_incoming(message)
-
- {:ok, _new_user} = User.update_and_set_cache(new_user, %{also_known_as: [old_user.ap_id]})
-
- assert {:ok, %Activity{} = activity} = Transmogrifier.handle_incoming(message)
- assert activity.actor == old_user.ap_id
- assert activity.data["actor"] == old_user.ap_id
- assert activity.data["object"] == old_user.ap_id
- assert activity.data["target"] == new_user.ap_id
- assert activity.data["type"] == "Move"
- end
- end
-
- describe "`handle_incoming/2`, Mastodon format `replies` handling" do
- setup do: clear_config([:activitypub, :note_replies_output_limit], 5)
- setup do: clear_config([:instance, :federation_incoming_replies_max_depth])
-
- setup do
- data =
- "test/fixtures/mastodon-post-activity.json"
- |> File.read!()
- |> Poison.decode!()
-
- items = get_in(data, ["object", "replies", "first", "items"])
- assert length(items) > 0
-
- %{data: data, items: items}
- end
-
- test "schedules background fetching of `replies` items if max thread depth limit allows", %{
- data: data,
- items: items
- } do
- Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 10)
-
- {:ok, _activity} = Transmogrifier.handle_incoming(data)
-
- for id <- items do
- job_args = %{"op" => "fetch_remote", "id" => id, "depth" => 1}
- assert_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker, args: job_args)
- end
- end
-
- test "does NOT schedule background fetching of `replies` beyond max thread depth limit allows",
- %{data: data} do
- Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 0)
-
- {:ok, _activity} = Transmogrifier.handle_incoming(data)
-
- assert all_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker) == []
- end
- end
-
- describe "`handle_incoming/2`, Pleroma format `replies` handling" do
- setup do: clear_config([:activitypub, :note_replies_output_limit], 5)
- setup do: clear_config([:instance, :federation_incoming_replies_max_depth])
-
- setup do
- user = insert(:user)
-
- {:ok, activity} = CommonAPI.post(user, %{status: "post1"})
-
- {:ok, reply1} =
- CommonAPI.post(user, %{status: "reply1", in_reply_to_status_id: activity.id})
-
- {:ok, reply2} =
- CommonAPI.post(user, %{status: "reply2", in_reply_to_status_id: activity.id})
-
- replies_uris = Enum.map([reply1, reply2], fn a -> a.object.data["id"] end)
-
- {:ok, federation_output} = Transmogrifier.prepare_outgoing(activity.data)
-
- Repo.delete(activity.object)
- Repo.delete(activity)
-
- %{federation_output: federation_output, replies_uris: replies_uris}
- end
-
- test "schedules background fetching of `replies` items if max thread depth limit allows", %{
- federation_output: federation_output,
- replies_uris: replies_uris
- } do
- Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 1)
-
- {:ok, _activity} = Transmogrifier.handle_incoming(federation_output)
-
- for id <- replies_uris do
- job_args = %{"op" => "fetch_remote", "id" => id, "depth" => 1}
- assert_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker, args: job_args)
- end
- end
-
- test "does NOT schedule background fetching of `replies` beyond max thread depth limit allows",
- %{federation_output: federation_output} do
- Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 0)
-
- {:ok, _activity} = Transmogrifier.handle_incoming(federation_output)
-
- assert all_enqueued(worker: Pleroma.Workers.RemoteFetcherWorker) == []
- end
- end
-
- describe "prepare outgoing" do
- test "it inlines private announced objects" do
- user = insert(:user)
-
- {:ok, activity} = CommonAPI.post(user, %{status: "hey", visibility: "private"})
-
- {:ok, announce_activity} = CommonAPI.repeat(activity.id, user)
-
- {:ok, modified} = Transmogrifier.prepare_outgoing(announce_activity.data)
-
- assert modified["object"]["content"] == "hey"
- assert modified["object"]["actor"] == modified["object"]["attributedTo"]
- end
-
- test "it turns mentions into tags" do
- user = insert(:user)
- other_user = insert(:user)
-
- {:ok, activity} =
- CommonAPI.post(user, %{status: "hey, @#{other_user.nickname}, how are ya? #2hu"})
-
- with_mock Pleroma.Notification,
- get_notified_from_activity: fn _, _ -> [] end do
- {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
-
- object = modified["object"]
-
- expected_mention = %{
- "href" => other_user.ap_id,
- "name" => "@#{other_user.nickname}",
- "type" => "Mention"
- }
-
- expected_tag = %{
- "href" => Pleroma.Web.Endpoint.url() <> "/tags/2hu",
- "type" => "Hashtag",
- "name" => "#2hu"
- }
-
- refute called(Pleroma.Notification.get_notified_from_activity(:_, :_))
- assert Enum.member?(object["tag"], expected_tag)
- assert Enum.member?(object["tag"], expected_mention)
- end
- end
-
- test "it adds the sensitive property" do
- user = insert(:user)
-
- {:ok, activity} = CommonAPI.post(user, %{status: "#nsfw hey"})
- {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
-
- assert modified["object"]["sensitive"]
- end
-
- test "it adds the json-ld context and the conversation property" do
- user = insert(:user)
-
- {:ok, activity} = CommonAPI.post(user, %{status: "hey"})
- {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
-
- assert modified["@context"] ==
- Pleroma.Web.ActivityPub.Utils.make_json_ld_header()["@context"]
-
- assert modified["object"]["conversation"] == modified["context"]
- end
-
- test "it sets the 'attributedTo' property to the actor of the object if it doesn't have one" do
- user = insert(:user)
-
- {:ok, activity} = CommonAPI.post(user, %{status: "hey"})
- {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
-
- assert modified["object"]["actor"] == modified["object"]["attributedTo"]
- end
-
- test "it strips internal hashtag data" do
- user = insert(:user)
-
- {:ok, activity} = CommonAPI.post(user, %{status: "#2hu"})
-
- expected_tag = %{
- "href" => Pleroma.Web.Endpoint.url() <> "/tags/2hu",
- "type" => "Hashtag",
- "name" => "#2hu"
- }
-
- {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
-
- assert modified["object"]["tag"] == [expected_tag]
- end
-
- test "it strips internal fields" do
- user = insert(:user)
-
- {:ok, activity} = CommonAPI.post(user, %{status: "#2hu :firefox:"})
-
- {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
-
- assert length(modified["object"]["tag"]) == 2
-
- assert is_nil(modified["object"]["emoji"])
- assert is_nil(modified["object"]["like_count"])
- assert is_nil(modified["object"]["announcements"])
- assert is_nil(modified["object"]["announcement_count"])
- assert is_nil(modified["object"]["context_id"])
- end
-
- test "it strips internal fields of article" do
- activity = insert(:article_activity)
-
- {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
-
- assert length(modified["object"]["tag"]) == 2
-
- assert is_nil(modified["object"]["emoji"])
- assert is_nil(modified["object"]["like_count"])
- assert is_nil(modified["object"]["announcements"])
- assert is_nil(modified["object"]["announcement_count"])
- assert is_nil(modified["object"]["context_id"])
- assert is_nil(modified["object"]["likes"])
- end
-
- test "the directMessage flag is present" do
- user = insert(:user)
- other_user = insert(:user)
-
- {:ok, activity} = CommonAPI.post(user, %{status: "2hu :moominmamma:"})
-
- {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
-
- assert modified["directMessage"] == false
-
- {:ok, activity} = CommonAPI.post(user, %{status: "@#{other_user.nickname} :moominmamma:"})
-
- {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
-
- assert modified["directMessage"] == false
-
- {:ok, activity} =
- CommonAPI.post(user, %{
- status: "@#{other_user.nickname} :moominmamma:",
- visibility: "direct"
- })
-
- {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
-
- assert modified["directMessage"] == true
- end
-
- test "it strips BCC field" do
- user = insert(:user)
- {:ok, list} = Pleroma.List.create("foo", user)
-
- {:ok, activity} = CommonAPI.post(user, %{status: "foobar", visibility: "list:#{list.id}"})
-
- {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
-
- assert is_nil(modified["bcc"])
- end
-
- test "it can handle Listen activities" do
- listen_activity = insert(:listen)
-
- {:ok, modified} = Transmogrifier.prepare_outgoing(listen_activity.data)
-
- assert modified["type"] == "Listen"
-
- user = insert(:user)
-
- {:ok, activity} = CommonAPI.listen(user, %{"title" => "lain radio episode 1"})
-
- {:ok, _modified} = Transmogrifier.prepare_outgoing(activity.data)
- end
- end
-
- describe "user upgrade" do
- test "it upgrades a user to activitypub" do
- user =
- insert(:user, %{
- nickname: "rye@niu.moe",
- local: false,
- ap_id: "https://niu.moe/users/rye",
- follower_address: User.ap_followers(%User{nickname: "rye@niu.moe"})
- })
-
- user_two = insert(:user)
- Pleroma.FollowingRelationship.follow(user_two, user, :follow_accept)
-
- {:ok, activity} = CommonAPI.post(user, %{status: "test"})
- {:ok, unrelated_activity} = CommonAPI.post(user_two, %{status: "test"})
- assert "http://localhost:4001/users/rye@niu.moe/followers" in activity.recipients
-
- user = User.get_cached_by_id(user.id)
- assert user.note_count == 1
-
- {:ok, user} = Transmogrifier.upgrade_user_from_ap_id("https://niu.moe/users/rye")
- ObanHelpers.perform_all()
-
- assert user.ap_enabled
- assert user.note_count == 1
- assert user.follower_address == "https://niu.moe/users/rye/followers"
- assert user.following_address == "https://niu.moe/users/rye/following"
-
- user = User.get_cached_by_id(user.id)
- assert user.note_count == 1
-
- activity = Activity.get_by_id(activity.id)
- assert user.follower_address in activity.recipients
-
- assert %{
- "url" => [
- %{
- "href" =>
- "https://cdn.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg"
- }
- ]
- } = user.avatar
-
- assert %{
- "url" => [
- %{
- "href" =>
- "https://cdn.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png"
- }
- ]
- } = user.banner
-
- refute "..." in activity.recipients
-
- unrelated_activity = Activity.get_by_id(unrelated_activity.id)
- refute user.follower_address in unrelated_activity.recipients
-
- user_two = User.get_cached_by_id(user_two.id)
- assert User.following?(user_two, user)
- refute "..." in User.following(user_two)
- end
- end
-
- describe "actor rewriting" do
- test "it fixes the actor URL property to be a proper URI" do
- data = %{
- "url" => %{"href" => "http://example.com"}
- }
-
- rewritten = Transmogrifier.maybe_fix_user_object(data)
- assert rewritten["url"] == "http://example.com"
- end
- end
-
- describe "actor origin containment" do
- test "it rejects activities which reference objects with bogus origins" do
- data = %{
- "@context" => "https://www.w3.org/ns/activitystreams",
- "id" => "http://mastodon.example.org/users/admin/activities/1234",
- "actor" => "http://mastodon.example.org/users/admin",
- "to" => ["https://www.w3.org/ns/activitystreams#Public"],
- "object" => "https://info.pleroma.site/activity.json",
- "type" => "Announce"
- }
-
- assert capture_log(fn ->
- {:error, _} = Transmogrifier.handle_incoming(data)
- end) =~ "Object containment failed"
- end
-
- test "it rejects activities which reference objects that have an incorrect attribution (variant 1)" do
- data = %{
- "@context" => "https://www.w3.org/ns/activitystreams",
- "id" => "http://mastodon.example.org/users/admin/activities/1234",
- "actor" => "http://mastodon.example.org/users/admin",
- "to" => ["https://www.w3.org/ns/activitystreams#Public"],
- "object" => "https://info.pleroma.site/activity2.json",
- "type" => "Announce"
- }
-
- assert capture_log(fn ->
- {:error, _} = Transmogrifier.handle_incoming(data)
- end) =~ "Object containment failed"
- end
-
- test "it rejects activities which reference objects that have an incorrect attribution (variant 2)" do
- data = %{
- "@context" => "https://www.w3.org/ns/activitystreams",
- "id" => "http://mastodon.example.org/users/admin/activities/1234",
- "actor" => "http://mastodon.example.org/users/admin",
- "to" => ["https://www.w3.org/ns/activitystreams#Public"],
- "object" => "https://info.pleroma.site/activity3.json",
- "type" => "Announce"
- }
-
- assert capture_log(fn ->
- {:error, _} = Transmogrifier.handle_incoming(data)
- end) =~ "Object containment failed"
- end
- end
-
- describe "reserialization" do
- test "successfully reserializes a message with inReplyTo == nil" do
- user = insert(:user)
-
- message = %{
- "@context" => "https://www.w3.org/ns/activitystreams",
- "to" => ["https://www.w3.org/ns/activitystreams#Public"],
- "cc" => [],
- "type" => "Create",
- "object" => %{
- "to" => ["https://www.w3.org/ns/activitystreams#Public"],
- "cc" => [],
- "type" => "Note",
- "content" => "Hi",
- "inReplyTo" => nil,
- "attributedTo" => user.ap_id
- },
- "actor" => user.ap_id
- }
-
- {:ok, activity} = Transmogrifier.handle_incoming(message)
-
- {:ok, _} = Transmogrifier.prepare_outgoing(activity.data)
- end
-
- test "successfully reserializes a message with AS2 objects in IR" do
- user = insert(:user)
-
- message = %{
- "@context" => "https://www.w3.org/ns/activitystreams",
- "to" => ["https://www.w3.org/ns/activitystreams#Public"],
- "cc" => [],
- "type" => "Create",
- "object" => %{
- "to" => ["https://www.w3.org/ns/activitystreams#Public"],
- "cc" => [],
- "type" => "Note",
- "content" => "Hi",
- "inReplyTo" => nil,
- "attributedTo" => user.ap_id,
- "tag" => [
- %{"name" => "#2hu", "href" => "http://example.com/2hu", "type" => "Hashtag"},
- %{"name" => "Bob", "href" => "http://example.com/bob", "type" => "Mention"}
- ]
- },
- "actor" => user.ap_id
- }
-
- {:ok, activity} = Transmogrifier.handle_incoming(message)
-
- {:ok, _} = Transmogrifier.prepare_outgoing(activity.data)
- end
- end
-
- describe "fix_explicit_addressing" do
- setup do
- user = insert(:user)
- [user: user]
- end
-
- test "moves non-explicitly mentioned actors to cc", %{user: user} do
- explicitly_mentioned_actors = [
- "https://pleroma.gold/users/user1",
- "https://pleroma.gold/user2"
- ]
-
- object = %{
- "actor" => user.ap_id,
- "to" => explicitly_mentioned_actors ++ ["https://social.beepboop.ga/users/dirb"],
- "cc" => [],
- "tag" =>
- Enum.map(explicitly_mentioned_actors, fn href ->
- %{"type" => "Mention", "href" => href}
- end)
- }
-
- fixed_object = Transmogrifier.fix_explicit_addressing(object)
- assert Enum.all?(explicitly_mentioned_actors, &(&1 in fixed_object["to"]))
- refute "https://social.beepboop.ga/users/dirb" in fixed_object["to"]
- assert "https://social.beepboop.ga/users/dirb" in fixed_object["cc"]
- end
-
- test "does not move actor's follower collection to cc", %{user: user} do
- object = %{
- "actor" => user.ap_id,
- "to" => [user.follower_address],
- "cc" => []
- }
-
- fixed_object = Transmogrifier.fix_explicit_addressing(object)
- assert user.follower_address in fixed_object["to"]
- refute user.follower_address in fixed_object["cc"]
- end
-
- test "removes recipient's follower collection from cc", %{user: user} do
- recipient = insert(:user)
-
- object = %{
- "actor" => user.ap_id,
- "to" => [recipient.ap_id, "https://www.w3.org/ns/activitystreams#Public"],
- "cc" => [user.follower_address, recipient.follower_address]
- }
-
- fixed_object = Transmogrifier.fix_explicit_addressing(object)
-
- assert user.follower_address in fixed_object["cc"]
- refute recipient.follower_address in fixed_object["cc"]
- refute recipient.follower_address in fixed_object["to"]
- end
- end
-
- describe "fix_summary/1" do
- test "returns fixed object" do
- assert Transmogrifier.fix_summary(%{"summary" => nil}) == %{"summary" => ""}
- assert Transmogrifier.fix_summary(%{"summary" => "ok"}) == %{"summary" => "ok"}
- assert Transmogrifier.fix_summary(%{}) == %{"summary" => ""}
- end
- end
-
- describe "fix_in_reply_to/2" do
- setup do: clear_config([:instance, :federation_incoming_replies_max_depth])
-
- setup do
- data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json"))
- [data: data]
- end
-
- test "returns not modified object when hasn't containts inReplyTo field", %{data: data} do
- assert Transmogrifier.fix_in_reply_to(data) == data
- end
-
- test "returns object with inReplyToAtomUri when denied incoming reply", %{data: data} do
- Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 0)
-
- object_with_reply =
- Map.put(data["object"], "inReplyTo", "https://shitposter.club/notice/2827873")
-
- modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
- assert modified_object["inReplyTo"] == "https://shitposter.club/notice/2827873"
- assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873"
-
- object_with_reply =
- Map.put(data["object"], "inReplyTo", %{"id" => "https://shitposter.club/notice/2827873"})
-
- modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
- assert modified_object["inReplyTo"] == %{"id" => "https://shitposter.club/notice/2827873"}
- assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873"
-
- object_with_reply =
- Map.put(data["object"], "inReplyTo", ["https://shitposter.club/notice/2827873"])
-
- modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
- assert modified_object["inReplyTo"] == ["https://shitposter.club/notice/2827873"]
- assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873"
-
- object_with_reply = Map.put(data["object"], "inReplyTo", [])
- modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
- assert modified_object["inReplyTo"] == []
- assert modified_object["inReplyToAtomUri"] == ""
- end
-
- @tag capture_log: true
- test "returns modified object when allowed incoming reply", %{data: data} do
- object_with_reply =
- Map.put(
- data["object"],
- "inReplyTo",
- "https://shitposter.club/notice/2827873"
- )
-
- Pleroma.Config.put([:instance, :federation_incoming_replies_max_depth], 5)
- modified_object = Transmogrifier.fix_in_reply_to(object_with_reply)
-
- assert modified_object["inReplyTo"] ==
- "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
-
- assert modified_object["inReplyToAtomUri"] == "https://shitposter.club/notice/2827873"
-
- assert modified_object["context"] ==
- "tag:shitposter.club,2017-05-05:objectType=thread:nonce=3c16e9c2681f6d26"
- end
- end
-
- describe "fix_url/1" do
- test "fixes data for object when url is map" do
- object = %{
- "url" => %{
- "type" => "Link",
- "mimeType" => "video/mp4",
- "href" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4"
- }
- }
-
- assert Transmogrifier.fix_url(object) == %{
- "url" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4"
- }
- end
-
- test "fixes data for video object" do
- object = %{
- "type" => "Video",
- "url" => [
- %{
- "type" => "Link",
- "mimeType" => "video/mp4",
- "href" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4"
- },
- %{
- "type" => "Link",
- "mimeType" => "video/mp4",
- "href" => "https://peertube46fb-ad81-2d4c2d1630e3-240.mp4"
- },
- %{
- "type" => "Link",
- "mimeType" => "text/html",
- "href" => "https://peertube.-2d4c2d1630e3"
- },
- %{
- "type" => "Link",
- "mimeType" => "text/html",
- "href" => "https://peertube.-2d4c2d16377-42"
- }
- ]
- }
-
- assert Transmogrifier.fix_url(object) == %{
- "attachment" => [
- %{
- "href" => "https://peede8d-46fb-ad81-2d4c2d1630e3-480.mp4",
- "mimeType" => "video/mp4",
- "type" => "Link"
- }
- ],
- "type" => "Video",
- "url" => "https://peertube.-2d4c2d1630e3"
- }
- end
-
- test "fixes url for not Video object" do
- object = %{
- "type" => "Text",
- "url" => [
- %{
- "type" => "Link",
- "mimeType" => "text/html",
- "href" => "https://peertube.-2d4c2d1630e3"
- },
- %{
- "type" => "Link",
- "mimeType" => "text/html",
- "href" => "https://peertube.-2d4c2d16377-42"
- }
- ]
- }
-
- assert Transmogrifier.fix_url(object) == %{
- "type" => "Text",
- "url" => "https://peertube.-2d4c2d1630e3"
- }
-
- assert Transmogrifier.fix_url(%{"type" => "Text", "url" => []}) == %{
- "type" => "Text",
- "url" => ""
- }
- end
-
- test "retunrs not modified object" do
- assert Transmogrifier.fix_url(%{"type" => "Text"}) == %{"type" => "Text"}
- end
- end
-
- describe "get_obj_helper/2" do
- test "returns nil when cannot normalize object" do
- assert capture_log(fn ->
- refute Transmogrifier.get_obj_helper("test-obj-id")
- end) =~ "Unsupported URI scheme"
- end
-
- @tag capture_log: true
- test "returns {:ok, %Object{}} for success case" do
- assert {:ok, %Object{}} =
- Transmogrifier.get_obj_helper("https://shitposter.club/notice/2827873")
- end
- end
-
- describe "fix_attachments/1" do
- test "returns not modified object" do
- data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json"))
- assert Transmogrifier.fix_attachments(data) == data
- end
-
- test "returns modified object when attachment is map" do
- assert Transmogrifier.fix_attachments(%{
- "attachment" => %{
- "mediaType" => "video/mp4",
- "url" => "https://peertube.moe/stat-480.mp4"
- }
- }) == %{
- "attachment" => [
- %{
- "mediaType" => "video/mp4",
- "type" => "Document",
- "url" => [
- %{
- "href" => "https://peertube.moe/stat-480.mp4",
- "mediaType" => "video/mp4",
- "type" => "Link"
- }
- ]
- }
- ]
- }
- end
-
- test "returns modified object when attachment is list" do
- assert Transmogrifier.fix_attachments(%{
- "attachment" => [
- %{"mediaType" => "video/mp4", "url" => "https://pe.er/stat-480.mp4"},
- %{"mimeType" => "video/mp4", "href" => "https://pe.er/stat-480.mp4"}
- ]
- }) == %{
- "attachment" => [
- %{
- "mediaType" => "video/mp4",
- "type" => "Document",
- "url" => [
- %{
- "href" => "https://pe.er/stat-480.mp4",
- "mediaType" => "video/mp4",
- "type" => "Link"
- }
- ]
- },
- %{
- "mediaType" => "video/mp4",
- "type" => "Document",
- "url" => [
- %{
- "href" => "https://pe.er/stat-480.mp4",
- "mediaType" => "video/mp4",
- "type" => "Link"
- }
- ]
- }
- ]
- }
- end
- end
-
- describe "fix_emoji/1" do
- test "returns not modified object when object not contains tags" do
- data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json"))
- assert Transmogrifier.fix_emoji(data) == data
- end
-
- test "returns object with emoji when object contains list tags" do
- assert Transmogrifier.fix_emoji(%{
- "tag" => [
- %{"type" => "Emoji", "name" => ":bib:", "icon" => %{"url" => "/test"}},
- %{"type" => "Hashtag"}
- ]
- }) == %{
- "emoji" => %{"bib" => "/test"},
- "tag" => [
- %{"icon" => %{"url" => "/test"}, "name" => ":bib:", "type" => "Emoji"},
- %{"type" => "Hashtag"}
- ]
- }
- end
-
- test "returns object with emoji when object contains map tag" do
- assert Transmogrifier.fix_emoji(%{
- "tag" => %{"type" => "Emoji", "name" => ":bib:", "icon" => %{"url" => "/test"}}
- }) == %{
- "emoji" => %{"bib" => "/test"},
- "tag" => %{"icon" => %{"url" => "/test"}, "name" => ":bib:", "type" => "Emoji"}
- }
- end
- end
-
- describe "set_replies/1" do
- setup do: clear_config([:activitypub, :note_replies_output_limit], 2)
-
- test "returns unmodified object if activity doesn't have self-replies" do
- data = Poison.decode!(File.read!("test/fixtures/mastodon-post-activity.json"))
- assert Transmogrifier.set_replies(data) == data
- end
-
- test "sets `replies` collection with a limited number of self-replies" do
- [user, another_user] = insert_list(2, :user)
-
- {:ok, %{id: id1} = activity} = CommonAPI.post(user, %{status: "1"})
-
- {:ok, %{id: id2} = self_reply1} =
- CommonAPI.post(user, %{status: "self-reply 1", in_reply_to_status_id: id1})
-
- {:ok, self_reply2} =
- CommonAPI.post(user, %{status: "self-reply 2", in_reply_to_status_id: id1})
-
- # Assuming to _not_ be present in `replies` due to :note_replies_output_limit is set to 2
- {:ok, _} = CommonAPI.post(user, %{status: "self-reply 3", in_reply_to_status_id: id1})
-
- {:ok, _} =
- CommonAPI.post(user, %{
- status: "self-reply to self-reply",
- in_reply_to_status_id: id2
- })
-
- {:ok, _} =
- CommonAPI.post(another_user, %{
- status: "another user's reply",
- in_reply_to_status_id: id1
- })
-
- object = Object.normalize(activity)
- replies_uris = Enum.map([self_reply1, self_reply2], fn a -> a.object.data["id"] end)
-
- assert %{"type" => "Collection", "items" => ^replies_uris} =
- Transmogrifier.set_replies(object.data)["replies"]
- end
- end
-
- test "take_emoji_tags/1" do
- user = insert(:user, %{emoji: %{"firefox" => "https://example.org/firefox.png"}})
-
- assert Transmogrifier.take_emoji_tags(user) == [
- %{
- "icon" => %{"type" => "Image", "url" => "https://example.org/firefox.png"},
- "id" => "https://example.org/firefox.png",
- "name" => ":firefox:",
- "type" => "Emoji",
- "updated" => "1970-01-01T00:00:00Z"
- }
- ]
- end
-end
diff --git a/test/web/admin_api/controllers/admin_api_controller_test.exs b/test/web/admin_api/controllers/admin_api_controller_test.exs
deleted file mode 100644
index 3bc88c6a9..000000000
--- a/test/web/admin_api/controllers/admin_api_controller_test.exs
+++ /dev/null
@@ -1,1979 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
- use Pleroma.Web.ConnCase
- use Oban.Testing, repo: Pleroma.Repo
-
- import ExUnit.CaptureLog
- import Mock
- import Pleroma.Factory
- import Swoosh.TestAssertions
-
- alias Pleroma.Activity
- alias Pleroma.Config
- alias Pleroma.HTML
- alias Pleroma.MFA
- alias Pleroma.ModerationLog
- alias Pleroma.Repo
- alias Pleroma.Tests.ObanHelpers
- alias Pleroma.User
- alias Pleroma.Web
- alias Pleroma.Web.ActivityPub.Relay
- alias Pleroma.Web.CommonAPI
- alias Pleroma.Web.MediaProxy
-
- setup_all do
- Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
-
- :ok
- end
-
- setup do
- admin = insert(:user, is_admin: true)
- token = insert(:oauth_admin_token, user: admin)
-
- conn =
- build_conn()
- |> assign(:user, admin)
- |> assign(:token, token)
-
- {:ok, %{admin: admin, token: token, conn: conn}}
- end
-
- test "with valid `admin_token` query parameter, skips OAuth scopes check" do
- clear_config([:admin_token], "password123")
-
- user = insert(:user)
-
- conn = get(build_conn(), "/api/pleroma/admin/users/#{user.nickname}?admin_token=password123")
-
- assert json_response(conn, 200)
- end
-
- describe "with [:auth, :enforce_oauth_admin_scope_usage]," do
- setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], true)
-
- test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope",
- %{admin: admin} do
- user = insert(:user)
- url = "/api/pleroma/admin/users/#{user.nickname}"
-
- good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
- good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
- good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
-
- bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
- bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
- bad_token3 = nil
-
- for good_token <- [good_token1, good_token2, good_token3] do
- conn =
- build_conn()
- |> assign(:user, admin)
- |> assign(:token, good_token)
- |> get(url)
-
- assert json_response(conn, 200)
- end
-
- for good_token <- [good_token1, good_token2, good_token3] do
- conn =
- build_conn()
- |> assign(:user, nil)
- |> assign(:token, good_token)
- |> get(url)
-
- assert json_response(conn, :forbidden)
- end
-
- for bad_token <- [bad_token1, bad_token2, bad_token3] do
- conn =
- build_conn()
- |> assign(:user, admin)
- |> assign(:token, bad_token)
- |> get(url)
-
- assert json_response(conn, :forbidden)
- end
- end
- end
-
- describe "unless [:auth, :enforce_oauth_admin_scope_usage]," do
- setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], false)
-
- test "GET /api/pleroma/admin/users/:nickname requires " <>
- "read:accounts or admin:read:accounts or broader scope",
- %{admin: admin} do
- user = insert(:user)
- url = "/api/pleroma/admin/users/#{user.nickname}"
-
- good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
- good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
- good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
- good_token4 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
- good_token5 = insert(:oauth_token, user: admin, scopes: ["read"])
-
- good_tokens = [good_token1, good_token2, good_token3, good_token4, good_token5]
-
- bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts:partial"])
- bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
- bad_token3 = nil
-
- for good_token <- good_tokens do
- conn =
- build_conn()
- |> assign(:user, admin)
- |> assign(:token, good_token)
- |> get(url)
-
- assert json_response(conn, 200)
- end
-
- for good_token <- good_tokens do
- conn =
- build_conn()
- |> assign(:user, nil)
- |> assign(:token, good_token)
- |> get(url)
-
- assert json_response(conn, :forbidden)
- end
-
- for bad_token <- [bad_token1, bad_token2, bad_token3] do
- conn =
- build_conn()
- |> assign(:user, admin)
- |> assign(:token, bad_token)
- |> get(url)
-
- assert json_response(conn, :forbidden)
- end
- end
- end
-
- describe "DELETE /api/pleroma/admin/users" do
- test "single user", %{admin: admin, conn: conn} do
- clear_config([:instance, :federating], true)
-
- user =
- insert(:user,
- avatar: %{"url" => [%{"href" => "https://someurl"}]},
- banner: %{"url" => [%{"href" => "https://somebanner"}]},
- bio: "Hello world!",
- name: "A guy"
- )
-
- # Create some activities to check they got deleted later
- follower = insert(:user)
- {:ok, _} = CommonAPI.post(user, %{status: "test"})
- {:ok, _, _, _} = CommonAPI.follow(user, follower)
- {:ok, _, _, _} = CommonAPI.follow(follower, user)
- user = Repo.get(User, user.id)
- assert user.note_count == 1
- assert user.follower_count == 1
- assert user.following_count == 1
- refute user.deactivated
-
- with_mock Pleroma.Web.Federator,
- publish: fn _ -> nil end,
- perform: fn _, _ -> nil end do
- conn =
- conn
- |> put_req_header("accept", "application/json")
- |> delete("/api/pleroma/admin/users?nickname=#{user.nickname}")
-
- ObanHelpers.perform_all()
-
- assert User.get_by_nickname(user.nickname).deactivated
-
- log_entry = Repo.one(ModerationLog)
-
- assert ModerationLog.get_log_entry_message(log_entry) ==
- "@#{admin.nickname} deleted users: @#{user.nickname}"
-
- assert json_response(conn, 200) == [user.nickname]
-
- user = Repo.get(User, user.id)
- assert user.deactivated
-
- assert user.avatar == %{}
- assert user.banner == %{}
- assert user.note_count == 0
- assert user.follower_count == 0
- assert user.following_count == 0
- assert user.bio == ""
- assert user.name == nil
-
- assert called(Pleroma.Web.Federator.publish(:_))
- end
- end
-
- test "multiple users", %{admin: admin, conn: conn} do
- user_one = insert(:user)
- user_two = insert(:user)
-
- conn =
- conn
- |> put_req_header("accept", "application/json")
- |> delete("/api/pleroma/admin/users", %{
- nicknames: [user_one.nickname, user_two.nickname]
- })
-
- log_entry = Repo.one(ModerationLog)
-
- assert ModerationLog.get_log_entry_message(log_entry) ==
- "@#{admin.nickname} deleted users: @#{user_one.nickname}, @#{user_two.nickname}"
-
- response = json_response(conn, 200)
- assert response -- [user_one.nickname, user_two.nickname] == []
- end
- end
-
- describe "/api/pleroma/admin/users" do
- test "Create", %{conn: conn} do
- conn =
- conn
- |> put_req_header("accept", "application/json")
- |> post("/api/pleroma/admin/users", %{
- "users" => [
- %{
- "nickname" => "lain",
- "email" => "lain@example.org",
- "password" => "test"
- },
- %{
- "nickname" => "lain2",
- "email" => "lain2@example.org",
- "password" => "test"
- }
- ]
- })
-
- response = json_response(conn, 200) |> Enum.map(&Map.get(&1, "type"))
- assert response == ["success", "success"]
-
- log_entry = Repo.one(ModerationLog)
-
- assert ["lain", "lain2"] -- Enum.map(log_entry.data["subjects"], & &1["nickname"]) == []
- end
-
- test "Cannot create user with existing email", %{conn: conn} do
- user = insert(:user)
-
- conn =
- conn
- |> put_req_header("accept", "application/json")
- |> post("/api/pleroma/admin/users", %{
- "users" => [
- %{
- "nickname" => "lain",
- "email" => user.email,
- "password" => "test"
- }
- ]
- })
-
- assert json_response(conn, 409) == [
- %{
- "code" => 409,
- "data" => %{
- "email" => user.email,
- "nickname" => "lain"
- },
- "error" => "email has already been taken",
- "type" => "error"
- }
- ]
- end
-
- test "Cannot create user with existing nickname", %{conn: conn} do
- user = insert(:user)
-
- conn =
- conn
- |> put_req_header("accept", "application/json")
- |> post("/api/pleroma/admin/users", %{
- "users" => [
- %{
- "nickname" => user.nickname,
- "email" => "someuser@plerama.social",
- "password" => "test"
- }
- ]
- })
-
- assert json_response(conn, 409) == [
- %{
- "code" => 409,
- "data" => %{
- "email" => "someuser@plerama.social",
- "nickname" => user.nickname
- },
- "error" => "nickname has already been taken",
- "type" => "error"
- }
- ]
- end
-
- test "Multiple user creation works in transaction", %{conn: conn} do
- user = insert(:user)
-
- conn =
- conn
- |> put_req_header("accept", "application/json")
- |> post("/api/pleroma/admin/users", %{
- "users" => [
- %{
- "nickname" => "newuser",
- "email" => "newuser@pleroma.social",
- "password" => "test"
- },
- %{
- "nickname" => "lain",
- "email" => user.email,
- "password" => "test"
- }
- ]
- })
-
- assert json_response(conn, 409) == [
- %{
- "code" => 409,
- "data" => %{
- "email" => user.email,
- "nickname" => "lain"
- },
- "error" => "email has already been taken",
- "type" => "error"
- },
- %{
- "code" => 409,
- "data" => %{
- "email" => "newuser@pleroma.social",
- "nickname" => "newuser"
- },
- "error" => "",
- "type" => "error"
- }
- ]
-
- assert User.get_by_nickname("newuser") === nil
- end
- end
-
- describe "/api/pleroma/admin/users/:nickname" do
- test "Show", %{conn: conn} do
- user = insert(:user)
-
- conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
-
- expected = %{
- "deactivated" => false,
- "id" => to_string(user.id),
- "local" => true,
- "nickname" => user.nickname,
- "roles" => %{"admin" => false, "moderator" => false},
- "tags" => [],
- "avatar" => User.avatar_url(user) |> MediaProxy.url(),
- "display_name" => HTML.strip_tags(user.name || user.nickname),
- "confirmation_pending" => false,
- "approval_pending" => false,
- "url" => user.ap_id,
- "registration_reason" => nil,
- "actor_type" => "Person"
- }
-
- assert expected == json_response(conn, 200)
- end
-
- test "when the user doesn't exist", %{conn: conn} do
- user = build(:user)
-
- conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
-
- assert %{"error" => "Not found"} == json_response(conn, 404)
- end
- end
-
- describe "/api/pleroma/admin/users/follow" do
- test "allows to force-follow another user", %{admin: admin, conn: conn} do
- user = insert(:user)
- follower = insert(:user)
-
- conn
- |> put_req_header("accept", "application/json")
- |> post("/api/pleroma/admin/users/follow", %{
- "follower" => follower.nickname,
- "followed" => user.nickname
- })
-
- user = User.get_cached_by_id(user.id)
- follower = User.get_cached_by_id(follower.id)
-
- assert User.following?(follower, user)
-
- log_entry = Repo.one(ModerationLog)
-
- assert ModerationLog.get_log_entry_message(log_entry) ==
- "@#{admin.nickname} made @#{follower.nickname} follow @#{user.nickname}"
- end
- end
-
- describe "/api/pleroma/admin/users/unfollow" do
- test "allows to force-unfollow another user", %{admin: admin, conn: conn} do
- user = insert(:user)
- follower = insert(:user)
-
- User.follow(follower, user)
-
- conn
- |> put_req_header("accept", "application/json")
- |> post("/api/pleroma/admin/users/unfollow", %{
- "follower" => follower.nickname,
- "followed" => user.nickname
- })
-
- user = User.get_cached_by_id(user.id)
- follower = User.get_cached_by_id(follower.id)
-
- refute User.following?(follower, user)
-
- log_entry = Repo.one(ModerationLog)
-
- assert ModerationLog.get_log_entry_message(log_entry) ==
- "@#{admin.nickname} made @#{follower.nickname} unfollow @#{user.nickname}"
- end
- end
-
- describe "PUT /api/pleroma/admin/users/tag" do
- setup %{conn: conn} do
- user1 = insert(:user, %{tags: ["x"]})
- user2 = insert(:user, %{tags: ["y"]})
- user3 = insert(:user, %{tags: ["unchanged"]})
-
- conn =
- conn
- |> put_req_header("accept", "application/json")
- |> put(
- "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
- "#{user2.nickname}&tags[]=foo&tags[]=bar"
- )
-
- %{conn: conn, user1: user1, user2: user2, user3: user3}
- end
-
- test "it appends specified tags to users with specified nicknames", %{
- conn: conn,
- admin: admin,
- user1: user1,
- user2: user2
- } do
- assert empty_json_response(conn)
- assert User.get_cached_by_id(user1.id).tags == ["x", "foo", "bar"]
- assert User.get_cached_by_id(user2.id).tags == ["y", "foo", "bar"]
-
- log_entry = Repo.one(ModerationLog)
-
- users =
- [user1.nickname, user2.nickname]
- |> Enum.map(&"@#{&1}")
- |> Enum.join(", ")
-
- tags = ["foo", "bar"] |> Enum.join(", ")
-
- assert ModerationLog.get_log_entry_message(log_entry) ==
- "@#{admin.nickname} added tags: #{tags} to users: #{users}"
- end
-
- test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
- assert empty_json_response(conn)
- assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
- end
- end
-
- describe "DELETE /api/pleroma/admin/users/tag" do
- setup %{conn: conn} do
- user1 = insert(:user, %{tags: ["x"]})
- user2 = insert(:user, %{tags: ["y", "z"]})
- user3 = insert(:user, %{tags: ["unchanged"]})
-
- conn =
- conn
- |> put_req_header("accept", "application/json")
- |> delete(
- "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
- "#{user2.nickname}&tags[]=x&tags[]=z"
- )
-
- %{conn: conn, user1: user1, user2: user2, user3: user3}
- end
-
- test "it removes specified tags from users with specified nicknames", %{
- conn: conn,
- admin: admin,
- user1: user1,
- user2: user2
- } do
- assert empty_json_response(conn)
- assert User.get_cached_by_id(user1.id).tags == []
- assert User.get_cached_by_id(user2.id).tags == ["y"]
-
- log_entry = Repo.one(ModerationLog)
-
- users =
- [user1.nickname, user2.nickname]
- |> Enum.map(&"@#{&1}")
- |> Enum.join(", ")
-
- tags = ["x", "z"] |> Enum.join(", ")
-
- assert ModerationLog.get_log_entry_message(log_entry) ==
- "@#{admin.nickname} removed tags: #{tags} from users: #{users}"
- end
-
- test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
- assert empty_json_response(conn)
- assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
- end
- end
-
- describe "/api/pleroma/admin/users/:nickname/permission_group" do
- test "GET is giving user_info", %{admin: admin, conn: conn} do
- conn =
- conn
- |> put_req_header("accept", "application/json")
- |> get("/api/pleroma/admin/users/#{admin.nickname}/permission_group/")
-
- assert json_response(conn, 200) == %{
- "is_admin" => true,
- "is_moderator" => false
- }
- end
-
- test "/:right POST, can add to a permission group", %{admin: admin, conn: conn} do
- user = insert(:user)
-
- conn =
- conn
- |> put_req_header("accept", "application/json")
- |> post("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
-
- assert json_response(conn, 200) == %{
- "is_admin" => true
- }
-
- log_entry = Repo.one(ModerationLog)
-
- assert ModerationLog.get_log_entry_message(log_entry) ==
- "@#{admin.nickname} made @#{user.nickname} admin"
- end
-
- test "/:right POST, can add to a permission group (multiple)", %{admin: admin, conn: conn} do
- user_one = insert(:user)
- user_two = insert(:user)
-
- conn =
- conn
- |> put_req_header("accept", "application/json")
- |> post("/api/pleroma/admin/users/permission_group/admin", %{
- nicknames: [user_one.nickname, user_two.nickname]
- })
-
- assert json_response(conn, 200) == %{"is_admin" => true}
-
- log_entry = Repo.one(ModerationLog)
-
- assert ModerationLog.get_log_entry_message(log_entry) ==
- "@#{admin.nickname} made @#{user_one.nickname}, @#{user_two.nickname} admin"
- end
-
- test "/:right DELETE, can remove from a permission group", %{admin: admin, conn: conn} do
- user = insert(:user, is_admin: true)
-
- conn =
- conn
- |> put_req_header("accept", "application/json")
- |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
-
- assert json_response(conn, 200) == %{"is_admin" => false}
-
- log_entry = Repo.one(ModerationLog)
-
- assert ModerationLog.get_log_entry_message(log_entry) ==
- "@#{admin.nickname} revoked admin role from @#{user.nickname}"
- end
-
- test "/:right DELETE, can remove from a permission group (multiple)", %{
- admin: admin,
- conn: conn
- } do
- user_one = insert(:user, is_admin: true)
- user_two = insert(:user, is_admin: true)
-
- conn =
- conn
- |> put_req_header("accept", "application/json")
- |> delete("/api/pleroma/admin/users/permission_group/admin", %{
- nicknames: [user_one.nickname, user_two.nickname]
- })
-
- assert json_response(conn, 200) == %{"is_admin" => false}
-
- log_entry = Repo.one(ModerationLog)
-
- assert ModerationLog.get_log_entry_message(log_entry) ==
- "@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{
- user_two.nickname
- }"
- end
- end
-
- test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do
- user = insert(:user)
-
- conn =
- conn
- |> put_req_header("accept", "application/json")
- |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset")
-
- resp = json_response(conn, 200)
-
- assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"])
- end
-
- describe "GET /api/pleroma/admin/users" do
- test "renders users array for the first page", %{conn: conn, admin: admin} do
- user = insert(:user, local: false, tags: ["foo", "bar"])
- user2 = insert(:user, approval_pending: true, registration_reason: "I'm a chill dude")
-
- conn = get(conn, "/api/pleroma/admin/users?page=1")
-
- users =
- [
- %{
- "deactivated" => admin.deactivated,
- "id" => admin.id,
- "nickname" => admin.nickname,
- "roles" => %{"admin" => true, "moderator" => false},
- "local" => true,
- "tags" => [],
- "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
- "display_name" => HTML.strip_tags(admin.name || admin.nickname),
- "confirmation_pending" => false,
- "approval_pending" => false,
- "url" => admin.ap_id,
- "registration_reason" => nil,
- "actor_type" => "Person"
- },
- %{
- "deactivated" => user.deactivated,
- "id" => user.id,
- "nickname" => user.nickname,
- "roles" => %{"admin" => false, "moderator" => false},
- "local" => false,
- "tags" => ["foo", "bar"],
- "avatar" => User.avatar_url(user) |> MediaProxy.url(),
- "display_name" => HTML.strip_tags(user.name || user.nickname),
- "confirmation_pending" => false,
- "approval_pending" => false,
- "url" => user.ap_id,
- "registration_reason" => nil,
- "actor_type" => "Person"
- },
- %{
- "deactivated" => user2.deactivated,
- "id" => user2.id,
- "nickname" => user2.nickname,
- "roles" => %{"admin" => false, "moderator" => false},
- "local" => true,
- "tags" => [],
- "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
- "display_name" => HTML.strip_tags(user2.name || user2.nickname),
- "confirmation_pending" => false,
- "approval_pending" => true,
- "url" => user2.ap_id,
- "registration_reason" => "I'm a chill dude",
- "actor_type" => "Person"
- }
- ]
- |> Enum.sort_by(& &1["nickname"])
-
- assert json_response(conn, 200) == %{
- "count" => 3,
- "page_size" => 50,
- "users" => users
- }
- end
-
- test "pagination works correctly with service users", %{conn: conn} do
- service1 = User.get_or_create_service_actor_by_ap_id(Web.base_url() <> "/meido", "meido")
-
- insert_list(25, :user)
-
- assert %{"count" => 26, "page_size" => 10, "users" => users1} =
- conn
- |> get("/api/pleroma/admin/users?page=1&filters=", %{page_size: "10"})
- |> json_response(200)
-
- assert Enum.count(users1) == 10
- assert service1 not in users1
-
- assert %{"count" => 26, "page_size" => 10, "users" => users2} =
- conn
- |> get("/api/pleroma/admin/users?page=2&filters=", %{page_size: "10"})
- |> json_response(200)
-
- assert Enum.count(users2) == 10
- assert service1 not in users2
-
- assert %{"count" => 26, "page_size" => 10, "users" => users3} =
- conn
- |> get("/api/pleroma/admin/users?page=3&filters=", %{page_size: "10"})
- |> json_response(200)
-
- assert Enum.count(users3) == 6
- assert service1 not in users3
- end
-
- test "renders empty array for the second page", %{conn: conn} do
- insert(:user)
-
- conn = get(conn, "/api/pleroma/admin/users?page=2")
-
- assert json_response(conn, 200) == %{
- "count" => 2,
- "page_size" => 50,
- "users" => []
- }
- end
-
- test "regular search", %{conn: conn} do
- user = insert(:user, nickname: "bob")
-
- conn = get(conn, "/api/pleroma/admin/users?query=bo")
-
- assert json_response(conn, 200) == %{
- "count" => 1,
- "page_size" => 50,
- "users" => [
- %{
- "deactivated" => user.deactivated,
- "id" => user.id,
- "nickname" => user.nickname,
- "roles" => %{"admin" => false, "moderator" => false},
- "local" => true,
- "tags" => [],
- "avatar" => User.avatar_url(user) |> MediaProxy.url(),
- "display_name" => HTML.strip_tags(user.name || user.nickname),
- "confirmation_pending" => false,
- "approval_pending" => false,
- "url" => user.ap_id,
- "registration_reason" => nil,
- "actor_type" => "Person"
- }
- ]
- }
- end
-
- test "search by domain", %{conn: conn} do
- user = insert(:user, nickname: "nickname@domain.com")
- insert(:user)
-
- conn = get(conn, "/api/pleroma/admin/users?query=domain.com")
-
- assert json_response(conn, 200) == %{
- "count" => 1,
- "page_size" => 50,
- "users" => [
- %{
- "deactivated" => user.deactivated,
- "id" => user.id,
- "nickname" => user.nickname,
- "roles" => %{"admin" => false, "moderator" => false},
- "local" => true,
- "tags" => [],
- "avatar" => User.avatar_url(user) |> MediaProxy.url(),
- "display_name" => HTML.strip_tags(user.name || user.nickname),
- "confirmation_pending" => false,
- "approval_pending" => false,
- "url" => user.ap_id,
- "registration_reason" => nil,
- "actor_type" => "Person"
- }
- ]
- }
- end
-
- test "search by full nickname", %{conn: conn} do
- user = insert(:user, nickname: "nickname@domain.com")
- insert(:user)
-
- conn = get(conn, "/api/pleroma/admin/users?query=nickname@domain.com")
-
- assert json_response(conn, 200) == %{
- "count" => 1,
- "page_size" => 50,
- "users" => [
- %{
- "deactivated" => user.deactivated,
- "id" => user.id,
- "nickname" => user.nickname,
- "roles" => %{"admin" => false, "moderator" => false},
- "local" => true,
- "tags" => [],
- "avatar" => User.avatar_url(user) |> MediaProxy.url(),
- "display_name" => HTML.strip_tags(user.name || user.nickname),
- "confirmation_pending" => false,
- "approval_pending" => false,
- "url" => user.ap_id,
- "registration_reason" => nil,
- "actor_type" => "Person"
- }
- ]
- }
- end
-
- test "search by display name", %{conn: conn} do
- user = insert(:user, name: "Display name")
- insert(:user)
-
- conn = get(conn, "/api/pleroma/admin/users?name=display")
-
- assert json_response(conn, 200) == %{
- "count" => 1,
- "page_size" => 50,
- "users" => [
- %{
- "deactivated" => user.deactivated,
- "id" => user.id,
- "nickname" => user.nickname,
- "roles" => %{"admin" => false, "moderator" => false},
- "local" => true,
- "tags" => [],
- "avatar" => User.avatar_url(user) |> MediaProxy.url(),
- "display_name" => HTML.strip_tags(user.name || user.nickname),
- "confirmation_pending" => false,
- "approval_pending" => false,
- "url" => user.ap_id,
- "registration_reason" => nil,
- "actor_type" => "Person"
- }
- ]
- }
- end
-
- test "search by email", %{conn: conn} do
- user = insert(:user, email: "email@example.com")
- insert(:user)
-
- conn = get(conn, "/api/pleroma/admin/users?email=email@example.com")
-
- assert json_response(conn, 200) == %{
- "count" => 1,
- "page_size" => 50,
- "users" => [
- %{
- "deactivated" => user.deactivated,
- "id" => user.id,
- "nickname" => user.nickname,
- "roles" => %{"admin" => false, "moderator" => false},
- "local" => true,
- "tags" => [],
- "avatar" => User.avatar_url(user) |> MediaProxy.url(),
- "display_name" => HTML.strip_tags(user.name || user.nickname),
- "confirmation_pending" => false,
- "approval_pending" => false,
- "url" => user.ap_id,
- "registration_reason" => nil,
- "actor_type" => "Person"
- }
- ]
- }
- end
-
- test "regular search with page size", %{conn: conn} do
- user = insert(:user, nickname: "aalice")
- user2 = insert(:user, nickname: "alice")
-
- conn1 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=1")
-
- assert json_response(conn1, 200) == %{
- "count" => 2,
- "page_size" => 1,
- "users" => [
- %{
- "deactivated" => user.deactivated,
- "id" => user.id,
- "nickname" => user.nickname,
- "roles" => %{"admin" => false, "moderator" => false},
- "local" => true,
- "tags" => [],
- "avatar" => User.avatar_url(user) |> MediaProxy.url(),
- "display_name" => HTML.strip_tags(user.name || user.nickname),
- "confirmation_pending" => false,
- "approval_pending" => false,
- "url" => user.ap_id,
- "registration_reason" => nil,
- "actor_type" => "Person"
- }
- ]
- }
-
- conn2 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=2")
-
- assert json_response(conn2, 200) == %{
- "count" => 2,
- "page_size" => 1,
- "users" => [
- %{
- "deactivated" => user2.deactivated,
- "id" => user2.id,
- "nickname" => user2.nickname,
- "roles" => %{"admin" => false, "moderator" => false},
- "local" => true,
- "tags" => [],
- "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
- "display_name" => HTML.strip_tags(user2.name || user2.nickname),
- "confirmation_pending" => false,
- "approval_pending" => false,
- "url" => user2.ap_id,
- "registration_reason" => nil,
- "actor_type" => "Person"
- }
- ]
- }
- end
-
- test "only local users" do
- admin = insert(:user, is_admin: true, nickname: "john")
- token = insert(:oauth_admin_token, user: admin)
- user = insert(:user, nickname: "bob")
-
- insert(:user, nickname: "bobb", local: false)
-
- conn =
- build_conn()
- |> assign(:user, admin)
- |> assign(:token, token)
- |> get("/api/pleroma/admin/users?query=bo&filters=local")
-
- assert json_response(conn, 200) == %{
- "count" => 1,
- "page_size" => 50,
- "users" => [
- %{
- "deactivated" => user.deactivated,
- "id" => user.id,
- "nickname" => user.nickname,
- "roles" => %{"admin" => false, "moderator" => false},
- "local" => true,
- "tags" => [],
- "avatar" => User.avatar_url(user) |> MediaProxy.url(),
- "display_name" => HTML.strip_tags(user.name || user.nickname),
- "confirmation_pending" => false,
- "approval_pending" => false,
- "url" => user.ap_id,
- "registration_reason" => nil,
- "actor_type" => "Person"
- }
- ]
- }
- end
-
- test "only local users with no query", %{conn: conn, admin: old_admin} do
- admin = insert(:user, is_admin: true, nickname: "john")
- user = insert(:user, nickname: "bob")
-
- insert(:user, nickname: "bobb", local: false)
-
- conn = get(conn, "/api/pleroma/admin/users?filters=local")
-
- users =
- [
- %{
- "deactivated" => user.deactivated,
- "id" => user.id,
- "nickname" => user.nickname,
- "roles" => %{"admin" => false, "moderator" => false},
- "local" => true,
- "tags" => [],
- "avatar" => User.avatar_url(user) |> MediaProxy.url(),
- "display_name" => HTML.strip_tags(user.name || user.nickname),
- "confirmation_pending" => false,
- "approval_pending" => false,
- "url" => user.ap_id,
- "registration_reason" => nil,
- "actor_type" => "Person"
- },
- %{
- "deactivated" => admin.deactivated,
- "id" => admin.id,
- "nickname" => admin.nickname,
- "roles" => %{"admin" => true, "moderator" => false},
- "local" => true,
- "tags" => [],
- "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
- "display_name" => HTML.strip_tags(admin.name || admin.nickname),
- "confirmation_pending" => false,
- "approval_pending" => false,
- "url" => admin.ap_id,
- "registration_reason" => nil,
- "actor_type" => "Person"
- },
- %{
- "deactivated" => false,
- "id" => old_admin.id,
- "local" => true,
- "nickname" => old_admin.nickname,
- "roles" => %{"admin" => true, "moderator" => false},
- "tags" => [],
- "avatar" => User.avatar_url(old_admin) |> MediaProxy.url(),
- "display_name" => HTML.strip_tags(old_admin.name || old_admin.nickname),
- "confirmation_pending" => false,
- "approval_pending" => false,
- "url" => old_admin.ap_id,
- "registration_reason" => nil,
- "actor_type" => "Person"
- }
- ]
- |> Enum.sort_by(& &1["nickname"])
-
- assert json_response(conn, 200) == %{
- "count" => 3,
- "page_size" => 50,
- "users" => users
- }
- end
-
- test "only unapproved users", %{conn: conn} do
- user =
- insert(:user,
- nickname: "sadboy",
- approval_pending: true,
- registration_reason: "Plz let me in!"
- )
-
- insert(:user, nickname: "happyboy", approval_pending: false)
-
- conn = get(conn, "/api/pleroma/admin/users?filters=need_approval")
-
- users =
- [
- %{
- "deactivated" => user.deactivated,
- "id" => user.id,
- "nickname" => user.nickname,
- "roles" => %{"admin" => false, "moderator" => false},
- "local" => true,
- "tags" => [],
- "avatar" => User.avatar_url(user) |> MediaProxy.url(),
- "display_name" => HTML.strip_tags(user.name || user.nickname),
- "confirmation_pending" => false,
- "approval_pending" => true,
- "url" => user.ap_id,
- "registration_reason" => "Plz let me in!",
- "actor_type" => "Person"
- }
- ]
- |> Enum.sort_by(& &1["nickname"])
-
- assert json_response(conn, 200) == %{
- "count" => 1,
- "page_size" => 50,
- "users" => users
- }
- end
-
- test "load only admins", %{conn: conn, admin: admin} do
- second_admin = insert(:user, is_admin: true)
- insert(:user)
- insert(:user)
-
- conn = get(conn, "/api/pleroma/admin/users?filters=is_admin")
-
- users =
- [
- %{
- "deactivated" => false,
- "id" => admin.id,
- "nickname" => admin.nickname,
- "roles" => %{"admin" => true, "moderator" => false},
- "local" => admin.local,
- "tags" => [],
- "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
- "display_name" => HTML.strip_tags(admin.name || admin.nickname),
- "confirmation_pending" => false,
- "approval_pending" => false,
- "url" => admin.ap_id,
- "registration_reason" => nil,
- "actor_type" => "Person"
- },
- %{
- "deactivated" => false,
- "id" => second_admin.id,
- "nickname" => second_admin.nickname,
- "roles" => %{"admin" => true, "moderator" => false},
- "local" => second_admin.local,
- "tags" => [],
- "avatar" => User.avatar_url(second_admin) |> MediaProxy.url(),
- "display_name" => HTML.strip_tags(second_admin.name || second_admin.nickname),
- "confirmation_pending" => false,
- "approval_pending" => false,
- "url" => second_admin.ap_id,
- "registration_reason" => nil,
- "actor_type" => "Person"
- }
- ]
- |> Enum.sort_by(& &1["nickname"])
-
- assert json_response(conn, 200) == %{
- "count" => 2,
- "page_size" => 50,
- "users" => users
- }
- end
-
- test "load only moderators", %{conn: conn} do
- moderator = insert(:user, is_moderator: true)
- insert(:user)
- insert(:user)
-
- conn = get(conn, "/api/pleroma/admin/users?filters=is_moderator")
-
- assert json_response(conn, 200) == %{
- "count" => 1,
- "page_size" => 50,
- "users" => [
- %{
- "deactivated" => false,
- "id" => moderator.id,
- "nickname" => moderator.nickname,
- "roles" => %{"admin" => false, "moderator" => true},
- "local" => moderator.local,
- "tags" => [],
- "avatar" => User.avatar_url(moderator) |> MediaProxy.url(),
- "display_name" => HTML.strip_tags(moderator.name || moderator.nickname),
- "confirmation_pending" => false,
- "approval_pending" => false,
- "url" => moderator.ap_id,
- "registration_reason" => nil,
- "actor_type" => "Person"
- }
- ]
- }
- end
-
- test "load users with tags list", %{conn: conn} do
- user1 = insert(:user, tags: ["first"])
- user2 = insert(:user, tags: ["second"])
- insert(:user)
- insert(:user)
-
- conn = get(conn, "/api/pleroma/admin/users?tags[]=first&tags[]=second")
-
- users =
- [
- %{
- "deactivated" => false,
- "id" => user1.id,
- "nickname" => user1.nickname,
- "roles" => %{"admin" => false, "moderator" => false},
- "local" => user1.local,
- "tags" => ["first"],
- "avatar" => User.avatar_url(user1) |> MediaProxy.url(),
- "display_name" => HTML.strip_tags(user1.name || user1.nickname),
- "confirmation_pending" => false,
- "approval_pending" => false,
- "url" => user1.ap_id,
- "registration_reason" => nil,
- "actor_type" => "Person"
- },
- %{
- "deactivated" => false,
- "id" => user2.id,
- "nickname" => user2.nickname,
- "roles" => %{"admin" => false, "moderator" => false},
- "local" => user2.local,
- "tags" => ["second"],
- "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
- "display_name" => HTML.strip_tags(user2.name || user2.nickname),
- "confirmation_pending" => false,
- "approval_pending" => false,
- "url" => user2.ap_id,
- "registration_reason" => nil,
- "actor_type" => "Person"
- }
- ]
- |> Enum.sort_by(& &1["nickname"])
-
- assert json_response(conn, 200) == %{
- "count" => 2,
- "page_size" => 50,
- "users" => users
- }
- end
-
- test "`active` filters out users pending approval", %{token: token} do
- insert(:user, approval_pending: true)
- %{id: user_id} = insert(:user, approval_pending: false)
- %{id: admin_id} = token.user
-
- conn =
- build_conn()
- |> assign(:user, token.user)
- |> assign(:token, token)
- |> get("/api/pleroma/admin/users?filters=active")
-
- assert %{
- "count" => 2,
- "page_size" => 50,
- "users" => [
- %{"id" => ^admin_id},
- %{"id" => ^user_id}
- ]
- } = json_response(conn, 200)
- end
-
- test "it works with multiple filters" do
- admin = insert(:user, nickname: "john", is_admin: true)
- token = insert(:oauth_admin_token, user: admin)
- user = insert(:user, nickname: "bob", local: false, deactivated: true)
-
- insert(:user, nickname: "ken", local: true, deactivated: true)
- insert(:user, nickname: "bobb", local: false, deactivated: false)
-
- conn =
- build_conn()
- |> assign(:user, admin)
- |> assign(:token, token)
- |> get("/api/pleroma/admin/users?filters=deactivated,external")
-
- assert json_response(conn, 200) == %{
- "count" => 1,
- "page_size" => 50,
- "users" => [
- %{
- "deactivated" => user.deactivated,
- "id" => user.id,
- "nickname" => user.nickname,
- "roles" => %{"admin" => false, "moderator" => false},
- "local" => user.local,
- "tags" => [],
- "avatar" => User.avatar_url(user) |> MediaProxy.url(),
- "display_name" => HTML.strip_tags(user.name || user.nickname),
- "confirmation_pending" => false,
- "approval_pending" => false,
- "url" => user.ap_id,
- "registration_reason" => nil,
- "actor_type" => "Person"
- }
- ]
- }
- end
-
- test "it omits relay user", %{admin: admin, conn: conn} do
- assert %User{} = Relay.get_actor()
-
- conn = get(conn, "/api/pleroma/admin/users")
-
- assert json_response(conn, 200) == %{
- "count" => 1,
- "page_size" => 50,
- "users" => [
- %{
- "deactivated" => admin.deactivated,
- "id" => admin.id,
- "nickname" => admin.nickname,
- "roles" => %{"admin" => true, "moderator" => false},
- "local" => true,
- "tags" => [],
- "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
- "display_name" => HTML.strip_tags(admin.name || admin.nickname),
- "confirmation_pending" => false,
- "approval_pending" => false,
- "url" => admin.ap_id,
- "registration_reason" => nil,
- "actor_type" => "Person"
- }
- ]
- }
- end
- end
-
- test "PATCH /api/pleroma/admin/users/activate", %{admin: admin, conn: conn} do
- user_one = insert(:user, deactivated: true)
- user_two = insert(:user, deactivated: true)
-
- conn =
- patch(
- conn,
- "/api/pleroma/admin/users/activate",
- %{nicknames: [user_one.nickname, user_two.nickname]}
- )
-
- response = json_response(conn, 200)
- assert Enum.map(response["users"], & &1["deactivated"]) == [false, false]
-
- log_entry = Repo.one(ModerationLog)
-
- assert ModerationLog.get_log_entry_message(log_entry) ==
- "@#{admin.nickname} activated users: @#{user_one.nickname}, @#{user_two.nickname}"
- end
-
- test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do
- user_one = insert(:user, deactivated: false)
- user_two = insert(:user, deactivated: false)
-
- conn =
- patch(
- conn,
- "/api/pleroma/admin/users/deactivate",
- %{nicknames: [user_one.nickname, user_two.nickname]}
- )
-
- response = json_response(conn, 200)
- assert Enum.map(response["users"], & &1["deactivated"]) == [true, true]
-
- log_entry = Repo.one(ModerationLog)
-
- assert ModerationLog.get_log_entry_message(log_entry) ==
- "@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}"
- end
-
- test "PATCH /api/pleroma/admin/users/approve", %{admin: admin, conn: conn} do
- user_one = insert(:user, approval_pending: true)
- user_two = insert(:user, approval_pending: true)
-
- conn =
- patch(
- conn,
- "/api/pleroma/admin/users/approve",
- %{nicknames: [user_one.nickname, user_two.nickname]}
- )
-
- response = json_response(conn, 200)
- assert Enum.map(response["users"], & &1["approval_pending"]) == [false, false]
-
- log_entry = Repo.one(ModerationLog)
-
- assert ModerationLog.get_log_entry_message(log_entry) ==
- "@#{admin.nickname} approved users: @#{user_one.nickname}, @#{user_two.nickname}"
- end
-
- test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do
- user = insert(:user)
-
- conn = patch(conn, "/api/pleroma/admin/users/#{user.nickname}/toggle_activation")
-
- assert json_response(conn, 200) ==
- %{
- "deactivated" => !user.deactivated,
- "id" => user.id,
- "nickname" => user.nickname,
- "roles" => %{"admin" => false, "moderator" => false},
- "local" => true,
- "tags" => [],
- "avatar" => User.avatar_url(user) |> MediaProxy.url(),
- "display_name" => HTML.strip_tags(user.name || user.nickname),
- "confirmation_pending" => false,
- "approval_pending" => false,
- "url" => user.ap_id,
- "registration_reason" => nil,
- "actor_type" => "Person"
- }
-
- log_entry = Repo.one(ModerationLog)
-
- assert ModerationLog.get_log_entry_message(log_entry) ==
- "@#{admin.nickname} deactivated users: @#{user.nickname}"
- end
-
- describe "PUT disable_mfa" do
- test "returns 200 and disable 2fa", %{conn: conn} do
- user =
- insert(:user,
- multi_factor_authentication_settings: %MFA.Settings{
- enabled: true,
- totp: %MFA.Settings.TOTP{secret: "otp_secret", confirmed: true}
- }
- )
-
- response =
- conn
- |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: user.nickname})
- |> json_response(200)
-
- assert response == user.nickname
- mfa_settings = refresh_record(user).multi_factor_authentication_settings
-
- refute mfa_settings.enabled
- refute mfa_settings.totp.confirmed
- end
-
- test "returns 404 if user not found", %{conn: conn} do
- response =
- conn
- |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: "nickname"})
- |> json_response(404)
-
- assert response == %{"error" => "Not found"}
- end
- end
-
- describe "GET /api/pleroma/admin/restart" do
- setup do: clear_config(:configurable_from_database, true)
-
- test "pleroma restarts", %{conn: conn} do
- capture_log(fn ->
- assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
- end) =~ "pleroma restarted"
-
- refute Restarter.Pleroma.need_reboot?()
- end
- end
-
- test "need_reboot flag", %{conn: conn} do
- assert conn
- |> get("/api/pleroma/admin/need_reboot")
- |> json_response(200) == %{"need_reboot" => false}
-
- Restarter.Pleroma.need_reboot()
-
- assert conn
- |> get("/api/pleroma/admin/need_reboot")
- |> json_response(200) == %{"need_reboot" => true}
-
- on_exit(fn -> Restarter.Pleroma.refresh() end)
- end
-
- describe "GET /api/pleroma/admin/users/:nickname/statuses" do
- setup do
- user = insert(:user)
-
- date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
- date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
- date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
-
- insert(:note_activity, user: user, published: date1)
- insert(:note_activity, user: user, published: date2)
- insert(:note_activity, user: user, published: date3)
-
- %{user: user}
- end
-
- test "renders user's statuses", %{conn: conn, user: user} do
- conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
-
- assert json_response(conn, 200) |> length() == 3
- end
-
- test "renders user's statuses with a limit", %{conn: conn, user: user} do
- conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
-
- assert json_response(conn, 200) |> length() == 2
- end
-
- test "doesn't return private statuses by default", %{conn: conn, user: user} do
- {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
-
- {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
-
- conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
-
- assert json_response(conn, 200) |> length() == 4
- end
-
- test "returns private statuses with godmode on", %{conn: conn, user: user} do
- {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
-
- {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
-
- conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
-
- assert json_response(conn, 200) |> length() == 5
- end
-
- test "excludes reblogs by default", %{conn: conn, user: user} do
- other_user = insert(:user)
- {:ok, activity} = CommonAPI.post(user, %{status: "."})
- {:ok, %Activity{}} = CommonAPI.repeat(activity.id, other_user)
-
- conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
- assert json_response(conn_res, 200) |> length() == 0
-
- conn_res =
- get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")
-
- assert json_response(conn_res, 200) |> length() == 1
- end
- end
-
- describe "GET /api/pleroma/admin/moderation_log" do
- setup do
- moderator = insert(:user, is_moderator: true)
-
- %{moderator: moderator}
- end
-
- test "returns the log", %{conn: conn, admin: admin} do
- Repo.insert(%ModerationLog{
- data: %{
- actor: %{
- "id" => admin.id,
- "nickname" => admin.nickname,
- "type" => "user"
- },
- action: "relay_follow",
- target: "https://example.org/relay"
- },
- inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
- })
-
- Repo.insert(%ModerationLog{
- data: %{
- actor: %{
- "id" => admin.id,
- "nickname" => admin.nickname,
- "type" => "user"
- },
- action: "relay_unfollow",
- target: "https://example.org/relay"
- },
- inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
- })
-
- conn = get(conn, "/api/pleroma/admin/moderation_log")
-
- response = json_response(conn, 200)
- [first_entry, second_entry] = response["items"]
-
- assert response["total"] == 2
- assert first_entry["data"]["action"] == "relay_unfollow"
-
- assert first_entry["message"] ==
- "@#{admin.nickname} unfollowed relay: https://example.org/relay"
-
- assert second_entry["data"]["action"] == "relay_follow"
-
- assert second_entry["message"] ==
- "@#{admin.nickname} followed relay: https://example.org/relay"
- end
-
- test "returns the log with pagination", %{conn: conn, admin: admin} do
- Repo.insert(%ModerationLog{
- data: %{
- actor: %{
- "id" => admin.id,
- "nickname" => admin.nickname,
- "type" => "user"
- },
- action: "relay_follow",
- target: "https://example.org/relay"
- },
- inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
- })
-
- Repo.insert(%ModerationLog{
- data: %{
- actor: %{
- "id" => admin.id,
- "nickname" => admin.nickname,
- "type" => "user"
- },
- action: "relay_unfollow",
- target: "https://example.org/relay"
- },
- inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
- })
-
- conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
-
- response1 = json_response(conn1, 200)
- [first_entry] = response1["items"]
-
- assert response1["total"] == 2
- assert response1["items"] |> length() == 1
- assert first_entry["data"]["action"] == "relay_unfollow"
-
- assert first_entry["message"] ==
- "@#{admin.nickname} unfollowed relay: https://example.org/relay"
-
- conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
-
- response2 = json_response(conn2, 200)
- [second_entry] = response2["items"]
-
- assert response2["total"] == 2
- assert response2["items"] |> length() == 1
- assert second_entry["data"]["action"] == "relay_follow"
-
- assert second_entry["message"] ==
- "@#{admin.nickname} followed relay: https://example.org/relay"
- end
-
- test "filters log by date", %{conn: conn, admin: admin} do
- first_date = "2017-08-15T15:47:06Z"
- second_date = "2017-08-20T15:47:06Z"
-
- Repo.insert(%ModerationLog{
- data: %{
- actor: %{
- "id" => admin.id,
- "nickname" => admin.nickname,
- "type" => "user"
- },
- action: "relay_follow",
- target: "https://example.org/relay"
- },
- inserted_at: NaiveDateTime.from_iso8601!(first_date)
- })
-
- Repo.insert(%ModerationLog{
- data: %{
- actor: %{
- "id" => admin.id,
- "nickname" => admin.nickname,
- "type" => "user"
- },
- action: "relay_unfollow",
- target: "https://example.org/relay"
- },
- inserted_at: NaiveDateTime.from_iso8601!(second_date)
- })
-
- conn1 =
- get(
- conn,
- "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
- )
-
- response1 = json_response(conn1, 200)
- [first_entry] = response1["items"]
-
- assert response1["total"] == 1
- assert first_entry["data"]["action"] == "relay_unfollow"
-
- assert first_entry["message"] ==
- "@#{admin.nickname} unfollowed relay: https://example.org/relay"
- end
-
- test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
- Repo.insert(%ModerationLog{
- data: %{
- actor: %{
- "id" => admin.id,
- "nickname" => admin.nickname,
- "type" => "user"
- },
- action: "relay_follow",
- target: "https://example.org/relay"
- }
- })
-
- Repo.insert(%ModerationLog{
- data: %{
- actor: %{
- "id" => moderator.id,
- "nickname" => moderator.nickname,
- "type" => "user"
- },
- action: "relay_unfollow",
- target: "https://example.org/relay"
- }
- })
-
- conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
-
- response1 = json_response(conn1, 200)
- [first_entry] = response1["items"]
-
- assert response1["total"] == 1
- assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
- end
-
- test "returns log filtered by search", %{conn: conn, moderator: moderator} do
- ModerationLog.insert_log(%{
- actor: moderator,
- action: "relay_follow",
- target: "https://example.org/relay"
- })
-
- ModerationLog.insert_log(%{
- actor: moderator,
- action: "relay_unfollow",
- target: "https://example.org/relay"
- })
-
- conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
-
- response1 = json_response(conn1, 200)
- [first_entry] = response1["items"]
-
- assert response1["total"] == 1
-
- assert get_in(first_entry, ["data", "message"]) ==
- "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
- end
- end
-
- test "gets a remote users when [:instance, :limit_to_local_content] is set to :unauthenticated",
- %{conn: conn} do
- clear_config(Pleroma.Config.get([:instance, :limit_to_local_content]), :unauthenticated)
- user = insert(:user, %{local: false, nickname: "u@peer1.com"})
- conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
-
- assert json_response(conn, 200)
- end
-
- describe "GET /users/:nickname/credentials" do
- test "gets the user credentials", %{conn: conn} do
- user = insert(:user)
- conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
-
- response = assert json_response(conn, 200)
- assert response["email"] == user.email
- end
-
- test "returns 403 if requested by a non-admin" do
- user = insert(:user)
-
- conn =
- build_conn()
- |> assign(:user, user)
- |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
-
- assert json_response(conn, :forbidden)
- end
- end
-
- describe "PATCH /users/:nickname/credentials" do
- setup do
- user = insert(:user)
- [user: user]
- end
-
- test "changes password and email", %{conn: conn, admin: admin, user: user} do
- assert user.password_reset_pending == false
-
- conn =
- patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
- "password" => "new_password",
- "email" => "new_email@example.com",
- "name" => "new_name"
- })
-
- assert json_response(conn, 200) == %{"status" => "success"}
-
- ObanHelpers.perform_all()
-
- updated_user = User.get_by_id(user.id)
-
- assert updated_user.email == "new_email@example.com"
- assert updated_user.name == "new_name"
- assert updated_user.password_hash != user.password_hash
- assert updated_user.password_reset_pending == true
-
- [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
-
- assert ModerationLog.get_log_entry_message(log_entry1) ==
- "@#{admin.nickname} updated users: @#{user.nickname}"
-
- assert ModerationLog.get_log_entry_message(log_entry2) ==
- "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
- end
-
- test "returns 403 if requested by a non-admin", %{user: user} do
- conn =
- build_conn()
- |> assign(:user, user)
- |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
- "password" => "new_password",
- "email" => "new_email@example.com",
- "name" => "new_name"
- })
-
- assert json_response(conn, :forbidden)
- end
-
- test "changes actor type from permitted list", %{conn: conn, user: user} do
- assert user.actor_type == "Person"
-
- assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
- "actor_type" => "Service"
- })
- |> json_response(200) == %{"status" => "success"}
-
- updated_user = User.get_by_id(user.id)
-
- assert updated_user.actor_type == "Service"
-
- assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
- "actor_type" => "Application"
- })
- |> json_response(400) == %{"errors" => %{"actor_type" => "is invalid"}}
- end
-
- test "update non existing user", %{conn: conn} do
- assert patch(conn, "/api/pleroma/admin/users/non-existing/credentials", %{
- "password" => "new_password"
- })
- |> json_response(404) == %{"error" => "Not found"}
- end
- end
-
- describe "PATCH /users/:nickname/force_password_reset" do
- test "sets password_reset_pending to true", %{conn: conn} do
- user = insert(:user)
- assert user.password_reset_pending == false
-
- conn =
- patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
-
- assert empty_json_response(conn) == ""
-
- ObanHelpers.perform_all()
-
- assert User.get_by_id(user.id).password_reset_pending == true
- end
- end
-
- describe "instances" do
- test "GET /instances/:instance/statuses", %{conn: conn} do
- user = insert(:user, local: false, nickname: "archaeme@archae.me")
- user2 = insert(:user, local: false, nickname: "test@test.com")
- insert_pair(:note_activity, user: user)
- activity = insert(:note_activity, user: user2)
-
- ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
-
- response = json_response(ret_conn, 200)
-
- assert length(response) == 2
-
- ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
-
- response = json_response(ret_conn, 200)
-
- assert length(response) == 1
-
- ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
-
- response = json_response(ret_conn, 200)
-
- assert Enum.empty?(response)
-
- CommonAPI.repeat(activity.id, user)
-
- ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
- response = json_response(ret_conn, 200)
- assert length(response) == 2
-
- ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
- response = json_response(ret_conn, 200)
- assert length(response) == 3
- end
- end
-
- describe "PATCH /confirm_email" do
- test "it confirms emails of two users", %{conn: conn, admin: admin} do
- [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
-
- assert first_user.confirmation_pending == true
- assert second_user.confirmation_pending == true
-
- ret_conn =
- patch(conn, "/api/pleroma/admin/users/confirm_email", %{
- nicknames: [
- first_user.nickname,
- second_user.nickname
- ]
- })
-
- assert ret_conn.status == 200
-
- assert first_user.confirmation_pending == true
- assert second_user.confirmation_pending == true
-
- log_entry = Repo.one(ModerationLog)
-
- assert ModerationLog.get_log_entry_message(log_entry) ==
- "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
- second_user.nickname
- }"
- end
- end
-
- describe "PATCH /resend_confirmation_email" do
- test "it resend emails for two users", %{conn: conn, admin: admin} do
- [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
-
- ret_conn =
- patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
- nicknames: [
- first_user.nickname,
- second_user.nickname
- ]
- })
-
- assert ret_conn.status == 200
-
- log_entry = Repo.one(ModerationLog)
-
- assert ModerationLog.get_log_entry_message(log_entry) ==
- "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
- second_user.nickname
- }"
-
- ObanHelpers.perform_all()
- assert_email_sent(Pleroma.Emails.UserEmail.account_confirmation_email(first_user))
- end
- end
-
- describe "/api/pleroma/admin/stats" do
- test "status visibility count", %{conn: conn} do
- admin = insert(:user, is_admin: true)
- user = insert(:user)
- CommonAPI.post(user, %{visibility: "public", status: "hey"})
- CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
- CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
-
- response =
- conn
- |> assign(:user, admin)
- |> get("/api/pleroma/admin/stats")
- |> json_response(200)
-
- assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
- response["status_visibility"]
- end
-
- test "by instance", %{conn: conn} do
- admin = insert(:user, is_admin: true)
- user1 = insert(:user)
- instance2 = "instance2.tld"
- user2 = insert(:user, %{ap_id: "https://#{instance2}/@actor"})
-
- CommonAPI.post(user1, %{visibility: "public", status: "hey"})
- CommonAPI.post(user2, %{visibility: "unlisted", status: "hey"})
- CommonAPI.post(user2, %{visibility: "private", status: "hey"})
-
- response =
- conn
- |> assign(:user, admin)
- |> get("/api/pleroma/admin/stats", instance: instance2)
- |> json_response(200)
-
- assert %{"direct" => 0, "private" => 1, "public" => 0, "unlisted" => 1} =
- response["status_visibility"]
- end
- end
-end
-
-# Needed for testing
-defmodule Pleroma.Web.Endpoint.NotReal do
-end
-
-defmodule Pleroma.Captcha.NotReal do
-end
diff --git a/test/web/masto_fe_controller_test.exs b/test/web/masto_fe_controller_test.exs
deleted file mode 100644
index f3b54b5f2..000000000
--- a/test/web/masto_fe_controller_test.exs
+++ /dev/null
@@ -1,85 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.MastodonAPI.MastoFEController do
- use Pleroma.Web.ConnCase
-
- alias Pleroma.Config
- alias Pleroma.User
-
- import Pleroma.Factory
-
- setup do: clear_config([:instance, :public])
-
- test "put settings", %{conn: conn} do
- user = insert(:user)
-
- conn =
- conn
- |> assign(:user, user)
- |> assign(:token, insert(:oauth_token, user: user, scopes: ["write:accounts"]))
- |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
-
- assert _result = json_response(conn, 200)
-
- user = User.get_cached_by_ap_id(user.ap_id)
- assert user.mastofe_settings == %{"programming" => "socks"}
- end
-
- describe "index/2 redirections" do
- setup %{conn: conn} do
- session_opts = [
- store: :cookie,
- key: "_test",
- signing_salt: "cooldude"
- ]
-
- conn =
- conn
- |> Plug.Session.call(Plug.Session.init(session_opts))
- |> fetch_session()
-
- test_path = "/web/statuses/test"
- %{conn: conn, path: test_path}
- end
-
- test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
- conn = get(conn, path)
-
- assert conn.status == 302
- assert redirected_to(conn) == "/web/login"
- end
-
- test "redirects not logged-in users to the login page on private instances", %{
- conn: conn,
- path: path
- } do
- Config.put([:instance, :public], false)
-
- conn = get(conn, path)
-
- assert conn.status == 302
- assert redirected_to(conn) == "/web/login"
- end
-
- test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
- token = insert(:oauth_token, scopes: ["read"])
-
- conn =
- conn
- |> assign(:user, token.user)
- |> assign(:token, token)
- |> get(path)
-
- assert conn.status == 200
- end
-
- test "saves referer path to session", %{conn: conn, path: path} do
- conn = get(conn, path)
- return_to = Plug.Conn.get_session(conn, :return_to)
-
- assert return_to == path
- end
- end
-end
diff --git a/test/web/mastodon_api/controllers/auth_controller_test.exs b/test/web/mastodon_api/controllers/auth_controller_test.exs
deleted file mode 100644
index 4fa95fce1..000000000
--- a/test/web/mastodon_api/controllers/auth_controller_test.exs
+++ /dev/null
@@ -1,162 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.MastodonAPI.AuthControllerTest do
- use Pleroma.Web.ConnCase
-
- alias Pleroma.Config
- alias Pleroma.Repo
- alias Pleroma.Tests.ObanHelpers
-
- import Pleroma.Factory
- import Swoosh.TestAssertions
-
- describe "GET /web/login" do
- setup %{conn: conn} do
- session_opts = [
- store: :cookie,
- key: "_test",
- signing_salt: "cooldude"
- ]
-
- conn =
- conn
- |> Plug.Session.call(Plug.Session.init(session_opts))
- |> fetch_session()
-
- test_path = "/web/statuses/test"
- %{conn: conn, path: test_path}
- end
-
- test "redirects to the saved path after log in", %{conn: conn, path: path} do
- app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
- auth = insert(:oauth_authorization, app: app)
-
- conn =
- conn
- |> put_session(:return_to, path)
- |> get("/web/login", %{code: auth.token})
-
- assert conn.status == 302
- assert redirected_to(conn) == path
- end
-
- test "redirects to the getting-started page when referer is not present", %{conn: conn} do
- app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
- auth = insert(:oauth_authorization, app: app)
-
- conn = get(conn, "/web/login", %{code: auth.token})
-
- assert conn.status == 302
- assert redirected_to(conn) == "/web/getting-started"
- end
- end
-
- describe "POST /auth/password, with valid parameters" do
- setup %{conn: conn} do
- user = insert(:user)
- conn = post(conn, "/auth/password?email=#{user.email}")
- %{conn: conn, user: user}
- end
-
- test "it returns 204", %{conn: conn} do
- assert json_response(conn, :no_content)
- end
-
- test "it creates a PasswordResetToken record for user", %{user: user} do
- token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
- assert token_record
- end
-
- test "it sends an email to user", %{user: user} do
- ObanHelpers.perform_all()
- token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
-
- email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token)
- notify_email = Config.get([:instance, :notify_email])
- instance_name = Config.get([:instance, :name])
-
- assert_email_sent(
- from: {instance_name, notify_email},
- to: {user.name, user.email},
- html_body: email.html_body
- )
- end
- end
-
- describe "POST /auth/password, with nickname" do
- test "it returns 204", %{conn: conn} do
- user = insert(:user)
-
- assert conn
- |> post("/auth/password?nickname=#{user.nickname}")
- |> json_response(:no_content)
-
- ObanHelpers.perform_all()
- token_record = Repo.get_by(Pleroma.PasswordResetToken, user_id: user.id)
-
- email = Pleroma.Emails.UserEmail.password_reset_email(user, token_record.token)
- notify_email = Config.get([:instance, :notify_email])
- instance_name = Config.get([:instance, :name])
-
- assert_email_sent(
- from: {instance_name, notify_email},
- to: {user.name, user.email},
- html_body: email.html_body
- )
- end
-
- test "it doesn't fail when a user has no email", %{conn: conn} do
- user = insert(:user, %{email: nil})
-
- assert conn
- |> post("/auth/password?nickname=#{user.nickname}")
- |> json_response(:no_content)
- end
- end
-
- describe "POST /auth/password, with invalid parameters" do
- setup do
- user = insert(:user)
- {:ok, user: user}
- end
-
- test "it returns 204 when user is not found", %{conn: conn, user: user} do
- conn = post(conn, "/auth/password?email=nonexisting_#{user.email}")
-
- assert conn
- |> json_response(:no_content)
- end
-
- test "it returns 204 when user is not local", %{conn: conn, user: user} do
- {:ok, user} = Repo.update(Ecto.Changeset.change(user, local: false))
- conn = post(conn, "/auth/password?email=#{user.email}")
-
- assert conn
- |> json_response(:no_content)
- end
-
- test "it returns 204 when user is deactivated", %{conn: conn, user: user} do
- {:ok, user} = Repo.update(Ecto.Changeset.change(user, deactivated: true, local: true))
- conn = post(conn, "/auth/password?email=#{user.email}")
-
- assert conn
- |> json_response(:no_content)
- end
- end
-
- describe "DELETE /auth/sign_out" do
- test "redirect to root page", %{conn: conn} do
- user = insert(:user)
-
- conn =
- conn
- |> assign(:user, user)
- |> delete("/auth/sign_out")
-
- assert conn.status == 302
- assert redirected_to(conn) == "/"
- end
- end
-end
diff --git a/test/web/mastodon_api/controllers/filter_controller_test.exs b/test/web/mastodon_api/controllers/filter_controller_test.exs
deleted file mode 100644
index 0d426ec34..000000000
--- a/test/web/mastodon_api/controllers/filter_controller_test.exs
+++ /dev/null
@@ -1,152 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.MastodonAPI.FilterControllerTest do
- use Pleroma.Web.ConnCase
-
- alias Pleroma.Web.MastodonAPI.FilterView
-
- test "creating a filter" do
- %{conn: conn} = oauth_access(["write:filters"])
-
- filter = %Pleroma.Filter{
- phrase: "knights",
- context: ["home"]
- }
-
- conn =
- conn
- |> put_req_header("content-type", "application/json")
- |> post("/api/v1/filters", %{"phrase" => filter.phrase, context: filter.context})
-
- assert response = json_response_and_validate_schema(conn, 200)
- assert response["phrase"] == filter.phrase
- assert response["context"] == filter.context
- assert response["irreversible"] == false
- assert response["id"] != nil
- assert response["id"] != ""
- end
-
- test "fetching a list of filters" do
- %{user: user, conn: conn} = oauth_access(["read:filters"])
-
- query_one = %Pleroma.Filter{
- user_id: user.id,
- filter_id: 1,
- phrase: "knights",
- context: ["home"]
- }
-
- query_two = %Pleroma.Filter{
- user_id: user.id,
- filter_id: 2,
- phrase: "who",
- context: ["home"]
- }
-
- {:ok, filter_one} = Pleroma.Filter.create(query_one)
- {:ok, filter_two} = Pleroma.Filter.create(query_two)
-
- response =
- conn
- |> get("/api/v1/filters")
- |> json_response_and_validate_schema(200)
-
- assert response ==
- render_json(
- FilterView,
- "index.json",
- filters: [filter_two, filter_one]
- )
- end
-
- test "get a filter" do
- %{user: user, conn: conn} = oauth_access(["read:filters"])
-
- # check whole_word false
- query = %Pleroma.Filter{
- user_id: user.id,
- filter_id: 2,
- phrase: "knight",
- context: ["home"],
- whole_word: false
- }
-
- {:ok, filter} = Pleroma.Filter.create(query)
-
- conn = get(conn, "/api/v1/filters/#{filter.filter_id}")
-
- assert response = json_response_and_validate_schema(conn, 200)
- assert response["whole_word"] == false
-
- # check whole_word true
- %{user: user, conn: conn} = oauth_access(["read:filters"])
-
- query = %Pleroma.Filter{
- user_id: user.id,
- filter_id: 3,
- phrase: "knight",
- context: ["home"],
- whole_word: true
- }
-
- {:ok, filter} = Pleroma.Filter.create(query)
-
- conn = get(conn, "/api/v1/filters/#{filter.filter_id}")
-
- assert response = json_response_and_validate_schema(conn, 200)
- assert response["whole_word"] == true
- end
-
- test "update a filter" do
- %{user: user, conn: conn} = oauth_access(["write:filters"])
-
- query = %Pleroma.Filter{
- user_id: user.id,
- filter_id: 2,
- phrase: "knight",
- context: ["home"],
- hide: true,
- whole_word: true
- }
-
- {:ok, _filter} = Pleroma.Filter.create(query)
-
- new = %Pleroma.Filter{
- phrase: "nii",
- context: ["home"]
- }
-
- conn =
- conn
- |> put_req_header("content-type", "application/json")
- |> put("/api/v1/filters/#{query.filter_id}", %{
- phrase: new.phrase,
- context: new.context
- })
-
- assert response = json_response_and_validate_schema(conn, 200)
- assert response["phrase"] == new.phrase
- assert response["context"] == new.context
- assert response["irreversible"] == true
- assert response["whole_word"] == true
- end
-
- test "delete a filter" do
- %{user: user, conn: conn} = oauth_access(["write:filters"])
-
- query = %Pleroma.Filter{
- user_id: user.id,
- filter_id: 2,
- phrase: "knight",
- context: ["home"]
- }
-
- {:ok, filter} = Pleroma.Filter.create(query)
-
- conn = delete(conn, "/api/v1/filters/#{filter.filter_id}")
-
- assert json_response_and_validate_schema(conn, 200) == %{}
- end
-end
diff --git a/test/web/mastodon_api/controllers/suggestion_controller_test.exs b/test/web/mastodon_api/controllers/suggestion_controller_test.exs
deleted file mode 100644
index 7f08e187c..000000000
--- a/test/web/mastodon_api/controllers/suggestion_controller_test.exs
+++ /dev/null
@@ -1,18 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.MastodonAPI.SuggestionControllerTest do
- use Pleroma.Web.ConnCase
-
- setup do: oauth_access(["read"])
-
- test "returns empty result", %{conn: conn} do
- res =
- conn
- |> get("/api/v1/suggestions")
- |> json_response_and_validate_schema(200)
-
- assert res == []
- end
-end
diff --git a/test/web/media_proxy/invalidations/script_test.exs b/test/web/media_proxy/invalidations/script_test.exs
deleted file mode 100644
index 51833ab18..000000000
--- a/test/web/media_proxy/invalidations/script_test.exs
+++ /dev/null
@@ -1,26 +0,0 @@
-defmodule Pleroma.Web.MediaProxy.Invalidation.ScriptTest do
- use ExUnit.Case
- alias Pleroma.Web.MediaProxy.Invalidation
-
- import ExUnit.CaptureLog
-
- setup do
- on_exit(fn -> Cachex.clear(:banned_urls_cache) end)
- end
-
- test "it logger error when script not found" do
- assert capture_log(fn ->
- assert Invalidation.Script.purge(
- ["http://example.com/media/example.jpg"],
- script_path: "./example"
- ) == {:error, "%ErlangError{original: :enoent}"}
- end) =~ "Error while cache purge: %ErlangError{original: :enoent}"
-
- capture_log(fn ->
- assert Invalidation.Script.purge(
- ["http://example.com/media/example.jpg"],
- []
- ) == {:error, "\"not found script path\""}
- end)
- end
-end
diff --git a/test/web/media_proxy/media_proxy_controller_test.exs b/test/web/media_proxy/media_proxy_controller_test.exs
deleted file mode 100644
index d4db44c63..000000000
--- a/test/web/media_proxy/media_proxy_controller_test.exs
+++ /dev/null
@@ -1,121 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do
- use Pleroma.Web.ConnCase
-
- import Mock
-
- alias Pleroma.Web.MediaProxy
- alias Pleroma.Web.MediaProxy.MediaProxyController
- alias Plug.Conn
-
- setup do
- on_exit(fn -> Cachex.clear(:banned_urls_cache) end)
- end
-
- test "it returns 404 when MediaProxy disabled", %{conn: conn} do
- clear_config([:media_proxy, :enabled], false)
-
- assert %Conn{
- status: 404,
- resp_body: "Not Found"
- } = get(conn, "/proxy/hhgfh/eeeee")
-
- assert %Conn{
- status: 404,
- resp_body: "Not Found"
- } = get(conn, "/proxy/hhgfh/eeee/fff")
- end
-
- describe "" do
- setup do
- clear_config([:media_proxy, :enabled], true)
- clear_config([Pleroma.Web.Endpoint, :secret_key_base], "00000000000")
- [url: MediaProxy.encode_url("https://google.fn/test.png")]
- end
-
- test "it returns 403 for invalid signature", %{conn: conn, url: url} do
- Pleroma.Config.put([Pleroma.Web.Endpoint, :secret_key_base], "000")
- %{path: path} = URI.parse(url)
-
- assert %Conn{
- status: 403,
- resp_body: "Forbidden"
- } = get(conn, path)
-
- assert %Conn{
- status: 403,
- resp_body: "Forbidden"
- } = get(conn, "/proxy/hhgfh/eeee")
-
- assert %Conn{
- status: 403,
- resp_body: "Forbidden"
- } = get(conn, "/proxy/hhgfh/eeee/fff")
- end
-
- test "redirects on valid url when filename is invalidated", %{conn: conn, url: url} do
- invalid_url = String.replace(url, "test.png", "test-file.png")
- response = get(conn, invalid_url)
- assert response.status == 302
- assert redirected_to(response) == url
- end
-
- test "it performs ReverseProxy.call with valid signature", %{conn: conn, url: url} do
- with_mock Pleroma.ReverseProxy,
- call: fn _conn, _url, _opts -> %Conn{status: :success} end do
- assert %Conn{status: :success} = get(conn, url)
- end
- end
-
- test "it returns 404 when url is in banned_urls cache", %{conn: conn, url: url} do
- MediaProxy.put_in_banned_urls("https://google.fn/test.png")
-
- with_mock Pleroma.ReverseProxy,
- call: fn _conn, _url, _opts -> %Conn{status: :success} end do
- assert %Conn{status: 404, resp_body: "Not Found"} = get(conn, url)
- end
- end
- end
-
- describe "filename_matches/3" do
- test "preserves the encoded or decoded path" do
- assert MediaProxyController.filename_matches(
- %{"filename" => "/Hello world.jpg"},
- "/Hello world.jpg",
- "http://pleroma.social/Hello world.jpg"
- ) == :ok
-
- assert MediaProxyController.filename_matches(
- %{"filename" => "/Hello%20world.jpg"},
- "/Hello%20world.jpg",
- "http://pleroma.social/Hello%20world.jpg"
- ) == :ok
-
- assert MediaProxyController.filename_matches(
- %{"filename" => "/my%2Flong%2Furl%2F2019%2F07%2FS.jpg"},
- "/my%2Flong%2Furl%2F2019%2F07%2FS.jpg",
- "http://pleroma.social/my%2Flong%2Furl%2F2019%2F07%2FS.jpg"
- ) == :ok
-
- assert MediaProxyController.filename_matches(
- %{"filename" => "/my%2Flong%2Furl%2F2019%2F07%2FS.jp"},
- "/my%2Flong%2Furl%2F2019%2F07%2FS.jp",
- "http://pleroma.social/my%2Flong%2Furl%2F2019%2F07%2FS.jpg"
- ) == {:wrong_filename, "my%2Flong%2Furl%2F2019%2F07%2FS.jpg"}
- end
-
- test "encoded url are tried to match for proxy as `conn.request_path` encodes the url" do
- # conn.request_path will return encoded url
- request_path = "/ANALYSE-DAI-_-LE-STABLECOIN-100-D%C3%89CENTRALIS%C3%89-BQ.jpg"
-
- assert MediaProxyController.filename_matches(
- true,
- request_path,
- "https://mydomain.com/uploads/2019/07/ANALYSE-DAI-_-LE-STABLECOIN-100-DÉCENTRALISÉ-BQ.jpg"
- ) == :ok
- end
- end
-end
diff --git a/test/web/metadata/metadata_test.exs b/test/web/metadata/metadata_test.exs
deleted file mode 100644
index 3f8b29e58..000000000
--- a/test/web/metadata/metadata_test.exs
+++ /dev/null
@@ -1,25 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.MetadataTest do
- use Pleroma.DataCase, async: true
-
- import Pleroma.Factory
-
- describe "restrict indexing remote users" do
- test "for remote user" do
- user = insert(:user, local: false)
-
- assert Pleroma.Web.Metadata.build_tags(%{user: user}) =~
- "<meta content=\"noindex, noarchive\" name=\"robots\">"
- end
-
- test "for local user" do
- user = insert(:user)
-
- refute Pleroma.Web.Metadata.build_tags(%{user: user}) =~
- "<meta content=\"noindex, noarchive\" name=\"robots\">"
- end
- end
-end
diff --git a/test/web/metadata/opengraph_test.exs b/test/web/metadata/opengraph_test.exs
deleted file mode 100644
index 218540e6c..000000000
--- a/test/web/metadata/opengraph_test.exs
+++ /dev/null
@@ -1,96 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.Metadata.Providers.OpenGraphTest do
- use Pleroma.DataCase
- import Pleroma.Factory
- alias Pleroma.Web.Metadata.Providers.OpenGraph
-
- setup do: clear_config([Pleroma.Web.Metadata, :unfurl_nsfw])
-
- test "it renders all supported types of attachments and skips unknown types" do
- user = insert(:user)
-
- note =
- insert(:note, %{
- data: %{
- "actor" => user.ap_id,
- "tag" => [],
- "id" => "https://pleroma.gov/objects/whatever",
- "content" => "pleroma in a nutshell",
- "attachment" => [
- %{
- "url" => [
- %{"mediaType" => "image/png", "href" => "https://pleroma.gov/tenshi.png"}
- ]
- },
- %{
- "url" => [
- %{
- "mediaType" => "application/octet-stream",
- "href" => "https://pleroma.gov/fqa/badapple.sfc"
- }
- ]
- },
- %{
- "url" => [
- %{"mediaType" => "video/webm", "href" => "https://pleroma.gov/about/juche.webm"}
- ]
- },
- %{
- "url" => [
- %{
- "mediaType" => "audio/basic",
- "href" => "http://www.gnu.org/music/free-software-song.au"
- }
- ]
- }
- ]
- }
- })
-
- result = OpenGraph.build_tags(%{object: note, url: note.data["id"], user: user})
-
- assert Enum.all?(
- [
- {:meta, [property: "og:image", content: "https://pleroma.gov/tenshi.png"], []},
- {:meta,
- [property: "og:audio", content: "http://www.gnu.org/music/free-software-song.au"],
- []},
- {:meta, [property: "og:video", content: "https://pleroma.gov/about/juche.webm"],
- []}
- ],
- fn element -> element in result end
- )
- end
-
- test "it does not render attachments if post is nsfw" do
- Pleroma.Config.put([Pleroma.Web.Metadata, :unfurl_nsfw], false)
- user = insert(:user, avatar: %{"url" => [%{"href" => "https://pleroma.gov/tenshi.png"}]})
-
- note =
- insert(:note, %{
- data: %{
- "actor" => user.ap_id,
- "id" => "https://pleroma.gov/objects/whatever",
- "content" => "#cuteposting #nsfw #hambaga",
- "tag" => ["cuteposting", "nsfw", "hambaga"],
- "sensitive" => true,
- "attachment" => [
- %{
- "url" => [
- %{"mediaType" => "image/png", "href" => "https://misskey.microsoft/corndog.png"}
- ]
- }
- ]
- }
- })
-
- result = OpenGraph.build_tags(%{object: note, url: note.data["id"], user: user})
-
- assert {:meta, [property: "og:image", content: "https://pleroma.gov/tenshi.png"], []} in result
-
- refute {:meta, [property: "og:image", content: "https://misskey.microsoft/corndog.png"], []} in result
- end
-end
diff --git a/test/web/twitter_api/password_controller_test.exs b/test/web/twitter_api/password_controller_test.exs
deleted file mode 100644
index 231a46c67..000000000
--- a/test/web/twitter_api/password_controller_test.exs
+++ /dev/null
@@ -1,81 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.TwitterAPI.PasswordControllerTest do
- use Pleroma.Web.ConnCase
-
- alias Pleroma.PasswordResetToken
- alias Pleroma.User
- alias Pleroma.Web.OAuth.Token
- import Pleroma.Factory
-
- describe "GET /api/pleroma/password_reset/token" do
- test "it returns error when token invalid", %{conn: conn} do
- response =
- conn
- |> get("/api/pleroma/password_reset/token")
- |> html_response(:ok)
-
- assert response =~ "<h2>Invalid Token</h2>"
- end
-
- test "it shows password reset form", %{conn: conn} do
- user = insert(:user)
- {:ok, token} = PasswordResetToken.create_token(user)
-
- response =
- conn
- |> get("/api/pleroma/password_reset/#{token.token}")
- |> html_response(:ok)
-
- assert response =~ "<h2>Password Reset for #{user.nickname}</h2>"
- end
- end
-
- describe "POST /api/pleroma/password_reset" do
- test "it returns HTTP 200", %{conn: conn} do
- user = insert(:user)
- {:ok, token} = PasswordResetToken.create_token(user)
- {:ok, _access_token} = Token.create_token(insert(:oauth_app), user, %{})
-
- params = %{
- "password" => "test",
- password_confirmation: "test",
- token: token.token
- }
-
- response =
- conn
- |> assign(:user, user)
- |> post("/api/pleroma/password_reset", %{data: params})
- |> html_response(:ok)
-
- assert response =~ "<h2>Password changed!</h2>"
-
- user = refresh_record(user)
- assert Pbkdf2.verify_pass("test", user.password_hash)
- assert Enum.empty?(Token.get_user_tokens(user))
- end
-
- test "it sets password_reset_pending to false", %{conn: conn} do
- user = insert(:user, password_reset_pending: true)
-
- {:ok, token} = PasswordResetToken.create_token(user)
- {:ok, _access_token} = Token.create_token(insert(:oauth_app), user, %{})
-
- params = %{
- "password" => "test",
- password_confirmation: "test",
- token: token.token
- }
-
- conn
- |> assign(:user, user)
- |> post("/api/pleroma/password_reset", %{data: params})
- |> html_response(:ok)
-
- assert User.get_by_id(user.id).password_reset_pending == false
- end
- end
-end
diff --git a/test/workers/cron/clear_oauth_token_worker_test.exs b/test/workers/cron/clear_oauth_token_worker_test.exs
deleted file mode 100644
index 67836f34f..000000000
--- a/test/workers/cron/clear_oauth_token_worker_test.exs
+++ /dev/null
@@ -1,22 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Workers.Cron.ClearOauthTokenWorkerTest do
- use Pleroma.DataCase
-
- import Pleroma.Factory
- alias Pleroma.Workers.Cron.ClearOauthTokenWorker
-
- setup do: clear_config([:oauth2, :clean_expired_tokens])
-
- test "deletes expired tokens" do
- insert(:oauth_token,
- valid_until: NaiveDateTime.add(NaiveDateTime.utc_now(), -60 * 10)
- )
-
- Pleroma.Config.put([:oauth2, :clean_expired_tokens], true)
- ClearOauthTokenWorker.perform(%Oban.Job{})
- assert Pleroma.Repo.all(Pleroma.Web.OAuth.Token) == []
- end
-end
diff --git a/test/workers/cron/purge_expired_activities_worker_test.exs b/test/workers/cron/purge_expired_activities_worker_test.exs
deleted file mode 100644
index d1acd9ae6..000000000
--- a/test/workers/cron/purge_expired_activities_worker_test.exs
+++ /dev/null
@@ -1,84 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Workers.Cron.PurgeExpiredActivitiesWorkerTest do
- use Pleroma.DataCase
-
- alias Pleroma.ActivityExpiration
- alias Pleroma.Workers.Cron.PurgeExpiredActivitiesWorker
-
- import Pleroma.Factory
- import ExUnit.CaptureLog
-
- setup do
- clear_config([ActivityExpiration, :enabled])
- end
-
- test "deletes an expiration activity" do
- Pleroma.Config.put([ActivityExpiration, :enabled], true)
- activity = insert(:note_activity)
-
- naive_datetime =
- NaiveDateTime.add(
- NaiveDateTime.utc_now(),
- -:timer.minutes(2),
- :millisecond
- )
-
- expiration =
- insert(
- :expiration_in_the_past,
- %{activity_id: activity.id, scheduled_at: naive_datetime}
- )
-
- Pleroma.Workers.Cron.PurgeExpiredActivitiesWorker.perform(%Oban.Job{})
-
- refute Pleroma.Repo.get(Pleroma.Activity, activity.id)
- refute Pleroma.Repo.get(Pleroma.ActivityExpiration, expiration.id)
- end
-
- test "works with ActivityExpirationPolicy" do
- Pleroma.Config.put([ActivityExpiration, :enabled], true)
-
- clear_config([:mrf, :policies], Pleroma.Web.ActivityPub.MRF.ActivityExpirationPolicy)
-
- user = insert(:user)
-
- days = Pleroma.Config.get([:mrf_activity_expiration, :days], 365)
-
- {:ok, %{id: id} = activity} = Pleroma.Web.CommonAPI.post(user, %{status: "cofe"})
-
- past_date =
- NaiveDateTime.utc_now() |> Timex.shift(days: -days) |> NaiveDateTime.truncate(:second)
-
- activity
- |> Repo.preload(:expiration)
- |> Map.get(:expiration)
- |> Ecto.Changeset.change(%{scheduled_at: past_date})
- |> Repo.update!()
-
- Pleroma.Workers.Cron.PurgeExpiredActivitiesWorker.perform(%Oban.Job{})
-
- assert [%{data: %{"type" => "Delete", "deleted_activity_id" => ^id}}] =
- Pleroma.Repo.all(Pleroma.Activity)
- end
-
- describe "delete_activity/1" do
- test "adds log message if activity isn't find" do
- assert capture_log([level: :error], fn ->
- PurgeExpiredActivitiesWorker.delete_activity(%ActivityExpiration{
- activity_id: "test-activity"
- })
- end) =~ "Couldn't delete expired activity: not found activity"
- end
-
- test "adds log message if actor isn't find" do
- assert capture_log([level: :error], fn ->
- PurgeExpiredActivitiesWorker.delete_activity(%ActivityExpiration{
- activity_id: "test-activity"
- })
- end) =~ "Couldn't delete expired activity: not found activity"
- end
- end
-end