From b31a934a804aed3f35442ceafe2080b0955e7317 Mon Sep 17 00:00:00 2001
From: dcc
Date: Wed, 15 May 2024 00:57:23 -0700
Subject: total rebase
---
lib/mix/pleroma.ex | 0
lib/mix/tasks/pleroma/app.ex | 0
lib/mix/tasks/pleroma/benchmark.ex | 113 ---
lib/mix/tasks/pleroma/config.ex | 0
lib/mix/tasks/pleroma/count_statuses.ex | 0
lib/mix/tasks/pleroma/database.ex | 2 +-
lib/mix/tasks/pleroma/digest.ex | 2 +-
lib/mix/tasks/pleroma/docs.ex | 0
lib/mix/tasks/pleroma/ecto.ex | 0
lib/mix/tasks/pleroma/ecto/migrate.ex | 0
lib/mix/tasks/pleroma/ecto/rollback.ex | 2 +-
lib/mix/tasks/pleroma/email.ex | 0
lib/mix/tasks/pleroma/emoji.ex | 2 +-
lib/mix/tasks/pleroma/frontend.ex | 0
lib/mix/tasks/pleroma/instance.ex | 4 +-
lib/mix/tasks/pleroma/notification_settings.ex | 0
lib/mix/tasks/pleroma/openapi_spec.ex | 67 +-
lib/mix/tasks/pleroma/refresh_counter_cache.ex | 0
lib/mix/tasks/pleroma/relay.ex | 0
lib/mix/tasks/pleroma/robots_txt.ex | 0
lib/mix/tasks/pleroma/search/meilisearch.ex | 145 +++
lib/mix/tasks/pleroma/uploads.ex | 0
lib/mix/tasks/pleroma/user.ex | 0
lib/phoenix/transports/web_socket/raw.ex | 94 --
lib/pleroma/activity.ex | 2 +-
lib/pleroma/activity/html.ex | 2 +-
lib/pleroma/activity/ir/topics.ex | 0
lib/pleroma/activity/queries.ex | 2 +-
lib/pleroma/activity/search.ex | 162 ----
lib/pleroma/announcement.ex | 16 +-
lib/pleroma/announcement_read_relationship.ex | 0
lib/pleroma/application.ex | 156 ++-
lib/pleroma/application_requirements.ex | 13 +-
lib/pleroma/bbs/authenticator.ex | 20 -
lib/pleroma/bbs/handler.ex | 246 -----
lib/pleroma/bookmark.ex | 41 +-
lib/pleroma/bookmark_folder.ex | 115 +++
lib/pleroma/caching.ex | 3 +
lib/pleroma/captcha.ex | 0
lib/pleroma/captcha/kocaptcha.ex | 2 +-
lib/pleroma/captcha/native.ex | 0
lib/pleroma/captcha/service.ex | 0
lib/pleroma/chat.ex | 12 +-
lib/pleroma/chat/message_reference.ex | 0
lib/pleroma/clippy.ex | 0
lib/pleroma/config.ex | 0
lib/pleroma/config/deprecation_warnings.ex | 36 +-
lib/pleroma/config/getting.ex | 7 +
lib/pleroma/config/helpers.ex | 0
lib/pleroma/config/holder.ex | 0
lib/pleroma/config/loader.ex | 0
lib/pleroma/config/oban.ex | 2 +-
lib/pleroma/config/release_runtime_provider.ex | 2 +-
lib/pleroma/config/transfer_task.ex | 9 +-
lib/pleroma/config_db.ex | 6 +-
lib/pleroma/constants.ex | 37 +
lib/pleroma/conversation.ex | 2 +-
lib/pleroma/conversation/participation.ex | 0
.../conversation/participation/recipient_ship.ex | 0
lib/pleroma/counter_cache.ex | 0
lib/pleroma/data_migration.ex | 2 +
lib/pleroma/delivery.ex | 0
lib/pleroma/docs/generator.ex | 4 +-
lib/pleroma/docs/json.ex | 2 +-
lib/pleroma/docs/markdown.ex | 0
lib/pleroma/docs/translator.ex | 0
lib/pleroma/docs/translator/compiler.ex | 0
lib/pleroma/ecto_enums.ex | 8 +
.../activity_pub/object_validators/bare_uri.ex | 25 +
.../activity_pub/object_validators/date_time.ex | 0
.../activity_pub/object_validators/emoji.ex | 0
.../activity_pub/object_validators/mime.ex | 0
.../activity_pub/object_validators/object_id.ex | 0
.../activity_pub/object_validators/recipients.ex | 0
.../activity_pub/object_validators/safe_text.ex | 0
.../activity_pub/object_validators/uri.ex | 0
lib/pleroma/ecto_type/config/atom.ex | 0
lib/pleroma/ecto_type/config/binary_value.ex | 0
lib/pleroma/emails/admin_email.ex | 0
lib/pleroma/emails/mailer.ex | 0
lib/pleroma/emails/new_users_digest_email.ex | 0
lib/pleroma/emails/user_email.ex | 0
lib/pleroma/emoji-test.txt | 0
lib/pleroma/emoji.ex | 63 +-
lib/pleroma/emoji/combinations.ex | 0
lib/pleroma/emoji/formatter.ex | 0
lib/pleroma/emoji/loader.ex | 6 +-
lib/pleroma/emoji/pack.ex | 14 +-
lib/pleroma/filter.ex | 3 -
lib/pleroma/following_relationship.ex | 10 +-
lib/pleroma/formatter.ex | 2 +-
lib/pleroma/frontend.ex | 0
lib/pleroma/gopher/server.ex | 2 +-
lib/pleroma/gun.ex | 0
lib/pleroma/gun/api.ex | 0
lib/pleroma/gun/conn.ex | 6 +-
lib/pleroma/gun/connection_pool.ex | 0
lib/pleroma/gun/connection_pool/reclaimer.ex | 2 +-
lib/pleroma/gun/connection_pool/worker.ex | 0
.../gun/connection_pool/worker_supervisor.ex | 6 +-
lib/pleroma/hashtag.ex | 0
lib/pleroma/healthcheck.ex | 0
lib/pleroma/helpers/auth_helper.ex | 0
lib/pleroma/helpers/inet_helper.ex | 0
lib/pleroma/helpers/media_helper.ex | 173 +---
lib/pleroma/helpers/qt_fast_start.ex | 37 +-
lib/pleroma/helpers/uri_helper.ex | 0
lib/pleroma/html.ex | 21 +-
lib/pleroma/http.ex | 4 +
lib/pleroma/http.ex.orig | 125 +++
lib/pleroma/http/adapter_helper.ex | 12 +-
lib/pleroma/http/adapter_helper/default.ex | 0
lib/pleroma/http/adapter_helper/gun.ex | 0
lib/pleroma/http/adapter_helper/hackney.ex | 0
lib/pleroma/http/ex_aws.ex | 0
lib/pleroma/http/request.ex | 0
lib/pleroma/http/request_builder.ex | 4 +-
lib/pleroma/http/tzdata.ex | 0
lib/pleroma/http/web_push.ex | 6 +-
lib/pleroma/instances.ex | 11 +-
lib/pleroma/instances/instance.ex | 114 ++-
lib/pleroma/job_queue_monitor.ex | 0
lib/pleroma/jwt.ex | 0
lib/pleroma/keys.ex | 0
lib/pleroma/list.ex | 0
lib/pleroma/logging.ex | 0
lib/pleroma/maintenance.ex | 2 +-
lib/pleroma/maps.ex | 15 +-
lib/pleroma/marker.ex | 0
lib/pleroma/mfa.ex | 2 +-
lib/pleroma/mfa/backup_codes.ex | 0
lib/pleroma/mfa/changeset.ex | 0
lib/pleroma/mfa/settings.ex | 0
lib/pleroma/mfa/token.ex | 0
lib/pleroma/mfa/totp.ex | 3 +-
.../migration_helper/notification_backfill.ex | 0
.../migrators/context_objects_deletion_migrator.ex | 0
lib/pleroma/migrators/hashtags_table_migrator.ex | 2 +-
lib/pleroma/migrators/support/base_migrator.ex | 11 +-
.../migrators/support/base_migrator_state.ex | 0
lib/pleroma/moderation_log.ex | 5 +-
lib/pleroma/notification.ex | 8 +-
lib/pleroma/object.ex | 85 +-
lib/pleroma/object/containment.ex | 0
lib/pleroma/object/fetcher.ex | 85 +-
lib/pleroma/object/fetcher.ex.orig | 238 +++++
lib/pleroma/object/fetcher.ex.rej | 13 +
lib/pleroma/object/updater.ex | 0
lib/pleroma/object_tombstone.ex | 0
lib/pleroma/otp_version.ex | 0
lib/pleroma/pagination.ex | 9 +-
lib/pleroma/password/pbkdf2.ex | 2 +-
lib/pleroma/password_reset_token.ex | 0
lib/pleroma/prom_ex.ex | 49 +
lib/pleroma/registration.ex | 0
lib/pleroma/release_tasks.ex | 6 -
lib/pleroma/repo.ex | 2 -
lib/pleroma/report_note.ex | 8 +-
lib/pleroma/reverse_proxy.ex | 20 +-
lib/pleroma/reverse_proxy/client.ex | 0
lib/pleroma/reverse_proxy/client/hackney.ex | 0
lib/pleroma/reverse_proxy/client/tesla.ex | 0
lib/pleroma/reverse_proxy/client/wrapper.ex | 0
lib/pleroma/scheduled_activity.ex | 9 +-
lib/pleroma/search.ex | 17 +
lib/pleroma/search/database_search.ex | 165 ++++
lib/pleroma/search/meilisearch.ex | 181 ++++
lib/pleroma/search/search_backend.ex | 24 +
lib/pleroma/signature.ex | 2 +-
lib/pleroma/stats.ex | 0
lib/pleroma/telemetry/logger.ex | 6 +-
lib/pleroma/tesla/middleware/connection_pool.ex | 0
lib/pleroma/tests/auth_test_controller.ex | 0
lib/pleroma/thread_mute.ex | 0
lib/pleroma/upload.ex | 20 +-
lib/pleroma/upload/filter.ex | 6 +-
lib/pleroma/upload/filter/analyze_metadata.ex | 44 +-
lib/pleroma/upload/filter/anonymize_filename.ex | 0
lib/pleroma/upload/filter/dedupe.ex | 0
.../upload/filter/exiftool/read_description.ex | 2 -
.../upload/filter/exiftool/strip_location.ex | 0
lib/pleroma/upload/filter/mogrifun.ex | 0
lib/pleroma/upload/filter/mogrify.ex | 0
lib/pleroma/upload/filter/only_media.ex | 20 +
lib/pleroma/uploaders/local.ex | 0
lib/pleroma/uploaders/s3.ex | 15 +-
lib/pleroma/uploaders/uploader.ex | 11 +-
lib/pleroma/user.ex | 121 ++-
lib/pleroma/user/.welcome_message.ex~.un~ | Bin 581 -> 0 bytes
lib/pleroma/user/backup.ex | 237 ++++-
lib/pleroma/user/import.ex | 0
lib/pleroma/user/notification_setting.ex | 0
lib/pleroma/user/query.ex | 4 +-
lib/pleroma/user/search.ex | 0
lib/pleroma/user/welcome_chat_message.ex | 0
lib/pleroma/user/welcome_email.ex | 0
lib/pleroma/user/welcome_message.ex | 4 +-
lib/pleroma/user_invite_token.ex | 2 +-
lib/pleroma/user_note.ex | 0
lib/pleroma/user_relationship.ex | 2 +
lib/pleroma/utils.ex | 0
lib/pleroma/web.ex | 2 +-
lib/pleroma/web/.router.ex.un~ | Bin 89164 -> 0 bytes
lib/pleroma/web/activity_pub/activity_pub.ex | 105 +-
.../web/activity_pub/activity_pub/persisting.ex | 0
.../web/activity_pub/activity_pub/streaming.ex | 0
.../web/activity_pub/activity_pub_controller.ex | 18 +-
lib/pleroma/web/activity_pub/builder.ex | 97 +-
.../web/activity_pub/internal_fetch_actor.ex | 0
lib/pleroma/web/activity_pub/mrf.ex | 19 +-
.../activity_pub/mrf/activity_expiration_policy.ex | 0
.../web/activity_pub/mrf/anti_followbot_policy.ex | 2 -
.../web/activity_pub/mrf/anti_link_spam_policy.ex | 0
lib/pleroma/web/activity_pub/mrf/drop_policy.ex | 0
lib/pleroma/web/activity_pub/mrf/emoji_policy.ex | 281 ++++++
.../web/activity_pub/mrf/ensure_re_prepended.ex | 0
.../web/activity_pub/mrf/follow_bot_policy.ex | 2 +-
.../activity_pub/mrf/force_bot_unlisted_policy.ex | 0
lib/pleroma/web/activity_pub/mrf/force_mention.ex | 59 ++
.../activity_pub/mrf/force_mentions_in_content.ex | 10 +-
lib/pleroma/web/activity_pub/mrf/hashtag_policy.ex | 4 +-
.../web/activity_pub/mrf/hellthread_policy.ex | 0
.../web/activity_pub/mrf/inline_quote_policy.ex | 77 ++
lib/pleroma/web/activity_pub/mrf/keyword_policy.ex | 21 +-
.../activity_pub/mrf/media_proxy_warming_policy.ex | 0
lib/pleroma/web/activity_pub/mrf/mention_policy.ex | 0
.../web/activity_pub/mrf/no_empty_policy.ex | 16 +-
lib/pleroma/web/activity_pub/mrf/no_op_policy.ex | 0
.../activity_pub/mrf/no_placeholder_text_policy.ex | 0
.../web/activity_pub/mrf/normalize_markup.ex | 0
.../web/activity_pub/mrf/object_age_policy.ex | 0
.../web/activity_pub/mrf/pipeline_filtering.ex | 0
lib/pleroma/web/activity_pub/mrf/policy.ex | 4 +-
.../activity_pub/mrf/quote_to_link_tag_policy.ex | 49 +
.../web/activity_pub/mrf/reject_non_public.ex | 0
lib/pleroma/web/activity_pub/mrf/simple_policy.ex | 0
.../web/activity_pub/mrf/steal_emoji_policy.ex | 10 +-
.../web/activity_pub/mrf/subchain_policy.ex | 0
lib/pleroma/web/activity_pub/mrf/tag_policy.ex | 0
.../web/activity_pub/mrf/user_allow_list_policy.ex | 0
lib/pleroma/web/activity_pub/mrf/utils.ex | 15 +
.../web/activity_pub/mrf/vocabulary_policy.ex | 0
lib/pleroma/web/activity_pub/object_validator.ex | 18 +-
.../activity_pub/object_validator/validating.ex | 0
.../object_validators/accept_reject_validator.ex | 0
.../object_validators/add_remove_validator.ex | 3 +-
.../object_validators/announce_validator.ex | 2 +-
.../object_validators/answer_validator.ex | 0
.../article_note_page_validator.ex | 1 +
.../object_validators/attachment_validator.ex | 4 +-
.../audio_image_video_validator.ex | 126 +++
.../object_validators/audio_video_validator.ex | 120 ---
.../object_validators/block_validator.ex | 0
.../object_validators/chat_message_validator.ex | 5 +
.../object_validators/common_fields.ex | 6 +-
.../activity_pub/object_validators/common_fixes.ex | 49 +
.../object_validators/common_validations.ex | 0
.../create_chat_message_validator.ex | 0
.../object_validators/create_generic_validator.ex | 0
.../object_validators/delete_validator.ex | 0
.../object_validators/emoji_react_validator.ex | 51 +-
.../object_validators/event_validator.ex | 0
.../object_validators/follow_validator.ex | 0
.../object_validators/like_validator.ex | 0
.../question_options_validator.ex | 4 +-
.../object_validators/question_validator.ex | 2 +
.../object_validators/tag_validator.ex | 20 +-
.../object_validators/undo_validator.ex | 0
.../object_validators/update_validator.ex | 0
lib/pleroma/web/activity_pub/pipeline.ex | 2 +-
lib/pleroma/web/activity_pub/publisher.ex | 204 ++--
lib/pleroma/web/activity_pub/relay.ex | 2 +-
lib/pleroma/web/activity_pub/side_effects.ex | 44 +-
.../web/activity_pub/side_effects/handling.ex | 2 +-
lib/pleroma/web/activity_pub/transmogrifier.ex | 85 +-
lib/pleroma/web/activity_pub/utils.ex | 122 ++-
lib/pleroma/web/activity_pub/views/object_view.ex | 0
lib/pleroma/web/activity_pub/views/user_view.ex | 13 +-
lib/pleroma/web/activity_pub/visibility.ex | 50 +-
.../admin_api/controllers/admin_api_controller.ex | 0
.../controllers/announcement_controller.ex | 0
.../web/admin_api/controllers/chat_controller.ex | 0
.../web/admin_api/controllers/config_controller.ex | 6 +-
.../admin_api/controllers/fallback_controller.ex | 0
.../admin_api/controllers/frontend_controller.ex | 25 +-
.../admin_api/controllers/instance_controller.ex | 0
.../controllers/instance_document_controller.ex | 13 +-
.../web/admin_api/controllers/invite_controller.ex | 14 +-
.../controllers/media_proxy_cache_controller.ex | 15 +-
.../admin_api/controllers/o_auth_app_controller.ex | 0
.../web/admin_api/controllers/relay_controller.ex | 18 +-
.../web/admin_api/controllers/report_controller.ex | 42 +-
.../web/admin_api/controllers/status_controller.ex | 0
.../web/admin_api/controllers/user_controller.ex | 107 +-
lib/pleroma/web/admin_api/report.ex | 0
lib/pleroma/web/admin_api/search.ex | 0
lib/pleroma/web/admin_api/views/account_view.ex | 0
.../web/admin_api/views/announcement_view.ex | 0
lib/pleroma/web/admin_api/views/chat_view.ex | 0
lib/pleroma/web/admin_api/views/config_view.ex | 0
lib/pleroma/web/admin_api/views/frontend_view.ex | 3 +-
lib/pleroma/web/admin_api/views/invite_view.ex | 0
.../web/admin_api/views/media_proxy_cache_view.ex | 0
.../web/admin_api/views/moderation_log_view.ex | 0
lib/pleroma/web/admin_api/views/o_auth_app_view.ex | 0
lib/pleroma/web/admin_api/views/report_view.ex | 0
lib/pleroma/web/admin_api/views/status_view.ex | 0
lib/pleroma/web/admin_api/views/user_view.ex | 0
lib/pleroma/web/api_spec.ex | 43 +-
lib/pleroma/web/api_spec/cast_and_validate.ex | 14 +-
lib/pleroma/web/api_spec/helpers.ex | 2 +-
.../web/api_spec/operations/account_operation.ex | 23 +-
.../operations/admin/announcement_operation.ex | 10 +-
.../api_spec/operations/admin/chat_operation.ex | 0
.../api_spec/operations/admin/config_operation.ex | 0
.../operations/admin/frontend_operation.ex | 9 +-
.../admin/instance_document_operation.ex | 0
.../api_spec/operations/admin/invite_operation.ex | 0
.../admin/media_proxy_cache_operation.ex | 0
.../operations/admin/o_auth_app_operation.ex | 8 +-
.../api_spec/operations/admin/relay_operation.ex | 0
.../api_spec/operations/admin/report_operation.ex | 12 +-
.../api_spec/operations/admin/status_operation.ex | 8 +-
.../api_spec/operations/admin/user_operation.ex | 0
.../api_spec/operations/announcement_operation.ex | 4 +-
.../web/api_spec/operations/app_operation.ex | 0
.../web/api_spec/operations/chat_operation.ex | 14 +-
.../api_spec/operations/conversation_operation.ex | 0
.../api_spec/operations/custom_emoji_operation.ex | 0
.../web/api_spec/operations/directory_operation.ex | 4 +-
.../api_spec/operations/domain_block_operation.ex | 0
.../operations/emoji_reaction_operation.ex | 6 +-
.../web/api_spec/operations/filter_operation.ex | 0
.../operations/follow_request_operation.ex | 0
.../web/api_spec/operations/instance_operation.ex | 205 +++-
.../web/api_spec/operations/list_operation.ex | 0
.../web/api_spec/operations/marker_operation.ex | 0
.../web/api_spec/operations/media_operation.ex | 0
.../api_spec/operations/notification_operation.ex | 2 +-
.../operations/pleroma_account_operation.ex | 2 +-
.../api_spec/operations/pleroma_app_operation.ex | 0
.../operations/pleroma_backup_operation.ex | 12 +-
.../pleroma_bookmark_folder_operation.ex | 125 +++
.../operations/pleroma_conversation_operation.ex | 0
.../operations/pleroma_emoji_file_operation.ex | 6 +-
.../operations/pleroma_emoji_pack_operation.ex | 28 +-
.../operations/pleroma_instances_operation.ex | 2 +-
.../operations/pleroma_mascot_operation.ex | 0
.../operations/pleroma_notification_operation.ex | 0
.../operations/pleroma_report_operation.ex | 0
.../operations/pleroma_scrobble_operation.ex | 10 +-
.../operations/pleroma_settings_operation.ex | 0
.../operations/pleroma_status_operation.ex | 45 +
.../web/api_spec/operations/poll_operation.ex | 2 +-
.../web/api_spec/operations/report_operation.ex | 0
.../operations/scheduled_activity_operation.ex | 2 +-
.../web/api_spec/operations/search_operation.ex | 4 +-
.../web/api_spec/operations/status_operation.ex | 43 +-
.../web/api_spec/operations/streaming_operation.ex | 464 +++++++++
.../api_spec/operations/subscription_operation.ex | 0
.../web/api_spec/operations/timeline_operation.ex | 7 +-
.../api_spec/operations/twitter_util_operation.ex | 35 +-
.../api_spec/operations/user_import_operation.ex | 0
lib/pleroma/web/api_spec/render_error.ex | 0
lib/pleroma/web/api_spec/schemas/account.ex | 0
lib/pleroma/web/api_spec/schemas/account_field.ex | 0
.../web/api_spec/schemas/account_relationship.ex | 0
lib/pleroma/web/api_spec/schemas/actor_type.ex | 0
lib/pleroma/web/api_spec/schemas/announcement.ex | 0
lib/pleroma/web/api_spec/schemas/api_error.ex | 0
lib/pleroma/web/api_spec/schemas/app.ex | 0
lib/pleroma/web/api_spec/schemas/attachment.ex | 2 +-
.../web/api_spec/schemas/bookmark_folder.ex | 26 +
lib/pleroma/web/api_spec/schemas/boolean_like.ex | 0
lib/pleroma/web/api_spec/schemas/chat.ex | 0
lib/pleroma/web/api_spec/schemas/chat_message.ex | 0
lib/pleroma/web/api_spec/schemas/conversation.ex | 0
lib/pleroma/web/api_spec/schemas/emoji.ex | 0
lib/pleroma/web/api_spec/schemas/flake_id.ex | 0
lib/pleroma/web/api_spec/schemas/list.ex | 0
lib/pleroma/web/api_spec/schemas/poll.ex | 14 +-
.../web/api_spec/schemas/push_subscription.ex | 0
.../web/api_spec/schemas/scheduled_status.ex | 0
lib/pleroma/web/api_spec/schemas/status.ex | 43 +-
lib/pleroma/web/api_spec/schemas/tag.ex | 0
.../web/api_spec/schemas/visibility_scope.ex | 0
lib/pleroma/web/api_spec/scopes/compiler.ex | 82 ++
lib/pleroma/web/api_spec/scopes/translator.ex | 10 +
lib/pleroma/web/auth/authenticator.ex | 2 +-
lib/pleroma/web/auth/helpers.ex | 0
lib/pleroma/web/auth/ldap_authenticator.ex | 0
lib/pleroma/web/auth/pleroma_authenticator.ex | 0
lib/pleroma/web/auth/totp_authenticator.ex | 0
lib/pleroma/web/auth/wrapper_authenticator.ex | 0
lib/pleroma/web/channels/user_socket.ex | 0
lib/pleroma/web/common_api.ex | 12 +-
lib/pleroma/web/common_api/activity_draft.ex | 53 +-
lib/pleroma/web/common_api/utils.ex | 24 +-
lib/pleroma/web/controller_helper.ex | 18 +-
lib/pleroma/web/embed_controller.ex | 4 +-
lib/pleroma/web/endpoint.ex | 105 +-
.../fallback/legacy_pleroma_api_rerouter_plug.ex | 0
lib/pleroma/web/fallback/redirect_controller.ex | 27 +-
lib/pleroma/web/federator.ex | 32 +-
lib/pleroma/web/federator/publisher.ex | 109 ---
lib/pleroma/web/federator/publishing.ex | 0
lib/pleroma/web/feed/feed_view.ex | 4 +-
lib/pleroma/web/feed/tag_controller.ex | 0
lib/pleroma/web/feed/user_controller.ex | 0
lib/pleroma/web/gettext.ex | 4 +-
lib/pleroma/web/instance_document.ex | 0
lib/pleroma/web/mailer/subscription_controller.ex | 0
lib/pleroma/web/manifest_controller.ex | 0
.../mastodon_api/controllers/account_controller.ex | 103 +-
.../controllers/announcement_controller.ex | 0
.../web/mastodon_api/controllers/app_controller.ex | 0
.../mastodon_api/controllers/auth_controller.ex | 0
.../controllers/conversation_controller.ex | 0
.../controllers/custom_emoji_controller.ex | 0
.../controllers/directory_controller.ex | 2 +-
.../controllers/domain_block_controller.ex | 18 +-
.../controllers/fallback_controller.ex | 0
.../mastodon_api/controllers/filter_controller.ex | 0
.../controllers/follow_request_controller.ex | 4 +-
.../controllers/instance_controller.ex | 7 +-
.../mastodon_api/controllers/list_controller.ex | 52 +-
.../mastodon_api/controllers/marker_controller.ex | 0
.../controllers/mastodon_api_controller.ex | 0
.../mastodon_api/controllers/media_controller.ex | 26 +-
.../controllers/notification_controller.ex | 63 +-
.../mastodon_api/controllers/poll_controller.ex | 12 +-
.../mastodon_api/controllers/report_controller.ex | 0
.../controllers/scheduled_activity_controller.ex | 17 +-
.../mastodon_api/controllers/search_controller.ex | 20 +-
.../mastodon_api/controllers/status_controller.ex | 192 +++-
.../controllers/subscription_controller.ex | 0
.../controllers/suggestion_controller.ex | 0
.../controllers/timeline_controller.ex | 0
lib/pleroma/web/mastodon_api/mastodon_api.ex | 0
lib/pleroma/web/mastodon_api/views/account_view.ex | 24 +-
.../web/mastodon_api/views/announcement_view.ex | 0
lib/pleroma/web/mastodon_api/views/app_view.ex | 0
.../web/mastodon_api/views/conversation_view.ex | 0
.../web/mastodon_api/views/custom_emoji_view.ex | 0
lib/pleroma/web/mastodon_api/views/filter_view.ex | 0
.../web/mastodon_api/views/follow_request_view.ex | 0
.../web/mastodon_api/views/instance_view.ex | 162 +++-
lib/pleroma/web/mastodon_api/views/list_view.ex | 0
lib/pleroma/web/mastodon_api/views/marker_view.ex | 0
lib/pleroma/web/mastodon_api/views/media_view.ex | 0
.../web/mastodon_api/views/notification_view.ex | 5 +-
lib/pleroma/web/mastodon_api/views/poll_view.ex | 5 +-
lib/pleroma/web/mastodon_api/views/report_view.ex | 0
.../mastodon_api/views/scheduled_activity_view.ex | 0
lib/pleroma/web/mastodon_api/views/status_view.ex | 164 +++-
.../web/mastodon_api/views/subscription_view.ex | 0
.../web/mastodon_api/views/suggestion_view.ex | 0
.../web/mastodon_api/views/timeline_view.ex | 0
lib/pleroma/web/mastodon_api/websocket_handler.ex | 249 +++--
lib/pleroma/web/media_proxy.ex | 0
lib/pleroma/web/media_proxy/invalidation.ex | 0
lib/pleroma/web/media_proxy/invalidation/http.ex | 0
lib/pleroma/web/media_proxy/invalidation/script.ex | 0
.../web/media_proxy/media_proxy_controller.ex | 2 +-
lib/pleroma/web/metadata.ex | 0
lib/pleroma/web/metadata/player_view.ex | 0
lib/pleroma/web/metadata/providers/feed.ex | 0
lib/pleroma/web/metadata/providers/open_graph.ex | 0
lib/pleroma/web/metadata/providers/provider.ex | 0
lib/pleroma/web/metadata/providers/rel_me.ex | 14 +-
.../web/metadata/providers/restrict_indexing.ex | 0
lib/pleroma/web/metadata/providers/twitter_card.ex | 13 +-
lib/pleroma/web/metadata/utils.ex | 0
.../web/mongoose_im/mongoose_im_controller.ex | 0
lib/pleroma/web/multipart.ex | 22 +
lib/pleroma/web/nodeinfo/nodeinfo.ex | 2 +-
lib/pleroma/web/nodeinfo/nodeinfo_controller.ex | 0
lib/pleroma/web/o_auth.ex | 0
lib/pleroma/web/o_auth/app.ex | 0
lib/pleroma/web/o_auth/authorization.ex | 8 +-
lib/pleroma/web/o_auth/fallback_controller.ex | 0
lib/pleroma/web/o_auth/mfa_controller.ex | 0
lib/pleroma/web/o_auth/mfa_view.ex | 0
lib/pleroma/web/o_auth/o_auth_controller.ex | 9 +-
lib/pleroma/web/o_auth/o_auth_view.ex | 0
lib/pleroma/web/o_auth/scopes.ex | 0
lib/pleroma/web/o_auth/token.ex | 9 +-
lib/pleroma/web/o_auth/token/query.ex | 4 +-
.../web/o_auth/token/strategy/refresh_token.ex | 0
lib/pleroma/web/o_auth/token/strategy/revoke.ex | 0
lib/pleroma/web/o_auth/token/utils.ex | 0
lib/pleroma/web/o_status/o_status_controller.ex | 9 +-
.../pleroma_api/controllers/account_controller.ex | 0
.../web/pleroma_api/controllers/app_controller.ex | 0
.../pleroma_api/controllers/backup_controller.ex | 0
.../controllers/bookmark_folder_controller.ex | 68 ++
.../web/pleroma_api/controllers/chat_controller.ex | 69 +-
.../controllers/conversation_controller.ex | 0
.../controllers/emoji_file_controller.ex | 24 +-
.../controllers/emoji_pack_controller.ex | 29 +-
.../controllers/emoji_reaction_controller.ex | 24 +-
.../controllers/instances_controller.ex | 0
.../pleroma_api/controllers/mascot_controller.ex | 13 +-
.../controllers/notification_controller.ex | 16 +-
.../pleroma_api/controllers/report_controller.ex | 0
.../pleroma_api/controllers/scrobble_controller.ex | 0
.../pleroma_api/controllers/settings_controller.ex | 0
.../pleroma_api/controllers/status_controller.ex | 66 ++
.../two_factor_authentication_controller.ex | 0
.../controllers/user_import_controller.ex | 41 +-
lib/pleroma/web/pleroma_api/views/account_view.ex | 0
lib/pleroma/web/pleroma_api/views/app_view.ex | 0
lib/pleroma/web/pleroma_api/views/backup_view.ex | 10 +
.../web/pleroma_api/views/bookmark_folder_view.ex | 42 +
.../views/chat/message_reference_view.ex | 13 +-
lib/pleroma/web/pleroma_api/views/chat_view.ex | 0
.../web/pleroma_api/views/conversation_view.ex | 0
.../web/pleroma_api/views/emoji_reaction_view.ex | 17 +-
.../web/pleroma_api/views/notification_view.ex | 0
lib/pleroma/web/pleroma_api/views/report_view.ex | 0
lib/pleroma/web/pleroma_api/views/scrobble_view.ex | 1 +
lib/pleroma/web/plug.ex | 0
.../web/plugs/admin_secret_authentication_plug.ex | 0
lib/pleroma/web/plugs/authentication_plug.ex | 0
lib/pleroma/web/plugs/basic_auth_decoder_plug.ex | 0
lib/pleroma/web/plugs/cache.ex | 2 +-
lib/pleroma/web/plugs/digest_plug.ex | 0
lib/pleroma/web/plugs/ensure_authenticated_plug.ex | 0
lib/pleroma/web/plugs/ensure_privileged_plug.ex | 0
.../plugs/ensure_public_or_authenticated_plug.ex | 0
.../web/plugs/ensure_user_token_assigns_plug.ex | 0
.../web/plugs/expect_authenticated_check_plug.ex | 0
.../expect_public_or_authenticated_check_plug.ex | 0
lib/pleroma/web/plugs/federating_plug.ex | 0
lib/pleroma/web/plugs/frontend_static.ex | 0
lib/pleroma/web/plugs/http_security_plug.ex | 20 +-
lib/pleroma/web/plugs/http_signature_plug.ex | 2 +-
lib/pleroma/web/plugs/idempotency_plug.ex | 0
lib/pleroma/web/plugs/instance_static.ex | 0
.../web/plugs/mapped_signature_to_identity_plug.ex | 0
lib/pleroma/web/plugs/o_auth_plug.ex | 4 +-
lib/pleroma/web/plugs/o_auth_scopes_plug.ex | 0
lib/pleroma/web/plugs/plug_helper.ex | 0
lib/pleroma/web/plugs/rate_limiter.ex | 2 +-
.../web/plugs/rate_limiter/limiter_supervisor.ex | 0
lib/pleroma/web/plugs/rate_limiter/supervisor.ex | 2 +-
lib/pleroma/web/plugs/remote_ip.ex | 2 +-
lib/pleroma/web/plugs/set_format_plug.ex | 0
lib/pleroma/web/plugs/set_locale_plug.ex | 0
lib/pleroma/web/plugs/set_user_session_id_plug.ex | 0
lib/pleroma/web/plugs/static_fe_plug.ex | 0
lib/pleroma/web/plugs/trailing_format_plug.ex | 0
lib/pleroma/web/plugs/uploaded_media.ex | 6 +-
lib/pleroma/web/plugs/user_enabled_plug.ex | 0
lib/pleroma/web/plugs/user_fetcher_plug.ex | 0
lib/pleroma/web/plugs/user_is_admin_plug.ex | 0
lib/pleroma/web/plugs/user_is_staff_plug.ex | 0
lib/pleroma/web/plugs/user_tracking_plug.ex | 0
lib/pleroma/web/preload.ex | 4 +-
lib/pleroma/web/preload/providers/instance.ex | 0
lib/pleroma/web/preload/providers/provider.ex | 0
lib/pleroma/web/preload/providers/timelines.ex | 0
lib/pleroma/web/preload/providers/user.ex | 0
lib/pleroma/web/push.ex | 2 +-
lib/pleroma/web/push/impl.ex | 2 +-
lib/pleroma/web/push/subscription.ex | 0
lib/pleroma/web/rel_me.ex | 0
lib/pleroma/web/rich_media/backfill.ex | 101 ++
lib/pleroma/web/rich_media/card.ex | 157 +++
lib/pleroma/web/rich_media/helpers.ex | 89 +-
lib/pleroma/web/rich_media/parser.ex | 169 +---
lib/pleroma/web/rich_media/parser/ttl.ex | 15 +-
.../web/rich_media/parser/ttl/aws_signed_url.ex | 15 +-
lib/pleroma/web/rich_media/parser/ttl/opengraph.ex | 20 +
.../web/rich_media/parsers/meta_tags_parser.ex | 0
lib/pleroma/web/rich_media/parsers/o_embed.ex | 0
lib/pleroma/web/rich_media/parsers/ogp.ex | 0
lib/pleroma/web/rich_media/parsers/twitter_card.ex | 0
lib/pleroma/web/router.ex | 223 ++++-
lib/pleroma/web/router.ex~ | 1017 --------------------
lib/pleroma/web/shout_channel.ex | 0
lib/pleroma/web/static_fe/static_fe_controller.ex | 13 +-
lib/pleroma/web/static_fe/static_fe_view.ex | 0
lib/pleroma/web/streamer.ex | 70 +-
lib/pleroma/web/templates/email/digest.html.eex | 0
.../web/templates/email/new_users_digest.html.eex | 0
.../web/templates/embed/_attachment.html.eex | 0
lib/pleroma/web/templates/embed/show.html.eex | 0
.../web/templates/feed/feed/_activity.atom.eex | 0
.../web/templates/feed/feed/_activity.rss.eex | 0
.../web/templates/feed/feed/_author.atom.eex | 0
.../web/templates/feed/feed/_author.rss.eex | 0
.../web/templates/feed/feed/_tag_activity.atom.eex | 0
.../web/templates/feed/feed/_tag_activity.xml.eex | 0
.../web/templates/feed/feed/_tag_author.atom.eex | 0
lib/pleroma/web/templates/feed/feed/tag.atom.eex | 0
lib/pleroma/web/templates/feed/feed/tag.rss.eex | 0
lib/pleroma/web/templates/feed/feed/user.atom.eex | 0
lib/pleroma/web/templates/feed/feed/user.rss.eex | 0
lib/pleroma/web/templates/layout/app.html.eex | 0
lib/pleroma/web/templates/layout/email.html.eex | 0
.../web/templates/layout/email_styled.html.eex | 0
lib/pleroma/web/templates/layout/embed.html.eex | 0
.../web/templates/layout/metadata_player.html.eex | 0
.../web/templates/layout/static_fe.html.eex | 0
.../subscription/unsubscribe_failure.html.eex | 0
.../subscription/unsubscribe_success.html.eex | 0
.../web/templates/o_auth/mfa/recovery.html.eex | 8 +-
lib/pleroma/web/templates/o_auth/mfa/totp.html.eex | 8 +-
.../web/templates/o_auth/o_auth/_scopes.html.eex | 2 +-
.../web/templates/o_auth/o_auth/consumer.html.eex | 0
.../o_auth/oob_authorization_created.html.eex | 0
.../o_auth/o_auth/oob_token_exists.html.eex | 0
.../web/templates/o_auth/o_auth/register.html.eex | 8 +-
.../web/templates/o_auth/o_auth/show.html.eex | 10 +-
.../static_fe/static_fe/_attachment.html.eex | 0
.../templates/static_fe/static_fe/_notice.html.eex | 0
.../static_fe/static_fe/_user_card.html.eex | 0
.../static_fe/static_fe/conversation.html.eex | 0
.../templates/static_fe/static_fe/error.html.eex | 0
.../templates/static_fe/static_fe/profile.html.eex | 0
.../twitter_api/password/invalid_token.html.eex | 0
.../templates/twitter_api/password/reset.html.eex | 0
.../twitter_api/password/reset_failed.html.eex | 0
.../twitter_api/password/reset_success.html.eex | 0
.../twitter_api/remote_follow/follow.html.eex | 0
.../remote_follow/follow_login.html.eex | 0
.../twitter_api/remote_follow/follow_mfa.html.eex | 0
.../twitter_api/remote_follow/followed.html.eex | 0
.../twitter_api/util/status_interact.html.eex | 0
.../templates/twitter_api/util/subscribe.html.eex | 0
lib/pleroma/web/translation_helpers.ex | 0
lib/pleroma/web/twitter_api/controller.ex | 0
.../twitter_api/controllers/password_controller.ex | 2 +-
.../controllers/remote_follow_controller.ex | 11 +-
.../web/twitter_api/controllers/util_controller.ex | 59 +-
lib/pleroma/web/twitter_api/twitter_api.ex | 0
lib/pleroma/web/twitter_api/views/password_view.ex | 0
.../web/twitter_api/views/remote_follow_view.ex | 0
lib/pleroma/web/twitter_api/views/token_view.ex | 0
lib/pleroma/web/twitter_api/views/util_view.ex | 0
lib/pleroma/web/uploader_controller.ex | 0
lib/pleroma/web/utils/guards.ex | 0
lib/pleroma/web/utils/params.ex | 0
lib/pleroma/web/views/email_view.ex | 0
lib/pleroma/web/views/embed_view.ex | 0
lib/pleroma/web/views/error_helpers.ex | 0
lib/pleroma/web/views/error_view.ex | 0
lib/pleroma/web/views/layout_view.ex | 0
lib/pleroma/web/views/mailer/subscription_view.ex | 0
lib/pleroma/web/views/manifest_view.ex | 0
lib/pleroma/web/views/streamer_view.ex | 61 +-
lib/pleroma/web/web_finger.ex | 10 +-
.../web/web_finger/web_finger_controller.ex | 2 +-
lib/pleroma/web/xml.ex | 2 +-
lib/pleroma/workers/attachments_cleanup_worker.ex | 0
lib/pleroma/workers/background_worker.ex | 7 +-
lib/pleroma/workers/backup_worker.ex | 2 +-
lib/pleroma/workers/cron/digest_emails_worker.ex | 2 +-
.../workers/cron/new_users_digest_worker.ex | 2 +-
lib/pleroma/workers/mailer_worker.ex | 0
lib/pleroma/workers/mute_expire_worker.ex | 0
lib/pleroma/workers/poll_worker.ex | 0
lib/pleroma/workers/publisher_worker.ex | 4 +-
lib/pleroma/workers/purge_expired_activity.ex | 0
lib/pleroma/workers/purge_expired_filter.ex | 0
lib/pleroma/workers/purge_expired_token.ex | 0
lib/pleroma/workers/receiver_worker.ex | 41 +-
lib/pleroma/workers/remote_fetcher_worker.ex | 20 +-
.../workers/rich_media_expiration_worker.ex | 15 +
lib/pleroma/workers/scheduled_activity_worker.ex | 0
lib/pleroma/workers/search_indexing_worker.ex | 23 +
lib/pleroma/workers/transmogrifier_worker.ex | 18 -
lib/pleroma/workers/web_pusher_worker.ex | 0
lib/pleroma/workers/worker_helper.ex | 0
lib/pleroma/xml_builder.ex | 0
676 files changed, 7303 insertions(+), 3735 deletions(-)
mode change 100755 => 100644 lib/mix/pleroma.ex
mode change 100755 => 100644 lib/mix/tasks/pleroma/app.ex
delete mode 100755 lib/mix/tasks/pleroma/benchmark.ex
mode change 100755 => 100644 lib/mix/tasks/pleroma/config.ex
mode change 100755 => 100644 lib/mix/tasks/pleroma/count_statuses.ex
mode change 100755 => 100644 lib/mix/tasks/pleroma/database.ex
mode change 100755 => 100644 lib/mix/tasks/pleroma/digest.ex
mode change 100755 => 100644 lib/mix/tasks/pleroma/docs.ex
mode change 100755 => 100644 lib/mix/tasks/pleroma/ecto.ex
mode change 100755 => 100644 lib/mix/tasks/pleroma/ecto/migrate.ex
mode change 100755 => 100644 lib/mix/tasks/pleroma/ecto/rollback.ex
mode change 100755 => 100644 lib/mix/tasks/pleroma/email.ex
mode change 100755 => 100644 lib/mix/tasks/pleroma/emoji.ex
mode change 100755 => 100644 lib/mix/tasks/pleroma/frontend.ex
mode change 100755 => 100644 lib/mix/tasks/pleroma/instance.ex
mode change 100755 => 100644 lib/mix/tasks/pleroma/notification_settings.ex
mode change 100755 => 100644 lib/mix/tasks/pleroma/openapi_spec.ex
mode change 100755 => 100644 lib/mix/tasks/pleroma/refresh_counter_cache.ex
mode change 100755 => 100644 lib/mix/tasks/pleroma/relay.ex
mode change 100755 => 100644 lib/mix/tasks/pleroma/robots_txt.ex
create mode 100644 lib/mix/tasks/pleroma/search/meilisearch.ex
mode change 100755 => 100644 lib/mix/tasks/pleroma/uploads.ex
mode change 100755 => 100644 lib/mix/tasks/pleroma/user.ex
delete mode 100755 lib/phoenix/transports/web_socket/raw.ex
mode change 100755 => 100644 lib/pleroma/activity.ex
mode change 100755 => 100644 lib/pleroma/activity/html.ex
mode change 100755 => 100644 lib/pleroma/activity/ir/topics.ex
mode change 100755 => 100644 lib/pleroma/activity/queries.ex
delete mode 100755 lib/pleroma/activity/search.ex
mode change 100755 => 100644 lib/pleroma/announcement.ex
mode change 100755 => 100644 lib/pleroma/announcement_read_relationship.ex
mode change 100755 => 100644 lib/pleroma/application.ex
mode change 100755 => 100644 lib/pleroma/application_requirements.ex
delete mode 100755 lib/pleroma/bbs/authenticator.ex
delete mode 100755 lib/pleroma/bbs/handler.ex
mode change 100755 => 100644 lib/pleroma/bookmark.ex
create mode 100644 lib/pleroma/bookmark_folder.ex
mode change 100755 => 100644 lib/pleroma/caching.ex
mode change 100755 => 100644 lib/pleroma/captcha.ex
mode change 100755 => 100644 lib/pleroma/captcha/kocaptcha.ex
mode change 100755 => 100644 lib/pleroma/captcha/native.ex
mode change 100755 => 100644 lib/pleroma/captcha/service.ex
mode change 100755 => 100644 lib/pleroma/chat.ex
mode change 100755 => 100644 lib/pleroma/chat/message_reference.ex
mode change 100755 => 100644 lib/pleroma/clippy.ex
mode change 100755 => 100644 lib/pleroma/config.ex
mode change 100755 => 100644 lib/pleroma/config/deprecation_warnings.ex
mode change 100755 => 100644 lib/pleroma/config/getting.ex
mode change 100755 => 100644 lib/pleroma/config/helpers.ex
mode change 100755 => 100644 lib/pleroma/config/holder.ex
mode change 100755 => 100644 lib/pleroma/config/loader.ex
mode change 100755 => 100644 lib/pleroma/config/oban.ex
mode change 100755 => 100644 lib/pleroma/config/release_runtime_provider.ex
mode change 100755 => 100644 lib/pleroma/config/transfer_task.ex
mode change 100755 => 100644 lib/pleroma/config_db.ex
mode change 100755 => 100644 lib/pleroma/constants.ex
mode change 100755 => 100644 lib/pleroma/conversation.ex
mode change 100755 => 100644 lib/pleroma/conversation/participation.ex
mode change 100755 => 100644 lib/pleroma/conversation/participation/recipient_ship.ex
mode change 100755 => 100644 lib/pleroma/counter_cache.ex
mode change 100755 => 100644 lib/pleroma/data_migration.ex
mode change 100755 => 100644 lib/pleroma/delivery.ex
mode change 100755 => 100644 lib/pleroma/docs/generator.ex
mode change 100755 => 100644 lib/pleroma/docs/json.ex
mode change 100755 => 100644 lib/pleroma/docs/markdown.ex
mode change 100755 => 100644 lib/pleroma/docs/translator.ex
mode change 100755 => 100644 lib/pleroma/docs/translator/compiler.ex
mode change 100755 => 100644 lib/pleroma/ecto_enums.ex
create mode 100644 lib/pleroma/ecto_type/activity_pub/object_validators/bare_uri.ex
mode change 100755 => 100644 lib/pleroma/ecto_type/activity_pub/object_validators/date_time.ex
mode change 100755 => 100644 lib/pleroma/ecto_type/activity_pub/object_validators/emoji.ex
mode change 100755 => 100644 lib/pleroma/ecto_type/activity_pub/object_validators/mime.ex
mode change 100755 => 100644 lib/pleroma/ecto_type/activity_pub/object_validators/object_id.ex
mode change 100755 => 100644 lib/pleroma/ecto_type/activity_pub/object_validators/recipients.ex
mode change 100755 => 100644 lib/pleroma/ecto_type/activity_pub/object_validators/safe_text.ex
mode change 100755 => 100644 lib/pleroma/ecto_type/activity_pub/object_validators/uri.ex
mode change 100755 => 100644 lib/pleroma/ecto_type/config/atom.ex
mode change 100755 => 100644 lib/pleroma/ecto_type/config/binary_value.ex
mode change 100755 => 100644 lib/pleroma/emails/admin_email.ex
mode change 100755 => 100644 lib/pleroma/emails/mailer.ex
mode change 100755 => 100644 lib/pleroma/emails/new_users_digest_email.ex
mode change 100755 => 100644 lib/pleroma/emails/user_email.ex
mode change 100755 => 100644 lib/pleroma/emoji-test.txt
mode change 100755 => 100644 lib/pleroma/emoji.ex
mode change 100755 => 100644 lib/pleroma/emoji/combinations.ex
mode change 100755 => 100644 lib/pleroma/emoji/formatter.ex
mode change 100755 => 100644 lib/pleroma/emoji/loader.ex
mode change 100755 => 100644 lib/pleroma/emoji/pack.ex
mode change 100755 => 100644 lib/pleroma/filter.ex
mode change 100755 => 100644 lib/pleroma/following_relationship.ex
mode change 100755 => 100644 lib/pleroma/formatter.ex
mode change 100755 => 100644 lib/pleroma/frontend.ex
mode change 100755 => 100644 lib/pleroma/gopher/server.ex
mode change 100755 => 100644 lib/pleroma/gun.ex
mode change 100755 => 100644 lib/pleroma/gun/api.ex
mode change 100755 => 100644 lib/pleroma/gun/conn.ex
mode change 100755 => 100644 lib/pleroma/gun/connection_pool.ex
mode change 100755 => 100644 lib/pleroma/gun/connection_pool/reclaimer.ex
mode change 100755 => 100644 lib/pleroma/gun/connection_pool/worker.ex
mode change 100755 => 100644 lib/pleroma/gun/connection_pool/worker_supervisor.ex
mode change 100755 => 100644 lib/pleroma/hashtag.ex
mode change 100755 => 100644 lib/pleroma/healthcheck.ex
mode change 100755 => 100644 lib/pleroma/helpers/auth_helper.ex
mode change 100755 => 100644 lib/pleroma/helpers/inet_helper.ex
mode change 100755 => 100644 lib/pleroma/helpers/media_helper.ex
mode change 100755 => 100644 lib/pleroma/helpers/qt_fast_start.ex
mode change 100755 => 100644 lib/pleroma/helpers/uri_helper.ex
mode change 100755 => 100644 lib/pleroma/html.ex
mode change 100755 => 100644 lib/pleroma/http.ex
create mode 100644 lib/pleroma/http.ex.orig
mode change 100755 => 100644 lib/pleroma/http/adapter_helper.ex
mode change 100755 => 100644 lib/pleroma/http/adapter_helper/default.ex
mode change 100755 => 100644 lib/pleroma/http/adapter_helper/gun.ex
mode change 100755 => 100644 lib/pleroma/http/adapter_helper/hackney.ex
mode change 100755 => 100644 lib/pleroma/http/ex_aws.ex
mode change 100755 => 100644 lib/pleroma/http/request.ex
mode change 100755 => 100644 lib/pleroma/http/request_builder.ex
mode change 100755 => 100644 lib/pleroma/http/tzdata.ex
mode change 100755 => 100644 lib/pleroma/http/web_push.ex
mode change 100755 => 100644 lib/pleroma/instances.ex
mode change 100755 => 100644 lib/pleroma/instances/instance.ex
mode change 100755 => 100644 lib/pleroma/job_queue_monitor.ex
mode change 100755 => 100644 lib/pleroma/jwt.ex
mode change 100755 => 100644 lib/pleroma/keys.ex
mode change 100755 => 100644 lib/pleroma/list.ex
mode change 100755 => 100644 lib/pleroma/logging.ex
mode change 100755 => 100644 lib/pleroma/maintenance.ex
mode change 100755 => 100644 lib/pleroma/maps.ex
mode change 100755 => 100644 lib/pleroma/marker.ex
mode change 100755 => 100644 lib/pleroma/mfa.ex
mode change 100755 => 100644 lib/pleroma/mfa/backup_codes.ex
mode change 100755 => 100644 lib/pleroma/mfa/changeset.ex
mode change 100755 => 100644 lib/pleroma/mfa/settings.ex
mode change 100755 => 100644 lib/pleroma/mfa/token.ex
mode change 100755 => 100644 lib/pleroma/mfa/totp.ex
mode change 100755 => 100644 lib/pleroma/migration_helper/notification_backfill.ex
mode change 100755 => 100644 lib/pleroma/migrators/context_objects_deletion_migrator.ex
mode change 100755 => 100644 lib/pleroma/migrators/hashtags_table_migrator.ex
mode change 100755 => 100644 lib/pleroma/migrators/support/base_migrator.ex
mode change 100755 => 100644 lib/pleroma/migrators/support/base_migrator_state.ex
mode change 100755 => 100644 lib/pleroma/moderation_log.ex
mode change 100755 => 100644 lib/pleroma/notification.ex
mode change 100755 => 100644 lib/pleroma/object.ex
mode change 100755 => 100644 lib/pleroma/object/containment.ex
mode change 100755 => 100644 lib/pleroma/object/fetcher.ex
create mode 100644 lib/pleroma/object/fetcher.ex.orig
create mode 100644 lib/pleroma/object/fetcher.ex.rej
mode change 100755 => 100644 lib/pleroma/object/updater.ex
mode change 100755 => 100644 lib/pleroma/object_tombstone.ex
mode change 100755 => 100644 lib/pleroma/otp_version.ex
mode change 100755 => 100644 lib/pleroma/pagination.ex
mode change 100755 => 100644 lib/pleroma/password/pbkdf2.ex
mode change 100755 => 100644 lib/pleroma/password_reset_token.ex
create mode 100644 lib/pleroma/prom_ex.ex
mode change 100755 => 100644 lib/pleroma/registration.ex
mode change 100755 => 100644 lib/pleroma/release_tasks.ex
mode change 100755 => 100644 lib/pleroma/repo.ex
mode change 100755 => 100644 lib/pleroma/report_note.ex
mode change 100755 => 100644 lib/pleroma/reverse_proxy.ex
mode change 100755 => 100644 lib/pleroma/reverse_proxy/client.ex
mode change 100755 => 100644 lib/pleroma/reverse_proxy/client/hackney.ex
mode change 100755 => 100644 lib/pleroma/reverse_proxy/client/tesla.ex
mode change 100755 => 100644 lib/pleroma/reverse_proxy/client/wrapper.ex
mode change 100755 => 100644 lib/pleroma/scheduled_activity.ex
create mode 100644 lib/pleroma/search.ex
create mode 100644 lib/pleroma/search/database_search.ex
create mode 100644 lib/pleroma/search/meilisearch.ex
create mode 100644 lib/pleroma/search/search_backend.ex
mode change 100755 => 100644 lib/pleroma/signature.ex
mode change 100755 => 100644 lib/pleroma/stats.ex
mode change 100755 => 100644 lib/pleroma/telemetry/logger.ex
mode change 100755 => 100644 lib/pleroma/tesla/middleware/connection_pool.ex
mode change 100755 => 100644 lib/pleroma/tests/auth_test_controller.ex
mode change 100755 => 100644 lib/pleroma/thread_mute.ex
mode change 100755 => 100644 lib/pleroma/upload.ex
mode change 100755 => 100644 lib/pleroma/upload/filter.ex
mode change 100755 => 100644 lib/pleroma/upload/filter/analyze_metadata.ex
mode change 100755 => 100644 lib/pleroma/upload/filter/anonymize_filename.ex
mode change 100755 => 100644 lib/pleroma/upload/filter/dedupe.ex
mode change 100755 => 100644 lib/pleroma/upload/filter/exiftool/read_description.ex
mode change 100755 => 100644 lib/pleroma/upload/filter/exiftool/strip_location.ex
mode change 100755 => 100644 lib/pleroma/upload/filter/mogrifun.ex
mode change 100755 => 100644 lib/pleroma/upload/filter/mogrify.ex
create mode 100644 lib/pleroma/upload/filter/only_media.ex
mode change 100755 => 100644 lib/pleroma/uploaders/local.ex
mode change 100755 => 100644 lib/pleroma/uploaders/s3.ex
mode change 100755 => 100644 lib/pleroma/uploaders/uploader.ex
mode change 100755 => 100644 lib/pleroma/user.ex
delete mode 100755 lib/pleroma/user/.welcome_message.ex~.un~
mode change 100755 => 100644 lib/pleroma/user/backup.ex
mode change 100755 => 100644 lib/pleroma/user/import.ex
mode change 100755 => 100644 lib/pleroma/user/notification_setting.ex
mode change 100755 => 100644 lib/pleroma/user/query.ex
mode change 100755 => 100644 lib/pleroma/user/search.ex
mode change 100755 => 100644 lib/pleroma/user/welcome_chat_message.ex
mode change 100755 => 100644 lib/pleroma/user/welcome_email.ex
mode change 100755 => 100644 lib/pleroma/user/welcome_message.ex
mode change 100755 => 100644 lib/pleroma/user_invite_token.ex
mode change 100755 => 100644 lib/pleroma/user_note.ex
mode change 100755 => 100644 lib/pleroma/user_relationship.ex
mode change 100755 => 100644 lib/pleroma/utils.ex
mode change 100755 => 100644 lib/pleroma/web.ex
delete mode 100755 lib/pleroma/web/.router.ex.un~
mode change 100755 => 100644 lib/pleroma/web/activity_pub/activity_pub.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/activity_pub/persisting.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/activity_pub/streaming.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/activity_pub_controller.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/builder.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/internal_fetch_actor.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/mrf.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/mrf/activity_expiration_policy.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/mrf/drop_policy.ex
create mode 100644 lib/pleroma/web/activity_pub/mrf/emoji_policy.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/mrf/follow_bot_policy.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/mrf/force_bot_unlisted_policy.ex
create mode 100644 lib/pleroma/web/activity_pub/mrf/force_mention.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/mrf/force_mentions_in_content.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/mrf/hashtag_policy.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex
create mode 100644 lib/pleroma/web/activity_pub/mrf/inline_quote_policy.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/mrf/keyword_policy.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/mrf/media_proxy_warming_policy.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/mrf/mention_policy.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/mrf/no_empty_policy.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/mrf/no_op_policy.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/mrf/normalize_markup.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/mrf/object_age_policy.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/mrf/pipeline_filtering.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/mrf/policy.ex
create mode 100644 lib/pleroma/web/activity_pub/mrf/quote_to_link_tag_policy.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/mrf/reject_non_public.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/mrf/simple_policy.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/mrf/steal_emoji_policy.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/mrf/subchain_policy.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/mrf/tag_policy.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/mrf/user_allow_list_policy.ex
create mode 100644 lib/pleroma/web/activity_pub/mrf/utils.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/object_validator.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/object_validator/validating.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/object_validators/accept_reject_validator.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/object_validators/add_remove_validator.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/object_validators/announce_validator.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/object_validators/answer_validator.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex
create mode 100644 lib/pleroma/web/activity_pub/object_validators/audio_image_video_validator.ex
delete mode 100755 lib/pleroma/web/activity_pub/object_validators/audio_video_validator.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/object_validators/block_validator.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/object_validators/chat_message_validator.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/object_validators/common_fields.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/object_validators/common_fixes.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/object_validators/common_validations.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/object_validators/create_chat_message_validator.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/object_validators/create_generic_validator.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/object_validators/delete_validator.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/object_validators/event_validator.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/object_validators/follow_validator.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/object_validators/like_validator.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/object_validators/question_options_validator.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/object_validators/question_validator.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/object_validators/tag_validator.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/object_validators/undo_validator.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/object_validators/update_validator.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/pipeline.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/publisher.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/relay.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/side_effects.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/side_effects/handling.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/transmogrifier.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/utils.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/views/object_view.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/views/user_view.ex
mode change 100755 => 100644 lib/pleroma/web/activity_pub/visibility.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/controllers/admin_api_controller.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/controllers/announcement_controller.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/controllers/chat_controller.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/controllers/config_controller.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/controllers/fallback_controller.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/controllers/frontend_controller.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/controllers/instance_controller.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/controllers/instance_document_controller.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/controllers/invite_controller.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/controllers/media_proxy_cache_controller.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/controllers/o_auth_app_controller.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/controllers/relay_controller.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/controllers/report_controller.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/controllers/status_controller.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/controllers/user_controller.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/report.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/search.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/views/account_view.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/views/announcement_view.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/views/chat_view.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/views/config_view.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/views/frontend_view.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/views/invite_view.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/views/media_proxy_cache_view.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/views/moderation_log_view.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/views/o_auth_app_view.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/views/report_view.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/views/status_view.ex
mode change 100755 => 100644 lib/pleroma/web/admin_api/views/user_view.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/cast_and_validate.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/helpers.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/account_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/admin/chat_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/admin/config_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/admin/frontend_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/admin/instance_document_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/admin/invite_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/admin/media_proxy_cache_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/admin/o_auth_app_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/admin/relay_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/admin/report_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/admin/status_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/admin/user_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/announcement_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/app_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/chat_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/conversation_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/custom_emoji_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/directory_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/domain_block_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/emoji_reaction_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/filter_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/follow_request_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/instance_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/list_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/marker_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/media_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/notification_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/pleroma_account_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/pleroma_app_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/pleroma_backup_operation.ex
create mode 100644 lib/pleroma/web/api_spec/operations/pleroma_bookmark_folder_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/pleroma_conversation_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/pleroma_emoji_file_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/pleroma_instances_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/pleroma_mascot_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/pleroma_notification_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/pleroma_report_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/pleroma_scrobble_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/pleroma_settings_operation.ex
create mode 100644 lib/pleroma/web/api_spec/operations/pleroma_status_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/poll_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/report_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/scheduled_activity_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/search_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/status_operation.ex
create mode 100644 lib/pleroma/web/api_spec/operations/streaming_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/subscription_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/timeline_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/twitter_util_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/operations/user_import_operation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/render_error.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/schemas/account.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/schemas/account_field.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/schemas/account_relationship.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/schemas/actor_type.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/schemas/announcement.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/schemas/api_error.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/schemas/app.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/schemas/attachment.ex
create mode 100644 lib/pleroma/web/api_spec/schemas/bookmark_folder.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/schemas/boolean_like.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/schemas/chat.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/schemas/chat_message.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/schemas/conversation.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/schemas/emoji.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/schemas/flake_id.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/schemas/list.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/schemas/poll.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/schemas/push_subscription.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/schemas/scheduled_status.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/schemas/status.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/schemas/tag.ex
mode change 100755 => 100644 lib/pleroma/web/api_spec/schemas/visibility_scope.ex
create mode 100644 lib/pleroma/web/api_spec/scopes/compiler.ex
create mode 100644 lib/pleroma/web/api_spec/scopes/translator.ex
mode change 100755 => 100644 lib/pleroma/web/auth/authenticator.ex
mode change 100755 => 100644 lib/pleroma/web/auth/helpers.ex
mode change 100755 => 100644 lib/pleroma/web/auth/ldap_authenticator.ex
mode change 100755 => 100644 lib/pleroma/web/auth/pleroma_authenticator.ex
mode change 100755 => 100644 lib/pleroma/web/auth/totp_authenticator.ex
mode change 100755 => 100644 lib/pleroma/web/auth/wrapper_authenticator.ex
mode change 100755 => 100644 lib/pleroma/web/channels/user_socket.ex
mode change 100755 => 100644 lib/pleroma/web/common_api.ex
mode change 100755 => 100644 lib/pleroma/web/common_api/activity_draft.ex
mode change 100755 => 100644 lib/pleroma/web/common_api/utils.ex
mode change 100755 => 100644 lib/pleroma/web/controller_helper.ex
mode change 100755 => 100644 lib/pleroma/web/embed_controller.ex
mode change 100755 => 100644 lib/pleroma/web/endpoint.ex
mode change 100755 => 100644 lib/pleroma/web/fallback/legacy_pleroma_api_rerouter_plug.ex
mode change 100755 => 100644 lib/pleroma/web/fallback/redirect_controller.ex
mode change 100755 => 100644 lib/pleroma/web/federator.ex
delete mode 100755 lib/pleroma/web/federator/publisher.ex
mode change 100755 => 100644 lib/pleroma/web/federator/publishing.ex
mode change 100755 => 100644 lib/pleroma/web/feed/feed_view.ex
mode change 100755 => 100644 lib/pleroma/web/feed/tag_controller.ex
mode change 100755 => 100644 lib/pleroma/web/feed/user_controller.ex
mode change 100755 => 100644 lib/pleroma/web/gettext.ex
mode change 100755 => 100644 lib/pleroma/web/instance_document.ex
mode change 100755 => 100644 lib/pleroma/web/mailer/subscription_controller.ex
mode change 100755 => 100644 lib/pleroma/web/manifest_controller.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/controllers/account_controller.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/controllers/app_controller.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/controllers/auth_controller.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/controllers/conversation_controller.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/controllers/custom_emoji_controller.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/controllers/directory_controller.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/controllers/filter_controller.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/controllers/instance_controller.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/controllers/list_controller.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/controllers/marker_controller.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/controllers/media_controller.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/controllers/notification_controller.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/controllers/poll_controller.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/controllers/report_controller.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/controllers/scheduled_activity_controller.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/controllers/search_controller.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/controllers/status_controller.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/controllers/suggestion_controller.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/mastodon_api.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/views/account_view.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/views/announcement_view.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/views/app_view.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/views/conversation_view.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/views/custom_emoji_view.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/views/filter_view.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/views/follow_request_view.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/views/instance_view.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/views/list_view.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/views/marker_view.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/views/media_view.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/views/notification_view.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/views/poll_view.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/views/report_view.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/views/status_view.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/views/subscription_view.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/views/suggestion_view.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/views/timeline_view.ex
mode change 100755 => 100644 lib/pleroma/web/mastodon_api/websocket_handler.ex
mode change 100755 => 100644 lib/pleroma/web/media_proxy.ex
mode change 100755 => 100644 lib/pleroma/web/media_proxy/invalidation.ex
mode change 100755 => 100644 lib/pleroma/web/media_proxy/invalidation/http.ex
mode change 100755 => 100644 lib/pleroma/web/media_proxy/invalidation/script.ex
mode change 100755 => 100644 lib/pleroma/web/media_proxy/media_proxy_controller.ex
mode change 100755 => 100644 lib/pleroma/web/metadata.ex
mode change 100755 => 100644 lib/pleroma/web/metadata/player_view.ex
mode change 100755 => 100644 lib/pleroma/web/metadata/providers/feed.ex
mode change 100755 => 100644 lib/pleroma/web/metadata/providers/open_graph.ex
mode change 100755 => 100644 lib/pleroma/web/metadata/providers/provider.ex
mode change 100755 => 100644 lib/pleroma/web/metadata/providers/rel_me.ex
mode change 100755 => 100644 lib/pleroma/web/metadata/providers/restrict_indexing.ex
mode change 100755 => 100644 lib/pleroma/web/metadata/providers/twitter_card.ex
mode change 100755 => 100644 lib/pleroma/web/metadata/utils.ex
mode change 100755 => 100644 lib/pleroma/web/mongoose_im/mongoose_im_controller.ex
create mode 100644 lib/pleroma/web/multipart.ex
mode change 100755 => 100644 lib/pleroma/web/nodeinfo/nodeinfo.ex
mode change 100755 => 100644 lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
mode change 100755 => 100644 lib/pleroma/web/o_auth.ex
mode change 100755 => 100644 lib/pleroma/web/o_auth/app.ex
mode change 100755 => 100644 lib/pleroma/web/o_auth/authorization.ex
mode change 100755 => 100644 lib/pleroma/web/o_auth/fallback_controller.ex
mode change 100755 => 100644 lib/pleroma/web/o_auth/mfa_controller.ex
mode change 100755 => 100644 lib/pleroma/web/o_auth/mfa_view.ex
mode change 100755 => 100644 lib/pleroma/web/o_auth/o_auth_controller.ex
mode change 100755 => 100644 lib/pleroma/web/o_auth/o_auth_view.ex
mode change 100755 => 100644 lib/pleroma/web/o_auth/scopes.ex
mode change 100755 => 100644 lib/pleroma/web/o_auth/token.ex
mode change 100755 => 100644 lib/pleroma/web/o_auth/token/query.ex
mode change 100755 => 100644 lib/pleroma/web/o_auth/token/strategy/refresh_token.ex
mode change 100755 => 100644 lib/pleroma/web/o_auth/token/strategy/revoke.ex
mode change 100755 => 100644 lib/pleroma/web/o_auth/token/utils.ex
mode change 100755 => 100644 lib/pleroma/web/o_status/o_status_controller.ex
mode change 100755 => 100644 lib/pleroma/web/pleroma_api/controllers/account_controller.ex
mode change 100755 => 100644 lib/pleroma/web/pleroma_api/controllers/app_controller.ex
mode change 100755 => 100644 lib/pleroma/web/pleroma_api/controllers/backup_controller.ex
create mode 100644 lib/pleroma/web/pleroma_api/controllers/bookmark_folder_controller.ex
mode change 100755 => 100644 lib/pleroma/web/pleroma_api/controllers/chat_controller.ex
mode change 100755 => 100644 lib/pleroma/web/pleroma_api/controllers/conversation_controller.ex
mode change 100755 => 100644 lib/pleroma/web/pleroma_api/controllers/emoji_file_controller.ex
mode change 100755 => 100644 lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex
mode change 100755 => 100644 lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex
mode change 100755 => 100644 lib/pleroma/web/pleroma_api/controllers/instances_controller.ex
mode change 100755 => 100644 lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex
mode change 100755 => 100644 lib/pleroma/web/pleroma_api/controllers/notification_controller.ex
mode change 100755 => 100644 lib/pleroma/web/pleroma_api/controllers/report_controller.ex
mode change 100755 => 100644 lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex
mode change 100755 => 100644 lib/pleroma/web/pleroma_api/controllers/settings_controller.ex
create mode 100644 lib/pleroma/web/pleroma_api/controllers/status_controller.ex
mode change 100755 => 100644 lib/pleroma/web/pleroma_api/controllers/two_factor_authentication_controller.ex
mode change 100755 => 100644 lib/pleroma/web/pleroma_api/controllers/user_import_controller.ex
mode change 100755 => 100644 lib/pleroma/web/pleroma_api/views/account_view.ex
mode change 100755 => 100644 lib/pleroma/web/pleroma_api/views/app_view.ex
mode change 100755 => 100644 lib/pleroma/web/pleroma_api/views/backup_view.ex
create mode 100644 lib/pleroma/web/pleroma_api/views/bookmark_folder_view.ex
mode change 100755 => 100644 lib/pleroma/web/pleroma_api/views/chat/message_reference_view.ex
mode change 100755 => 100644 lib/pleroma/web/pleroma_api/views/chat_view.ex
mode change 100755 => 100644 lib/pleroma/web/pleroma_api/views/conversation_view.ex
mode change 100755 => 100644 lib/pleroma/web/pleroma_api/views/emoji_reaction_view.ex
mode change 100755 => 100644 lib/pleroma/web/pleroma_api/views/notification_view.ex
mode change 100755 => 100644 lib/pleroma/web/pleroma_api/views/report_view.ex
mode change 100755 => 100644 lib/pleroma/web/pleroma_api/views/scrobble_view.ex
mode change 100755 => 100644 lib/pleroma/web/plug.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/admin_secret_authentication_plug.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/authentication_plug.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/basic_auth_decoder_plug.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/cache.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/digest_plug.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/ensure_authenticated_plug.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/ensure_privileged_plug.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/ensure_public_or_authenticated_plug.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/ensure_user_token_assigns_plug.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/expect_authenticated_check_plug.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/expect_public_or_authenticated_check_plug.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/federating_plug.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/frontend_static.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/http_security_plug.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/http_signature_plug.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/idempotency_plug.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/instance_static.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/mapped_signature_to_identity_plug.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/o_auth_plug.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/o_auth_scopes_plug.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/plug_helper.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/rate_limiter.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/rate_limiter/limiter_supervisor.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/rate_limiter/supervisor.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/remote_ip.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/set_format_plug.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/set_locale_plug.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/set_user_session_id_plug.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/static_fe_plug.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/trailing_format_plug.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/uploaded_media.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/user_enabled_plug.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/user_fetcher_plug.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/user_is_admin_plug.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/user_is_staff_plug.ex
mode change 100755 => 100644 lib/pleroma/web/plugs/user_tracking_plug.ex
mode change 100755 => 100644 lib/pleroma/web/preload.ex
mode change 100755 => 100644 lib/pleroma/web/preload/providers/instance.ex
mode change 100755 => 100644 lib/pleroma/web/preload/providers/provider.ex
mode change 100755 => 100644 lib/pleroma/web/preload/providers/timelines.ex
mode change 100755 => 100644 lib/pleroma/web/preload/providers/user.ex
mode change 100755 => 100644 lib/pleroma/web/push.ex
mode change 100755 => 100644 lib/pleroma/web/push/impl.ex
mode change 100755 => 100644 lib/pleroma/web/push/subscription.ex
mode change 100755 => 100644 lib/pleroma/web/rel_me.ex
create mode 100644 lib/pleroma/web/rich_media/backfill.ex
create mode 100644 lib/pleroma/web/rich_media/card.ex
mode change 100755 => 100644 lib/pleroma/web/rich_media/helpers.ex
mode change 100755 => 100644 lib/pleroma/web/rich_media/parser.ex
mode change 100755 => 100644 lib/pleroma/web/rich_media/parser/ttl.ex
mode change 100755 => 100644 lib/pleroma/web/rich_media/parser/ttl/aws_signed_url.ex
create mode 100644 lib/pleroma/web/rich_media/parser/ttl/opengraph.ex
mode change 100755 => 100644 lib/pleroma/web/rich_media/parsers/meta_tags_parser.ex
mode change 100755 => 100644 lib/pleroma/web/rich_media/parsers/o_embed.ex
mode change 100755 => 100644 lib/pleroma/web/rich_media/parsers/ogp.ex
mode change 100755 => 100644 lib/pleroma/web/rich_media/parsers/twitter_card.ex
mode change 100755 => 100644 lib/pleroma/web/router.ex
delete mode 100755 lib/pleroma/web/router.ex~
mode change 100755 => 100644 lib/pleroma/web/shout_channel.ex
mode change 100755 => 100644 lib/pleroma/web/static_fe/static_fe_controller.ex
mode change 100755 => 100644 lib/pleroma/web/static_fe/static_fe_view.ex
mode change 100755 => 100644 lib/pleroma/web/streamer.ex
mode change 100755 => 100644 lib/pleroma/web/templates/email/digest.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/email/new_users_digest.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/embed/_attachment.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/embed/show.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/feed/feed/_activity.atom.eex
mode change 100755 => 100644 lib/pleroma/web/templates/feed/feed/_activity.rss.eex
mode change 100755 => 100644 lib/pleroma/web/templates/feed/feed/_author.atom.eex
mode change 100755 => 100644 lib/pleroma/web/templates/feed/feed/_author.rss.eex
mode change 100755 => 100644 lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex
mode change 100755 => 100644 lib/pleroma/web/templates/feed/feed/_tag_activity.xml.eex
mode change 100755 => 100644 lib/pleroma/web/templates/feed/feed/_tag_author.atom.eex
mode change 100755 => 100644 lib/pleroma/web/templates/feed/feed/tag.atom.eex
mode change 100755 => 100644 lib/pleroma/web/templates/feed/feed/tag.rss.eex
mode change 100755 => 100644 lib/pleroma/web/templates/feed/feed/user.atom.eex
mode change 100755 => 100644 lib/pleroma/web/templates/feed/feed/user.rss.eex
mode change 100755 => 100644 lib/pleroma/web/templates/layout/app.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/layout/email.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/layout/email_styled.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/layout/embed.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/layout/metadata_player.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/layout/static_fe.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/mailer/subscription/unsubscribe_failure.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/mailer/subscription/unsubscribe_success.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/o_auth/mfa/recovery.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/o_auth/mfa/totp.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/o_auth/o_auth/consumer.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/o_auth/o_auth/oob_authorization_created.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/o_auth/o_auth/oob_token_exists.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/o_auth/o_auth/register.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/o_auth/o_auth/show.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/static_fe/static_fe/_attachment.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/static_fe/static_fe/_notice.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/static_fe/static_fe/_user_card.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/static_fe/static_fe/conversation.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/static_fe/static_fe/error.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/twitter_api/password/invalid_token.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/twitter_api/password/reset.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/twitter_api/password/reset_failed.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/twitter_api/password/reset_success.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/twitter_api/remote_follow/follow.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/twitter_api/remote_follow/follow_login.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/twitter_api/remote_follow/follow_mfa.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/twitter_api/remote_follow/followed.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/twitter_api/util/status_interact.html.eex
mode change 100755 => 100644 lib/pleroma/web/templates/twitter_api/util/subscribe.html.eex
mode change 100755 => 100644 lib/pleroma/web/translation_helpers.ex
mode change 100755 => 100644 lib/pleroma/web/twitter_api/controller.ex
mode change 100755 => 100644 lib/pleroma/web/twitter_api/controllers/password_controller.ex
mode change 100755 => 100644 lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex
mode change 100755 => 100644 lib/pleroma/web/twitter_api/controllers/util_controller.ex
mode change 100755 => 100644 lib/pleroma/web/twitter_api/twitter_api.ex
mode change 100755 => 100644 lib/pleroma/web/twitter_api/views/password_view.ex
mode change 100755 => 100644 lib/pleroma/web/twitter_api/views/remote_follow_view.ex
mode change 100755 => 100644 lib/pleroma/web/twitter_api/views/token_view.ex
mode change 100755 => 100644 lib/pleroma/web/twitter_api/views/util_view.ex
mode change 100755 => 100644 lib/pleroma/web/uploader_controller.ex
mode change 100755 => 100644 lib/pleroma/web/utils/guards.ex
mode change 100755 => 100644 lib/pleroma/web/utils/params.ex
mode change 100755 => 100644 lib/pleroma/web/views/email_view.ex
mode change 100755 => 100644 lib/pleroma/web/views/embed_view.ex
mode change 100755 => 100644 lib/pleroma/web/views/error_helpers.ex
mode change 100755 => 100644 lib/pleroma/web/views/error_view.ex
mode change 100755 => 100644 lib/pleroma/web/views/layout_view.ex
mode change 100755 => 100644 lib/pleroma/web/views/mailer/subscription_view.ex
mode change 100755 => 100644 lib/pleroma/web/views/manifest_view.ex
mode change 100755 => 100644 lib/pleroma/web/views/streamer_view.ex
mode change 100755 => 100644 lib/pleroma/web/web_finger.ex
mode change 100755 => 100644 lib/pleroma/web/web_finger/web_finger_controller.ex
mode change 100755 => 100644 lib/pleroma/web/xml.ex
mode change 100755 => 100644 lib/pleroma/workers/attachments_cleanup_worker.ex
mode change 100755 => 100644 lib/pleroma/workers/background_worker.ex
mode change 100755 => 100644 lib/pleroma/workers/backup_worker.ex
mode change 100755 => 100644 lib/pleroma/workers/cron/digest_emails_worker.ex
mode change 100755 => 100644 lib/pleroma/workers/cron/new_users_digest_worker.ex
mode change 100755 => 100644 lib/pleroma/workers/mailer_worker.ex
mode change 100755 => 100644 lib/pleroma/workers/mute_expire_worker.ex
mode change 100755 => 100644 lib/pleroma/workers/poll_worker.ex
mode change 100755 => 100644 lib/pleroma/workers/publisher_worker.ex
mode change 100755 => 100644 lib/pleroma/workers/purge_expired_activity.ex
mode change 100755 => 100644 lib/pleroma/workers/purge_expired_filter.ex
mode change 100755 => 100644 lib/pleroma/workers/purge_expired_token.ex
mode change 100755 => 100644 lib/pleroma/workers/receiver_worker.ex
mode change 100755 => 100644 lib/pleroma/workers/remote_fetcher_worker.ex
create mode 100644 lib/pleroma/workers/rich_media_expiration_worker.ex
mode change 100755 => 100644 lib/pleroma/workers/scheduled_activity_worker.ex
create mode 100644 lib/pleroma/workers/search_indexing_worker.ex
delete mode 100755 lib/pleroma/workers/transmogrifier_worker.ex
mode change 100755 => 100644 lib/pleroma/workers/web_pusher_worker.ex
mode change 100755 => 100644 lib/pleroma/workers/worker_helper.ex
mode change 100755 => 100644 lib/pleroma/xml_builder.ex
(limited to 'lib')
diff --git a/lib/mix/pleroma.ex b/lib/mix/pleroma.ex
old mode 100755
new mode 100644
diff --git a/lib/mix/tasks/pleroma/app.ex b/lib/mix/tasks/pleroma/app.ex
old mode 100755
new mode 100644
diff --git a/lib/mix/tasks/pleroma/benchmark.ex b/lib/mix/tasks/pleroma/benchmark.ex
deleted file mode 100755
index f324921..0000000
--- a/lib/mix/tasks/pleroma/benchmark.ex
+++ /dev/null
@@ -1,113 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2022 Pleroma Authors
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Mix.Tasks.Pleroma.Benchmark do
- import Mix.Pleroma
- use Mix.Task
-
- def run(["search"]) do
- start_pleroma()
-
- Benchee.run(%{
- "search" => fn ->
- Pleroma.Activity.search(nil, "cofe")
- end
- })
- end
-
- def run(["tag"]) do
- start_pleroma()
-
- Benchee.run(%{
- "tag" => fn ->
- %{"type" => "Create", "tag" => "cofe"}
- |> Pleroma.Web.ActivityPub.ActivityPub.fetch_public_activities()
- end
- })
- end
-
- def run(["render_timeline", nickname | _] = args) do
- start_pleroma()
- user = Pleroma.User.get_by_nickname(nickname)
-
- activities =
- %{}
- |> Map.put("type", ["Create", "Announce"])
- |> Map.put("blocking_user", user)
- |> Map.put("muting_user", user)
- |> Map.put("user", user)
- |> Map.put("limit", 4096)
- |> Pleroma.Web.ActivityPub.ActivityPub.fetch_public_activities()
- |> Enum.reverse()
-
- inputs = %{
- "1 activity" => Enum.take_random(activities, 1),
- "10 activities" => Enum.take_random(activities, 10),
- "20 activities" => Enum.take_random(activities, 20),
- "40 activities" => Enum.take_random(activities, 40),
- "80 activities" => Enum.take_random(activities, 80)
- }
-
- inputs =
- if Enum.at(args, 2) == "extended" do
- Map.merge(inputs, %{
- "200 activities" => Enum.take_random(activities, 200),
- "500 activities" => Enum.take_random(activities, 500),
- "2000 activities" => Enum.take_random(activities, 2000),
- "4096 activities" => Enum.take_random(activities, 4096)
- })
- else
- inputs
- end
-
- Benchee.run(
- %{
- "Standart rendering" => fn activities ->
- Pleroma.Web.MastodonAPI.StatusView.render("index.json", %{
- activities: activities,
- for: user,
- as: :activity
- })
- end
- },
- inputs: inputs
- )
- end
-
- def run(["adapters"]) do
- start_pleroma()
-
- :ok =
- Pleroma.Gun.Conn.open(
- "https://httpbin.org/stream-bytes/1500",
- :gun_connections
- )
-
- Process.sleep(1_500)
-
- Benchee.run(
- %{
- "Without conn and without pool" => fn ->
- {:ok, %Tesla.Env{}} =
- Pleroma.HTTP.get("https://httpbin.org/stream-bytes/1500", [],
- pool: :no_pool,
- receive_conn: false
- )
- end,
- "Without conn and with pool" => fn ->
- {:ok, %Tesla.Env{}} =
- Pleroma.HTTP.get("https://httpbin.org/stream-bytes/1500", [], receive_conn: false)
- end,
- "With reused conn and without pool" => fn ->
- {:ok, %Tesla.Env{}} =
- Pleroma.HTTP.get("https://httpbin.org/stream-bytes/1500", [], pool: :no_pool)
- end,
- "With reused conn and with pool" => fn ->
- {:ok, %Tesla.Env{}} = Pleroma.HTTP.get("https://httpbin.org/stream-bytes/1500")
- end
- },
- parallel: 10
- )
- end
-end
diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex
old mode 100755
new mode 100644
diff --git a/lib/mix/tasks/pleroma/count_statuses.ex b/lib/mix/tasks/pleroma/count_statuses.ex
old mode 100755
new mode 100644
diff --git a/lib/mix/tasks/pleroma/database.ex b/lib/mix/tasks/pleroma/database.ex
old mode 100755
new mode 100644
index ed560c1..93ee57d
--- a/lib/mix/tasks/pleroma/database.ex
+++ b/lib/mix/tasks/pleroma/database.ex
@@ -193,7 +193,7 @@ defmodule Mix.Tasks.Pleroma.Database do
"ALTER DATABASE #{db} SET default_text_search_config = '#{tsconfig}';"
)
- # non-exist config will not raise excpetion but only give >0 messages
+ # non-exist config will not raise exception but only give >0 messages
if length(msg) > 0 do
shell_info("Error: #{inspect(msg, pretty: true)}")
else
diff --git a/lib/mix/tasks/pleroma/digest.ex b/lib/mix/tasks/pleroma/digest.ex
old mode 100755
new mode 100644
index aea9c8a..53cac0b
--- a/lib/mix/tasks/pleroma/digest.ex
+++ b/lib/mix/tasks/pleroma/digest.ex
@@ -30,7 +30,7 @@ defmodule Mix.Tasks.Pleroma.Digest do
shell_info("Digest email have been sent to #{nickname} (#{user.email})")
else
_ ->
- shell_info("Cound't find any mentions for #{nickname} since #{last_digest_emailed_at}")
+ shell_info("Couldn't find any mentions for #{nickname} since #{last_digest_emailed_at}")
end
end
end
diff --git a/lib/mix/tasks/pleroma/docs.ex b/lib/mix/tasks/pleroma/docs.ex
old mode 100755
new mode 100644
diff --git a/lib/mix/tasks/pleroma/ecto.ex b/lib/mix/tasks/pleroma/ecto.ex
old mode 100755
new mode 100644
diff --git a/lib/mix/tasks/pleroma/ecto/migrate.ex b/lib/mix/tasks/pleroma/ecto/migrate.ex
old mode 100755
new mode 100644
diff --git a/lib/mix/tasks/pleroma/ecto/rollback.ex b/lib/mix/tasks/pleroma/ecto/rollback.ex
old mode 100755
new mode 100644
index 3d78eae..121890f
--- a/lib/mix/tasks/pleroma/ecto/rollback.ex
+++ b/lib/mix/tasks/pleroma/ecto/rollback.ex
@@ -61,7 +61,7 @@ defmodule Mix.Tasks.Pleroma.Ecto.Rollback do
Logger.configure(level: :info)
if opts[:env] == "test" do
- Logger.info("Rollback succesfully")
+ Logger.info("Rollback successfully")
else
{:ok, _, _} =
Ecto.Migrator.with_repo(Pleroma.Repo, &Ecto.Migrator.run(&1, path, :down, opts))
diff --git a/lib/mix/tasks/pleroma/email.ex b/lib/mix/tasks/pleroma/email.ex
old mode 100755
new mode 100644
diff --git a/lib/mix/tasks/pleroma/emoji.ex b/lib/mix/tasks/pleroma/emoji.ex
old mode 100755
new mode 100644
index 537f071..8b9c921
--- a/lib/mix/tasks/pleroma/emoji.ex
+++ b/lib/mix/tasks/pleroma/emoji.ex
@@ -111,7 +111,7 @@ defmodule Mix.Tasks.Pleroma.Emoji do
{:ok, _} =
:zip.unzip(binary_archive,
- cwd: pack_path,
+ cwd: String.to_charlist(pack_path),
file_list: files_to_unzip
)
diff --git a/lib/mix/tasks/pleroma/frontend.ex b/lib/mix/tasks/pleroma/frontend.ex
old mode 100755
new mode 100644
diff --git a/lib/mix/tasks/pleroma/instance.ex b/lib/mix/tasks/pleroma/instance.ex
old mode 100755
new mode 100644
index 5d8b254..0dc3054
--- a/lib/mix/tasks/pleroma/instance.ex
+++ b/lib/mix/tasks/pleroma/instance.ex
@@ -292,7 +292,7 @@ defmodule Mix.Tasks.Pleroma.Instance do
if db_configurable? do
shell_info(
- " Please transfer your config to the database after running database migrations. Refer to \"Transfering the config to/from the database\" section of the docs for more information."
+ " Please transfer your config to the database after running database migrations. Refer to \"Transferring the config to/from the database\" section of the docs for more information."
)
end
else
@@ -352,6 +352,4 @@ defmodule Mix.Tasks.Pleroma.Instance do
enabled_filters
end
-
- defp upload_filters(_), do: []
end
diff --git a/lib/mix/tasks/pleroma/notification_settings.ex b/lib/mix/tasks/pleroma/notification_settings.ex
old mode 100755
new mode 100644
diff --git a/lib/mix/tasks/pleroma/openapi_spec.ex b/lib/mix/tasks/pleroma/openapi_spec.ex
old mode 100755
new mode 100644
index 884f931..1ea4684
--- a/lib/mix/tasks/pleroma/openapi_spec.ex
+++ b/lib/mix/tasks/pleroma/openapi_spec.ex
@@ -6,7 +6,70 @@ defmodule Mix.Tasks.Pleroma.OpenapiSpec do
def run([path]) do
# Load Pleroma application to get version info
Application.load(:pleroma)
- spec = Pleroma.Web.ApiSpec.spec(server_specific: false) |> Jason.encode!()
- File.write(path, spec)
+
+ spec_json = Pleroma.Web.ApiSpec.spec(server_specific: false) |> Jason.encode!()
+ # to get rid of the structs
+ spec_regened = spec_json |> Jason.decode!()
+
+ check_specs!(spec_regened)
+
+ File.write(path, spec_json)
+ end
+
+ defp check_specs!(spec) do
+ with :ok <- check_specs(spec) do
+ :ok
+ else
+ {_, errors} ->
+ IO.puts(IO.ANSI.format([:red, :bright, "Spec check failed, errors:"]))
+ Enum.map(errors, &IO.puts/1)
+
+ raise "Spec check failed"
+ end
+ end
+
+ def check_specs(spec) do
+ errors =
+ spec["paths"]
+ |> Enum.flat_map(fn {path, %{} = endpoints} ->
+ Enum.map(
+ endpoints,
+ fn {method, endpoint} ->
+ with :ok <- check_endpoint(spec, endpoint) do
+ :ok
+ else
+ error ->
+ "#{endpoint["operationId"]} (#{method} #{path}): #{error}"
+ end
+ end
+ )
+ |> Enum.reject(fn res -> res == :ok end)
+ end)
+
+ if errors == [] do
+ :ok
+ else
+ {:error, errors}
+ end
+ end
+
+ defp check_endpoint(spec, endpoint) do
+ valid_tags = available_tags(spec)
+
+ with {_, [_ | _] = tags} <- {:tags, endpoint["tags"]},
+ {_, []} <- {:unavailable, Enum.reject(tags, &(&1 in valid_tags))} do
+ :ok
+ else
+ {:tags, _} ->
+ "No tags specified"
+
+ {:unavailable, tags} ->
+ "Tags #{inspect(tags)} not available. Please add it in \"x-tagGroups\" in Pleroma.Web.ApiSpec"
+ end
+ end
+
+ defp available_tags(spec) do
+ spec["x-tagGroups"]
+ |> Enum.flat_map(fn %{"tags" => tags} -> tags end)
end
end
diff --git a/lib/mix/tasks/pleroma/refresh_counter_cache.ex b/lib/mix/tasks/pleroma/refresh_counter_cache.ex
old mode 100755
new mode 100644
diff --git a/lib/mix/tasks/pleroma/relay.ex b/lib/mix/tasks/pleroma/relay.ex
old mode 100755
new mode 100644
diff --git a/lib/mix/tasks/pleroma/robots_txt.ex b/lib/mix/tasks/pleroma/robots_txt.ex
old mode 100755
new mode 100644
diff --git a/lib/mix/tasks/pleroma/search/meilisearch.ex b/lib/mix/tasks/pleroma/search/meilisearch.ex
new file mode 100644
index 0000000..8379a0c
--- /dev/null
+++ b/lib/mix/tasks/pleroma/search/meilisearch.ex
@@ -0,0 +1,145 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Mix.Tasks.Pleroma.Search.Meilisearch do
+ require Pleroma.Constants
+
+ import Mix.Pleroma
+ import Ecto.Query
+
+ import Pleroma.Search.Meilisearch,
+ only: [meili_post: 2, meili_put: 2, meili_get: 1, meili_delete: 1]
+
+ def run(["index"]) do
+ start_pleroma()
+ Pleroma.HTML.compile_scrubbers()
+
+ meili_version =
+ (
+ {:ok, result} = meili_get("/version")
+
+ result["pkgVersion"]
+ )
+
+ # The ranking rule syntax was changed but nothing about that is mentioned in the changelog
+ if not Version.match?(meili_version, ">= 0.25.0") do
+ raise "Meilisearch <0.24.0 not supported"
+ end
+
+ {:ok, _} =
+ meili_post(
+ "/indexes/objects/settings/ranking-rules",
+ [
+ "published:desc",
+ "words",
+ "exactness",
+ "proximity",
+ "typo",
+ "attribute",
+ "sort"
+ ]
+ )
+
+ {:ok, _} =
+ meili_post(
+ "/indexes/objects/settings/searchable-attributes",
+ [
+ "content"
+ ]
+ )
+
+ IO.puts("Created indices. Starting to insert posts.")
+
+ chunk_size = Pleroma.Config.get([Pleroma.Search.Meilisearch, :initial_indexing_chunk_size])
+
+ Pleroma.Repo.transaction(
+ fn ->
+ query =
+ from(Pleroma.Object,
+ # Only index public and unlisted posts which are notes and have some text
+ where:
+ fragment("data->>'type' = 'Note'") and
+ (fragment("data->'to' \\? ?", ^Pleroma.Constants.as_public()) or
+ fragment("data->'cc' \\? ?", ^Pleroma.Constants.as_public())),
+ order_by: [desc: fragment("data->'published'")]
+ )
+
+ count = query |> Pleroma.Repo.aggregate(:count, :data)
+ IO.puts("Entries to index: #{count}")
+
+ Pleroma.Repo.stream(
+ query,
+ timeout: :infinity
+ )
+ |> Stream.map(&Pleroma.Search.Meilisearch.object_to_search_data/1)
+ |> Stream.filter(fn o -> not is_nil(o) end)
+ |> Stream.chunk_every(chunk_size)
+ |> Stream.transform(0, fn objects, acc ->
+ new_acc = acc + Enum.count(objects)
+
+ # Reset to the beginning of the line and rewrite it
+ IO.write("\r")
+ IO.write("Indexed #{new_acc} entries")
+
+ {[objects], new_acc}
+ end)
+ |> Stream.each(fn objects ->
+ result =
+ meili_put(
+ "/indexes/objects/documents",
+ objects
+ )
+
+ with {:ok, res} <- result do
+ if not Map.has_key?(res, "uid") do
+ IO.puts("\nFailed to index: #{inspect(result)}")
+ end
+ else
+ e -> IO.puts("\nFailed to index due to network error: #{inspect(e)}")
+ end
+ end)
+ |> Stream.run()
+ end,
+ timeout: :infinity
+ )
+
+ IO.write("\n")
+ end
+
+ def run(["clear"]) do
+ start_pleroma()
+
+ meili_delete("/indexes/objects/documents")
+ end
+
+ def run(["show-keys", master_key]) do
+ start_pleroma()
+
+ endpoint = Pleroma.Config.get([Pleroma.Search.Meilisearch, :url])
+
+ {:ok, result} =
+ Pleroma.HTTP.get(
+ Path.join(endpoint, "/keys"),
+ [{"Authorization", "Bearer #{master_key}"}]
+ )
+
+ decoded = Jason.decode!(result.body)
+
+ if decoded["results"] do
+ Enum.each(decoded["results"], fn %{"description" => desc, "key" => key} ->
+ IO.puts("#{desc}: #{key}")
+ end)
+ else
+ IO.puts("Error fetching the keys, check the master key is correct: #{inspect(decoded)}")
+ end
+ end
+
+ def run(["stats"]) do
+ start_pleroma()
+
+ {:ok, result} = meili_get("/indexes/objects/stats")
+ IO.puts("Number of entries: #{result["numberOfDocuments"]}")
+ IO.puts("Indexing? #{result["isIndexing"]}")
+ end
+end
diff --git a/lib/mix/tasks/pleroma/uploads.ex b/lib/mix/tasks/pleroma/uploads.ex
old mode 100755
new mode 100644
diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex
old mode 100755
new mode 100644
diff --git a/lib/phoenix/transports/web_socket/raw.ex b/lib/phoenix/transports/web_socket/raw.ex
deleted file mode 100755
index 8cf9c32..0000000
--- a/lib/phoenix/transports/web_socket/raw.ex
+++ /dev/null
@@ -1,94 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2022 Pleroma Authors
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Phoenix.Transports.WebSocket.Raw do
- import Plug.Conn,
- only: [
- fetch_query_params: 1,
- send_resp: 3
- ]
-
- alias Phoenix.Socket.Transport
-
- def default_config do
- [
- timeout: 60_000,
- transport_log: false,
- cowboy: Phoenix.Endpoint.CowboyWebSocket
- ]
- end
-
- def init(%Plug.Conn{method: "GET"} = conn, {endpoint, handler, transport}) do
- {_, opts} = handler.__transport__(transport)
-
- conn =
- conn
- |> fetch_query_params
- |> Transport.transport_log(opts[:transport_log])
- |> Transport.force_ssl(handler, endpoint, opts)
- |> Transport.check_origin(handler, endpoint, opts)
-
- case conn do
- %{halted: false} = conn ->
- case handler.connect(%{
- endpoint: endpoint,
- transport: transport,
- options: [serializer: nil],
- params: conn.params
- }) do
- {:ok, socket} ->
- {:ok, conn, {__MODULE__, {socket, opts}}}
-
- :error ->
- send_resp(conn, :forbidden, "")
- {:error, conn}
- end
-
- _ ->
- {:error, conn}
- end
- end
-
- def init(conn, _) do
- send_resp(conn, :bad_request, "")
- {:error, conn}
- end
-
- def ws_init({socket, config}) do
- Process.flag(:trap_exit, true)
- {:ok, %{socket: socket}, config[:timeout]}
- end
-
- def ws_handle(op, data, state) do
- state.socket.handler
- |> apply(:handle, [op, data, state])
- |> case do
- {op, data} ->
- {:reply, {op, data}, state}
-
- {op, data, state} ->
- {:reply, {op, data}, state}
-
- %{} = state ->
- {:ok, state}
-
- _ ->
- {:ok, state}
- end
- end
-
- def ws_info({_, _} = tuple, state) do
- {:reply, tuple, state}
- end
-
- def ws_info(_tuple, state), do: {:ok, state}
-
- def ws_close(state) do
- ws_handle(:closed, :normal, state)
- end
-
- def ws_terminate(reason, state) do
- ws_handle(:closed, reason, state)
- end
-end
diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex
old mode 100755
new mode 100644
index 3556aaf..8a512dc
--- a/lib/pleroma/activity.ex
+++ b/lib/pleroma/activity.ex
@@ -368,7 +368,7 @@ defmodule Pleroma.Activity do
)
end
- defdelegate search(user, query, options \\ []), to: Pleroma.Activity.Search
+ defdelegate search(user, query, options \\ []), to: Pleroma.Search.DatabaseSearch
def direct_conversation_id(activity, for_user) do
alias Pleroma.Conversation.Participation
diff --git a/lib/pleroma/activity/html.ex b/lib/pleroma/activity/html.ex
old mode 100755
new mode 100644
index 706b2d3..ba284b4
--- a/lib/pleroma/activity/html.ex
+++ b/lib/pleroma/activity/html.ex
@@ -28,7 +28,7 @@ defmodule Pleroma.Activity.HTML do
end
end
- defp add_cache_key_for(activity_id, additional_key) do
+ def add_cache_key_for(activity_id, additional_key) do
current = get_cache_keys_for(activity_id)
unless additional_key in current do
diff --git a/lib/pleroma/activity/ir/topics.ex b/lib/pleroma/activity/ir/topics.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/activity/queries.ex b/lib/pleroma/activity/queries.ex
old mode 100755
new mode 100644
index 81c44ac..d770b9f
--- a/lib/pleroma/activity/queries.ex
+++ b/lib/pleroma/activity/queries.ex
@@ -9,7 +9,7 @@ defmodule Pleroma.Activity.Queries do
import Ecto.Query, only: [from: 2, where: 3]
- @type query :: Ecto.Queryable.t() | Activity.t()
+ @type query :: Ecto.Queryable.t() | Pleroma.Activity.t()
alias Pleroma.Activity
alias Pleroma.User
diff --git a/lib/pleroma/activity/search.ex b/lib/pleroma/activity/search.ex
deleted file mode 100755
index 0b9b24a..0000000
--- a/lib/pleroma/activity/search.ex
+++ /dev/null
@@ -1,162 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2022 Pleroma Authors
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Activity.Search do
- alias Pleroma.Activity
- alias Pleroma.Object.Fetcher
- alias Pleroma.Pagination
- alias Pleroma.User
- alias Pleroma.Web.ActivityPub.Visibility
-
- require Pleroma.Constants
-
- import Ecto.Query
-
- def search(user, search_query, options \\ []) do
- index_type = if Pleroma.Config.get([:database, :rum_enabled]), do: :rum, else: :gin
- limit = Enum.min([Keyword.get(options, :limit), 40])
- offset = Keyword.get(options, :offset, 0)
- author = Keyword.get(options, :author)
-
- search_function =
- if :persistent_term.get({Pleroma.Repo, :postgres_version}) >= 11 do
- :websearch
- else
- :plain
- end
-
- try do
- Activity
- |> Activity.with_preloaded_object()
- |> Activity.restrict_deactivated_users()
- |> restrict_public(user)
- |> query_with(index_type, search_query, search_function)
- |> maybe_restrict_local(user)
- |> maybe_restrict_author(author)
- |> maybe_restrict_blocked(user)
- |> Pagination.fetch_paginated(
- %{"offset" => offset, "limit" => limit, "skip_order" => index_type == :rum},
- :offset
- )
- |> maybe_fetch(user, search_query)
- rescue
- _ -> maybe_fetch([], user, search_query)
- end
- end
-
- def maybe_restrict_author(query, %User{} = author) do
- Activity.Queries.by_author(query, author)
- end
-
- def maybe_restrict_author(query, _), do: query
-
- def maybe_restrict_blocked(query, %User{} = user) do
- Activity.Queries.exclude_authors(query, User.blocked_users_ap_ids(user))
- end
-
- def maybe_restrict_blocked(query, _), do: query
-
- defp restrict_public(q, user) when not is_nil(user) do
- intended_recipients = [
- Pleroma.Constants.as_public(),
- Pleroma.Web.ActivityPub.Utils.as_local_public()
- ]
-
- from([a, o] in q,
- where: fragment("?->>'type' = 'Create'", a.data),
- where: fragment("? && ?", ^intended_recipients, a.recipients)
- )
- end
-
- defp restrict_public(q, _user) do
- from([a, o] in q,
- where: fragment("?->>'type' = 'Create'", a.data),
- where: ^Pleroma.Constants.as_public() in a.recipients
- )
- end
-
- defp query_with(q, :gin, search_query, :plain) do
- %{rows: [[tsc]]} =
- Ecto.Adapters.SQL.query!(
- Pleroma.Repo,
- "select current_setting('default_text_search_config')::regconfig::oid;"
- )
-
- from([a, o] in q,
- where:
- fragment(
- "to_tsvector(?::oid::regconfig, ?->>'content') @@ plainto_tsquery(?)",
- ^tsc,
- o.data,
- ^search_query
- )
- )
- end
-
- defp query_with(q, :gin, search_query, :websearch) do
- %{rows: [[tsc]]} =
- Ecto.Adapters.SQL.query!(
- Pleroma.Repo,
- "select current_setting('default_text_search_config')::regconfig::oid;"
- )
-
- from([a, o] in q,
- where:
- fragment(
- "to_tsvector(?::oid::regconfig, ?->>'content') @@ websearch_to_tsquery(?)",
- ^tsc,
- o.data,
- ^search_query
- )
- )
- end
-
- defp query_with(q, :rum, search_query, :plain) do
- from([a, o] in q,
- where:
- fragment(
- "? @@ plainto_tsquery(?)",
- o.fts_content,
- ^search_query
- ),
- order_by: [fragment("? <=> now()::date", o.inserted_at)]
- )
- end
-
- defp query_with(q, :rum, search_query, :websearch) do
- from([a, o] in q,
- where:
- fragment(
- "? @@ websearch_to_tsquery(?)",
- o.fts_content,
- ^search_query
- ),
- order_by: [fragment("? <=> now()::date", o.inserted_at)]
- )
- end
-
- defp maybe_restrict_local(q, user) do
- limit = Pleroma.Config.get([:instance, :limit_to_local_content], :unauthenticated)
-
- case {limit, user} do
- {:all, _} -> restrict_local(q)
- {:unauthenticated, %User{}} -> q
- {:unauthenticated, _} -> restrict_local(q)
- {false, _} -> q
- end
- end
-
- defp restrict_local(q), do: where(q, local: true)
-
- defp maybe_fetch(activities, user, search_query) do
- with true <- Regex.match?(~r/https?:/, search_query),
- {:ok, object} <- Fetcher.fetch_object_from_id(search_query),
- %Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]),
- true <- Visibility.visible_for_user?(activity, user) do
- [activity | activities]
- else
- _ -> activities
- end
- end
-end
diff --git a/lib/pleroma/announcement.ex b/lib/pleroma/announcement.ex
old mode 100755
new mode 100644
index d97c5e7..5a3c710
--- a/lib/pleroma/announcement.ex
+++ b/lib/pleroma/announcement.ex
@@ -23,19 +23,21 @@ defmodule Pleroma.Announcement do
timestamps(type: :utc_datetime)
end
- def change(struct, params \\ %{}) do
- struct
- |> cast(validate_params(struct, params), [:data, :starts_at, :ends_at, :rendered])
+ @doc "Generates changeset for %Pleroma.Announcement{}"
+ @spec changeset(%__MODULE__{}, map()) :: %Ecto.Changeset{}
+ def changeset(announcement \\ %__MODULE__{}, params \\ %{data: %{}}) do
+ announcement
+ |> cast(validate_params(announcement, params), [:data, :starts_at, :ends_at, :rendered])
|> validate_required([:data])
end
- defp validate_params(struct, params) do
+ defp validate_params(announcement, params) do
base_data =
%{
"content" => "",
"all_day" => false
}
- |> Map.merge((struct && struct.data) || %{})
+ |> Map.merge((announcement && announcement.data) || %{})
merged_data =
Map.merge(base_data, params.data)
@@ -61,13 +63,13 @@ defmodule Pleroma.Announcement do
end
def add(params) do
- changeset = change(%__MODULE__{}, params)
+ changeset = changeset(%__MODULE__{}, params)
Repo.insert(changeset)
end
def update(announcement, params) do
- changeset = change(announcement, params)
+ changeset = changeset(announcement, params)
Repo.update(changeset)
end
diff --git a/lib/pleroma/announcement_read_relationship.ex b/lib/pleroma/announcement_read_relationship.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex
old mode 100755
new mode 100644
index e68a3c5..75154f9
--- a/lib/pleroma/application.ex
+++ b/lib/pleroma/application.ex
@@ -14,7 +14,6 @@ defmodule Pleroma.Application do
@name Mix.Project.config()[:name]
@version Mix.Project.config()[:version]
@repository Mix.Project.config()[:source_url]
- @mix_env Mix.env()
def name, do: @name
def version, do: @version
@@ -54,7 +53,6 @@ defmodule Pleroma.Application do
Config.DeprecationWarnings.warn()
Pleroma.Web.Plugs.HTTPSecurityPlug.warn_if_disabled()
Pleroma.ApplicationRequirements.verify!()
- setup_instrumenters()
load_custom_modules()
Pleroma.Docs.JSON.compile()
limiters_setup()
@@ -91,6 +89,7 @@ defmodule Pleroma.Application do
# Define workers and child supervisors to be supervised
children =
[
+ Pleroma.PromEx,
Pleroma.Repo,
Config.TransferTask,
Pleroma.Emoji,
@@ -98,7 +97,7 @@ defmodule Pleroma.Application do
{Task.Supervisor, name: Pleroma.TaskSupervisor}
] ++
cachex_children() ++
- http_children(adapter, @mix_env) ++
+ http_children(adapter) ++
[
Pleroma.Stats,
Pleroma.JobQueueMonitor,
@@ -106,8 +105,9 @@ defmodule Pleroma.Application do
{Oban, Config.get(Oban)},
Pleroma.Web.Endpoint
] ++
- task_children(@mix_env) ++
- dont_run_in_test(@mix_env) ++
+ task_children() ++
+ streamer_registry() ++
+ background_migrators() ++
shout_child(shout_enabled?()) ++
[Pleroma.Gopher.Server]
@@ -116,36 +116,10 @@ defmodule Pleroma.Application do
# If we have a lot of caches, default max_restarts can cause test
# resets to fail.
# Go for the default 3 unless we're in test
- max_restarts =
- if @mix_env == :test do
- 100
- else
- 3
- end
+ max_restarts = Application.get_env(:pleroma, __MODULE__)[:max_restarts]
opts = [strategy: :one_for_one, name: Pleroma.Supervisor, max_restarts: max_restarts]
- result = Supervisor.start_link(children, opts)
-
- set_postgres_server_version()
-
- result
- end
-
- defp set_postgres_server_version do
- version =
- with %{rows: [[version]]} <- Ecto.Adapters.SQL.query!(Pleroma.Repo, "show server_version"),
- {num, _} <- Float.parse(version) do
- num
- else
- e ->
- Logger.warn(
- "Could not get the postgres version: #{inspect(e)}.\nSetting the default value of 9.6"
- )
-
- 9.6
- end
-
- :persistent_term.put({Pleroma.Repo, :postgres_version}, version)
+ Supervisor.start_link(children, opts)
end
def load_custom_modules do
@@ -159,7 +133,7 @@ defmodule Pleroma.Application do
raise "Invalid custom modules"
{:ok, modules, _warnings} ->
- if @mix_env != :test do
+ if Application.get_env(:pleroma, __MODULE__)[:load_custom_modules] do
Enum.each(modules, fn mod ->
Logger.info("Custom module loaded: #{inspect(mod)}")
end)
@@ -170,29 +144,6 @@ defmodule Pleroma.Application do
end
end
- defp setup_instrumenters do
- require Prometheus.Registry
-
- if Application.get_env(:prometheus, Pleroma.Repo.Instrumenter) do
- :ok =
- :telemetry.attach(
- "prometheus-ecto",
- [:pleroma, :repo, :query],
- &Pleroma.Repo.Instrumenter.handle_event/4,
- %{}
- )
-
- Pleroma.Repo.Instrumenter.setup()
- end
-
- Pleroma.Web.Endpoint.MetricsExporter.setup()
- Pleroma.Web.Endpoint.PipelineInstrumenter.setup()
-
- # Note: disabled until prometheus-phx is integrated into prometheus-phoenix:
- # Pleroma.Web.Endpoint.Instrumenter.setup()
- PrometheusPhx.setup()
- end
-
defp cachex_children do
[
build_cachex("used_captcha", ttl_interval: seconds_valid_interval()),
@@ -205,6 +156,7 @@ defmodule Pleroma.Application do
build_cachex("web_resp", limit: 2500),
build_cachex("emoji_packs", expiration: emoji_packs_expiration(), limit: 10),
build_cachex("failed_proxy_url", limit: 2500),
+ build_cachex("failed_media_helper_url", default_ttl: :timer.minutes(15), limit: 2_500),
build_cachex("banned_urls", default_ttl: :timer.hours(24 * 30), limit: 5_000),
build_cachex("chat_message_id_idempotency_key",
expiration: chat_message_id_idempotency_key_expiration(),
@@ -236,24 +188,30 @@ defmodule Pleroma.Application do
defp shout_enabled?, do: Config.get([:shout, :enabled])
- defp dont_run_in_test(env) when env in [:test, :benchmark], do: []
-
- defp dont_run_in_test(_) do
- [
- {Registry,
- [
- name: Pleroma.Web.Streamer.registry(),
- keys: :duplicate,
- partitions: System.schedulers_online()
- ]}
- ] ++ background_migrators()
+ defp streamer_registry do
+ if Application.get_env(:pleroma, __MODULE__)[:streamer_registry] do
+ [
+ {Registry,
+ [
+ name: Pleroma.Web.Streamer.registry(),
+ keys: :duplicate,
+ partitions: System.schedulers_online()
+ ]}
+ ]
+ else
+ []
+ end
end
defp background_migrators do
- [
- Pleroma.Migrators.HashtagsTableMigrator,
- Pleroma.Migrators.ContextObjectsDeletionMigrator
- ]
+ if Application.get_env(:pleroma, __MODULE__)[:background_migrators] do
+ [
+ Pleroma.Migrators.HashtagsTableMigrator,
+ Pleroma.Migrators.ContextObjectsDeletionMigrator
+ ]
+ else
+ []
+ end
end
defp shout_child(true) do
@@ -265,37 +223,43 @@ defmodule Pleroma.Application do
defp shout_child(_), do: []
- defp task_children(:test) do
- [
+ defp task_children do
+ children = [
%{
id: :web_push_init,
start: {Task, :start_link, [&Pleroma.Web.Push.init/0]},
restart: :temporary
}
]
- end
- defp task_children(_) do
- [
- %{
- id: :web_push_init,
- start: {Task, :start_link, [&Pleroma.Web.Push.init/0]},
- restart: :temporary
- },
- %{
- id: :internal_fetch_init,
- start: {Task, :start_link, [&Pleroma.Web.ActivityPub.InternalFetchActor.init/0]},
- restart: :temporary
- }
- ]
+ if Application.get_env(:pleroma, __MODULE__)[:internal_fetch] do
+ children ++
+ [
+ %{
+ id: :internal_fetch_init,
+ start: {Task, :start_link, [&Pleroma.Web.ActivityPub.InternalFetchActor.init/0]},
+ restart: :temporary
+ }
+ ]
+ else
+ children
+ end
end
# start hackney and gun pools in tests
- defp http_children(_, :test) do
- http_children(Tesla.Adapter.Hackney, nil) ++ http_children(Tesla.Adapter.Gun, nil)
+ defp http_children(adapter) do
+ if Application.get_env(:pleroma, __MODULE__)[:test_http_pools] do
+ http_children_hackney() ++ http_children_gun()
+ else
+ cond do
+ match?(Tesla.Adapter.Hackney, adapter) -> http_children_hackney()
+ match?(Tesla.Adapter.Gun, adapter) -> http_children_gun()
+ true -> []
+ end
+ end
end
- defp http_children(Tesla.Adapter.Hackney, _) do
+ defp http_children_hackney do
pools = [:federation, :media]
pools =
@@ -311,18 +275,20 @@ defmodule Pleroma.Application do
end
end
- defp http_children(Tesla.Adapter.Gun, _) do
+ defp http_children_gun do
Pleroma.Gun.ConnectionPool.children() ++
[{Task, &Pleroma.HTTP.AdapterHelper.Gun.limiter_setup/0}]
end
- defp http_children(_, _), do: []
-
@spec limiters_setup() :: :ok
def limiters_setup do
config = Config.get(ConcurrentLimiter, [])
- [Pleroma.Web.RichMedia.Helpers, Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy]
+ [
+ Pleroma.Web.RichMedia.Helpers,
+ Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy,
+ Pleroma.Search
+ ]
|> Enum.each(fn module ->
mod_config = Keyword.get(config, module, [])
diff --git a/lib/pleroma/application_requirements.ex b/lib/pleroma/application_requirements.ex
old mode 100755
new mode 100644
index 44b1c17..8192454
--- a/lib/pleroma/application_requirements.ex
+++ b/lib/pleroma/application_requirements.ex
@@ -7,7 +7,10 @@ defmodule Pleroma.ApplicationRequirements do
The module represents the collection of validations to runs before start server.
"""
- defmodule VerifyError, do: defexception([:message])
+ defmodule VerifyError do
+ defexception([:message])
+ @type t :: %__MODULE__{}
+ end
alias Pleroma.Config
alias Pleroma.Helpers.MediaHelper
@@ -34,7 +37,7 @@ defmodule Pleroma.ApplicationRequirements do
defp check_welcome_message_config!(:ok) do
if Pleroma.Config.get([:welcome, :email, :enabled], false) and
not Pleroma.Emails.Mailer.enabled?() do
- Logger.warn("""
+ Logger.warning("""
To send welcome emails, you need to enable the mailer.
Welcome emails will NOT be sent with the current config.
@@ -53,7 +56,7 @@ defmodule Pleroma.ApplicationRequirements do
def check_confirmation_accounts!(:ok) do
if Pleroma.Config.get([:instance, :account_activation_required]) &&
not Pleroma.Emails.Mailer.enabled?() do
- Logger.warn("""
+ Logger.warning("""
Account activation is required, but the mailer is disabled.
Users will NOT be able to confirm their accounts with this config.
Either disable account activation or enable the mailer.
@@ -168,8 +171,6 @@ defmodule Pleroma.ApplicationRequirements do
check_filter(Pleroma.Upload.Filter.Exiftool.ReadDescription, "exiftool"),
check_filter(Pleroma.Upload.Filter.Mogrify, "mogrify"),
check_filter(Pleroma.Upload.Filter.Mogrifun, "mogrify"),
- check_filter(Pleroma.Upload.Filter.AnalyzeMetadata, "mogrify"),
- check_filter(Pleroma.Upload.Filter.AnalyzeMetadata, "convert"),
check_filter(Pleroma.Upload.Filter.AnalyzeMetadata, "ffprobe")
]
@@ -195,8 +196,6 @@ defmodule Pleroma.ApplicationRequirements do
end
end
- defp check_system_commands!(result), do: result
-
defp check_repo_pool_size!(:ok) do
if Pleroma.Config.get([Pleroma.Repo, :pool_size], 10) != 10 and
not Pleroma.Config.get([:dangerzone, :override_repo_pool_size], false) do
diff --git a/lib/pleroma/bbs/authenticator.ex b/lib/pleroma/bbs/authenticator.ex
deleted file mode 100755
index 0f7543f..0000000
--- a/lib/pleroma/bbs/authenticator.ex
+++ /dev/null
@@ -1,20 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2022 Pleroma Authors
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.BBS.Authenticator do
- use Sshd.PasswordAuthenticator
- alias Pleroma.User
- alias Pleroma.Web.Plugs.AuthenticationPlug
-
- def authenticate(username, password) do
- username = to_string(username)
- password = to_string(password)
-
- with %User{} = user <- User.get_by_nickname(username) do
- AuthenticationPlug.checkpw(password, user.password_hash)
- else
- _e -> false
- end
- end
-end
diff --git a/lib/pleroma/bbs/handler.ex b/lib/pleroma/bbs/handler.ex
deleted file mode 100755
index 2779933..0000000
--- a/lib/pleroma/bbs/handler.ex
+++ /dev/null
@@ -1,246 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2022 Pleroma Authors
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.BBS.Handler do
- use Sshd.ShellHandler
- alias Pleroma.Activity
- alias Pleroma.HTML
- alias Pleroma.Web.ActivityPub.ActivityPub
- alias Pleroma.Web.CommonAPI
-
- def on_shell(username, _pubkey, _ip, _port) do
- :ok = IO.puts("Welcome to #{Pleroma.Config.get([:instance, :name])}!")
- user = Pleroma.User.get_cached_by_nickname(to_string(username))
- Logger.debug("#{inspect(user)}")
- loop(run_state(user: user))
- end
-
- def on_connect(username, ip, port, method) do
- Logger.debug(fn ->
- """
- Incoming SSH shell #{inspect(self())} requested for #{username} from #{inspect(ip)}:#{inspect(port)} using #{inspect(method)}
- """
- end)
- end
-
- def on_disconnect(username, ip, port) do
- Logger.debug(fn ->
- "Disconnecting SSH shell for #{username} from #{inspect(ip)}:#{inspect(port)}"
- end)
- end
-
- defp loop(state) do
- self_pid = self()
- counter = state.counter
- prefix = state.prefix
- user = state.user
-
- input = spawn(fn -> io_get(self_pid, prefix, counter, user.nickname) end)
- wait_input(state, input)
- end
-
- def puts_activity(activity) do
- status = Pleroma.Web.MastodonAPI.StatusView.render("show.json", %{activity: activity})
-
- IO.puts("-- #{status.id} by #{status.account.display_name} (#{status.account.acct})")
-
- status.content
- |> String.split("
")
- |> Enum.map(&HTML.strip_tags/1)
- |> Enum.map(&HtmlEntities.decode/1)
- |> Enum.map(&IO.puts/1)
- end
-
- def puts_notification(activity, user) do
- notification =
- Pleroma.Web.MastodonAPI.NotificationView.render("show.json", %{
- notification: activity,
- for: user
- })
-
- IO.puts(
- "== (#{notification.type}) #{notification.status.id} by #{notification.account.display_name} (#{notification.account.acct})"
- )
-
- notification.status.content
- |> String.split("
")
- |> Enum.map(&HTML.strip_tags/1)
- |> Enum.map(&HtmlEntities.decode/1)
- |> (fn x ->
- case x do
- [content] ->
- "> " <> content
-
- [head | _tail] ->
- # "> " <> hd <> "..."
- head
- |> String.slice(1, 80)
- |> (fn x -> "> " <> x <> "..." end).()
- end
- end).()
- |> IO.puts()
-
- IO.puts("")
- end
-
- def handle_command(state, "help") do
- IO.puts("Available commands:")
- IO.puts("help - This help")
- IO.puts("home - Show the home timeline")
- IO.puts("p - Post the given text")
- IO.puts("r - Reply to the post with the given id")
- IO.puts("t - Show a thread from the given id")
- IO.puts("n - Show notifications")
- IO.puts("n read - Mark all notifactions as read")
- IO.puts("f - Favourites the post with the given id")
- IO.puts("R - Repeat the post with the given id")
- IO.puts("quit - Quit")
-
- state
- end
-
- def handle_command(%{user: user} = state, "r " <> text) do
- text = String.trim(text)
- [activity_id, rest] = String.split(text, " ", parts: 2)
-
- with %Activity{} <- Activity.get_by_id(activity_id),
- {:ok, _activity} <-
- CommonAPI.post(user, %{status: rest, in_reply_to_status_id: activity_id}) do
- IO.puts("Replied!")
- else
- _e -> IO.puts("Could not reply...")
- end
-
- state
- end
-
- def handle_command(%{user: user} = state, "t " <> activity_id) do
- with %Activity{} = activity <- Activity.get_by_id(activity_id) do
- activities =
- ActivityPub.fetch_activities_for_context(activity.data["context"], %{
- blocking_user: user,
- user: user,
- exclude_id: activity.id
- })
-
- case activities do
- [] ->
- activity_id
- |> Activity.get_by_id()
- |> puts_activity()
-
- _ ->
- activities
- |> Enum.reverse()
- |> Enum.each(&puts_activity/1)
- end
- else
- _e -> IO.puts("Could not show this thread...")
- end
-
- state
- end
-
- def handle_command(%{user: user} = state, "n read") do
- Pleroma.Notification.clear(user)
- IO.puts("All notifications were marked as read")
-
- state
- end
-
- def handle_command(%{user: user} = state, "n") do
- user
- |> Pleroma.Web.MastodonAPI.MastodonAPI.get_notifications(%{})
- |> Enum.each(&puts_notification(&1, user))
-
- state
- end
-
- def handle_command(%{user: user} = state, "p " <> text) do
- text = String.trim(text)
-
- with {:ok, activity} <- CommonAPI.post(user, %{status: text}) do
- IO.puts("Posted! ID: #{activity.id}")
- else
- _e -> IO.puts("Could not post...")
- end
-
- state
- end
-
- def handle_command(%{user: user} = state, "f " <> id) do
- id = String.trim(id)
-
- with %Activity{} = activity <- Activity.get_by_id(id),
- {:ok, _activity} <- CommonAPI.favorite(user, activity) do
- IO.puts("Favourited!")
- else
- _e -> IO.puts("Could not Favourite...")
- end
-
- state
- end
-
- def handle_command(state, "home") do
- user = state.user
-
- params =
- %{}
- |> Map.put(:type, ["Create"])
- |> Map.put(:blocking_user, user)
- |> Map.put(:muting_user, user)
- |> Map.put(:user, user)
-
- activities =
- [user.ap_id | Pleroma.User.following(user)]
- |> ActivityPub.fetch_activities(params)
-
- Enum.each(activities, fn activity ->
- puts_activity(activity)
- end)
-
- state
- end
-
- def handle_command(state, command) do
- IO.puts("Unknown command '#{command}'")
- state
- end
-
- defp wait_input(state, input) do
- receive do
- {:input, ^input, "quit\n"} ->
- IO.puts("Exiting...")
-
- {:input, ^input, code} when is_binary(code) ->
- code = String.trim(code)
-
- state = handle_command(state, code)
-
- loop(%{state | counter: state.counter + 1})
-
- {:input, ^input, {:error, :interrupted}} ->
- IO.puts("Caught Ctrl+C...")
- loop(%{state | counter: state.counter + 1})
-
- {:input, ^input, msg} ->
- :ok = Logger.warn("received unknown message: #{inspect(msg)}")
- loop(%{state | counter: state.counter + 1})
- end
- end
-
- defp run_state(opts) do
- %{prefix: "pleroma", counter: 1, user: opts[:user]}
- end
-
- defp io_get(pid, prefix, counter, username) do
- prompt = prompt(prefix, counter, username)
- send(pid, {:input, self(), IO.gets(:stdio, prompt)})
- end
-
- defp prompt(prefix, counter, username) do
- prompt = "#{username}@#{prefix}:#{counter}>"
- prompt <> " "
- end
-end
diff --git a/lib/pleroma/bookmark.ex b/lib/pleroma/bookmark.ex
old mode 100755
new mode 100644
index 187749e..1a2a63b
--- a/lib/pleroma/bookmark.ex
+++ b/lib/pleroma/bookmark.ex
@@ -10,6 +10,7 @@ defmodule Pleroma.Bookmark do
alias Pleroma.Activity
alias Pleroma.Bookmark
+ alias Pleroma.BookmarkFolder
alias Pleroma.Repo
alias Pleroma.User
@@ -18,33 +19,46 @@ defmodule Pleroma.Bookmark do
schema "bookmarks" do
belongs_to(:user, User, type: FlakeId.Ecto.CompatType)
belongs_to(:activity, Activity, type: FlakeId.Ecto.CompatType)
+ belongs_to(:folder, BookmarkFolder, type: FlakeId.Ecto.CompatType)
timestamps()
end
- @spec create(FlakeId.Ecto.CompatType.t(), FlakeId.Ecto.CompatType.t()) ::
- {:ok, Bookmark.t()} | {:error, Changeset.t()}
- def create(user_id, activity_id) do
+ @spec create(Ecto.UUID.t(), Ecto.UUID.t()) ::
+ {:ok, Bookmark.t()} | {:error, Ecto.Changeset.t()}
+ def create(user_id, activity_id, folder_id \\ nil) do
attrs = %{
user_id: user_id,
- activity_id: activity_id
+ activity_id: activity_id,
+ folder_id: folder_id
}
%Bookmark{}
- |> cast(attrs, [:user_id, :activity_id])
+ |> cast(attrs, [:user_id, :activity_id, :folder_id])
|> validate_required([:user_id, :activity_id])
|> unique_constraint(:activity_id, name: :bookmarks_user_id_activity_id_index)
- |> Repo.insert()
+ |> Repo.insert(
+ on_conflict: [set: [folder_id: folder_id]],
+ conflict_target: [:user_id, :activity_id]
+ )
end
- @spec for_user_query(FlakeId.Ecto.CompatType.t()) :: Ecto.Query.t()
- def for_user_query(user_id) do
+ @spec for_user_query(Ecto.UUID.t()) :: Ecto.Query.t()
+ def for_user_query(user_id, folder_id \\ nil) do
Bookmark
|> where(user_id: ^user_id)
+ |> maybe_filter_by_folder(folder_id)
|> join(:inner, [b], activity in assoc(b, :activity))
|> preload([b, a], activity: a)
end
+ defp maybe_filter_by_folder(query, nil), do: query
+
+ defp maybe_filter_by_folder(query, folder_id) do
+ query
+ |> where(folder_id: ^folder_id)
+ end
+
def get(user_id, activity_id) do
Bookmark
|> where(user_id: ^user_id)
@@ -52,8 +66,8 @@ defmodule Pleroma.Bookmark do
|> Repo.one()
end
- @spec destroy(FlakeId.Ecto.CompatType.t(), FlakeId.Ecto.CompatType.t()) ::
- {:ok, Bookmark.t()} | {:error, Changeset.t()}
+ @spec destroy(Ecto.UUID.t(), Ecto.UUID.t()) ::
+ {:ok, Bookmark.t()} | {:error, Ecto.Changeset.t()}
def destroy(user_id, activity_id) do
from(b in Bookmark,
where: b.user_id == ^user_id,
@@ -62,4 +76,11 @@ defmodule Pleroma.Bookmark do
|> Repo.one()
|> Repo.delete()
end
+
+ def set_folder(bookmark, folder_id) do
+ bookmark
+ |> cast(%{folder_id: folder_id}, [:folder_id])
+ |> validate_required([:folder_id])
+ |> Repo.update()
+ end
end
diff --git a/lib/pleroma/bookmark_folder.ex b/lib/pleroma/bookmark_folder.ex
new file mode 100644
index 0000000..14d37e1
--- /dev/null
+++ b/lib/pleroma/bookmark_folder.ex
@@ -0,0 +1,115 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2024 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.BookmarkFolder do
+ use Ecto.Schema
+
+ import Ecto.Changeset
+ import Ecto.Query
+
+ alias Pleroma.BookmarkFolder
+ alias Pleroma.Emoji
+ alias Pleroma.Repo
+ alias Pleroma.User
+
+ @type t :: %__MODULE__{}
+ @primary_key {:id, FlakeId.Ecto.CompatType, autogenerate: true}
+
+ schema "bookmark_folders" do
+ field(:name, :string)
+ field(:emoji, :string)
+
+ belongs_to(:user, User, type: FlakeId.Ecto.CompatType)
+
+ timestamps()
+ end
+
+ def get_by_id(id), do: Repo.get_by(BookmarkFolder, id: id)
+
+ def create(user_id, name, emoji \\ nil) do
+ %BookmarkFolder{}
+ |> cast(
+ %{
+ user_id: user_id,
+ name: name,
+ emoji: emoji
+ },
+ [:user_id, :name, :emoji]
+ )
+ |> validate_required([:user_id, :name])
+ |> fix_emoji()
+ |> validate_emoji()
+ |> unique_constraint([:user_id, :name])
+ |> Repo.insert()
+ end
+
+ def update(folder_id, name, emoji \\ nil) do
+ get_by_id(folder_id)
+ |> cast(
+ %{
+ name: name,
+ emoji: emoji
+ },
+ [:name, :emoji]
+ )
+ |> fix_emoji()
+ |> validate_emoji()
+ |> unique_constraint([:user_id, :name])
+ |> Repo.update()
+ end
+
+ defp fix_emoji(changeset) do
+ with {:emoji_field, emoji} when is_binary(emoji) <-
+ {:emoji_field, get_field(changeset, :emoji)},
+ {:fixed_emoji, emoji} <-
+ {:fixed_emoji,
+ emoji
+ |> Pleroma.Emoji.fully_qualify_emoji()
+ |> Pleroma.Emoji.maybe_quote()} do
+ put_change(changeset, :emoji, emoji)
+ else
+ {:emoji_field, _} -> changeset
+ end
+ end
+
+ defp validate_emoji(changeset) do
+ validate_change(changeset, :emoji, fn
+ :emoji, nil ->
+ []
+
+ :emoji, emoji ->
+ if Emoji.unicode?(emoji) or valid_local_custom_emoji?(emoji) do
+ []
+ else
+ [emoji: "Invalid emoji"]
+ end
+ end)
+ end
+
+ defp valid_local_custom_emoji?(emoji) do
+ with %{file: _path} <- Emoji.get(emoji) do
+ true
+ else
+ _ -> false
+ end
+ end
+
+ def delete(folder_id) do
+ BookmarkFolder
+ |> Repo.get_by(id: folder_id)
+ |> Repo.delete()
+ end
+
+ def for_user(user_id) do
+ BookmarkFolder
+ |> where(user_id: ^user_id)
+ |> Repo.all()
+ end
+
+ def belongs_to_user?(folder_id, user_id) do
+ BookmarkFolder
+ |> where(id: ^folder_id, user_id: ^user_id)
+ |> Repo.exists?()
+ end
+end
diff --git a/lib/pleroma/caching.ex b/lib/pleroma/caching.ex
old mode 100755
new mode 100644
index eb05887..796a465
--- a/lib/pleroma/caching.ex
+++ b/lib/pleroma/caching.ex
@@ -8,10 +8,13 @@ defmodule Pleroma.Caching do
@callback put(Cachex.cache(), any(), any(), Keyword.t()) :: {Cachex.status(), boolean()}
@callback put(Cachex.cache(), any(), any()) :: {Cachex.status(), boolean()}
@callback fetch!(Cachex.cache(), any(), function() | nil) :: any()
+ @callback fetch(Cachex.cache(), any(), function() | nil) ::
+ {atom(), any()} | {atom(), any(), any()}
# @callback del(Cachex.cache(), any(), Keyword.t()) :: {Cachex.status(), boolean()}
@callback del(Cachex.cache(), any()) :: {Cachex.status(), boolean()}
@callback stream!(Cachex.cache(), any()) :: Enumerable.t()
@callback expire_at(Cachex.cache(), binary(), number()) :: {Cachex.status(), boolean()}
+ @callback expire(Cachex.cache(), binary(), number()) :: {Cachex.status(), boolean()}
@callback exists?(Cachex.cache(), any()) :: {Cachex.status(), boolean()}
@callback execute!(Cachex.cache(), function()) :: any()
@callback get_and_update(Cachex.cache(), any(), function()) ::
diff --git a/lib/pleroma/captcha.ex b/lib/pleroma/captcha.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/captcha/kocaptcha.ex b/lib/pleroma/captcha/kocaptcha.ex
old mode 100755
new mode 100644
index e786e28..c4987d4
--- a/lib/pleroma/captcha/kocaptcha.ex
+++ b/lib/pleroma/captcha/kocaptcha.ex
@@ -29,7 +29,7 @@ defmodule Pleroma.Captcha.Kocaptcha do
@impl Service
def validate(_token, captcha, answer_data) do
- # Here the token is unsed, because the unencrypted captcha answer is just passed to method
+ # Here the token is unused, because the unencrypted captcha answer is just passed to method
if not is_nil(captcha) and
:crypto.hash(:md5, captcha) |> Base.encode16() == String.upcase(answer_data),
do: :ok,
diff --git a/lib/pleroma/captcha/native.ex b/lib/pleroma/captcha/native.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/captcha/service.ex b/lib/pleroma/captcha/service.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/chat.ex b/lib/pleroma/chat.ex
old mode 100755
new mode 100644
index fe32ec0..5c4dbc1
--- a/lib/pleroma/chat.ex
+++ b/lib/pleroma/chat.ex
@@ -42,7 +42,7 @@ defmodule Pleroma.Chat do
|> unique_constraint(:user_id, name: :chats_user_id_recipient_index)
end
- @spec get_by_user_and_id(User.t(), FlakeId.Ecto.CompatType.t()) ::
+ @spec get_by_user_and_id(User.t(), Ecto.UUID.t()) ::
{:ok, t()} | {:error, :not_found}
def get_by_user_and_id(%User{id: user_id}, id) do
from(c in __MODULE__,
@@ -52,17 +52,17 @@ defmodule Pleroma.Chat do
|> Repo.find_resource()
end
- @spec get_by_id(FlakeId.Ecto.CompatType.t()) :: t() | nil
+ @spec get_by_id(Ecto.UUID.t()) :: t() | nil
def get_by_id(id) do
Repo.get(__MODULE__, id)
end
- @spec get(FlakeId.Ecto.CompatType.t(), String.t()) :: t() | nil
+ @spec get(Ecto.UUID.t(), String.t()) :: t() | nil
def get(user_id, recipient) do
Repo.get_by(__MODULE__, user_id: user_id, recipient: recipient)
end
- @spec get_or_create(FlakeId.Ecto.CompatType.t(), String.t()) ::
+ @spec get_or_create(Ecto.UUID.t(), String.t()) ::
{:ok, t()} | {:error, Ecto.Changeset.t()}
def get_or_create(user_id, recipient) do
%__MODULE__{}
@@ -75,7 +75,7 @@ defmodule Pleroma.Chat do
)
end
- @spec bump_or_create(FlakeId.Ecto.CompatType.t(), String.t()) ::
+ @spec bump_or_create(Ecto.UUID.t(), String.t()) ::
{:ok, t()} | {:error, Ecto.Changeset.t()}
def bump_or_create(user_id, recipient) do
%__MODULE__{}
@@ -87,7 +87,7 @@ defmodule Pleroma.Chat do
)
end
- @spec for_user_query(FlakeId.Ecto.CompatType.t()) :: Ecto.Query.t()
+ @spec for_user_query(Ecto.UUID.t()) :: Ecto.Query.t()
def for_user_query(user_id) do
from(c in Chat,
where: c.user_id == ^user_id,
diff --git a/lib/pleroma/chat/message_reference.ex b/lib/pleroma/chat/message_reference.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/clippy.ex b/lib/pleroma/clippy.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/config.ex b/lib/pleroma/config.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/config/deprecation_warnings.ex b/lib/pleroma/config/deprecation_warnings.ex
old mode 100755
new mode 100644
index b53b15d..58d164d
--- a/lib/pleroma/config/deprecation_warnings.ex
+++ b/lib/pleroma/config/deprecation_warnings.ex
@@ -24,7 +24,7 @@ defmodule Pleroma.Config.DeprecationWarnings do
filters = Config.get([Pleroma.Upload]) |> Keyword.get(:filters, [])
if Pleroma.Upload.Filter.Exiftool in filters do
- Logger.warn("""
+ Logger.warning("""
!!!DEPRECATION WARNING!!!
Your config is using Exiftool as a filter instead of Exiftool.StripLocation. This should work for now, but you are advised to change to the new configuration to prevent possible issues later:
@@ -63,7 +63,7 @@ defmodule Pleroma.Config.DeprecationWarnings do
|> Enum.any?(fn {_, v} -> Enum.any?(v, &is_binary/1) end)
if has_strings do
- Logger.warn("""
+ Logger.warning("""
!!!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:
@@ -121,7 +121,7 @@ defmodule Pleroma.Config.DeprecationWarnings do
has_strings = Config.get([:instance, :quarantined_instances]) |> Enum.any?(&is_binary/1)
if has_strings do
- Logger.warn("""
+ Logger.warning("""
!!!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:
@@ -158,7 +158,7 @@ defmodule Pleroma.Config.DeprecationWarnings do
has_strings = Config.get([:mrf, :transparency_exclusions]) |> Enum.any?(&is_binary/1)
if has_strings do
- Logger.warn("""
+ Logger.warning("""
!!!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:
@@ -172,7 +172,7 @@ defmodule Pleroma.Config.DeprecationWarnings do
```
config :pleroma, :mrf,
- transparency_exclusions: [{"instance.tld", "Reason to exlude transparency"}]
+ transparency_exclusions: [{"instance.tld", "Reason to exclude transparency"}]
```
""")
@@ -193,7 +193,7 @@ defmodule Pleroma.Config.DeprecationWarnings do
def check_hellthread_threshold do
if Config.get([:mrf_hellthread, :threshold]) do
- Logger.warn("""
+ Logger.warning("""
!!!DEPRECATION WARNING!!!
You are using the old configuration mechanism for the hellthread filter. Please check config.md.
""")
@@ -213,7 +213,7 @@ defmodule Pleroma.Config.DeprecationWarnings do
check_gun_pool_options(),
check_activity_expiration_config(),
check_remote_ip_plug_name(),
- check_uploders_s3_public_endpoint(),
+ check_uploaders_s3_public_endpoint(),
check_old_chat_shoutbox(),
check_quarantined_instances_tuples(),
check_transparency_exclusions_tuples(),
@@ -256,7 +256,7 @@ defmodule Pleroma.Config.DeprecationWarnings do
move_namespace_and_warn(@mrf_config_map, warning_preface)
end
- @spec move_namespace_and_warn([config_map()], String.t()) :: :ok | nil
+ @spec move_namespace_and_warn([config_map()], String.t()) :: :ok | :error
def move_namespace_and_warn(config_map, warning_preface) do
warning =
Enum.reduce(config_map, "", fn
@@ -274,17 +274,17 @@ defmodule Pleroma.Config.DeprecationWarnings do
if warning == "" do
:ok
else
- Logger.warn(warning_preface <> warning)
+ Logger.warning(warning_preface <> warning)
:error
end
end
- @spec check_media_proxy_whitelist_config() :: :ok | nil
+ @spec check_media_proxy_whitelist_config() :: :ok | :error
def check_media_proxy_whitelist_config do
whitelist = Config.get([:media_proxy, :whitelist])
if Enum.any?(whitelist, &(not String.starts_with?(&1, "http"))) do
- Logger.warn("""
+ Logger.warning("""
!!!DEPRECATION WARNING!!!
Your config is using old format (only domain) for MediaProxy whitelist option. Setting should work for now, but you are advised to change format to scheme with port to prevent possible issues later.
""")
@@ -299,7 +299,7 @@ defmodule Pleroma.Config.DeprecationWarnings do
pool_config = Config.get(:connections_pool)
if timeout = pool_config[:await_up_timeout] do
- Logger.warn("""
+ Logger.warning("""
!!!DEPRECATION WARNING!!!
Your config is using old setting `config :pleroma, :connections_pool, await_up_timeout`. Please change to `config :pleroma, :connections_pool, connect_timeout` to ensure compatibility with future releases.
""")
@@ -331,7 +331,7 @@ defmodule Pleroma.Config.DeprecationWarnings do
"\n* `:timeout` options in #{pool_name} pool is now `:recv_timeout`"
end)
- Logger.warn(Enum.join([warning_preface | pool_warnings]))
+ Logger.warning(Enum.join([warning_preface | pool_warnings]))
Config.put(:pools, updated_config)
:error
@@ -340,7 +340,7 @@ defmodule Pleroma.Config.DeprecationWarnings do
end
end
- @spec check_activity_expiration_config() :: :ok | nil
+ @spec check_activity_expiration_config() :: :ok | :error
def check_activity_expiration_config do
warning_preface = """
!!!DEPRECATION WARNING!!!
@@ -356,7 +356,7 @@ defmodule Pleroma.Config.DeprecationWarnings do
)
end
- @spec check_remote_ip_plug_name() :: :ok | nil
+ @spec check_remote_ip_plug_name() :: :ok | :error
def check_remote_ip_plug_name do
warning_preface = """
!!!DEPRECATION WARNING!!!
@@ -372,8 +372,8 @@ defmodule Pleroma.Config.DeprecationWarnings do
)
end
- @spec check_uploders_s3_public_endpoint() :: :ok | nil
- def check_uploders_s3_public_endpoint do
+ @spec check_uploaders_s3_public_endpoint() :: :ok | :error
+ def check_uploaders_s3_public_endpoint do
s3_config = Pleroma.Config.get([Pleroma.Uploaders.S3])
use_old_config = Keyword.has_key?(s3_config, :public_endpoint)
@@ -393,7 +393,7 @@ defmodule Pleroma.Config.DeprecationWarnings do
end
end
- @spec check_old_chat_shoutbox() :: :ok | nil
+ @spec check_old_chat_shoutbox() :: :ok | :error
def check_old_chat_shoutbox do
instance_config = Pleroma.Config.get([:instance])
chat_config = Pleroma.Config.get([:chat]) || []
diff --git a/lib/pleroma/config/getting.ex b/lib/pleroma/config/getting.ex
old mode 100755
new mode 100644
index f9b66bb..ec93fd0
--- a/lib/pleroma/config/getting.ex
+++ b/lib/pleroma/config/getting.ex
@@ -5,4 +5,11 @@
defmodule Pleroma.Config.Getting do
@callback get(any()) :: any()
@callback get(any(), any()) :: any()
+
+ def get(key), do: get(key, nil)
+ def get(key, default), do: impl().get(key, default)
+
+ def impl do
+ Application.get_env(:pleroma, :config_impl, Pleroma.Config)
+ end
end
diff --git a/lib/pleroma/config/helpers.ex b/lib/pleroma/config/helpers.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/config/holder.ex b/lib/pleroma/config/holder.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/config/loader.ex b/lib/pleroma/config/loader.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/config/oban.ex b/lib/pleroma/config/oban.ex
old mode 100755
new mode 100644
index 483d2bb..836f0c1
--- a/lib/pleroma/config/oban.ex
+++ b/lib/pleroma/config/oban.ex
@@ -23,7 +23,7 @@ defmodule Pleroma.Config.Oban do
You are using old workers in Oban crontab settings, which were removed.
Please, remove setting from crontab in your config file (prod.secret.exs): #{inspect(setting)}
"""
- |> Logger.warn()
+ |> Logger.warning()
List.delete(acc, setting)
else
diff --git a/lib/pleroma/config/release_runtime_provider.ex b/lib/pleroma/config/release_runtime_provider.ex
old mode 100755
new mode 100644
index 9ec0f97..3516398
--- a/lib/pleroma/config/release_runtime_provider.ex
+++ b/lib/pleroma/config/release_runtime_provider.ex
@@ -21,7 +21,7 @@ defmodule Pleroma.Config.ReleaseRuntimeProvider do
with_runtime_config =
if File.exists?(config_path) do
#
- %File.Stat{mode: mode} = File.lstat!(config_path)
+ %File.Stat{mode: mode} = File.stat!(config_path)
if Bitwise.band(mode, 0o007) > 0 do
raise "Configuration at #{config_path} has world-permissions, execute the following: chmod o= #{config_path}"
diff --git a/lib/pleroma/config/transfer_task.ex b/lib/pleroma/config/transfer_task.ex
old mode 100755
new mode 100644
index 44a9840..9188534
--- a/lib/pleroma/config/transfer_task.ex
+++ b/lib/pleroma/config/transfer_task.ex
@@ -55,8 +55,7 @@ defmodule Pleroma.Config.TransferTask do
started_applications = Application.started_applications()
- # TODO: some problem with prometheus after restart!
- reject = [nil, :prometheus, :postgrex]
+ reject = [nil, :postgrex]
reject =
if restart_pleroma? do
@@ -145,7 +144,7 @@ defmodule Pleroma.Config.TransferTask do
error_msg =
"updating env causes error, group: #{inspect(group)}, key: #{inspect(key)}, value: #{inspect(value)} error: #{inspect(error)}"
- Logger.warn(error_msg)
+ Logger.warning(error_msg)
nil
end
@@ -179,12 +178,12 @@ defmodule Pleroma.Config.TransferTask do
:ok = Application.start(app)
else
nil ->
- Logger.warn("#{app} is not started.")
+ Logger.warning("#{app} is not started.")
error ->
error
|> inspect()
- |> Logger.warn()
+ |> Logger.warning()
end
end
diff --git a/lib/pleroma/config_db.ex b/lib/pleroma/config_db.ex
old mode 100755
new mode 100644
index 846cede..e28fcb1
--- a/lib/pleroma/config_db.ex
+++ b/lib/pleroma/config_db.ex
@@ -54,7 +54,7 @@ defmodule Pleroma.ConfigDB do
@spec get_by_params(map()) :: ConfigDB.t() | nil
def get_by_params(%{group: _, key: _} = params), do: Repo.get_by(ConfigDB, params)
- @spec changeset(ConfigDB.t(), map()) :: Changeset.t()
+ @spec changeset(ConfigDB.t(), map()) :: Ecto.Changeset.t()
def changeset(config, params \\ %{}) do
config
|> cast(params, [:key, :group, :value])
@@ -138,7 +138,7 @@ defmodule Pleroma.ConfigDB do
end
end
- @spec update_or_create(map()) :: {:ok, ConfigDB.t()} | {:error, Changeset.t()}
+ @spec update_or_create(map()) :: {:ok, ConfigDB.t()} | {:error, Ecto.Changeset.t()}
def update_or_create(params) do
params = Map.put(params, :value, to_elixir_types(params[:value]))
search_opts = Map.take(params, [:group, :key])
@@ -175,7 +175,7 @@ defmodule Pleroma.ConfigDB do
end)
end
- @spec delete(ConfigDB.t() | map()) :: {:ok, ConfigDB.t()} | {:error, Changeset.t()}
+ @spec delete(ConfigDB.t() | map()) :: {:ok, ConfigDB.t()} | {:error, Ecto.Changeset.t()}
def delete(%ConfigDB{} = config), do: Repo.delete(config)
def delete(params) do
diff --git a/lib/pleroma/constants.ex b/lib/pleroma/constants.ex
old mode 100755
new mode 100644
index cfb4052..d814b49
--- a/lib/pleroma/constants.ex
+++ b/lib/pleroma/constants.ex
@@ -42,6 +42,18 @@ defmodule Pleroma.Constants do
]
)
+ const(status_object_types,
+ do: [
+ "Note",
+ "Question",
+ "Audio",
+ "Video",
+ "Event",
+ "Article",
+ "Page"
+ ]
+ )
+
const(updatable_object_types,
do: [
"Note",
@@ -64,9 +76,34 @@ defmodule Pleroma.Constants do
]
)
+ const(allowed_user_actor_types,
+ do: [
+ "Person",
+ "Service",
+ "Group"
+ ]
+ )
+
# basic regex, just there to weed out potential mistakes
# https://datatracker.ietf.org/doc/html/rfc2045#section-5.1
const(mime_regex,
do: ~r/^[^[:cntrl:] ()<>@,;:\\"\/\[\]?=]+\/[^[:cntrl:] ()<>@,;:\\"\/\[\]?=]+(; .*)?$/
)
+
+ const(upload_object_types, do: ["Document", "Image"])
+
+ const(activity_json_canonical_mime_type,
+ do: "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
+ )
+
+ const(activity_json_mime_types,
+ do: [
+ "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"",
+ "application/activity+json"
+ ]
+ )
+
+ const(public_streams,
+ do: ["public", "public:local", "public:media", "public:local:media"]
+ )
end
diff --git a/lib/pleroma/conversation.ex b/lib/pleroma/conversation.ex
old mode 100755
new mode 100644
index 42028aa..0be609a
--- a/lib/pleroma/conversation.ex
+++ b/lib/pleroma/conversation.ex
@@ -57,7 +57,7 @@ defmodule Pleroma.Conversation do
3. Bump all relevant participations to 'unread'
"""
def create_or_bump_for(activity, opts \\ []) do
- with true <- Pleroma.Web.ActivityPub.Visibility.is_direct?(activity),
+ with true <- Pleroma.Web.ActivityPub.Visibility.direct?(activity),
"Create" <- activity.data["type"],
%Object{} = object <- Object.normalize(activity, fetch: false),
true <- object.data["type"] in ["Note", "Question"],
diff --git a/lib/pleroma/conversation/participation.ex b/lib/pleroma/conversation/participation.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/conversation/participation/recipient_ship.ex b/lib/pleroma/conversation/participation/recipient_ship.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/counter_cache.ex b/lib/pleroma/counter_cache.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/data_migration.ex b/lib/pleroma/data_migration.ex
old mode 100755
new mode 100644
index 8451678..be4bf64
--- a/lib/pleroma/data_migration.ex
+++ b/lib/pleroma/data_migration.ex
@@ -12,6 +12,8 @@ defmodule Pleroma.DataMigration do
import Ecto.Changeset
import Ecto.Query
+ @type t :: %__MODULE__{}
+
schema "data_migrations" do
field(:name, :string)
field(:state, State, default: :pending)
diff --git a/lib/pleroma/delivery.ex b/lib/pleroma/delivery.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/docs/generator.ex b/lib/pleroma/docs/generator.ex
old mode 100755
new mode 100644
index 6508f19..93b1948
--- a/lib/pleroma/docs/generator.ex
+++ b/lib/pleroma/docs/generator.ex
@@ -15,8 +15,10 @@ defmodule Pleroma.Docs.Generator do
:code.all_loaded()
|> Enum.filter(fn {module, _} ->
# This shouldn't be needed as all modules are expected to have module_info/1,
- # but in test enviroments some transient modules `:elixir_compiler_XX`
+ # but in test environments some transient modules `:elixir_compiler_XX`
# are loaded for some reason (where XX is a random integer).
+ Code.ensure_loaded(module)
+
if function_exported?(module, :module_info, 1) do
module.module_info(:attributes)
|> Keyword.get_values(:behaviour)
diff --git a/lib/pleroma/docs/json.ex b/lib/pleroma/docs/json.ex
old mode 100755
new mode 100644
index 05f46f3..f698549
--- a/lib/pleroma/docs/json.ex
+++ b/lib/pleroma/docs/json.ex
@@ -18,7 +18,7 @@ defmodule Pleroma.Docs.JSON do
:persistent_term.put(@term, Pleroma.Docs.Generator.convert_to_strings(descriptions))
end
- @spec compiled_descriptions :: Map.t()
+ @spec compiled_descriptions :: map()
def compiled_descriptions do
:persistent_term.get(@term)
end
diff --git a/lib/pleroma/docs/markdown.ex b/lib/pleroma/docs/markdown.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/docs/translator.ex b/lib/pleroma/docs/translator.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/docs/translator/compiler.ex b/lib/pleroma/docs/translator/compiler.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/ecto_enums.ex b/lib/pleroma/ecto_enums.ex
old mode 100755
new mode 100644
index a4890b4..b346b39
--- a/lib/pleroma/ecto_enums.ex
+++ b/lib/pleroma/ecto_enums.ex
@@ -27,3 +27,11 @@ defenum(Pleroma.DataMigration.State,
failed: 4,
manual: 5
)
+
+defenum(Pleroma.User.Backup.State,
+ pending: 1,
+ running: 2,
+ complete: 3,
+ failed: 4,
+ invalid: 5
+)
diff --git a/lib/pleroma/ecto_type/activity_pub/object_validators/bare_uri.ex b/lib/pleroma/ecto_type/activity_pub/object_validators/bare_uri.ex
new file mode 100644
index 0000000..a1af8fa
--- /dev/null
+++ b/lib/pleroma/ecto_type/activity_pub/object_validators/bare_uri.ex
@@ -0,0 +1,25 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2023 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.BareUri do
+ use Ecto.Type
+
+ def type, do: :string
+
+ def cast(uri) when is_binary(uri) do
+ parsed = URI.parse(uri)
+
+ if is_nil(parsed.scheme) do
+ :error
+ else
+ {:ok, uri}
+ end
+ end
+
+ def cast(_), do: :error
+
+ def dump(data), do: {:ok, data}
+
+ def load(data), do: {:ok, data}
+end
diff --git a/lib/pleroma/ecto_type/activity_pub/object_validators/date_time.ex b/lib/pleroma/ecto_type/activity_pub/object_validators/date_time.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/ecto_type/activity_pub/object_validators/emoji.ex b/lib/pleroma/ecto_type/activity_pub/object_validators/emoji.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/ecto_type/activity_pub/object_validators/mime.ex b/lib/pleroma/ecto_type/activity_pub/object_validators/mime.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/ecto_type/activity_pub/object_validators/object_id.ex b/lib/pleroma/ecto_type/activity_pub/object_validators/object_id.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/ecto_type/activity_pub/object_validators/recipients.ex b/lib/pleroma/ecto_type/activity_pub/object_validators/recipients.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/ecto_type/activity_pub/object_validators/safe_text.ex b/lib/pleroma/ecto_type/activity_pub/object_validators/safe_text.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/ecto_type/activity_pub/object_validators/uri.ex b/lib/pleroma/ecto_type/activity_pub/object_validators/uri.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/ecto_type/config/atom.ex b/lib/pleroma/ecto_type/config/atom.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/ecto_type/config/binary_value.ex b/lib/pleroma/ecto_type/config/binary_value.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/emails/admin_email.ex b/lib/pleroma/emails/admin_email.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/emails/mailer.ex b/lib/pleroma/emails/mailer.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/emails/new_users_digest_email.ex b/lib/pleroma/emails/new_users_digest_email.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/emails/user_email.ex b/lib/pleroma/emails/user_email.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/emoji-test.txt b/lib/pleroma/emoji-test.txt
old mode 100755
new mode 100644
diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex
old mode 100755
new mode 100644
index dd65d56..21bcb01
--- a/lib/pleroma/emoji.ex
+++ b/lib/pleroma/emoji.ex
@@ -24,6 +24,8 @@ defmodule Pleroma.Emoji do
defstruct [:code, :file, :tags, :safe_code, :safe_file]
+ @type t :: %__MODULE__{}
+
@doc "Build emoji struct"
def build({code, file, tags}) do
%__MODULE__{
@@ -49,10 +51,12 @@ defmodule Pleroma.Emoji do
end
@doc "Returns the path of the emoji `name`."
- @spec get(String.t()) :: String.t() | nil
+ @spec get(String.t()) :: Pleroma.Emoji.t() | nil
def get(name) do
+ name = maybe_strip_name(name)
+
case :ets.lookup(@ets, name) do
- [{_, path}] -> path
+ [{_, emoji}] -> emoji
_ -> nil
end
end
@@ -134,10 +138,61 @@ defmodule Pleroma.Emoji do
emojis = emojis ++ regional_indicators
for emoji <- emojis do
- def is_unicode_emoji?(unquote(emoji)), do: true
+ def unicode?(unquote(emoji)), do: true
+ end
+
+ def unicode?(_), do: false
+
+ @emoji_regex ~r/:[A-Za-z0-9_-]+(@.+)?:/
+
+ def custom?(s) when is_binary(s), do: Regex.match?(@emoji_regex, s)
+
+ def custom?(_), do: false
+
+ def maybe_strip_name(name) when is_binary(name), do: String.trim(name, ":")
+
+ def maybe_strip_name(name), do: name
+
+ def maybe_quote(name) when is_binary(name) do
+ if unicode?(name) do
+ name
+ else
+ if String.starts_with?(name, ":") do
+ name
+ else
+ ":#{name}:"
+ end
+ end
end
- def is_unicode_emoji?(_), do: false
+ def maybe_quote(name), do: name
+
+ def emoji_url(%{"type" => "EmojiReact", "content" => _, "tag" => []}), do: nil
+
+ def emoji_url(%{"type" => "EmojiReact", "content" => emoji, "tag" => tags}) do
+ emoji = maybe_strip_name(emoji)
+
+ tag =
+ tags
+ |> Enum.find(fn tag ->
+ tag["type"] == "Emoji" && !is_nil(tag["name"]) && tag["name"] == emoji
+ end)
+
+ if is_nil(tag) do
+ nil
+ else
+ tag
+ |> Map.get("icon")
+ |> Map.get("url")
+ end
+ end
+
+ def emoji_url(_), do: nil
+
+ def emoji_name_with_instance(name, url) do
+ url = url |> URI.parse() |> Map.get(:host)
+ "#{name}@#{url}"
+ end
emoji_qualification_map =
emojis
diff --git a/lib/pleroma/emoji/combinations.ex b/lib/pleroma/emoji/combinations.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/emoji/formatter.ex b/lib/pleroma/emoji/formatter.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/emoji/loader.ex b/lib/pleroma/emoji/loader.ex
old mode 100755
new mode 100644
index 97d4b8f..b6e5443
--- a/lib/pleroma/emoji/loader.ex
+++ b/lib/pleroma/emoji/loader.ex
@@ -15,8 +15,6 @@ defmodule Pleroma.Emoji.Loader do
require Logger
- @mix_env Mix.env()
-
@type pattern :: Regex.t() | module() | String.t()
@type patterns :: pattern() | [pattern()]
@type group_patterns :: keyword(patterns())
@@ -59,7 +57,7 @@ defmodule Pleroma.Emoji.Loader do
Logger.info("Found emoji packs: #{Enum.join(packs, ", ")}")
if not Enum.empty?(files) do
- Logger.warn(
+ Logger.warning(
"Found files in the emoji folder. These will be ignored, please move them to a subdirectory\nFound files: #{Enum.join(files, ", ")}"
)
end
@@ -79,7 +77,7 @@ defmodule Pleroma.Emoji.Loader do
# for testing emoji.txt entries we do not want exposed in normal operation
test_emoji =
- if @mix_env == :test do
+ if Application.get_env(:pleroma, __MODULE__)[:test_emoji] do
load_from_file("test/config/emoji.txt", emoji_groups)
else
[]
diff --git a/lib/pleroma/emoji/pack.ex b/lib/pleroma/emoji/pack.ex
old mode 100755
new mode 100644
index 6e58f88..afc3418
--- a/lib/pleroma/emoji/pack.ex
+++ b/lib/pleroma/emoji/pack.ex
@@ -100,7 +100,7 @@ defmodule Pleroma.Emoji.Pack do
{:ok, _emoji_files} =
:zip.unzip(
to_charlist(file.path),
- [{:file_list, Enum.map(emojies, & &1[:path])}, {:cwd, tmp_dir}]
+ [{:file_list, Enum.map(emojies, & &1[:path])}, {:cwd, String.to_charlist(tmp_dir)}]
)
{_, updated_pack} =
@@ -209,7 +209,9 @@ defmodule Pleroma.Emoji.Pack do
with :ok <- validate_shareable_packs_available(uri) do
uri
- |> URI.merge("/api/pleroma/emoji/packs?page=#{opts[:page]}&page_size=#{opts[:page_size]}")
+ |> URI.merge(
+ "/api/v1/pleroma/emoji/packs?page=#{opts[:page]}&page_size=#{opts[:page_size]}"
+ )
|> http_get()
end
end
@@ -249,8 +251,12 @@ defmodule Pleroma.Emoji.Pack do
uri = url |> String.trim() |> URI.parse()
with :ok <- validate_shareable_packs_available(uri),
+ {:ok, %{"files_count" => files_count}} <-
+ uri |> URI.merge("/api/v1/pleroma/emoji/pack?name=#{name}&page_size=0") |> http_get(),
{:ok, remote_pack} <-
- uri |> URI.merge("/api/pleroma/emoji/pack?name=#{name}") |> http_get(),
+ uri
+ |> URI.merge("/api/v1/pleroma/emoji/pack?name=#{name}&page_size=#{files_count}")
+ |> http_get(),
{:ok, %{sha: sha, url: url} = pack_info} <- fetch_pack_info(remote_pack, uri, name),
{:ok, archive} <- download_archive(url, sha),
pack <- copy_as(remote_pack, as || name),
@@ -592,7 +598,7 @@ defmodule Pleroma.Emoji.Pack do
{:ok,
%{
sha: sha,
- url: URI.merge(uri, "/api/pleroma/emoji/packs/archive?name=#{name}") |> to_string()
+ url: URI.merge(uri, "/api/v1/pleroma/emoji/packs/archive?name=#{name}") |> to_string()
}}
%{"fallback-src" => src, "fallback-src-sha256" => sha} when is_binary(src) ->
diff --git a/lib/pleroma/filter.ex b/lib/pleroma/filter.ex
old mode 100755
new mode 100644
index db88bc0..e827d3c
--- a/lib/pleroma/filter.ex
+++ b/lib/pleroma/filter.ex
@@ -216,9 +216,6 @@ defmodule Pleroma.Filter do
:re ->
~r/\b#{phrases}\b/i
-
- _ ->
- nil
end
end
diff --git a/lib/pleroma/following_relationship.ex b/lib/pleroma/following_relationship.ex
old mode 100755
new mode 100644
index 15664c8..f38c2fc
--- a/lib/pleroma/following_relationship.ex
+++ b/lib/pleroma/following_relationship.ex
@@ -241,13 +241,13 @@ defmodule Pleroma.FollowingRelationship do
end
@doc """
- For a query with joined activity,
- keeps rows where activity's actor is followed by user -or- is NOT domain-blocked by user.
+ For a query with joined activity's actor,
+ keeps rows where actor is followed by user -or- is NOT domain-blocked by user.
"""
def keep_following_or_not_domain_blocked(query, user) do
where(
query,
- [_, activity],
+ [_, user_actor: user_actor],
fragment(
# "(actor's domain NOT in domain_blocks) OR (actor IS in followed AP IDs)"
"""
@@ -255,9 +255,9 @@ defmodule Pleroma.FollowingRelationship do
? = ANY(SELECT ap_id FROM users AS u INNER JOIN following_relationships AS fr
ON u.id = fr.following_id WHERE fr.follower_id = ? AND fr.state = ?)
""",
- activity.actor,
+ user_actor.ap_id,
^user.domain_blocks,
- activity.actor,
+ user_actor.ap_id,
^User.binary_id(user.id),
^accept_state_code()
)
diff --git a/lib/pleroma/formatter.ex b/lib/pleroma/formatter.ex
old mode 100755
new mode 100644
index a46c3e3..11d5af2
--- a/lib/pleroma/formatter.ex
+++ b/lib/pleroma/formatter.ex
@@ -124,7 +124,7 @@ defmodule Pleroma.Formatter do
end
def markdown_to_html(text) do
- Earmark.as_html!(text, %Earmark.Options{compact_output: true})
+ Earmark.as_html!(text, %Earmark.Options{compact_output: true, smartypants: false})
end
def html_escape({text, mentions, hashtags}, type) do
diff --git a/lib/pleroma/frontend.ex b/lib/pleroma/frontend.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/gopher/server.ex b/lib/pleroma/gopher/server.ex
old mode 100755
new mode 100644
index 0fde0ad..54245c9
--- a/lib/pleroma/gopher/server.ex
+++ b/lib/pleroma/gopher/server.ex
@@ -114,7 +114,7 @@ defmodule Pleroma.Gopher.Server.ProtocolHandler do
def response("/notices/" <> id) do
with %Activity{} = activity <- Activity.get_by_id(id),
- true <- Visibility.is_public?(activity) do
+ true <- Visibility.public?(activity) do
activities =
ActivityPub.fetch_activities_for_context(activity.data["context"])
|> render_activities
diff --git a/lib/pleroma/gun.ex b/lib/pleroma/gun.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/gun/api.ex b/lib/pleroma/gun/api.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/gun/conn.ex b/lib/pleroma/gun/conn.ex
old mode 100755
new mode 100644
index 7c5785d..804cd11
--- a/lib/pleroma/gun/conn.ex
+++ b/lib/pleroma/gun/conn.ex
@@ -56,7 +56,7 @@ defmodule Pleroma.Gun.Conn do
{:ok, conn, protocol}
else
error ->
- Logger.warn(
+ Logger.warning(
"Opening proxied connection to #{compose_uri_log(uri)} failed with error #{inspect(error)}"
)
@@ -90,7 +90,7 @@ defmodule Pleroma.Gun.Conn do
{:ok, conn, protocol}
else
error ->
- Logger.warn(
+ Logger.warning(
"Opening socks proxied connection to #{compose_uri_log(uri)} failed with error #{inspect(error)}"
)
@@ -106,7 +106,7 @@ defmodule Pleroma.Gun.Conn do
{:ok, conn, protocol}
else
error ->
- Logger.warn(
+ Logger.warning(
"Opening connection to #{compose_uri_log(uri)} failed with error #{inspect(error)}"
)
diff --git a/lib/pleroma/gun/connection_pool.ex b/lib/pleroma/gun/connection_pool.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/gun/connection_pool/reclaimer.ex b/lib/pleroma/gun/connection_pool/reclaimer.ex
old mode 100755
new mode 100644
index efd5c9f..35e7f4b
--- a/lib/pleroma/gun/connection_pool/reclaimer.ex
+++ b/lib/pleroma/gun/connection_pool/reclaimer.ex
@@ -9,7 +9,7 @@ defmodule Pleroma.Gun.ConnectionPool.Reclaimer do
def start_monitor do
pid =
- case :gen_server.start(__MODULE__, [], name: {:via, Registry, {registry(), "reclaimer"}}) do
+ case GenServer.start_link(__MODULE__, [], name: {:via, Registry, {registry(), "reclaimer"}}) do
{:ok, pid} ->
pid
diff --git a/lib/pleroma/gun/connection_pool/worker.ex b/lib/pleroma/gun/connection_pool/worker.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/gun/connection_pool/worker_supervisor.ex b/lib/pleroma/gun/connection_pool/worker_supervisor.ex
old mode 100755
new mode 100644
index d26a70b..eb83962
--- a/lib/pleroma/gun/connection_pool/worker_supervisor.ex
+++ b/lib/pleroma/gun/connection_pool/worker_supervisor.ex
@@ -18,10 +18,12 @@ defmodule Pleroma.Gun.ConnectionPool.WorkerSupervisor do
)
end
- def start_worker(opts, retry \\ false) do
+ def start_worker(opts, last_attempt \\ false) do
case DynamicSupervisor.start_child(__MODULE__, {Pleroma.Gun.ConnectionPool.Worker, opts}) do
{:error, :max_children} ->
- if retry or free_pool() == :error do
+ funs = [fn -> last_attempt end, fn -> match?(:error, free_pool()) end]
+
+ if Enum.any?(funs, fn fun -> fun.() end) do
:telemetry.execute([:pleroma, :connection_pool, :provision_failure], %{opts: opts})
{:error, :pool_full}
else
diff --git a/lib/pleroma/hashtag.ex b/lib/pleroma/hashtag.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/healthcheck.ex b/lib/pleroma/healthcheck.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/helpers/auth_helper.ex b/lib/pleroma/helpers/auth_helper.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/helpers/inet_helper.ex b/lib/pleroma/helpers/inet_helper.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/helpers/media_helper.ex b/lib/pleroma/helpers/media_helper.ex
old mode 100755
new mode 100644
index 24c845f..e44114d
--- a/lib/pleroma/helpers/media_helper.ex
+++ b/lib/pleroma/helpers/media_helper.ex
@@ -8,11 +8,14 @@ defmodule Pleroma.Helpers.MediaHelper do
"""
alias Pleroma.HTTP
+ alias Vix.Vips.Operation
require Logger
+ @cachex Pleroma.Config.get([:cachex, :provider], Cachex)
+
def missing_dependencies do
- Enum.reduce([imagemagick: "convert", ffmpeg: "ffmpeg"], [], fn {sym, executable}, acc ->
+ Enum.reduce([ffmpeg: "ffmpeg"], [], fn {sym, executable}, acc ->
if Pleroma.Utils.command_available?(executable) do
acc
else
@@ -22,141 +25,63 @@ defmodule Pleroma.Helpers.MediaHelper do
end
def image_resize(url, options) do
- with executable when is_binary(executable) <- System.find_executable("convert"),
- {:ok, args} <- prepare_image_resize_args(options),
- {:ok, env} <- HTTP.get(url, [], pool: :media),
- {:ok, fifo_path} <- mkfifo() do
- args = List.flatten([fifo_path, args])
- run_fifo(fifo_path, env, executable, args)
+ with {:ok, env} <- HTTP.get(url, [], pool: :media),
+ {:ok, resized} <-
+ Operation.thumbnail_buffer(env.body, options.max_width,
+ height: options.max_height,
+ size: :VIPS_SIZE_DOWN
+ ) do
+ if options[:format] == "png" do
+ Operation.pngsave_buffer(resized, Q: options[:quality])
+ else
+ Operation.jpegsave_buffer(resized, Q: options[:quality], interlace: true)
+ end
else
- nil -> {:error, {:convert, :command_not_found}}
{:error, _} = error -> error
end
end
- defp prepare_image_resize_args(
- %{max_width: max_width, max_height: max_height, format: "png"} = options
- ) do
- quality = options[:quality] || 85
- resize = Enum.join([max_width, "x", max_height, ">"])
-
- args = [
- "-resize",
- resize,
- "-quality",
- to_string(quality),
- "png:-"
- ]
-
- {:ok, args}
- end
-
- defp prepare_image_resize_args(%{max_width: max_width, max_height: max_height} = options) do
- quality = options[:quality] || 85
- resize = Enum.join([max_width, "x", max_height, ">"])
-
- args = [
- "-interlace",
- "Plane",
- "-resize",
- resize,
- "-quality",
- to_string(quality),
- "jpg:-"
- ]
-
- {:ok, args}
- end
-
- defp prepare_image_resize_args(_), do: {:error, :missing_options}
-
# Note: video thumbnail is intentionally not resized (always has original dimensions)
+ @spec video_framegrab(String.t()) :: {:ok, binary()} | {:error, any()}
def video_framegrab(url) do
with executable when is_binary(executable) <- System.find_executable("ffmpeg"),
+ false <- @cachex.exists?(:failed_media_helper_cache, url),
{:ok, env} <- HTTP.get(url, [], pool: :media),
- {:ok, fifo_path} <- mkfifo(),
- args = [
- "-y",
- "-i",
- fifo_path,
- "-vframes",
- "1",
- "-f",
- "mjpeg",
- "-loglevel",
- "error",
- "-"
- ] do
- run_fifo(fifo_path, env, executable, args)
+ {:ok, pid} <- StringIO.open(env.body) do
+ body_stream = IO.binstream(pid, 1)
+
+ task =
+ Task.async(fn ->
+ Exile.stream!(
+ [
+ executable,
+ "-i",
+ "pipe:0",
+ "-vframes",
+ "1",
+ "-f",
+ "mjpeg",
+ "pipe:1"
+ ],
+ input: body_stream,
+ ignore_epipe: true,
+ stderr: :disable
+ )
+ |> Enum.into(<<>>)
+ end)
+
+ case Task.yield(task, 5_000) do
+ nil ->
+ Task.shutdown(task)
+ @cachex.put(:failed_media_helper_cache, url, nil)
+ {:error, {:ffmpeg, :timeout}}
+
+ result ->
+ {:ok, result}
+ end
else
nil -> {:error, {:ffmpeg, :command_not_found}}
{:error, _} = error -> error
end
end
-
- defp run_fifo(fifo_path, env, executable, args) do
- pid =
- Port.open({:spawn_executable, executable}, [
- :use_stdio,
- :stream,
- :exit_status,
- :binary,
- args: args
- ])
-
- fifo = Port.open(to_charlist(fifo_path), [:eof, :binary, :stream, :out])
- fix = Pleroma.Helpers.QtFastStart.fix(env.body)
- true = Port.command(fifo, fix)
- :erlang.port_close(fifo)
- loop_recv(pid)
- after
- File.rm(fifo_path)
- end
-
- defp mkfifo do
- path = Path.join(System.tmp_dir!(), "pleroma-media-preview-pipe-#{Ecto.UUID.generate()}")
-
- case System.cmd("mkfifo", [path]) do
- {_, 0} ->
- spawn(fifo_guard(path))
- {:ok, path}
-
- {_, err} ->
- {:error, {:fifo_failed, err}}
- end
- end
-
- defp fifo_guard(path) do
- pid = self()
-
- fn ->
- ref = Process.monitor(pid)
-
- receive do
- {:DOWN, ^ref, :process, ^pid, _} ->
- File.rm(path)
- end
- end
- end
-
- defp loop_recv(pid) do
- loop_recv(pid, <<>>)
- end
-
- defp loop_recv(pid, acc) do
- receive do
- {^pid, {:data, data}} ->
- loop_recv(pid, acc <> data)
-
- {^pid, {:exit_status, 0}} ->
- {:ok, acc}
-
- {^pid, {:exit_status, status}} ->
- {:error, status}
- after
- 5000 ->
- :erlang.port_close(pid)
- {:error, :timeout}
- end
- end
end
diff --git a/lib/pleroma/helpers/qt_fast_start.ex b/lib/pleroma/helpers/qt_fast_start.ex
old mode 100755
new mode 100644
index 5711c71..0b200b2
--- a/lib/pleroma/helpers/qt_fast_start.ex
+++ b/lib/pleroma/helpers/qt_fast_start.ex
@@ -40,16 +40,21 @@ defmodule Pleroma.Helpers.QtFastStart do
got_mdat,
acc
) do
- full_size = (size - 8) * 8
- <> = rest
-
- acc = [
- {fourcc, pos, pos + size, size,
- <>}
- | acc
- ]
-
- fix(rest, pos + size, got_moov || fourcc == "moov", got_mdat || fourcc == "mdat", acc)
+ try do
+ full_size = (size - 8) * 8
+ <> = rest
+
+ acc = [
+ {fourcc, pos, pos + size, size,
+ <>}
+ | acc
+ ]
+
+ fix(rest, pos + size, got_moov || fourcc == "moov", got_mdat || fourcc == "mdat", acc)
+ rescue
+ _ ->
+ :abort
+ end
end
defp fix(<<>>, _pos, _, _, acc) do
@@ -121,9 +126,15 @@ defmodule Pleroma.Helpers.QtFastStart do
<>,
acc
) do
- rewrite_entries(unquote(size), offset, rest, [
- acc | <>
- ])
+ rewrite_entries(
+ unquote(size),
+ offset,
+ rest,
+ acc ++
+ [
+ <>
+ ]
+ )
end
end
diff --git a/lib/pleroma/helpers/uri_helper.ex b/lib/pleroma/helpers/uri_helper.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex
old mode 100755
new mode 100644
index 5bf735c..4de7cbb
--- a/lib/pleroma/html.ex
+++ b/lib/pleroma/html.ex
@@ -6,8 +6,6 @@ defmodule Pleroma.HTML do
# Scrubbers are compiled on boot so they can be configured in OTP releases
# @on_load :compile_scrubbers
- @cachex Pleroma.Config.get([:cachex, :provider], Cachex)
-
def compile_scrubbers do
dir = Path.join(:code.priv_dir(:pleroma), "scrubbers")
@@ -67,22 +65,9 @@ defmodule Pleroma.HTML do
end
end
- def extract_first_external_url_from_object(%{data: %{"content" => content}} = object)
+ @spec extract_first_external_url_from_object(Pleroma.Object.t()) :: String.t() | nil
+ def extract_first_external_url_from_object(%{data: %{"content" => content}})
when is_binary(content) do
- unless object.data["fake"] do
- key = "URL|#{object.id}"
-
- @cachex.fetch!(:scrubber_cache, key, fn _key ->
- {:commit, {:ok, extract_first_external_url(content)}}
- end)
- else
- {:ok, extract_first_external_url(content)}
- end
- end
-
- def extract_first_external_url_from_object(_), do: {:error, :no_content}
-
- def extract_first_external_url(content) do
content
|> Floki.parse_fragment!()
|> Floki.find("a:not(.mention,.hashtag,.attachment,[rel~=\"tag\"])")
@@ -90,4 +75,6 @@ defmodule Pleroma.HTML do
|> Floki.attribute("href")
|> Enum.at(0)
end
+
+ def extract_first_external_url_from_object(_), do: nil
end
diff --git a/lib/pleroma/http.ex b/lib/pleroma/http.ex
old mode 100755
new mode 100644
index 6c430fc..46fae92
--- a/lib/pleroma/http.ex
+++ b/lib/pleroma/http.ex
@@ -106,6 +106,10 @@ defmodule Pleroma.HTTP do
[Tesla.Middleware.FollowRedirects, Pleroma.Tesla.Middleware.ConnectionPool]
end
+ defp adapter_middlewares({Tesla.Adapter.Finch, _}) do
+ [Tesla.Middleware.FollowRedirects]
+ end
+
defp adapter_middlewares(Tesla.Adapter.Hackney) do
if Pleroma.Config.get([:http, :adapter, :follow_redirect]) != false do
[Tesla.Middleware.FollowRedirects]
diff --git a/lib/pleroma/http.ex.orig b/lib/pleroma/http.ex.orig
new file mode 100644
index 0000000..d582e5d
--- /dev/null
+++ b/lib/pleroma/http.ex.orig
@@ -0,0 +1,125 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2022 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.HTTP do
+ @moduledoc """
+ Wrapper for `Tesla.request/2`.
+ """
+
+ alias Pleroma.HTTP.AdapterHelper
+ alias Pleroma.HTTP.Request
+ alias Pleroma.HTTP.RequestBuilder, as: Builder
+ alias Tesla.Client
+ alias Tesla.Env
+
+ require Logger
+
+ @type t :: __MODULE__
+ @type method() :: :get | :post | :put | :delete | :head
+
+ @doc """
+ Performs GET request.
+
+ See `Pleroma.HTTP.request/5`
+ """
+ @spec get(Request.url() | nil, Request.headers(), keyword()) ::
+ nil | {:ok, Env.t()} | {:error, any()}
+ def get(url, headers \\ [], options \\ [])
+ def get(nil, _, _), do: nil
+ def get(url, headers, options), do: request(:get, url, "", headers, options)
+
+ @spec head(Request.url(), Request.headers(), keyword()) :: {:ok, Env.t()} | {:error, any()}
+ def head(url, headers \\ [], options \\ []), do: request(:head, url, "", headers, options)
+
+ @doc """
+ Performs POST request.
+
+ See `Pleroma.HTTP.request/5`
+ """
+ @spec post(Request.url(), String.t(), Request.headers(), keyword()) ::
+ {:ok, Env.t()} | {:error, any()}
+ def post(url, body, headers \\ [], options \\ []),
+ do: request(:post, url, body, headers, options)
+
+ @doc """
+ Builds and performs http request.
+
+ # Arguments:
+ `method` - :get, :post, :put, :delete, :head
+ `url` - full url
+ `body` - request body
+ `headers` - a keyworld list of headers, e.g. `[{"content-type", "text/plain"}]`
+ `options` - custom, per-request middleware or adapter options
+
+ # Returns:
+ `{:ok, %Tesla.Env{}}` or `{:error, error}`
+
+ """
+ @spec request(method(), Request.url(), String.t(), Request.headers(), keyword()) ::
+ {:ok, Env.t()} | {:error, any()}
+ def request(method, url, body, headers, options) when is_binary(url) do
+ uri = URI.parse(url)
+ adapter_opts = AdapterHelper.options(uri, options || [])
+
+ options = put_in(options[:adapter], adapter_opts)
+ params = options[:params] || []
+ request = build_request(method, headers, options, url, body, params)
+
+ adapter = Application.get_env(:tesla, :adapter)
+
+ client = Tesla.client(adapter_middlewares(adapter), adapter)
+
+ maybe_limit(
+ fn ->
+ request(client, request)
+ end,
+ adapter,
+ adapter_opts
+ )
+ end
+
+ @spec request(Client.t(), keyword()) :: {:ok, Env.t()} | {:error, any()}
+ def request(client, request), do: Tesla.request(client, request)
+
+ defp build_request(method, headers, options, url, body, params) do
+ Builder.new()
+ |> Builder.method(method)
+ |> Builder.headers(headers)
+ |> Builder.opts(options)
+ |> Builder.url(url)
+ |> Builder.add_param(:body, :body, body)
+ |> Builder.add_param(:query, :query, params)
+ |> Builder.convert_to_keyword()
+ end
+
+ @prefix Pleroma.Gun.ConnectionPool
+ defp maybe_limit(fun, Tesla.Adapter.Gun, opts) do
+ ConcurrentLimiter.limit(:"#{@prefix}.#{opts[:pool] || :default}", fun)
+ end
+
+ defp maybe_limit(fun, _, _) do
+ fun.()
+ end
+
+ defp adapter_middlewares(Tesla.Adapter.Gun) do
+ [Tesla.Middleware.FollowRedirects, Pleroma.Tesla.Middleware.ConnectionPool]
+ end
+
+ defp adapter_middlewares({Tesla.Adapter.Finch, _}) do
+ [Tesla.Middleware.FollowRedirects]
+ end
+
+ defp adapter_middlewares(Tesla.Adapter.Hackney) do
+ [Tesla.Middleware.FollowRedirects]
+ end
+
+ defp adapter_middlewares(_) do
+ if Pleroma.Config.get(:env) == :test do
+ # Emulate redirects in test env, which are handled by adapters in other environments
+ [Tesla.Middleware.FollowRedirects]
+ else
+ []
+ end
+ end
+end
diff --git a/lib/pleroma/http/adapter_helper.ex b/lib/pleroma/http/adapter_helper.ex
old mode 100755
new mode 100644
index 252a6ab..dcb27a2
--- a/lib/pleroma/http/adapter_helper.ex
+++ b/lib/pleroma/http/adapter_helper.ex
@@ -15,8 +15,8 @@ defmodule Pleroma.HTTP.AdapterHelper do
require Logger
@type proxy ::
- {Connection.host(), pos_integer()}
- | {Connection.proxy_type(), Connection.host(), pos_integer()}
+ {host(), pos_integer()}
+ | {proxy_type(), host(), pos_integer()}
@callback options(keyword(), URI.t()) :: keyword()
@@ -70,15 +70,15 @@ defmodule Pleroma.HTTP.AdapterHelper do
{:ok, parse_host(host), port}
else
{_, _} ->
- Logger.warn("Parsing port failed #{inspect(proxy)}")
+ Logger.warning("Parsing port failed #{inspect(proxy)}")
{:error, :invalid_proxy_port}
:error ->
- Logger.warn("Parsing port failed #{inspect(proxy)}")
+ Logger.warning("Parsing port failed #{inspect(proxy)}")
{:error, :invalid_proxy_port}
_ ->
- Logger.warn("Parsing proxy failed #{inspect(proxy)}")
+ Logger.warning("Parsing proxy failed #{inspect(proxy)}")
{:error, :invalid_proxy}
end
end
@@ -88,7 +88,7 @@ defmodule Pleroma.HTTP.AdapterHelper do
{:ok, type, parse_host(host), port}
else
_ ->
- Logger.warn("Parsing proxy failed #{inspect(proxy)}")
+ Logger.warning("Parsing proxy failed #{inspect(proxy)}")
{:error, :invalid_proxy}
end
end
diff --git a/lib/pleroma/http/adapter_helper/default.ex b/lib/pleroma/http/adapter_helper/default.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/http/adapter_helper/gun.ex b/lib/pleroma/http/adapter_helper/gun.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/http/adapter_helper/hackney.ex b/lib/pleroma/http/adapter_helper/hackney.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/http/ex_aws.ex b/lib/pleroma/http/ex_aws.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/http/request.ex b/lib/pleroma/http/request.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/http/request_builder.ex b/lib/pleroma/http/request_builder.ex
old mode 100755
new mode 100644
index f16fb3b..0a028a6
--- a/lib/pleroma/http/request_builder.ex
+++ b/lib/pleroma/http/request_builder.ex
@@ -54,12 +54,12 @@ defmodule Pleroma.HTTP.RequestBuilder do
@doc """
Add optional parameters to the request
"""
- @spec add_param(Request.t(), atom(), atom(), any()) :: Request.t()
+ @spec add_param(Request.t(), atom(), atom() | String.t(), any()) :: Request.t()
def add_param(request, :query, :query, values), do: %{request | query: values}
def add_param(request, :body, :body, value), do: %{request | body: value}
- def add_param(request, :body, key, value) do
+ def add_param(request, :body, key, value) when is_binary(key) do
request
|> Map.put(:body, Multipart.new())
|> Map.update!(
diff --git a/lib/pleroma/http/tzdata.ex b/lib/pleroma/http/tzdata.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/http/web_push.ex b/lib/pleroma/http/web_push.ex
old mode 100755
new mode 100644
index ca399b6..888079c
--- a/lib/pleroma/http/web_push.ex
+++ b/lib/pleroma/http/web_push.ex
@@ -6,7 +6,11 @@ defmodule Pleroma.HTTP.WebPush do
@moduledoc false
def post(url, payload, headers, options \\ []) do
- list_headers = Map.to_list(headers)
+ list_headers =
+ headers
+ |> Map.to_list()
+ |> Kernel.++([{"content-type", "octet-stream"}])
+
Pleroma.HTTP.post(url, payload, list_headers, options)
end
end
diff --git a/lib/pleroma/instances.ex b/lib/pleroma/instances.ex
old mode 100755
new mode 100644
index 782948f..b6d83f5
--- a/lib/pleroma/instances.ex
+++ b/lib/pleroma/instances.ex
@@ -7,16 +7,15 @@ defmodule Pleroma.Instances do
alias Pleroma.Instances.Instance
- def filter_reachable(urls_or_hosts), do: Instance.filter_reachable(urls_or_hosts)
+ defdelegate filter_reachable(urls_or_hosts), to: Instance
- def reachable?(url_or_host), do: Instance.reachable?(url_or_host)
+ defdelegate reachable?(url_or_host), to: Instance
- def set_reachable(url_or_host), do: Instance.set_reachable(url_or_host)
+ defdelegate set_reachable(url_or_host), to: Instance
- def set_unreachable(url_or_host, unreachable_since \\ nil),
- do: Instance.set_unreachable(url_or_host, unreachable_since)
+ defdelegate set_unreachable(url_or_host, unreachable_since \\ nil), to: Instance
- def get_consistently_unreachable, do: Instance.get_consistently_unreachable()
+ defdelegate get_consistently_unreachable, to: Instance
def set_consistently_unreachable(url_or_host),
do: set_unreachable(url_or_host, reachability_datetime_threshold())
diff --git a/lib/pleroma/instances/instance.ex b/lib/pleroma/instances/instance.ex
old mode 100755
new mode 100644
index a5529ad..c497a4f
--- a/lib/pleroma/instances/instance.ex
+++ b/lib/pleroma/instances/instance.ex
@@ -7,6 +7,7 @@ defmodule Pleroma.Instances.Instance do
alias Pleroma.Instances
alias Pleroma.Instances.Instance
+ alias Pleroma.Maps
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Workers.BackgroundWorker
@@ -24,6 +25,14 @@ defmodule Pleroma.Instances.Instance do
field(:favicon, :string)
field(:favicon_updated_at, :naive_datetime)
+ embeds_one :metadata, Pleroma.Instances.Metadata, primary_key: false do
+ field(:software_name, :string)
+ field(:software_version, :string)
+ field(:software_repository, :string)
+ end
+
+ field(:metadata_updated_at, :utc_datetime)
+
timestamps()
end
@@ -31,11 +40,17 @@ defmodule Pleroma.Instances.Instance do
def changeset(struct, params \\ %{}) do
struct
- |> cast(params, [:host, :unreachable_since, :favicon, :favicon_updated_at])
+ |> cast(params, __schema__(:fields) -- [:metadata])
+ |> cast_embed(:metadata, with: &metadata_changeset/2)
|> validate_required([:host])
|> unique_constraint(:host)
end
+ def metadata_changeset(struct, params \\ %{}) do
+ struct
+ |> cast(params, [:software_name, :software_version, :software_repository])
+ end
+
def filter_reachable([]), do: %{}
def filter_reachable(urls_or_hosts) when is_list(urls_or_hosts) do
@@ -82,13 +97,9 @@ defmodule Pleroma.Instances.Instance do
def reachable?(url_or_host) when is_binary(url_or_host), do: true
def set_reachable(url_or_host) when is_binary(url_or_host) do
- with host <- host(url_or_host),
- %Instance{} = existing_record <- Repo.get_by(Instance, %{host: host}) do
- {:ok, _instance} =
- existing_record
- |> changeset(%{unreachable_since: nil})
- |> Repo.update()
- end
+ %Instance{host: host(url_or_host)}
+ |> changeset(%{unreachable_since: nil})
+ |> Repo.insert(on_conflict: {:replace, [:unreachable_since]}, conflict_target: :host)
end
def set_reachable(_), do: {:error, nil}
@@ -162,7 +173,7 @@ defmodule Pleroma.Instances.Instance do
end
rescue
e ->
- Logger.warn("Instance.get_or_update_favicon(\"#{host}\") error: #{inspect(e)}")
+ Logger.warning("Instance.get_or_update_favicon(\"#{host}\") error: #{inspect(e)}")
nil
end
@@ -190,7 +201,7 @@ defmodule Pleroma.Instances.Instance do
end
rescue
e ->
- Logger.warn(
+ Logger.warning(
"Instance.scrape_favicon(\"#{to_string(instance_uri)}\") error: #{inspect(e)}"
)
@@ -198,6 +209,89 @@ defmodule Pleroma.Instances.Instance do
end
end
+ def get_or_update_metadata(%URI{host: host} = instance_uri) do
+ existing_record = Repo.get_by(Instance, %{host: host})
+ now = NaiveDateTime.utc_now()
+
+ if existing_record && existing_record.metadata_updated_at &&
+ NaiveDateTime.diff(now, existing_record.metadata_updated_at) < 86_400 do
+ existing_record.metadata
+ else
+ metadata = scrape_metadata(instance_uri)
+
+ if existing_record do
+ existing_record
+ |> changeset(%{metadata: metadata, metadata_updated_at: now})
+ |> Repo.update()
+ else
+ %Instance{}
+ |> changeset(%{host: host, metadata: metadata, metadata_updated_at: now})
+ |> Repo.insert()
+ end
+
+ metadata
+ end
+ end
+
+ defp get_nodeinfo_uri(well_known) do
+ links = Map.get(well_known, "links", [])
+
+ nodeinfo21 =
+ Enum.find(links, &(&1["rel"] == "http://nodeinfo.diaspora.software/ns/schema/2.1"))["href"]
+
+ nodeinfo20 =
+ Enum.find(links, &(&1["rel"] == "http://nodeinfo.diaspora.software/ns/schema/2.0"))["href"]
+
+ cond do
+ is_binary(nodeinfo21) -> {:ok, nodeinfo21}
+ is_binary(nodeinfo20) -> {:ok, nodeinfo20}
+ true -> {:error, :no_links}
+ end
+ end
+
+ defp scrape_metadata(%URI{} = instance_uri) do
+ try do
+ with {_, true} <- {:reachable, reachable?(instance_uri.host)},
+ {:ok, %Tesla.Env{body: well_known_body}} <-
+ instance_uri
+ |> URI.merge("/.well-known/nodeinfo")
+ |> to_string()
+ |> Pleroma.HTTP.get([{"accept", "application/json"}]),
+ {:ok, well_known_json} <- Jason.decode(well_known_body),
+ {:ok, nodeinfo_uri} <- get_nodeinfo_uri(well_known_json),
+ {:ok, %Tesla.Env{body: nodeinfo_body}} <-
+ Pleroma.HTTP.get(nodeinfo_uri, [{"accept", "application/json"}]),
+ {:ok, nodeinfo} <- Jason.decode(nodeinfo_body) do
+ # Can extract more metadata from NodeInfo but need to be careful about it's size,
+ # can't just dump the entire thing
+ software = Map.get(nodeinfo, "software", %{})
+
+ %{
+ software_name: software["name"],
+ software_version: software["version"]
+ }
+ |> Maps.put_if_present(:software_repository, software["repository"])
+ else
+ {:reachable, false} ->
+ Logger.debug(
+ "Instance.scrape_metadata(\"#{to_string(instance_uri)}\") ignored unreachable host"
+ )
+
+ nil
+
+ _ ->
+ nil
+ end
+ rescue
+ e ->
+ Logger.warning(
+ "Instance.scrape_metadata(\"#{to_string(instance_uri)}\") error: #{inspect(e)}"
+ )
+
+ nil
+ end
+ end
+
@doc """
Deletes all users from an instance in a background task, thus also deleting
all of those users' activities and notifications.
diff --git a/lib/pleroma/job_queue_monitor.ex b/lib/pleroma/job_queue_monitor.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/jwt.ex b/lib/pleroma/jwt.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/keys.ex b/lib/pleroma/keys.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/list.ex b/lib/pleroma/list.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/logging.ex b/lib/pleroma/logging.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/maintenance.ex b/lib/pleroma/maintenance.ex
old mode 100755
new mode 100644
index eb5a6ef..1e39b03
--- a/lib/pleroma/maintenance.ex
+++ b/lib/pleroma/maintenance.ex
@@ -20,7 +20,7 @@ defmodule Pleroma.Maintenance do
"full" ->
Logger.info("Running VACUUM FULL.")
- Logger.warn(
+ Logger.warning(
"Re-packing your entire database may take a while and will consume extra disk space during the process."
)
diff --git a/lib/pleroma/maps.ex b/lib/pleroma/maps.ex
old mode 100755
new mode 100644
index 6d586e5..5020a8f
--- a/lib/pleroma/maps.ex
+++ b/lib/pleroma/maps.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2022 Pleroma Authors
+# Copyright © 2017-2024 Pleroma Authors
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Maps do
@@ -18,4 +18,17 @@ defmodule Pleroma.Maps do
rescue
_ -> data
end
+
+ def filter_empty_values(data) do
+ # TODO: Change to Map.filter in Elixir 1.13+
+ data
+ |> Enum.filter(fn
+ {_k, nil} -> false
+ {_k, ""} -> false
+ {_k, []} -> false
+ {_k, %{} = v} -> Map.keys(v) != []
+ {_k, _v} -> true
+ end)
+ |> Map.new()
+ end
end
diff --git a/lib/pleroma/marker.ex b/lib/pleroma/marker.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/mfa.ex b/lib/pleroma/mfa.ex
old mode 100755
new mode 100644
index 01b730c..ce30cd4
--- a/lib/pleroma/mfa.ex
+++ b/lib/pleroma/mfa.ex
@@ -77,7 +77,7 @@ defmodule Pleroma.MFA do
{:ok, codes}
else
{:error, msg} ->
- %{error: msg}
+ {:error, msg}
end
end
diff --git a/lib/pleroma/mfa/backup_codes.ex b/lib/pleroma/mfa/backup_codes.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/mfa/changeset.ex b/lib/pleroma/mfa/changeset.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/mfa/settings.ex b/lib/pleroma/mfa/settings.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/mfa/token.ex b/lib/pleroma/mfa/token.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/mfa/totp.ex b/lib/pleroma/mfa/totp.ex
old mode 100755
new mode 100644
index 429c4b7..96fa8d7
--- a/lib/pleroma/mfa/totp.ex
+++ b/lib/pleroma/mfa/totp.ex
@@ -14,6 +14,7 @@ defmodule Pleroma.MFA.TOTP do
@doc """
https://github.com/google/google-authenticator/wiki/Key-Uri-Format
"""
+ @spec provisioning_uri(String.t(), String.t(), list()) :: String.t()
def provisioning_uri(secret, label, opts \\ []) do
query =
%{
@@ -27,7 +28,7 @@ defmodule Pleroma.MFA.TOTP do
|> URI.encode_query()
%URI{scheme: "otpauth", host: "totp", path: "/" <> label, query: query}
- |> URI.to_string()
+ |> to_string()
end
defp default_period, do: Config.get(@config_ns ++ [:period])
diff --git a/lib/pleroma/migration_helper/notification_backfill.ex b/lib/pleroma/migration_helper/notification_backfill.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/migrators/context_objects_deletion_migrator.ex b/lib/pleroma/migrators/context_objects_deletion_migrator.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/migrators/hashtags_table_migrator.ex b/lib/pleroma/migrators/hashtags_table_migrator.ex
old mode 100755
new mode 100644
index dca4bfa..bd4dd2f
--- a/lib/pleroma/migrators/hashtags_table_migrator.ex
+++ b/lib/pleroma/migrators/hashtags_table_migrator.ex
@@ -100,7 +100,7 @@ defmodule Pleroma.Migrators.HashtagsTableMigrator do
|> where([_o, hashtags_objects], is_nil(hashtags_objects.object_id))
end
- @spec transfer_object_hashtags(Map.t()) :: {:noop | :ok | :error, integer()}
+ @spec transfer_object_hashtags(map()) :: {:noop | :ok | :error, integer()}
defp transfer_object_hashtags(object) do
embedded_tags = if Map.has_key?(object, :tag), do: object.tag, else: object.data["tag"]
hashtags = Object.object_data_hashtags(%{"tag" => embedded_tags})
diff --git a/lib/pleroma/migrators/support/base_migrator.ex b/lib/pleroma/migrators/support/base_migrator.ex
old mode 100755
new mode 100644
index 3bcd59f..76a5d45
--- a/lib/pleroma/migrators/support/base_migrator.ex
+++ b/lib/pleroma/migrators/support/base_migrator.ex
@@ -73,7 +73,7 @@ defmodule Pleroma.Migrators.Support.BaseMigrator do
data_migration.state == :manual or data_migration.name in manual_migrations ->
message = "Data migration is in manual execution or manual fix mode."
update_status(:manual, message)
- Logger.warn("#{__MODULE__}: #{message}")
+ Logger.warning("#{__MODULE__}: #{message}")
data_migration.state == :complete ->
on_complete(data_migration)
@@ -109,7 +109,7 @@ defmodule Pleroma.Migrators.Support.BaseMigrator do
Putting data migration to manual fix mode. Try running `#{__MODULE__}.retry_failed/0`.
"""
- Logger.warn("#{__MODULE__}: #{message}")
+ Logger.warning("#{__MODULE__}: #{message}")
update_status(:manual, message)
on_complete(data_migration())
@@ -125,7 +125,7 @@ defmodule Pleroma.Migrators.Support.BaseMigrator do
defp on_complete(data_migration) do
if data_migration.feature_lock || feature_state() == :disabled do
- Logger.warn(
+ Logger.warning(
"#{__MODULE__}: migration complete but feature is locked; consider enabling."
)
@@ -188,10 +188,11 @@ defmodule Pleroma.Migrators.Support.BaseMigrator do
end
defp fault_rate do
- with failures_count when is_integer(failures_count) <- failures_count() do
+ with failures_count when is_integer(failures_count) <- failures_count(),
+ true <- failures_count > 0 do
failures_count / Enum.max([get_stat(:affected_count, 0), 1])
else
- _ -> :error
+ _ -> 0
end
end
diff --git a/lib/pleroma/migrators/support/base_migrator_state.ex b/lib/pleroma/migrators/support/base_migrator_state.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/moderation_log.ex b/lib/pleroma/moderation_log.ex
old mode 100755
new mode 100644
index 7203423..5c3ca58
--- a/lib/pleroma/moderation_log.ex
+++ b/lib/pleroma/moderation_log.ex
@@ -121,7 +121,7 @@ defmodule Pleroma.ModerationLog do
defp prepare_log_data(attrs), do: attrs
- @spec insert_log(log_params()) :: {:ok, ModerationLog} | {:error, any}
+ @spec insert_log(log_params()) :: {:ok, ModerationLog.t()} | {:error, any}
def insert_log(%{actor: %User{}, subject: subjects, permission: permission} = attrs) do
data =
attrs
@@ -248,7 +248,8 @@ defmodule Pleroma.ModerationLog do
|> insert_log_entry_with_message()
end
- @spec insert_log_entry_with_message(ModerationLog) :: {:ok, ModerationLog} | {:error, any}
+ @spec insert_log_entry_with_message(ModerationLog.t()) ::
+ {:ok, ModerationLog.t()} | {:error, any}
defp insert_log_entry_with_message(entry) do
entry.data["message"]
|> put_in(get_log_entry_message(entry))
diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex
old mode 100755
new mode 100644
index 48d467c..710b198
--- a/lib/pleroma/notification.ex
+++ b/lib/pleroma/notification.ex
@@ -88,7 +88,7 @@ defmodule Pleroma.Notification do
where: q.seen == true,
select: type(q.id, :string),
limit: 1,
- order_by: [desc: :id]
+ order_by: fragment("? desc nulls last", q.id)
)
end
@@ -137,7 +137,7 @@ defmodule Pleroma.Notification do
blocked_ap_ids = opts[:blocked_users_ap_ids] || User.blocked_users_ap_ids(user)
query
- |> where([n, a], a.actor not in ^blocked_ap_ids)
+ |> where([..., user_actor: user_actor], user_actor.ap_id not in ^blocked_ap_ids)
|> FollowingRelationship.keep_following_or_not_domain_blocked(user)
end
@@ -148,7 +148,7 @@ defmodule Pleroma.Notification do
blocker_ap_ids = User.incoming_relationships_ungrouped_ap_ids(user, [:block])
query
- |> where([n, a], a.actor not in ^blocker_ap_ids)
+ |> where([..., user_actor: user_actor], user_actor.ap_id not in ^blocker_ap_ids)
end
end
@@ -161,7 +161,7 @@ defmodule Pleroma.Notification do
opts[:notification_muted_users_ap_ids] || User.notification_muted_users_ap_ids(user)
query
- |> where([n, a], a.actor not in ^notification_muted_ap_ids)
+ |> where([..., user_actor: user_actor], user_actor.ap_id not in ^notification_muted_ap_ids)
|> join(:left, [n, a], tm in ThreadMute,
on: tm.user_id == ^user.id and tm.context == fragment("?->>'context'", a.data),
as: :thread_mute
diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex
old mode 100755
new mode 100644
index 38accae..55b646b
--- a/lib/pleroma/object.ex
+++ b/lib/pleroma/object.ex
@@ -177,7 +177,10 @@ defmodule Pleroma.Object do
ap_id
Keyword.get(options, :fetch) ->
- Fetcher.fetch_object_from_id!(ap_id, options)
+ case Fetcher.fetch_object_from_id(ap_id, options) do
+ {:ok, object} -> object
+ _ -> nil
+ end
true ->
get_cached_by_ap_id(ap_id)
@@ -239,17 +242,17 @@ defmodule Pleroma.Object do
{:ok, _} <- invalid_object_cache(object) do
cleanup_attachments(
Config.get([:instance, :cleanup_attachments]),
- %{"object" => object}
+ object
)
{:ok, object, deleted_activity}
end
end
- @spec cleanup_attachments(boolean(), %{required(:object) => map()}) ::
+ @spec cleanup_attachments(boolean(), Object.t()) ::
{:ok, Oban.Job.t() | nil}
- def cleanup_attachments(true, %{"object" => _} = params) do
- AttachmentsCleanupWorker.enqueue("cleanup_attachments", params)
+ def cleanup_attachments(true, %Object{} = object) do
+ AttachmentsCleanupWorker.enqueue("cleanup_attachments", %{"object" => object})
end
def cleanup_attachments(_, _), do: {:ok, nil}
@@ -328,6 +331,52 @@ defmodule Pleroma.Object do
end
end
+ def increase_quotes_count(ap_id) do
+ Object
+ |> where([o], fragment("?->>'id' = ?::text", o.data, ^to_string(ap_id)))
+ |> update([o],
+ set: [
+ data:
+ fragment(
+ """
+ safe_jsonb_set(?, '{quotesCount}',
+ (coalesce((?->>'quotesCount')::int, 0) + 1)::varchar::jsonb, true)
+ """,
+ o.data,
+ o.data
+ )
+ ]
+ )
+ |> Repo.update_all([])
+ |> case do
+ {1, [object]} -> set_cache(object)
+ _ -> {:error, "Not found"}
+ end
+ end
+
+ def decrease_quotes_count(ap_id) do
+ Object
+ |> where([o], fragment("?->>'id' = ?::text", o.data, ^to_string(ap_id)))
+ |> update([o],
+ set: [
+ data:
+ fragment(
+ """
+ safe_jsonb_set(?, '{quotesCount}',
+ (greatest(0, (?->>'quotesCount')::int - 1))::varchar::jsonb, true)
+ """,
+ o.data,
+ o.data
+ )
+ ]
+ )
+ |> Repo.update_all([])
+ |> case do
+ {1, [object]} -> set_cache(object)
+ _ -> {:error, "Not found"}
+ end
+ end
+
def increase_vote_count(ap_id, name, actor) do
with %Object{} = object <- Object.normalize(ap_id, fetch: false),
"Question" <- object.data["type"] do
@@ -425,4 +474,30 @@ defmodule Pleroma.Object do
end
def object_data_hashtags(_), do: []
+
+ def get_emoji_reactions(object) do
+ reactions = object.data["reactions"]
+
+ if is_list(reactions) or is_map(reactions) do
+ reactions
+ |> Enum.map(fn
+ [_emoji, users, _maybe_url] = item when is_list(users) ->
+ item
+
+ [emoji, users] when is_list(users) ->
+ [emoji, users, nil]
+
+ # This case is here to process the Map situation, which will happen
+ # only with the legacy two-value format.
+ {emoji, users} when is_list(users) ->
+ [emoji, users, nil]
+
+ _ ->
+ nil
+ end)
+ |> Enum.reject(&is_nil/1)
+ else
+ []
+ end
+ end
end
diff --git a/lib/pleroma/object/containment.ex b/lib/pleroma/object/containment.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex
old mode 100755
new mode 100644
index cc37725..2350664
--- a/lib/pleroma/object/fetcher.ex
+++ b/lib/pleroma/object/fetcher.ex
@@ -3,9 +3,11 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Object.Fetcher do
+ @behaviour HTTPSignatures.Adapter
alias Pleroma.HTTP
alias Pleroma.Instances
alias Pleroma.Maps
+ alias Pleroma.Keys
alias Pleroma.Object
alias Pleroma.Object.Containment
alias Pleroma.Signature
@@ -72,20 +74,25 @@ defmodule Pleroma.Object.Fetcher do
{:object, data, Object.normalize(activity, fetch: false)} do
{:ok, object}
else
- {:allowed_depth, false} ->
- {:error, "Max thread distance exceeded."}
+ {:allowed_depth, false} = e ->
+ log_fetch_error(id, e)
+ {:error, :allowed_depth}
- {:containment, _} ->
- {:error, "Object containment failed."}
+ {:containment, reason} = e ->
+ log_fetch_error(id, e)
+ {:error, reason}
- {:transmogrifier, {:error, {:reject, e}}} ->
- {:reject, e}
+ {:transmogrifier, {:error, {:reject, reason}}} = e ->
+ log_fetch_error(id, e)
+ {:reject, reason}
- {:transmogrifier, {:reject, e}} ->
- {:reject, e}
+ {:transmogrifier, {:reject, reason}} = e ->
+ log_fetch_error(id, e)
+ {:reject, reason}
- {:transmogrifier, _} = e ->
- {:error, e}
+ {:transmogrifier, reason} = e ->
+ log_fetch_error(id, e)
+ {:error, reason}
{:object, data, nil} ->
reinject_object(%Object{}, data)
@@ -96,14 +103,21 @@ defmodule Pleroma.Object.Fetcher do
{:fetch_object, %Object{} = object} ->
{:ok, object}
- {:fetch, {:error, error}} ->
- {:error, error}
+ {:fetch, {:error, reason}} = e ->
+ log_fetch_error(id, e)
+ {:error, reason}
e ->
- e
+ log_fetch_error(id, e)
+ {:error, e}
end
end
+ defp log_fetch_error(id, error) do
+ Logger.metadata(object: id)
+ Logger.error("Object rejected while fetching #{id} #{inspect(error)}")
+ end
+
defp prepare_activity_params(data) do
%{
"type" => "Create",
@@ -117,36 +131,34 @@ defmodule Pleroma.Object.Fetcher do
|> Maps.put_if_present("bcc", data["bcc"])
end
- def fetch_object_from_id!(id, options \\ []) do
- with {:ok, object} <- fetch_object_from_id(id, options) do
- object
- else
- {:error, %Tesla.Mock.Error{}} ->
- nil
-
- {:error, "Object has been deleted"} ->
- nil
-
- {:reject, reason} ->
- Logger.info("Rejected #{id} while fetching: #{inspect(reason)}")
- nil
-
- e ->
- Logger.error("Error while fetching #{id}: #{inspect(e)}")
- nil
- end
- end
-
defp make_signature(id, date) do
uri = URI.parse(id)
- signature =
+ spoofed_pem = Pleroma.Config.get([:activitypub, :spoofed_key])
+ # workaround for syntax shite disallowing me from defining signature in "if" block
+ spoofed_key = if Pleroma.Config.get([:activitypub, :spoof_object_fetch_signatures]) do
+ with {:ok, private_key, _} <- Keys.keys_from_pem(spoofed_pem) do
+ private_key
+ end
+ else
+ ""
+ end
+ spoofed_instance = Pleroma.Config.get([:activitypub, :spoofed_instance])
+
+ signature = if Pleroma.Config.get([:activitypub, :spoof_object_fetch_signatures]) do
+ HTTPSignatures.sign(spoofed_key, spoofed_instance <> "/internal/fetch#main-key", %{
+ "(request-target)": "get #{uri.path}",
+ host: uri.host,
+ date: date
+ })
+ else
InternalFetchActor.get_actor()
|> Signature.sign(%{
"(request-target)": "get #{uri.path}",
host: uri.host,
date: date
})
+ end
{"signature", signature}
end
@@ -227,8 +239,11 @@ defmodule Pleroma.Object.Fetcher do
{:error, {:content_type, nil}}
end
+ {:ok, %{status: code}} when code in [401, 403] ->
+ {:error, :forbidden}
+
{:ok, %{status: code}} when code in [404, 410] ->
- {:error, "Object has been deleted"}
+ {:error, :not_found}
{:error, e} ->
{:error, e}
diff --git a/lib/pleroma/object/fetcher.ex.orig b/lib/pleroma/object/fetcher.ex.orig
new file mode 100644
index 0000000..af5642a
--- /dev/null
+++ b/lib/pleroma/object/fetcher.ex.orig
@@ -0,0 +1,238 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2022 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Object.Fetcher do
+ alias Pleroma.HTTP
+ alias Pleroma.Instances
+ alias Pleroma.Maps
+ alias Pleroma.Object
+ alias Pleroma.Object.Containment
+ alias Pleroma.Signature
+ alias Pleroma.Web.ActivityPub.InternalFetchActor
+ alias Pleroma.Web.ActivityPub.MRF
+ alias Pleroma.Web.ActivityPub.ObjectValidator
+ alias Pleroma.Web.ActivityPub.Pipeline
+ alias Pleroma.Web.ActivityPub.Transmogrifier
+ alias Pleroma.Web.Federator
+
+ require Logger
+ require Pleroma.Constants
+
+ @spec reinject_object(struct(), map()) :: {:ok, Object.t()} | {:error, any()}
+ defp reinject_object(%Object{data: %{}} = object, new_data) do
+ Logger.debug("Reinjecting object #{new_data["id"]}")
+
+ with {:ok, new_data, _} <- ObjectValidator.validate(new_data, %{}),
+ {:ok, new_data} <- MRF.filter(new_data),
+ {:ok, new_object, _} <-
+ Object.Updater.do_update_and_invalidate_cache(
+ object,
+ new_data,
+ _touch_changeset? = true
+ ) do
+ {:ok, new_object}
+ else
+ e ->
+ Logger.error("Error while processing object: #{inspect(e)}")
+ {:error, e}
+ end
+ end
+
+ defp reinject_object(_, new_data) do
+ with {:ok, object, _} <- Pipeline.common_pipeline(new_data, local: false) do
+ {:ok, object}
+ else
+ e -> e
+ end
+ end
+
+ def refetch_object(%Object{data: %{"id" => id}} = object) do
+ with {:local, false} <- {:local, Object.local?(object)},
+ {:ok, new_data} <- fetch_and_contain_remote_object_from_id(id),
+ {:ok, object} <- reinject_object(object, new_data) do
+ {:ok, object}
+ else
+ {:local, true} -> {:ok, object}
+ e -> {:error, e}
+ end
+ end
+
+ # Note: will create a Create activity, which we need internally at the moment.
+ def fetch_object_from_id(id, options \\ []) do
+ with {_, nil} <- {:fetch_object, Object.get_cached_by_ap_id(id)},
+ {_, true} <- {:allowed_depth, Federator.allowed_thread_distance?(options[:depth])},
+ {_, {:ok, data}} <- {:fetch, fetch_and_contain_remote_object_from_id(id)},
+ {_, nil} <- {:normalize, Object.normalize(data, fetch: false)},
+ params <- prepare_activity_params(data),
+ {_, :ok} <- {:containment, Containment.contain_origin(id, params)},
+ {_, {:ok, activity}} <-
+ {:transmogrifier, Transmogrifier.handle_incoming(params, options)},
+ {_, _data, %Object{} = object} <-
+ {:object, data, Object.normalize(activity, fetch: false)} do
+ {:ok, object}
+ else
+ {:allowed_depth, false} = e ->
+ log_fetch_error(id, e)
+ {:error, :allowed_depth}
+
+ {:containment, reason} = e ->
+ log_fetch_error(id, e)
+ {:error, reason}
+
+ {:transmogrifier, {:error, {:reject, reason}}} = e ->
+ log_fetch_error(id, e)
+ {:reject, reason}
+
+ {:transmogrifier, {:reject, reason}} = e ->
+ log_fetch_error(id, e)
+ {:reject, reason}
+
+ {:transmogrifier, reason} = e ->
+ log_fetch_error(id, e)
+ {:error, reason}
+
+ {:object, data, nil} ->
+ reinject_object(%Object{}, data)
+
+ {:normalize, object = %Object{}} ->
+ {:ok, object}
+
+ {:fetch_object, %Object{} = object} ->
+ {:ok, object}
+
+ {:fetch, {:error, reason}} = e ->
+ log_fetch_error(id, e)
+ {:error, reason}
+
+ e ->
+ log_fetch_error(id, e)
+ {:error, e}
+ end
+ end
+
+ defp log_fetch_error(id, error) do
+ Logger.metadata(object: id)
+ Logger.error("Object rejected while fetching #{id} #{inspect(error)}")
+ end
+
+ defp prepare_activity_params(data) do
+ %{
+ "type" => "Create",
+ # Should we seriously keep this attributedTo thing?
+ "actor" => data["actor"] || data["attributedTo"],
+ "object" => data
+ }
+ |> Maps.put_if_present("to", data["to"])
+ |> Maps.put_if_present("cc", data["cc"])
+ |> Maps.put_if_present("bto", data["bto"])
+ |> Maps.put_if_present("bcc", data["bcc"])
+ end
+
+ defp make_signature(id, date) do
+ uri = URI.parse(id)
+
+ signature =
+ InternalFetchActor.get_actor()
+ |> Signature.sign(%{
+ "(request-target)": "get #{uri.path}",
+ host: uri.host,
+ date: date
+ })
+
+ {"signature", signature}
+ end
+
+ defp sign_fetch(headers, id, date) do
+ if Pleroma.Config.get([:activitypub, :sign_object_fetches]) do
+ [make_signature(id, date) | headers]
+ else
+ headers
+ end
+ end
+
+ defp maybe_date_fetch(headers, date) do
+ if Pleroma.Config.get([:activitypub, :sign_object_fetches]) do
+ [{"date", date} | headers]
+ else
+ headers
+ end
+ end
+
+ def fetch_and_contain_remote_object_from_id(id)
+
+ def fetch_and_contain_remote_object_from_id(%{"id" => id}),
+ do: fetch_and_contain_remote_object_from_id(id)
+
+ def fetch_and_contain_remote_object_from_id(id) when is_binary(id) do
+ Logger.debug("Fetching object #{id} via AP")
+
+ with {:scheme, true} <- {:scheme, String.starts_with?(id, "http")},
+ {:ok, body} <- get_object(id),
+ {:ok, data} <- safe_json_decode(body),
+ :ok <- Containment.contain_origin_from_id(id, data) do
+ if not Instances.reachable?(id) do
+ Instances.set_reachable(id)
+ end
+
+ {:ok, data}
+ else
+ {:scheme, _} ->
+ {:error, "Unsupported URI scheme"}
+
+ {:error, e} ->
+ {:error, e}
+
+ e ->
+ {:error, e}
+ end
+ end
+
+ def fetch_and_contain_remote_object_from_id(_id),
+ do: {:error, "id must be a string"}
+
+ defp get_object(id) do
+ date = Pleroma.Signature.signed_date()
+
+ headers =
+ [{"accept", "application/activity+json"}]
+ |> maybe_date_fetch(date)
+ |> sign_fetch(id, date)
+
+ case HTTP.get(id, headers) do
+ {:ok, %{body: body, status: code, headers: headers}} when code in 200..299 ->
+ case List.keyfind(headers, "content-type", 0) do
+ {_, content_type} ->
+ case Plug.Conn.Utils.media_type(content_type) do
+ {:ok, "application", "activity+json", _} ->
+ {:ok, body}
+
+ {:ok, "application", "ld+json",
+ %{"profile" => "https://www.w3.org/ns/activitystreams"}} ->
+ {:ok, body}
+
+ _ ->
+ {:error, {:content_type, content_type}}
+ end
+
+ _ ->
+ {:error, {:content_type, nil}}
+ end
+
+ {:ok, %{status: code}} when code in [401, 403] ->
+ {:error, :forbidden}
+
+ {:ok, %{status: code}} when code in [404, 410] ->
+ {:error, :not_found}
+
+ {:error, e} ->
+ {:error, e}
+
+ e ->
+ {:error, e}
+ end
+ end
+
+ defp safe_json_decode(nil), do: {:ok, nil}
+ defp safe_json_decode(json), do: Jason.decode(json)
+end
diff --git a/lib/pleroma/object/fetcher.ex.rej b/lib/pleroma/object/fetcher.ex.rej
new file mode 100644
index 0000000..25b13f5
--- /dev/null
+++ b/lib/pleroma/object/fetcher.ex.rej
@@ -0,0 +1,13 @@
+--- lib/pleroma/object/fetcher.ex
++++ lib/pleroma/object/fetcher.ex
+@@ -3,7 +3,10 @@
+ # SPDX-License-Identifier: AGPL-3.0-only
+
+ defmodule Pleroma.Object.Fetcher do
++ @behaviour HTTPSignatures.Adapter
++
+ alias Pleroma.HTTP
++ alias Pleroma.Keys
+ alias Pleroma.Maps
+ alias Pleroma.Object
+ alias Pleroma.Object.Containment
diff --git a/lib/pleroma/object/updater.ex b/lib/pleroma/object/updater.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/object_tombstone.ex b/lib/pleroma/object_tombstone.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/otp_version.ex b/lib/pleroma/otp_version.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/pagination.ex b/lib/pleroma/pagination.ex
old mode 100755
new mode 100644
index f12ca28..8db732c
--- a/lib/pleroma/pagination.ex
+++ b/lib/pleroma/pagination.ex
@@ -61,15 +61,16 @@ defmodule Pleroma.Pagination do
|> Repo.all()
end
- @spec paginate(Ecto.Query.t(), map(), type(), atom() | nil) :: [Ecto.Schema.t()]
- def paginate(query, options, method \\ :keyset, table_binding \\ nil)
-
- def paginate(list, options, _method, _table_binding) when is_list(list) do
+ @spec paginate_list(list(), keyword()) :: list()
+ def paginate_list(list, options) do
offset = options[:offset] || 0
limit = options[:limit] || 0
Enum.slice(list, offset, limit)
end
+ @spec paginate(Ecto.Query.t(), map(), type(), atom() | nil) :: [Ecto.Schema.t()]
+ def paginate(query, options, method \\ :keyset, table_binding \\ nil)
+
def paginate(query, options, :keyset, table_binding) do
query
|> restrict(:min_id, options, table_binding)
diff --git a/lib/pleroma/password/pbkdf2.ex b/lib/pleroma/password/pbkdf2.ex
old mode 100755
new mode 100644
index 92e9e19..9c6d2e3
--- a/lib/pleroma/password/pbkdf2.ex
+++ b/lib/pleroma/password/pbkdf2.ex
@@ -28,7 +28,7 @@ defmodule Pleroma.Password.Pbkdf2 do
iterations = String.to_integer(iterations)
- digest = String.to_atom(digest)
+ digest = String.to_existing_atom(digest)
binary_hash =
KeyGenerator.generate(password, salt, digest: digest, iterations: iterations, length: 64)
diff --git a/lib/pleroma/password_reset_token.ex b/lib/pleroma/password_reset_token.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/prom_ex.ex b/lib/pleroma/prom_ex.ex
new file mode 100644
index 0000000..6608708
--- /dev/null
+++ b/lib/pleroma/prom_ex.ex
@@ -0,0 +1,49 @@
+defmodule Pleroma.PromEx do
+ use PromEx, otp_app: :pleroma
+
+ alias PromEx.Plugins
+
+ @impl true
+ def plugins do
+ [
+ # PromEx built in plugins
+ Plugins.Application,
+ Plugins.Beam,
+ {Plugins.Phoenix, router: Pleroma.Web.Router, endpoint: Pleroma.Web.Endpoint},
+ Plugins.Ecto,
+ Plugins.Oban
+ # Plugins.PhoenixLiveView,
+ # Plugins.Absinthe,
+ # Plugins.Broadway,
+
+ # Add your own PromEx metrics plugins
+ # Pleroma.Users.PromExPlugin
+ ]
+ end
+
+ @impl true
+ def dashboard_assigns do
+ [
+ datasource_id: Pleroma.Config.get([Pleroma.PromEx, :datasource]),
+ default_selected_interval: "30s"
+ ]
+ end
+
+ @impl true
+ def dashboards do
+ [
+ # PromEx built in Grafana dashboards
+ {:prom_ex, "application.json"},
+ {:prom_ex, "beam.json"},
+ {:prom_ex, "phoenix.json"},
+ {:prom_ex, "ecto.json"},
+ {:prom_ex, "oban.json"}
+ # {:prom_ex, "phoenix_live_view.json"},
+ # {:prom_ex, "absinthe.json"},
+ # {:prom_ex, "broadway.json"},
+
+ # Add your dashboard definitions here with the format: {:otp_app, "path_in_priv"}
+ # {:pleroma, "/grafana_dashboards/user_metrics.json"}
+ ]
+ end
+end
diff --git a/lib/pleroma/registration.ex b/lib/pleroma/registration.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/release_tasks.ex b/lib/pleroma/release_tasks.ex
old mode 100755
new mode 100644
index f9e8d19..bcfcd12
--- a/lib/pleroma/release_tasks.ex
+++ b/lib/pleroma/release_tasks.ex
@@ -55,12 +55,6 @@ defmodule Pleroma.ReleaseTasks do
{:error, term} when is_binary(term) ->
IO.puts(:stderr, "The database for #{inspect(@repo)} couldn't be created: #{term}")
-
- {:error, term} ->
- IO.puts(
- :stderr,
- "The database for #{inspect(@repo)} couldn't be created: #{inspect(term)}"
- )
end
end
end
diff --git a/lib/pleroma/repo.ex b/lib/pleroma/repo.ex
old mode 100755
new mode 100644
index 515b0c1..a50a59b
--- a/lib/pleroma/repo.ex
+++ b/lib/pleroma/repo.ex
@@ -11,8 +11,6 @@ defmodule Pleroma.Repo do
import Ecto.Query
require Logger
- defmodule Instrumenter, do: use(Prometheus.EctoInstrumenter)
-
@doc """
Dynamically loads the repository url from the
DATABASE_URL environment variable.
diff --git a/lib/pleroma/report_note.ex b/lib/pleroma/report_note.ex
old mode 100755
new mode 100644
index f2ad76f..f59e545
--- a/lib/pleroma/report_note.ex
+++ b/lib/pleroma/report_note.ex
@@ -23,8 +23,8 @@ defmodule Pleroma.ReportNote do
timestamps()
end
- @spec create(FlakeId.Ecto.CompatType.t(), FlakeId.Ecto.CompatType.t(), String.t()) ::
- {:ok, ReportNote.t()} | {:error, Changeset.t()}
+ @spec create(Ecto.UUID.t(), Ecto.UUID.t(), String.t()) ::
+ {:ok, ReportNote.t()} | {:error, Ecto.Changeset.t()}
def create(user_id, activity_id, content) do
attrs = %{
user_id: user_id,
@@ -38,8 +38,8 @@ defmodule Pleroma.ReportNote do
|> Repo.insert()
end
- @spec destroy(FlakeId.Ecto.CompatType.t()) ::
- {:ok, ReportNote.t()} | {:error, Changeset.t()}
+ @spec destroy(Ecto.UUID.t()) ::
+ {:ok, ReportNote.t()} | {:error, Ecto.Changeset.t()}
def destroy(id) do
from(r in ReportNote, where: r.id == ^id)
|> Repo.one()
diff --git a/lib/pleroma/reverse_proxy.ex b/lib/pleroma/reverse_proxy.ex
old mode 100755
new mode 100644
index 2248c27..4d13e51
--- a/lib/pleroma/reverse_proxy.ex
+++ b/lib/pleroma/reverse_proxy.ex
@@ -8,7 +8,7 @@ defmodule Pleroma.ReverseProxy do
~w(if-unmodified-since if-none-match) ++ @range_headers
@resp_cache_headers ~w(etag date last-modified)
@keep_resp_headers @resp_cache_headers ++
- ~w(content-length content-type content-disposition content-encoding) ++
+ ~w(content-type content-disposition content-encoding) ++
~w(content-range accept-ranges vary)
@default_cache_control_header "public, max-age=1209600"
@valid_resp_codes [200, 206, 304]
@@ -81,16 +81,16 @@ defmodule Pleroma.ReverseProxy do
import Plug.Conn
@type option() ::
- {:max_read_duration, :timer.time() | :infinity}
+ {:max_read_duration, non_neg_integer() | :infinity}
| {:max_body_length, non_neg_integer() | :infinity}
- | {:failed_request_ttl, :timer.time() | :infinity}
- | {:http, []}
+ | {:failed_request_ttl, non_neg_integer() | :infinity}
+ | {:http, keyword()}
| {:req_headers, [{String.t(), String.t()}]}
| {:resp_headers, [{String.t(), String.t()}]}
- | {:inline_content_types, boolean() | [String.t()]}
+ | {:inline_content_types, boolean() | list(String.t())}
| {:redirect_on_failure, boolean()}
- @spec call(Plug.Conn.t(), url :: String.t(), [option()]) :: Plug.Conn.t()
+ @spec call(Plug.Conn.t(), String.t(), list(option())) :: Plug.Conn.t()
def call(_conn, _url, _opts \\ [])
def call(conn = %{method: method}, url, opts) when method in @methods do
@@ -192,7 +192,7 @@ defmodule Pleroma.ReverseProxy do
halt(conn)
{:error, error, conn} ->
- Logger.warn(
+ Logger.warning(
"#{__MODULE__} request to #{url} failed while reading/chunking: #{inspect(error)}"
)
@@ -388,8 +388,6 @@ defmodule Pleroma.ReverseProxy do
defp body_size_constraint(_, _), do: :ok
- defp check_read_duration(nil = _duration, max), do: check_read_duration(@max_read_duration, max)
-
defp check_read_duration(duration, max)
when is_integer(duration) and is_integer(max) and max > 0 do
if duration > max do
@@ -407,10 +405,6 @@ defmodule Pleroma.ReverseProxy do
{:ok, previous_duration + duration}
end
- defp increase_read_duration(_) do
- {:ok, :no_duration_limit, :no_duration_limit}
- end
-
defp client, do: Pleroma.ReverseProxy.Client.Wrapper
defp track_failed_url(url, error, opts) do
diff --git a/lib/pleroma/reverse_proxy/client.ex b/lib/pleroma/reverse_proxy/client.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/reverse_proxy/client/hackney.ex b/lib/pleroma/reverse_proxy/client/hackney.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/reverse_proxy/client/tesla.ex b/lib/pleroma/reverse_proxy/client/tesla.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/reverse_proxy/client/wrapper.ex b/lib/pleroma/reverse_proxy/client/wrapper.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/scheduled_activity.ex b/lib/pleroma/scheduled_activity.ex
old mode 100755
new mode 100644
index 0ed51ad..63c6cb4
--- a/lib/pleroma/scheduled_activity.ex
+++ b/lib/pleroma/scheduled_activity.ex
@@ -6,7 +6,6 @@ defmodule Pleroma.ScheduledActivity do
use Ecto.Schema
alias Ecto.Multi
- alias Pleroma.Config
alias Pleroma.Repo
alias Pleroma.ScheduledActivity
alias Pleroma.User
@@ -20,6 +19,8 @@ defmodule Pleroma.ScheduledActivity do
@min_offset :timer.minutes(5)
+ @config_impl Application.compile_env(:pleroma, [__MODULE__, :config_impl], Pleroma.Config)
+
schema "scheduled_activities" do
belongs_to(:user, User, type: FlakeId.Ecto.CompatType)
field(:scheduled_at, :naive_datetime)
@@ -87,7 +88,7 @@ defmodule Pleroma.ScheduledActivity do
|> where([sa], type(sa.scheduled_at, :date) == type(^scheduled_at, :date))
|> select([sa], count(sa.id))
|> Repo.one()
- |> Kernel.>=(Config.get([ScheduledActivity, :daily_user_limit]))
+ |> Kernel.>=(@config_impl.get([ScheduledActivity, :daily_user_limit]))
end
def exceeds_total_user_limit?(user_id) do
@@ -95,7 +96,7 @@ defmodule Pleroma.ScheduledActivity do
|> where(user_id: ^user_id)
|> select([sa], count(sa.id))
|> Repo.one()
- |> Kernel.>=(Config.get([ScheduledActivity, :total_user_limit]))
+ |> Kernel.>=(@config_impl.get([ScheduledActivity, :total_user_limit]))
end
def far_enough?(scheduled_at) when is_binary(scheduled_at) do
@@ -123,7 +124,7 @@ defmodule Pleroma.ScheduledActivity do
def create(%User{} = user, attrs) do
Multi.new()
|> Multi.insert(:scheduled_activity, new(user, attrs))
- |> maybe_add_jobs(Config.get([ScheduledActivity, :enabled]))
+ |> maybe_add_jobs(@config_impl.get([ScheduledActivity, :enabled]))
|> Repo.transaction()
|> transaction_response
end
diff --git a/lib/pleroma/search.ex b/lib/pleroma/search.ex
new file mode 100644
index 0000000..3b266e5
--- /dev/null
+++ b/lib/pleroma/search.ex
@@ -0,0 +1,17 @@
+defmodule Pleroma.Search do
+ alias Pleroma.Workers.SearchIndexingWorker
+
+ def add_to_index(%Pleroma.Activity{id: activity_id}) do
+ SearchIndexingWorker.enqueue("add_to_index", %{"activity" => activity_id})
+ end
+
+ def remove_from_index(%Pleroma.Object{id: object_id}) do
+ SearchIndexingWorker.enqueue("remove_from_index", %{"object" => object_id})
+ end
+
+ def search(query, options) do
+ search_module = Pleroma.Config.get([Pleroma.Search, :module], Pleroma.Activity)
+
+ search_module.search(options[:for_user], query, options)
+ end
+end
diff --git a/lib/pleroma/search/database_search.ex b/lib/pleroma/search/database_search.ex
new file mode 100644
index 0000000..31bfc7e
--- /dev/null
+++ b/lib/pleroma/search/database_search.ex
@@ -0,0 +1,165 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Search.DatabaseSearch do
+ alias Pleroma.Activity
+ alias Pleroma.Config
+ alias Pleroma.Object.Fetcher
+ alias Pleroma.Pagination
+ alias Pleroma.User
+ alias Pleroma.Web.ActivityPub.Visibility
+
+ require Pleroma.Constants
+
+ import Ecto.Query
+
+ @behaviour Pleroma.Search.SearchBackend
+
+ @impl true
+ def search(user, search_query, options \\ []) do
+ index_type = if Config.get([:database, :rum_enabled]), do: :rum, else: :gin
+ limit = Enum.min([Keyword.get(options, :limit), 40])
+ offset = Keyword.get(options, :offset, 0)
+ author = Keyword.get(options, :author)
+
+ try do
+ Activity
+ |> Activity.with_preloaded_object()
+ |> Activity.restrict_deactivated_users()
+ |> restrict_public(user)
+ |> query_with(index_type, search_query, :websearch)
+ |> maybe_restrict_local(user)
+ |> maybe_restrict_author(author)
+ |> maybe_restrict_blocked(user)
+ |> Pagination.fetch_paginated(
+ %{"offset" => offset, "limit" => limit, "skip_order" => index_type == :rum},
+ :offset
+ )
+ |> maybe_fetch(user, search_query)
+ rescue
+ _ -> maybe_fetch([], user, search_query)
+ end
+ end
+
+ @impl true
+ def add_to_index(_activity), do: :ok
+
+ @impl true
+ def remove_from_index(_object), do: :ok
+
+ def maybe_restrict_author(query, %User{} = author) do
+ Activity.Queries.by_author(query, author)
+ end
+
+ def maybe_restrict_author(query, _), do: query
+
+ def maybe_restrict_blocked(query, %User{} = user) do
+ Activity.Queries.exclude_authors(query, User.blocked_users_ap_ids(user))
+ end
+
+ def maybe_restrict_blocked(query, _), do: query
+
+ defp restrict_public(q, user) when not is_nil(user) do
+ intended_recipients = [
+ Pleroma.Constants.as_public(),
+ Pleroma.Web.ActivityPub.Utils.as_local_public()
+ ]
+
+ from([a, o] in q,
+ where: fragment("?->>'type' = 'Create'", a.data),
+ where: fragment("? && ?", ^intended_recipients, a.recipients)
+ )
+ end
+
+ defp restrict_public(q, _user) do
+ from([a, o] in q,
+ where: fragment("?->>'type' = 'Create'", a.data),
+ where: ^Pleroma.Constants.as_public() in a.recipients
+ )
+ end
+
+ defp query_with(q, :gin, search_query, :plain) do
+ %{rows: [[tsc]]} =
+ Ecto.Adapters.SQL.query!(
+ Pleroma.Repo,
+ "select current_setting('default_text_search_config')::regconfig::oid;"
+ )
+
+ from([a, o] in q,
+ where:
+ fragment(
+ "to_tsvector(?::oid::regconfig, ?->>'content') @@ plainto_tsquery(?)",
+ ^tsc,
+ o.data,
+ ^search_query
+ )
+ )
+ end
+
+ defp query_with(q, :gin, search_query, :websearch) do
+ %{rows: [[tsc]]} =
+ Ecto.Adapters.SQL.query!(
+ Pleroma.Repo,
+ "select current_setting('default_text_search_config')::regconfig::oid;"
+ )
+
+ from([a, o] in q,
+ where:
+ fragment(
+ "to_tsvector(?::oid::regconfig, ?->>'content') @@ websearch_to_tsquery(?)",
+ ^tsc,
+ o.data,
+ ^search_query
+ )
+ )
+ end
+
+ defp query_with(q, :rum, search_query, :plain) do
+ from([a, o] in q,
+ where:
+ fragment(
+ "? @@ plainto_tsquery(?)",
+ o.fts_content,
+ ^search_query
+ ),
+ order_by: [fragment("? <=> now()::date", o.inserted_at)]
+ )
+ end
+
+ defp query_with(q, :rum, search_query, :websearch) do
+ from([a, o] in q,
+ where:
+ fragment(
+ "? @@ websearch_to_tsquery(?)",
+ o.fts_content,
+ ^search_query
+ ),
+ order_by: [fragment("? <=> now()::date", o.inserted_at)]
+ )
+ end
+
+ def maybe_restrict_local(q, user) do
+ limit = Config.get([:instance, :limit_to_local_content], :unauthenticated)
+
+ case {limit, user} do
+ {:all, _} -> restrict_local(q)
+ {:unauthenticated, %User{}} -> q
+ {:unauthenticated, _} -> restrict_local(q)
+ {false, _} -> q
+ end
+ end
+
+ defp restrict_local(q), do: where(q, local: true)
+
+ def maybe_fetch(activities, user, search_query) do
+ with true <- Regex.match?(~r/https?:/, search_query),
+ {:ok, object} <- Fetcher.fetch_object_from_id(search_query),
+ %Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]),
+ true <- Visibility.visible_for_user?(activity, user) do
+ [activity | activities]
+ else
+ _ -> activities
+ end
+ end
+end
diff --git a/lib/pleroma/search/meilisearch.ex b/lib/pleroma/search/meilisearch.ex
new file mode 100644
index 0000000..2bff663
--- /dev/null
+++ b/lib/pleroma/search/meilisearch.ex
@@ -0,0 +1,181 @@
+defmodule Pleroma.Search.Meilisearch do
+ require Logger
+ require Pleroma.Constants
+
+ alias Pleroma.Activity
+ alias Pleroma.Config.Getting, as: Config
+
+ import Pleroma.Search.DatabaseSearch
+ import Ecto.Query
+
+ @behaviour Pleroma.Search.SearchBackend
+
+ defp meili_headers do
+ private_key = Config.get([Pleroma.Search.Meilisearch, :private_key])
+
+ [{"Content-Type", "application/json"}] ++
+ if is_nil(private_key), do: [], else: [{"Authorization", "Bearer #{private_key}"}]
+ end
+
+ def meili_get(path) do
+ endpoint = Config.get([Pleroma.Search.Meilisearch, :url])
+
+ result =
+ Pleroma.HTTP.get(
+ Path.join(endpoint, path),
+ meili_headers()
+ )
+
+ with {:ok, res} <- result do
+ {:ok, Jason.decode!(res.body)}
+ end
+ end
+
+ def meili_post(path, params) do
+ endpoint = Config.get([Pleroma.Search.Meilisearch, :url])
+
+ result =
+ Pleroma.HTTP.post(
+ Path.join(endpoint, path),
+ Jason.encode!(params),
+ meili_headers()
+ )
+
+ with {:ok, res} <- result do
+ {:ok, Jason.decode!(res.body)}
+ end
+ end
+
+ def meili_put(path, params) do
+ endpoint = Config.get([Pleroma.Search.Meilisearch, :url])
+
+ result =
+ Pleroma.HTTP.request(
+ :put,
+ Path.join(endpoint, path),
+ Jason.encode!(params),
+ meili_headers(),
+ []
+ )
+
+ with {:ok, res} <- result do
+ {:ok, Jason.decode!(res.body)}
+ end
+ end
+
+ def meili_delete(path) do
+ endpoint = Config.get([Pleroma.Search.Meilisearch, :url])
+
+ with {:ok, _} <-
+ Pleroma.HTTP.request(
+ :delete,
+ Path.join(endpoint, path),
+ "",
+ meili_headers(),
+ []
+ ) do
+ :ok
+ else
+ _ -> {:error, "Could not remove from index"}
+ end
+ end
+
+ @impl true
+ def search(user, query, options \\ []) do
+ limit = Enum.min([Keyword.get(options, :limit), 40])
+ offset = Keyword.get(options, :offset, 0)
+ author = Keyword.get(options, :author)
+
+ res =
+ meili_post(
+ "/indexes/objects/search",
+ %{q: query, offset: offset, limit: limit}
+ )
+
+ with {:ok, result} <- res do
+ hits = result["hits"] |> Enum.map(& &1["ap"])
+
+ try do
+ hits
+ |> Activity.create_by_object_ap_id()
+ |> Activity.with_preloaded_object()
+ |> Activity.restrict_deactivated_users()
+ |> maybe_restrict_local(user)
+ |> maybe_restrict_author(author)
+ |> maybe_restrict_blocked(user)
+ |> maybe_fetch(user, query)
+ |> order_by([object: obj], desc: obj.data["published"])
+ |> Pleroma.Repo.all()
+ rescue
+ _ -> maybe_fetch([], user, query)
+ end
+ end
+ end
+
+ def object_to_search_data(object) do
+ # Only index public or unlisted Notes
+ if not is_nil(object) and object.data["type"] == "Note" and
+ not is_nil(object.data["content"]) and
+ (Pleroma.Constants.as_public() in object.data["to"] or
+ Pleroma.Constants.as_public() in object.data["cc"]) and
+ object.data["content"] not in ["", "."] do
+ data = object.data
+
+ content_str =
+ case data["content"] do
+ [nil | rest] -> to_string(rest)
+ str -> str
+ end
+
+ content =
+ with {:ok, scrubbed} <-
+ FastSanitize.Sanitizer.scrub(content_str, Pleroma.HTML.Scrubber.SearchIndexing),
+ trimmed <- String.trim(scrubbed) do
+ trimmed
+ end
+
+ # Make sure we have a non-empty string
+ if content != "" do
+ {:ok, published, _} = DateTime.from_iso8601(data["published"])
+
+ %{
+ id: object.id,
+ content: content,
+ ap: data["id"],
+ published: published |> DateTime.to_unix()
+ }
+ end
+ end
+ end
+
+ @impl true
+ def add_to_index(activity) do
+ maybe_search_data = object_to_search_data(activity.object)
+
+ if activity.data["type"] == "Create" and maybe_search_data do
+ result =
+ meili_put(
+ "/indexes/objects/documents",
+ [maybe_search_data]
+ )
+
+ with {:ok, %{"status" => "enqueued"}} <- result do
+ # Added successfully
+ :ok
+ else
+ _ ->
+ # There was an error, report it
+ Logger.error("Failed to add activity #{activity.id} to index: #{inspect(result)}")
+ {:error, result}
+ end
+ else
+ # The post isn't something we can search, that's ok
+ :ok
+ end
+ end
+
+ @impl true
+ def remove_from_index(object) do
+ meili_delete("/indexes/objects/documents/#{object.id}")
+ end
+end
diff --git a/lib/pleroma/search/search_backend.ex b/lib/pleroma/search/search_backend.ex
new file mode 100644
index 0000000..68bc48c
--- /dev/null
+++ b/lib/pleroma/search/search_backend.ex
@@ -0,0 +1,24 @@
+defmodule Pleroma.Search.SearchBackend do
+ @doc """
+ Search statuses with a query, restricting to only those the user should have access to.
+ """
+ @callback search(user :: Pleroma.User.t(), query :: String.t(), options :: [any()]) :: [
+ Pleroma.Activity.t()
+ ]
+
+ @doc """
+ Add the object associated with the activity to the search index.
+
+ The whole activity is passed, to allow filtering on things such as scope.
+ """
+ @callback add_to_index(activity :: Pleroma.Activity.t()) :: :ok | {:error, any()}
+
+ @doc """
+ Remove the object from the index.
+
+ Just the object, as opposed to the whole activity, is passed, since the object
+ is what contains the actual content and there is no need for filtering when removing
+ from index.
+ """
+ @callback remove_from_index(object :: Pleroma.Object.t()) :: :ok | {:error, any()}
+end
diff --git a/lib/pleroma/signature.ex b/lib/pleroma/signature.ex
old mode 100755
new mode 100644
index 5cfdae0..8fd422a
--- a/lib/pleroma/signature.ex
+++ b/lib/pleroma/signature.ex
@@ -27,7 +27,7 @@ defmodule Pleroma.Signature do
_ ->
case Pleroma.Web.WebFinger.finger(maybe_ap_id) do
- %{"ap_id" => ap_id} -> {:ok, ap_id}
+ {:ok, %{"ap_id" => ap_id}} -> {:ok, ap_id}
_ -> {:error, maybe_ap_id}
end
end
diff --git a/lib/pleroma/stats.ex b/lib/pleroma/stats.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/telemetry/logger.ex b/lib/pleroma/telemetry/logger.ex
old mode 100755
new mode 100644
index 384c70f..9998d81
--- a/lib/pleroma/telemetry/logger.ex
+++ b/lib/pleroma/telemetry/logger.ex
@@ -59,7 +59,7 @@ defmodule Pleroma.Telemetry.Logger do
_,
_
) do
- Logger.error(fn ->
+ Logger.debug(fn ->
"Connection pool had to refuse opening a connection to #{key} due to connection limit exhaustion"
end)
end
@@ -70,7 +70,7 @@ defmodule Pleroma.Telemetry.Logger do
%{key: key},
_
) do
- Logger.warn(fn ->
+ Logger.warning(fn ->
"Pool worker for #{key}: Client #{inspect(client_pid)} died before releasing the connection with #{inspect(reason)}"
end)
end
@@ -81,7 +81,7 @@ defmodule Pleroma.Telemetry.Logger do
%{key: key, protocol: :http},
_
) do
- Logger.info(fn ->
+ Logger.debug(fn ->
"Pool worker for #{key}: #{length(clients)} clients are using an HTTP1 connection at the same time, head-of-line blocking might occur."
end)
end
diff --git a/lib/pleroma/tesla/middleware/connection_pool.ex b/lib/pleroma/tesla/middleware/connection_pool.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/tests/auth_test_controller.ex b/lib/pleroma/tests/auth_test_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/thread_mute.ex b/lib/pleroma/thread_mute.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/upload.ex b/lib/pleroma/upload.ex
old mode 100755
new mode 100644
index 4aee932..e6c4845
--- a/lib/pleroma/upload.ex
+++ b/lib/pleroma/upload.ex
@@ -34,7 +34,6 @@ defmodule Pleroma.Upload do
"""
alias Ecto.UUID
- alias Pleroma.Config
alias Pleroma.Maps
alias Pleroma.Web.ActivityPub.Utils
require Logger
@@ -52,6 +51,7 @@ defmodule Pleroma.Upload do
| {:size_limit, nil | non_neg_integer()}
| {:uploader, module()}
| {:filters, [module()]}
+ | {:actor, String.t()}
@type t :: %__MODULE__{
id: String.t(),
@@ -76,6 +76,8 @@ defmodule Pleroma.Upload do
:path
]
+ @config_impl Application.compile_env(:pleroma, [__MODULE__, :config_impl], Pleroma.Config)
+
defp get_description(upload) do
case {upload.description, Pleroma.Config.get([Pleroma.Upload, :default_description])} do
{description, _} when is_binary(description) -> description
@@ -85,7 +87,7 @@ defmodule Pleroma.Upload do
end
end
- @spec store(source, options :: [option()]) :: {:ok, Map.t()} | {:error, any()}
+ @spec store(source, options :: [option()]) :: {:ok, map()} | {:error, any()}
@doc "Store a file. If using a `Plug.Upload{}` as the source, be sure to use `Majic.Plug` to ensure its content_type and filename is correct."
def store(upload, opts \\ []) do
opts = get_opts(opts)
@@ -174,7 +176,7 @@ defmodule Pleroma.Upload do
defp prepare_upload(%{img: "data:image/" <> image_data}, opts) do
parsed = Regex.named_captures(~r/(?jpeg|png|gif);base64,(?.*)/, image_data)
data = Base.decode64!(parsed["data"], ignore: :whitespace)
- hash = Base.encode16(:crypto.hash(:sha256, data), lower: true)
+ hash = Base.encode16(:crypto.hash(:sha256, data), case: :upper)
with :ok <- check_binary_size(data, opts.size_limit),
tmp_path <- tempfile_for_image(data),
@@ -244,18 +246,18 @@ defmodule Pleroma.Upload do
defp url_from_spec(_upload, _base_url, {:url, url}), do: url
def base_url do
- uploader = Config.get([Pleroma.Upload, :uploader])
- upload_base_url = Config.get([Pleroma.Upload, :base_url])
- public_endpoint = Config.get([uploader, :public_endpoint])
+ uploader = @config_impl.get([Pleroma.Upload, :uploader])
+ upload_base_url = @config_impl.get([Pleroma.Upload, :base_url])
+ public_endpoint = @config_impl.get([uploader, :public_endpoint])
case uploader do
Pleroma.Uploaders.Local ->
upload_base_url || Pleroma.Web.Endpoint.url() <> "/media/"
Pleroma.Uploaders.S3 ->
- bucket = Config.get([Pleroma.Uploaders.S3, :bucket])
- truncated_namespace = Config.get([Pleroma.Uploaders.S3, :truncated_namespace])
- namespace = Config.get([Pleroma.Uploaders.S3, :bucket_namespace])
+ bucket = @config_impl.get([Pleroma.Uploaders.S3, :bucket])
+ truncated_namespace = @config_impl.get([Pleroma.Uploaders.S3, :truncated_namespace])
+ namespace = @config_impl.get([Pleroma.Uploaders.S3, :bucket_namespace])
bucket_with_namespace =
cond do
diff --git a/lib/pleroma/upload/filter.ex b/lib/pleroma/upload/filter.ex
old mode 100755
new mode 100644
index 717f066..809bc6e
--- a/lib/pleroma/upload/filter.ex
+++ b/lib/pleroma/upload/filter.ex
@@ -38,9 +38,9 @@ defmodule Pleroma.Upload.Filter do
{:ok, :noop} ->
filter(rest, upload)
- error ->
- Logger.error("#{__MODULE__}: Filter #{filter} failed: #{inspect(error)}")
- error
+ {:error, e} ->
+ Logger.error("#{__MODULE__}: Filter #{filter} failed: #{inspect(e)}")
+ {:error, e}
end
end
end
diff --git a/lib/pleroma/upload/filter/analyze_metadata.ex b/lib/pleroma/upload/filter/analyze_metadata.ex
old mode 100755
new mode 100644
index 9a76a99..7ee6432
--- a/lib/pleroma/upload/filter/analyze_metadata.ex
+++ b/lib/pleroma/upload/filter/analyze_metadata.ex
@@ -8,27 +8,28 @@ defmodule Pleroma.Upload.Filter.AnalyzeMetadata do
"""
require Logger
+ alias Vix.Vips.Image
+ alias Vix.Vips.Operation
+
@behaviour Pleroma.Upload.Filter
@spec filter(Pleroma.Upload.t()) ::
{:ok, :filtered, Pleroma.Upload.t()} | {:ok, :noop} | {:error, String.t()}
def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _} = upload) do
try do
- image =
- file
- |> Mogrify.open()
- |> Mogrify.verbose()
+ {:ok, image} = Image.new_from_file(file)
+ {width, height} = {Image.width(image), Image.height(image)}
upload =
upload
- |> Map.put(:width, image.width)
- |> Map.put(:height, image.height)
- |> Map.put(:blurhash, get_blurhash(file))
+ |> Map.put(:width, width)
+ |> Map.put(:height, height)
+ |> Map.put(:blurhash, get_blurhash(image))
{:ok, :filtered, upload}
rescue
e in ErlangError ->
- Logger.warn("#{__MODULE__}: #{inspect(e)}")
+ Logger.warning("#{__MODULE__}: #{inspect(e)}")
{:ok, :noop}
end
end
@@ -45,7 +46,7 @@ defmodule Pleroma.Upload.Filter.AnalyzeMetadata do
{:ok, :filtered, upload}
rescue
e in ErlangError ->
- Logger.warn("#{__MODULE__}: #{inspect(e)}")
+ Logger.warning("#{__MODULE__}: #{inspect(e)}")
{:ok, :noop}
end
end
@@ -53,7 +54,7 @@ defmodule Pleroma.Upload.Filter.AnalyzeMetadata do
def filter(_), do: {:ok, :noop}
defp get_blurhash(file) do
- with {:ok, blurhash} <- :eblurhash.magick(file) do
+ with {:ok, blurhash} <- vips_blurhash(file) do
blurhash
else
_ -> nil
@@ -77,7 +78,28 @@ defmodule Pleroma.Upload.Filter.AnalyzeMetadata do
%{width: width, height: height}
else
nil -> {:error, {:ffprobe, :command_not_found}}
- {:error, _} = error -> error
+ error -> {:error, error}
+ end
+ end
+
+ defp vips_blurhash(%Vix.Vips.Image{} = image) do
+ with {:ok, resized_image} <- Operation.thumbnail_image(image, 100),
+ {height, width} <- {Image.height(resized_image), Image.width(resized_image)},
+ max <- max(height, width),
+ {x, y} <- {max(round(width * 5 / max), 1), max(round(height * 5 / max), 1)} do
+ {:ok, rgb} =
+ if Image.has_alpha?(resized_image) do
+ # remove alpha channel
+ resized_image
+ |> Operation.extract_band!(0, n: 3)
+ |> Image.write_to_binary()
+ else
+ Image.write_to_binary(resized_image)
+ end
+
+ Blurhash.encode(rgb, width, height, x, y)
+ else
+ _ -> nil
end
end
end
diff --git a/lib/pleroma/upload/filter/anonymize_filename.ex b/lib/pleroma/upload/filter/anonymize_filename.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/upload/filter/dedupe.ex b/lib/pleroma/upload/filter/dedupe.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/upload/filter/exiftool/read_description.ex b/lib/pleroma/upload/filter/exiftool/read_description.ex
old mode 100755
new mode 100644
index 543b220..8c1ed82
--- a/lib/pleroma/upload/filter/exiftool/read_description.ex
+++ b/lib/pleroma/upload/filter/exiftool/read_description.ex
@@ -10,8 +10,6 @@ defmodule Pleroma.Upload.Filter.Exiftool.ReadDescription do
"""
@behaviour Pleroma.Upload.Filter
- @spec filter(Pleroma.Upload.t()) :: {:ok, any()} | {:error, String.t()}
-
def filter(%Pleroma.Upload{description: description})
when is_binary(description),
do: {:ok, :noop}
diff --git a/lib/pleroma/upload/filter/exiftool/strip_location.ex b/lib/pleroma/upload/filter/exiftool/strip_location.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/upload/filter/mogrifun.ex b/lib/pleroma/upload/filter/mogrifun.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/upload/filter/mogrify.ex b/lib/pleroma/upload/filter/mogrify.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/upload/filter/only_media.ex b/lib/pleroma/upload/filter/only_media.ex
new file mode 100644
index 0000000..a9caeba
--- /dev/null
+++ b/lib/pleroma/upload/filter/only_media.ex
@@ -0,0 +1,20 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2023 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Upload.Filter.OnlyMedia do
+ @behaviour Pleroma.Upload.Filter
+ alias Pleroma.Upload
+
+ def filter(%Upload{content_type: content_type}) do
+ [type, _subtype] = String.split(content_type, "/")
+
+ if type in ["image", "video", "audio"] do
+ {:ok, :noop}
+ else
+ {:error, "Disallowed content-type: #{content_type}"}
+ end
+ end
+
+ def filter(_), do: {:ok, :noop}
+end
diff --git a/lib/pleroma/uploaders/local.ex b/lib/pleroma/uploaders/local.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/uploaders/s3.ex b/lib/pleroma/uploaders/s3.ex
old mode 100755
new mode 100644
index 19287c5..7b32bd8
--- a/lib/pleroma/uploaders/s3.ex
+++ b/lib/pleroma/uploaders/s3.ex
@@ -6,7 +6,8 @@ defmodule Pleroma.Uploaders.S3 do
@behaviour Pleroma.Uploaders.Uploader
require Logger
- alias Pleroma.Config
+ @ex_aws_impl Application.compile_env(:pleroma, [__MODULE__, :ex_aws_impl], ExAws)
+ @config_impl Application.compile_env(:pleroma, [__MODULE__, :config_impl], Pleroma.Config)
# The file name is re-encoded with S3's constraints here to comply with previous
# links with less strict filenames
@@ -22,7 +23,7 @@ defmodule Pleroma.Uploaders.S3 do
@impl true
def put_file(%Pleroma.Upload{} = upload) do
- config = Config.get([__MODULE__])
+ config = @config_impl.get([__MODULE__])
bucket = Keyword.get(config, :bucket)
streaming = Keyword.get(config, :streaming_enabled)
@@ -56,7 +57,7 @@ defmodule Pleroma.Uploaders.S3 do
])
end
- case ExAws.request(op) do
+ case @ex_aws_impl.request(op) do
{:ok, _} ->
{:ok, {:file, s3_name}}
@@ -69,9 +70,9 @@ defmodule Pleroma.Uploaders.S3 do
@impl true
def delete_file(file) do
[__MODULE__, :bucket]
- |> Config.get()
+ |> @config_impl.get()
|> ExAws.S3.delete_object(file)
- |> ExAws.request()
+ |> @ex_aws_impl.request()
|> case do
{:ok, %{status_code: 204}} -> :ok
error -> {:error, inspect(error)}
@@ -83,3 +84,7 @@ defmodule Pleroma.Uploaders.S3 do
String.replace(name, @regex, "-")
end
end
+
+defmodule Pleroma.Uploaders.S3.ExAwsAPI do
+ @callback request(op :: ExAws.Operation.t()) :: {:ok, ExAws.Operation.t()} | {:error, term()}
+end
diff --git a/lib/pleroma/uploaders/uploader.ex b/lib/pleroma/uploaders/uploader.ex
old mode 100755
new mode 100644
index 77f6f02..3396fe0
--- a/lib/pleroma/uploaders/uploader.ex
+++ b/lib/pleroma/uploaders/uploader.ex
@@ -5,8 +5,6 @@
defmodule Pleroma.Uploaders.Uploader do
import Pleroma.Web.Gettext
- @mix_env Mix.env()
-
@moduledoc """
Defines the contract to put and get an uploaded file to any backend.
"""
@@ -40,7 +38,7 @@ defmodule Pleroma.Uploaders.Uploader do
@callback delete_file(file :: String.t()) :: :ok | {:error, String.t()}
- @callback http_callback(Plug.Conn.t(), Map.t()) ::
+ @callback http_callback(Plug.Conn.t(), map()) ::
{:ok, Plug.Conn.t()}
| {:ok, Plug.Conn.t(), file_spec()}
| {:error, Plug.Conn.t(), String.t()}
@@ -75,10 +73,5 @@ defmodule Pleroma.Uploaders.Uploader do
end
end
- defp callback_timeout do
- case @mix_env do
- :test -> 1_000
- _ -> 30_000
- end
- end
+ defp callback_timeout, do: Application.get_env(:pleroma, __MODULE__)[:timeout]
end
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
old mode 100755
new mode 100644
index f6e3055..778e205
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -8,6 +8,7 @@ defmodule Pleroma.User do
import Ecto.Changeset
import Ecto.Query
import Ecto, only: [assoc: 2]
+ import Pleroma.Web.Utils.Guards, only: [not_empty_string: 1]
alias Ecto.Multi
alias Pleroma.Activity
@@ -39,6 +40,7 @@ defmodule Pleroma.User do
alias Pleroma.Workers.BackgroundWorker
require Logger
+ require Pleroma.Constants
@type t :: %__MODULE__{}
@type account_status ::
@@ -124,7 +126,6 @@ defmodule Pleroma.User do
field(:domain_blocks, {:array, :string}, default: [])
field(:is_active, :boolean, default: true)
field(:no_rich_text, :boolean, default: false)
- field(:ap_enabled, :boolean, default: false)
field(:is_moderator, :boolean, default: false)
field(:is_admin, :boolean, default: false)
field(:show_role, :boolean, default: true)
@@ -488,7 +489,6 @@ defmodule Pleroma.User do
:nickname,
:public_key,
:avatar,
- :ap_enabled,
:banner,
:is_locked,
:last_refreshed_at,
@@ -581,7 +581,7 @@ defmodule Pleroma.User do
|> validate_format(:nickname, local_nickname_regex())
|> validate_length(:bio, max: bio_limit)
|> validate_length(:name, min: 1, max: name_limit)
- |> validate_inclusion(:actor_type, ["Person", "Service"])
+ |> validate_inclusion(:actor_type, Pleroma.Constants.allowed_user_actor_types())
|> put_fields()
|> put_emoji()
|> put_change_if_present(:bio, &{:ok, parse_bio(&1, struct)})
@@ -597,9 +597,23 @@ defmodule Pleroma.User do
defp put_fields(changeset) do
if raw_fields = get_change(changeset, :raw_fields) do
+ old_fields = changeset.data.raw_fields
+
raw_fields =
raw_fields
|> Enum.filter(fn %{"name" => n} -> n != "" end)
+ |> Enum.map(fn field ->
+ previous =
+ old_fields
+ |> Enum.find(fn %{"value" => value} -> field["value"] == value end)
+
+ if previous && Map.has_key?(previous, "verified_at") do
+ field
+ |> Map.put("verified_at", previous["verified_at"])
+ else
+ field
+ end
+ end)
fields =
raw_fields
@@ -673,7 +687,7 @@ defmodule Pleroma.User do
|> validate_inclusion(:actor_type, ["Person", "Service"])
end
- @spec update_as_admin(User.t(), map()) :: {:ok, User.t()} | {:error, Changeset.t()}
+ @spec update_as_admin(User.t(), map()) :: {:ok, User.t()} | {:error, Ecto.Changeset.t()}
def update_as_admin(user, params) do
params = Map.put(params, "password_confirmation", params["password"])
changeset = update_as_admin_changeset(user, params)
@@ -694,7 +708,7 @@ defmodule Pleroma.User do
|> put_change(:password_reset_pending, false)
end
- @spec reset_password(User.t(), map()) :: {:ok, User.t()} | {:error, Changeset.t()}
+ @spec reset_password(User.t(), map()) :: {:ok, User.t()} | {:error, Ecto.Changeset.t()}
def reset_password(%User{} = user, params) do
reset_password(user, user, params)
end
@@ -1012,7 +1026,7 @@ defmodule Pleroma.User do
def maybe_send_confirmation_email(_), do: {:ok, :noop}
- @spec send_confirmation_email(Uset.t()) :: User.t()
+ @spec send_confirmation_email(User.t()) :: User.t()
def send_confirmation_email(%User{} = user) do
user
|> Pleroma.Emails.UserEmail.account_confirmation_email()
@@ -1049,7 +1063,8 @@ defmodule Pleroma.User do
def needs_update?(_), do: true
- @spec maybe_direct_follow(User.t(), User.t()) :: {:ok, User.t()} | {:error, String.t()}
+ @spec maybe_direct_follow(User.t(), User.t()) ::
+ {:ok, User.t(), User.t()} | {:error, String.t()}
# "Locked" (self-locked) users demand explicit authorization of follow requests
def maybe_direct_follow(%User{} = follower, %User{local: true, is_locked: true} = followed) do
@@ -1061,11 +1076,7 @@ defmodule Pleroma.User do
end
def maybe_direct_follow(%User{} = follower, %User{} = followed) do
- if not ap_enabled?(followed) do
- follow(follower, followed)
- else
- {:ok, follower, followed}
- end
+ {:ok, follower, followed}
end
@doc "A mass follow for local users. Respects blocks in both directions but does not create activities."
@@ -1204,6 +1215,10 @@ defmodule Pleroma.User do
def update_and_set_cache(changeset) do
with {:ok, user} <- Repo.update(changeset, stale_error_field: :id) do
+ if get_change(changeset, :raw_fields) do
+ BackgroundWorker.enqueue("verify_fields_links", %{"user_id" => user.id})
+ end
+
set_cache(user)
end
end
@@ -1566,7 +1581,7 @@ defmodule Pleroma.User do
unmute(muter, mutee)
else
{who, result} = error ->
- Logger.warn(
+ Logger.warning(
"User.unmute/2 failed. #{who}: #{result}, muter_id: #{muter_id}, mutee_id: #{mutee_id}"
)
@@ -1788,14 +1803,17 @@ defmodule Pleroma.User do
BackgroundWorker.enqueue("user_activation", %{"user_id" => user.id, "status" => status})
end
- @spec set_activation([User.t()], boolean()) :: {:ok, User.t()} | {:error, Changeset.t()}
+ @spec set_activation([User.t()], boolean()) :: {:ok, User.t()} | {:error, Ecto.Changeset.t()}
def set_activation(users, status) when is_list(users) do
Repo.transaction(fn ->
- for user <- users, do: set_activation(user, status)
+ for user <- users do
+ {:ok, user} = set_activation(user, status)
+ user
+ end
end)
end
- @spec set_activation(User.t(), boolean()) :: {:ok, User.t()} | {:error, Changeset.t()}
+ @spec set_activation(User.t(), boolean()) :: {:ok, User.t()} | {:error, Ecto.Changeset.t()}
def set_activation(%User{} = user, status) do
with {:ok, user} <- set_activation_status(user, status) do
user
@@ -1873,7 +1891,7 @@ defmodule Pleroma.User do
|> update_and_set_cache()
end
- @spec purge_user_changeset(User.t()) :: Changeset.t()
+ @spec purge_user_changeset(User.t()) :: Ecto.Changeset.t()
def purge_user_changeset(user) do
# "Right to be forgotten"
# https://gdpr.eu/right-to-be-forgotten/
@@ -1898,7 +1916,6 @@ defmodule Pleroma.User do
confirmation_token: nil,
domain_blocks: [],
is_active: false,
- ap_enabled: false,
is_moderator: false,
is_admin: false,
mascot: nil,
@@ -1977,8 +1994,45 @@ defmodule Pleroma.User do
maybe_delete_from_db(user)
end
+ def perform(:verify_fields_links, user) do
+ profile_urls = [user.ap_id]
+
+ fields =
+ user.raw_fields
+ |> Enum.map(&verify_field_link(&1, profile_urls))
+
+ changeset =
+ user
+ |> update_changeset(%{raw_fields: fields})
+
+ with {:ok, user} <- Repo.update(changeset, stale_error_field: :id) do
+ set_cache(user)
+ end
+ end
+
def perform(:set_activation_async, user, status), do: set_activation(user, status)
+ defp verify_field_link(field, profile_urls) do
+ verified_at =
+ with %{"value" => value} <- field,
+ {:verified_at, nil} <- {:verified_at, Map.get(field, "verified_at")},
+ %{scheme: scheme, userinfo: nil, host: host}
+ when not_empty_string(host) and scheme in ["http", "https"] <-
+ URI.parse(value),
+ {:not_idn, true} <- {:not_idn, to_string(:idna.encode(host)) == host},
+ "me" <- Pleroma.Web.RelMe.maybe_put_rel_me(value, profile_urls) do
+ CommonUtils.to_masto_date(NaiveDateTime.utc_now())
+ else
+ {:verified_at, value} when not_empty_string(value) ->
+ value
+
+ _ ->
+ nil
+ end
+
+ Map.put(field, "verified_at", verified_at)
+ end
+
@spec external_users_query() :: Ecto.Query.t()
def external_users_query do
User.Query.build(%{
@@ -2143,7 +2197,7 @@ defmodule Pleroma.User do
def public_key(_), do: {:error, "key not found"}
def get_public_key_for_ap_id(ap_id) do
- with {:ok, %User{} = user} <- get_or_fetch_by_ap_id(ap_id),
+ with %User{} = user <- get_cached_by_ap_id(ap_id),
{:ok, public_key} <- public_key(user) do
{:ok, public_key}
else
@@ -2151,10 +2205,6 @@ defmodule Pleroma.User do
end
end
- def ap_enabled?(%User{local: true}), do: true
- def ap_enabled?(%User{ap_enabled: ap_enabled}), do: ap_enabled
- def ap_enabled?(_), do: false
-
@doc "Gets or fetch a user by uri or nickname."
@spec get_or_fetch(String.t()) :: {:ok, User.t()} | {:error, String.t()}
def get_or_fetch("http://" <> _host = uri), do: get_or_fetch_by_ap_id(uri)
@@ -2263,7 +2313,7 @@ defmodule Pleroma.User do
if String.contains?(user.nickname, "@") do
user.nickname
else
- %{host: host} = URI.parse(user.ap_id)
+ host = Pleroma.Web.WebFinger.host()
user.nickname <> "@" <> host
end
end
@@ -2369,7 +2419,7 @@ defmodule Pleroma.User do
updated_user
end
- @spec set_confirmation(User.t(), boolean()) :: {:ok, User.t()} | {:error, Changeset.t()}
+ @spec set_confirmation(User.t(), boolean()) :: {:ok, User.t()} | {:error, Ecto.Changeset.t()}
def set_confirmation(%User{} = user, bool) do
user
|> confirmation_changeset(set_confirmation: bool)
@@ -2413,9 +2463,9 @@ defmodule Pleroma.User do
defp put_password_hash(changeset), do: changeset
- def is_internal_user?(%User{nickname: nil}), do: true
- def is_internal_user?(%User{local: true, nickname: "internal." <> _}), do: true
- def is_internal_user?(_), do: false
+ def internal?(%User{nickname: nil}), do: true
+ def internal?(%User{local: true, nickname: "internal." <> _}), do: true
+ def internal?(_), do: false
# A hack because user delete activities have a fake id for whatever reason
# TODO: Get rid of this
@@ -2547,7 +2597,7 @@ defmodule Pleroma.User do
|> update_and_set_cache()
end
- @spec confirmation_changeset(User.t(), keyword()) :: Changeset.t()
+ @spec confirmation_changeset(User.t(), keyword()) :: Ecto.Changeset.t()
def confirmation_changeset(user, set_confirmation: confirmed?) do
params =
if confirmed? do
@@ -2565,9 +2615,9 @@ defmodule Pleroma.User do
cast(user, params, [:is_confirmed, :confirmation_token])
end
- @spec approval_changeset(User.t(), keyword()) :: Changeset.t()
- def approval_changeset(user, set_approval: approved?) do
- cast(user, %{is_approved: approved?}, [:is_approved])
+ @spec approval_changeset(Ecto.Changeset.t(), keyword()) :: Ecto.Changeset.t()
+ def approval_changeset(changeset, set_approval: approved?) do
+ cast(changeset, %{is_approved: approved?}, [:is_approved])
end
@spec add_pinned_object_id(User.t(), String.t()) :: {:ok, User.t()} | {:error, term()}
@@ -2670,10 +2720,11 @@ defmodule Pleroma.User do
# - display name
def sanitize_html(%User{} = user, filter) do
fields =
- Enum.map(user.fields, fn %{"name" => name, "value" => value} ->
+ Enum.map(user.fields, fn %{"name" => name, "value" => value} = fields ->
%{
"name" => name,
- "value" => HTML.filter_tags(value, Pleroma.HTML.Scrubber.LinksOnly)
+ "value" => HTML.filter_tags(value, Pleroma.HTML.Scrubber.LinksOnly),
+ "verified_at" => Map.get(fields, "verified_at")
}
end)
@@ -2692,6 +2743,8 @@ defmodule Pleroma.User do
|> update_and_set_cache()
end
+ def update_last_active_at(user), do: user
+
def active_user_count(days \\ 30) do
active_after = Timex.shift(NaiveDateTime.utc_now(), days: -days)
diff --git a/lib/pleroma/user/.welcome_message.ex~.un~ b/lib/pleroma/user/.welcome_message.ex~.un~
deleted file mode 100755
index 45c641d..0000000
Binary files a/lib/pleroma/user/.welcome_message.ex~.un~ and /dev/null differ
diff --git a/lib/pleroma/user/backup.ex b/lib/pleroma/user/backup.ex
old mode 100755
new mode 100644
index 9df0106..65e0bac
--- a/lib/pleroma/user/backup.ex
+++ b/lib/pleroma/user/backup.ex
@@ -9,28 +9,36 @@ defmodule Pleroma.User.Backup do
import Ecto.Query
import Pleroma.Web.Gettext
+ require Logger
require Pleroma.Constants
alias Pleroma.Activity
alias Pleroma.Bookmark
alias Pleroma.Repo
alias Pleroma.User
+ alias Pleroma.User.Backup.State
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.ActivityPub.UserView
alias Pleroma.Workers.BackupWorker
+ @type t :: %__MODULE__{}
+
schema "backups" do
field(:content_type, :string)
field(:file_name, :string)
field(:file_size, :integer, default: 0)
field(:processed, :boolean, default: false)
+ field(:state, State, default: :invalid)
+ field(:processed_number, :integer, default: 0)
belongs_to(:user, User, type: FlakeId.Ecto.CompatType)
timestamps()
end
+ @config_impl Application.compile_env(:pleroma, [__MODULE__, :config_impl], Pleroma.Config)
+
def create(user, admin_id \\ nil) do
with :ok <- validate_limit(user, admin_id),
{:ok, backup} <- user |> new() |> Repo.insert() do
@@ -46,7 +54,8 @@ defmodule Pleroma.User.Backup do
%__MODULE__{
user_id: user.id,
content_type: "application/zip",
- file_name: name
+ file_name: name,
+ state: :pending
}
end
@@ -109,30 +118,109 @@ defmodule Pleroma.User.Backup do
def get(id), do: Repo.get(__MODULE__, id)
- def process(%__MODULE__{} = backup) do
- with {:ok, zip_file} <- export(backup),
- {:ok, %{size: size}} <- File.stat(zip_file),
- {:ok, _upload} <- upload(backup, zip_file) do
- backup
- |> cast(%{file_size: size, processed: true}, [:file_size, :processed])
- |> Repo.update()
+ defp set_state(backup, state, processed_number \\ nil) do
+ struct =
+ %{state: state}
+ |> Pleroma.Maps.put_if_present(:processed_number, processed_number)
+
+ backup
+ |> cast(struct, [:state, :processed_number])
+ |> Repo.update()
+ end
+
+ def process(
+ %__MODULE__{} = backup,
+ processor_module \\ __MODULE__.Processor
+ ) do
+ set_state(backup, :running, 0)
+
+ current_pid = self()
+
+ task =
+ Task.Supervisor.async_nolink(
+ Pleroma.TaskSupervisor,
+ processor_module,
+ :do_process,
+ [backup, current_pid]
+ )
+
+ wait_backup(backup, backup.processed_number, task)
+ end
+
+ defp wait_backup(backup, current_processed, task) do
+ wait_time = @config_impl.get([__MODULE__, :process_wait_time])
+
+ receive do
+ {:progress, new_processed} ->
+ total_processed = current_processed + new_processed
+
+ set_state(backup, :running, total_processed)
+ wait_backup(backup, total_processed, task)
+
+ {:DOWN, _ref, _proc, _pid, reason} ->
+ backup = get(backup.id)
+
+ if reason != :normal do
+ Logger.error("Backup #{backup.id} process ended abnormally: #{inspect(reason)}")
+
+ {:ok, backup} = set_state(backup, :failed)
+
+ cleanup(backup)
+
+ {:error,
+ %{
+ backup: backup,
+ reason: :exit,
+ details: reason
+ }}
+ else
+ {:ok, backup}
+ end
+ after
+ wait_time ->
+ Logger.error(
+ "Backup #{backup.id} timed out after no response for #{wait_time}ms, terminating"
+ )
+
+ Task.Supervisor.terminate_child(Pleroma.TaskSupervisor, task.pid)
+
+ {:ok, backup} = set_state(backup, :failed)
+
+ cleanup(backup)
+
+ {:error,
+ %{
+ backup: backup,
+ reason: :timeout
+ }}
end
end
- @files ['actor.json', 'outbox.json', 'likes.json', 'bookmarks.json']
- def export(%__MODULE__{} = backup) do
+ @files [
+ 'actor.json',
+ 'outbox.json',
+ 'likes.json',
+ 'bookmarks.json',
+ 'followers.json',
+ 'following.json'
+ ]
+ @spec export(Pleroma.User.Backup.t(), pid()) :: {:ok, String.t()} | :error
+ def export(%__MODULE__{} = backup, caller_pid) do
backup = Repo.preload(backup, :user)
- name = String.trim_trailing(backup.file_name, ".zip")
- dir = dir(name)
+ dir = backup_tempdir(backup)
with :ok <- File.mkdir(dir),
- :ok <- actor(dir, backup.user),
- :ok <- statuses(dir, backup.user),
- :ok <- likes(dir, backup.user),
- :ok <- bookmarks(dir, backup.user),
- {:ok, zip_path} <- :zip.create(String.to_charlist(dir <> ".zip"), @files, cwd: dir),
+ :ok <- actor(dir, backup.user, caller_pid),
+ :ok <- statuses(dir, backup.user, caller_pid),
+ :ok <- likes(dir, backup.user, caller_pid),
+ :ok <- bookmarks(dir, backup.user, caller_pid),
+ :ok <- followers(dir, backup.user, caller_pid),
+ :ok <- following(dir, backup.user, caller_pid),
+ {:ok, zip_path} <- :zip.create(backup.file_name, @files, cwd: dir),
{:ok, _} <- File.rm_rf(dir) do
- {:ok, to_string(zip_path)}
+ {:ok, zip_path}
+ else
+ _ -> :error
end
end
@@ -157,11 +245,12 @@ defmodule Pleroma.User.Backup do
end
end
- defp actor(dir, user) do
+ defp actor(dir, user, caller_pid) do
with {:ok, json} <-
UserView.render("user.json", %{user: user})
|> Map.merge(%{"likes" => "likes.json", "bookmarks" => "bookmarks.json"})
|> Jason.encode() do
+ send(caller_pid, {:progress, 1})
File.write(Path.join(dir, "actor.json"), json)
end
end
@@ -180,47 +269,80 @@ defmodule Pleroma.User.Backup do
)
end
- defp write(query, dir, name, fun) do
+ defp should_report?(num, chunk_size), do: rem(num, chunk_size) == 0
+
+ defp backup_tempdir(backup) do
+ name = String.trim_trailing(backup.file_name, ".zip")
+ dir(name)
+ end
+
+ defp cleanup(backup) do
+ dir = backup_tempdir(backup)
+ File.rm_rf(dir)
+ end
+
+ defp write(query, dir, name, fun, caller_pid) do
path = Path.join(dir, "#{name}.json")
+ chunk_size = Pleroma.Config.get([__MODULE__, :process_chunk_size])
+
with {:ok, file} <- File.open(path, [:write, :utf8]),
:ok <- write_header(file, name) do
total =
query
- |> Pleroma.Repo.chunk_stream(100)
+ |> Pleroma.Repo.chunk_stream(chunk_size, _returns_as = :one, timeout: :infinity)
|> Enum.reduce(0, fn i, acc ->
- with {:ok, data} <- fun.(i),
+ with {:ok, data} <-
+ (try do
+ fun.(i)
+ rescue
+ e -> {:error, e}
+ end),
{:ok, str} <- Jason.encode(data),
:ok <- IO.write(file, str <> ",\n") do
+ if should_report?(acc + 1, chunk_size) do
+ send(caller_pid, {:progress, chunk_size})
+ end
+
acc + 1
else
- _ -> acc
+ {:error, e} ->
+ Logger.warning(
+ "Error processing backup item: #{inspect(e)}\n The item is: #{inspect(i)}"
+ )
+
+ acc
+
+ _ ->
+ acc
end
end)
+ send(caller_pid, {:progress, rem(total, chunk_size)})
+
with :ok <- :file.pwrite(file, {:eof, -2}, "\n],\n \"totalItems\": #{total}}") do
File.close(file)
end
end
end
- defp bookmarks(dir, %{id: user_id} = _user) do
+ defp bookmarks(dir, %{id: user_id} = _user, caller_pid) do
Bookmark
|> where(user_id: ^user_id)
|> join(:inner, [b], activity in assoc(b, :activity))
|> select([b, a], %{id: b.id, object: fragment("(?)->>'object'", a.data)})
- |> write(dir, "bookmarks", fn a -> {:ok, a.object} end)
+ |> write(dir, "bookmarks", fn a -> {:ok, a.object} end, caller_pid)
end
- defp likes(dir, user) do
+ defp likes(dir, user, caller_pid) do
user.ap_id
|> Activity.Queries.by_actor()
|> Activity.Queries.by_type("Like")
|> select([like], %{id: like.id, object: fragment("(?)->>'object'", like.data)})
- |> write(dir, "likes", fn a -> {:ok, a.object} end)
+ |> write(dir, "likes", fn a -> {:ok, a.object} end, caller_pid)
end
- defp statuses(dir, user) do
+ defp statuses(dir, user, caller_pid) do
opts =
%{}
|> Map.put(:type, ["Create", "Announce"])
@@ -233,10 +355,59 @@ defmodule Pleroma.User.Backup do
]
|> Enum.concat()
|> ActivityPub.fetch_activities_query(opts)
- |> write(dir, "outbox", fn a ->
- with {:ok, activity} <- Transmogrifier.prepare_outgoing(a.data) do
- {:ok, Map.delete(activity, "@context")}
- end
- end)
+ |> write(
+ dir,
+ "outbox",
+ fn a ->
+ with {:ok, activity} <- Transmogrifier.prepare_outgoing(a.data) do
+ {:ok, Map.delete(activity, "@context")}
+ end
+ end,
+ caller_pid
+ )
+ end
+
+ defp followers(dir, user, caller_pid) do
+ User.get_followers_query(user)
+ |> write(dir, "followers", fn a -> {:ok, a.ap_id} end, caller_pid)
+ end
+
+ defp following(dir, user, caller_pid) do
+ User.get_friends_query(user)
+ |> write(dir, "following", fn a -> {:ok, a.ap_id} end, caller_pid)
+ end
+end
+
+defmodule Pleroma.User.Backup.ProcessorAPI do
+ @callback do_process(%Pleroma.User.Backup{}, pid()) ::
+ {:ok, %Pleroma.User.Backup{}} | {:error, any()}
+end
+
+defmodule Pleroma.User.Backup.Processor do
+ @behaviour Pleroma.User.Backup.ProcessorAPI
+
+ alias Pleroma.Repo
+ alias Pleroma.User.Backup
+
+ import Ecto.Changeset
+
+ @impl true
+ def do_process(backup, current_pid) do
+ with {:ok, zip_file} <- Backup.export(backup, current_pid),
+ {:ok, %{size: size}} <- File.stat(zip_file),
+ {:ok, _upload} <- Backup.upload(backup, zip_file) do
+ backup
+ |> cast(
+ %{
+ file_size: size,
+ processed: true,
+ state: :complete
+ },
+ [:file_size, :processed, :state]
+ )
+ |> Repo.update()
+ else
+ e -> {:error, e}
+ end
end
end
diff --git a/lib/pleroma/user/import.ex b/lib/pleroma/user/import.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/user/notification_setting.ex b/lib/pleroma/user/notification_setting.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/user/query.ex b/lib/pleroma/user/query.ex
old mode 100755
new mode 100644
index 3e090ca..cd95864
--- a/lib/pleroma/user/query.ex
+++ b/lib/pleroma/user/query.ex
@@ -22,7 +22,7 @@ defmodule Pleroma.User.Query do
- pass non empty string
- e.g. Pleroma.User.Query.build(%{email: "email@example.com"})
- *contains criteria*
- - add field to @containns_criteria list
+ - add field to @contains_criteria list
- pass values list
- e.g. Pleroma.User.Query.build(%{ap_id: ["http://ap_id1", "http://ap_id2"]})
"""
@@ -71,7 +71,7 @@ defmodule Pleroma.User.Query do
@equal_criteria [:email]
@contains_criteria [:ap_id, :nickname]
- @spec build(Query.t(), criteria()) :: Query.t()
+ @spec build(Ecto.Query.t(), criteria()) :: Ecto.Query.t()
def build(query \\ base_query(), criteria) do
prepare_query(query, criteria)
end
diff --git a/lib/pleroma/user/search.ex b/lib/pleroma/user/search.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/user/welcome_chat_message.ex b/lib/pleroma/user/welcome_chat_message.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/user/welcome_email.ex b/lib/pleroma/user/welcome_email.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/user/welcome_message.ex b/lib/pleroma/user/welcome_message.ex
old mode 100755
new mode 100644
index 0442189..6010e80
--- a/lib/pleroma/user/welcome_message.ex
+++ b/lib/pleroma/user/welcome_message.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors
+# Copyright © 2017-2022 Pleroma Authors
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.User.WelcomeMessage do
@@ -23,7 +23,7 @@ defmodule Pleroma.User.WelcomeMessage do
CommonAPI.post(
sender,
%{
- visibility: "public",
+ visibility: "direct",
status: "@#{nickname}\n#{message}"
}
)
diff --git a/lib/pleroma/user_invite_token.ex b/lib/pleroma/user_invite_token.ex
old mode 100755
new mode 100644
index b242a88..4bfb3a6
--- a/lib/pleroma/user_invite_token.ex
+++ b/lib/pleroma/user_invite_token.ex
@@ -64,7 +64,7 @@ defmodule Pleroma.UserInviteToken do
end
@spec update_invite(UserInviteToken.t(), map()) ::
- {:ok, UserInviteToken.t()} | {:error, Changeset.t()}
+ {:ok, UserInviteToken.t()} | {:error, Ecto.Changeset.t()}
def update_invite(invite, changes) do
change(invite, changes) |> Repo.update()
end
diff --git a/lib/pleroma/user_note.ex b/lib/pleroma/user_note.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/user_relationship.ex b/lib/pleroma/user_relationship.ex
old mode 100755
new mode 100644
index fbecf31..82fcc1c
--- a/lib/pleroma/user_relationship.ex
+++ b/lib/pleroma/user_relationship.ex
@@ -14,6 +14,8 @@ defmodule Pleroma.UserRelationship do
alias Pleroma.User
alias Pleroma.UserRelationship
+ @type t :: %__MODULE__{}
+
schema "user_relationships" do
belongs_to(:source, User, type: FlakeId.Ecto.CompatType)
belongs_to(:target, User, type: FlakeId.Ecto.CompatType)
diff --git a/lib/pleroma/utils.ex b/lib/pleroma/utils.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web.ex b/lib/pleroma/web.ex
old mode 100755
new mode 100644
index aee41b0..7a8b176
--- a/lib/pleroma/web.ex
+++ b/lib/pleroma/web.ex
@@ -136,7 +136,7 @@ defmodule Pleroma.Web do
namespace: Pleroma.Web
# Import convenience functions from controllers
- import Phoenix.Controller, only: [get_csrf_token: 0, get_flash: 2, view_module: 1]
+ import Phoenix.Controller, only: [get_csrf_token: 0, view_module: 1]
import Pleroma.Web.ErrorHelpers
import Pleroma.Web.Gettext
diff --git a/lib/pleroma/web/.router.ex.un~ b/lib/pleroma/web/.router.ex.un~
deleted file mode 100755
index 7ec278f..0000000
Binary files a/lib/pleroma/web/.router.ex.un~ and /dev/null differ
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
old mode 100755
new mode 100644
index 1ab2db9..a1fccc7
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -74,29 +74,40 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp check_remote_limit(_), do: true
def increase_note_count_if_public(actor, object) do
- if is_public?(object), do: User.increase_note_count(actor), else: {:ok, actor}
+ if public?(object), do: User.increase_note_count(actor), else: {:ok, actor}
end
def decrease_note_count_if_public(actor, object) do
- if is_public?(object), do: User.decrease_note_count(actor), else: {:ok, actor}
+ if public?(object), do: User.decrease_note_count(actor), else: {:ok, actor}
end
def update_last_status_at_if_public(actor, object) do
- if is_public?(object), do: User.update_last_status_at(actor), else: {:ok, actor}
+ if public?(object), do: User.update_last_status_at(actor), else: {:ok, actor}
end
defp increase_replies_count_if_reply(%{
"object" => %{"inReplyTo" => reply_ap_id} = object,
"type" => "Create"
}) do
- if is_public?(object) do
+ if public?(object) do
Object.increase_replies_count(reply_ap_id)
end
end
defp increase_replies_count_if_reply(_create_data), do: :noop
- @object_types ~w[ChatMessage Question Answer Audio Video Event Article Note Page]
+ defp increase_quotes_count_if_quote(%{
+ "object" => %{"quoteUrl" => quote_ap_id} = object,
+ "type" => "Create"
+ }) do
+ if public?(object) do
+ Object.increase_quotes_count(quote_ap_id)
+ end
+ end
+
+ defp increase_quotes_count_if_quote(_create_data), do: :noop
+
+ @object_types ~w[ChatMessage Question Answer Audio Video Image Event Article Note Page]
@impl true
def persist(%{"type" => type} = object, meta) when type in @object_types do
with {:ok, object} <- Object.create(object) do
@@ -136,9 +147,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
# Splice in the child object if we have one.
activity = Maps.put_if_present(activity, :object, object)
- ConcurrentLimiter.limit(Pleroma.Web.RichMedia.Helpers, fn ->
- Task.start(fn -> Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) end)
- end)
+ Pleroma.Web.RichMedia.Card.get_by_activity(activity)
+
+ # Add local posts to search index
+ if local, do: Pleroma.Search.add_to_index(activity)
{:ok, activity}
else
@@ -163,7 +175,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
id: "pleroma:fakeid"
}
- Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
+ Pleroma.Web.RichMedia.Card.get_by_activity(activity)
{:ok, activity}
{:remote_limit_pass, _} ->
@@ -299,11 +311,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
with {:ok, activity} <- insert(create_data, local, fake),
{:fake, false, activity} <- {:fake, fake, activity},
_ <- increase_replies_count_if_reply(create_data),
+ _ <- increase_quotes_count_if_quote(create_data),
{:quick_insert, false, activity} <- {:quick_insert, quick_insert?, activity},
{:ok, _actor} <- increase_note_count_if_public(actor, activity),
{:ok, _actor} <- update_last_status_at_if_public(actor, activity),
_ <- notify_and_stream(activity),
:ok <- maybe_schedule_poll_notifications(activity),
+ :ok <- maybe_handle_group_posts(activity),
:ok <- maybe_federate(activity) do
{:ok, activity}
else
@@ -455,6 +469,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|> maybe_preload_objects(opts)
|> maybe_preload_bookmarks(opts)
|> maybe_set_thread_muted_field(opts)
+ |> restrict_unauthenticated(opts[:user])
|> restrict_blocked(opts)
|> restrict_blockers_visibility(opts)
|> restrict_recipients(recipients, opts[:user])
@@ -482,7 +497,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
@spec fetch_latest_direct_activity_id_for_context(String.t(), keyword() | map()) ::
- FlakeId.Ecto.CompatType.t() | nil
+ Ecto.UUID.t() | nil
def fetch_latest_direct_activity_id_for_context(context, opts \\ %{}) do
context
|> fetch_activities_for_context_query(Map.merge(%{skip_preload: true}, opts))
@@ -1215,6 +1230,35 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp restrict_filtered(query, _), do: query
+ defp restrict_unauthenticated(query, nil) do
+ local = Config.restrict_unauthenticated_access?(:activities, :local)
+ remote = Config.restrict_unauthenticated_access?(:activities, :remote)
+
+ cond do
+ local and remote ->
+ from(activity in query, where: false)
+
+ local ->
+ from(activity in query, where: activity.local == false)
+
+ remote ->
+ from(activity in query, where: activity.local == true)
+
+ true ->
+ query
+ end
+ end
+
+ defp restrict_unauthenticated(query, _), do: query
+
+ defp restrict_quote_url(query, %{quote_url: quote_url}) do
+ from([_activity, object] in query,
+ where: fragment("(?)->'quoteUrl' = ?", object.data, ^quote_url)
+ )
+ end
+
+ defp restrict_quote_url(query, _), do: query
+
defp exclude_poll_votes(query, %{include_poll_votes: true}), do: query
defp exclude_poll_votes(query, _) do
@@ -1377,6 +1421,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|> restrict_instance(opts)
|> restrict_announce_object_actor(opts)
|> restrict_filtered(opts)
+ |> restrict_quote_url(opts)
|> maybe_restrict_deactivated_users(opts)
|> exclude_poll_votes(opts)
|> exclude_chat_messages(opts)
@@ -1547,7 +1592,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
%{
ap_id: data["id"],
uri: get_actor_url(data["url"]),
- ap_enabled: true,
banner: normalize_image(data["image"]),
fields: fields,
emoji: emojis,
@@ -1652,9 +1696,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
Fetcher.fetch_and_contain_remote_object_from_id(first) do
{:ok, false}
else
- {:error, {:ok, %{status: code}}} when code in [401, 403] -> {:ok, true}
- {:error, _} = e -> e
- e -> {:error, e}
+ {:error, _} -> {:ok, true}
end
end
@@ -1668,7 +1710,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
end
- def fetch_and_prepare_user_from_ap_id(ap_id, additional \\ []) do
+ defp fetch_and_prepare_user_from_ap_id(ap_id, additional) do
with {:ok, data} <- Fetcher.fetch_and_contain_remote_object_from_id(ap_id),
{:ok, data} <- user_data_from_user_object(data, additional) do
{:ok, maybe_update_follow_information(data)}
@@ -1721,6 +1763,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end)
end
+ def pin_data_from_featured_collection(obj) do
+ Logger.error("Could not parse featured collection #{inspect(obj)}")
+ %{}
+ end
+
def fetch_and_prepare_featured_from_ap_id(nil) do
{:ok, %{}}
end
@@ -1751,24 +1798,20 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
def make_user_from_ap_id(ap_id, additional \\ []) do
user = User.get_cached_by_ap_id(ap_id)
- if user && !User.ap_enabled?(user) do
- Transmogrifier.upgrade_user_from_ap_id(ap_id)
- else
- with {:ok, data} <- fetch_and_prepare_user_from_ap_id(ap_id, additional) do
- {:ok, _pid} = Task.start(fn -> pinned_fetch_task(data) end)
+ with {:ok, data} <- fetch_and_prepare_user_from_ap_id(ap_id, additional) do
+ {:ok, _pid} = Task.start(fn -> pinned_fetch_task(data) end)
- if user do
- user
- |> User.remote_user_changeset(data)
- |> User.update_and_set_cache()
- else
- maybe_handle_clashing_nickname(data)
+ if user do
+ user
+ |> User.remote_user_changeset(data)
+ |> User.update_and_set_cache()
+ else
+ maybe_handle_clashing_nickname(data)
- data
- |> User.remote_user_changeset()
- |> Repo.insert()
- |> User.set_cache()
- end
+ data
+ |> User.remote_user_changeset()
+ |> Repo.insert()
+ |> User.set_cache()
end
end
end
diff --git a/lib/pleroma/web/activity_pub/activity_pub/persisting.ex b/lib/pleroma/web/activity_pub/activity_pub/persisting.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/activity_pub/streaming.ex b/lib/pleroma/web/activity_pub/activity_pub/streaming.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
old mode 100755
new mode 100644
index 1357c37..e38a949
--- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
@@ -273,12 +273,17 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
end
def inbox(%{assigns: %{valid_signature: true}} = conn, %{"nickname" => nickname} = params) do
- with %User{} = recipient <- User.get_cached_by_nickname(nickname),
- {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(params["actor"]),
+ with %User{is_active: true} = recipient <- User.get_cached_by_nickname(nickname),
+ {:ok, %User{is_active: true} = actor} <- User.get_or_fetch_by_ap_id(params["actor"]),
true <- Utils.recipient_in_message(recipient, actor, params),
params <- Utils.maybe_splice_recipient(recipient.ap_id, params) do
Federator.incoming_ap_doc(params)
json(conn, "ok")
+ else
+ _ ->
+ conn
+ |> put_status(:bad_request)
+ |> json("Invalid request.")
end
end
@@ -287,10 +292,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
json(conn, "ok")
end
- def inbox(%{assigns: %{valid_signature: false}} = conn, _params) do
- conn
- |> put_status(:bad_request)
- |> json("Invalid HTTP Signature")
+ def inbox(%{assigns: %{valid_signature: false}, req_headers: req_headers} = conn, params) do
+ Federator.incoming_ap_doc(%{req_headers: req_headers, params: params})
+ json(conn, "ok")
end
# POST /relay/inbox -or- POST /internal/fetch/inbox
@@ -476,7 +480,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|> json(message)
e ->
- Logger.warn(fn -> "AP C2S: #{inspect(e)}" end)
+ Logger.warning(fn -> "AP C2S: #{inspect(e)}" end)
conn
|> put_status(:bad_request)
diff --git a/lib/pleroma/web/activity_pub/builder.ex b/lib/pleroma/web/activity_pub/builder.ex
old mode 100755
new mode 100644
index 5320475..2a1e562
--- a/lib/pleroma/web/activity_pub/builder.ex
+++ b/lib/pleroma/web/activity_pub/builder.ex
@@ -9,6 +9,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
This module encodes our addressing policies and general shape of our objects.
"""
+ alias Pleroma.Activity
alias Pleroma.Emoji
alias Pleroma.Object
alias Pleroma.User
@@ -16,6 +17,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.CommonAPI.ActivityDraft
+ alias Pleroma.Web.Endpoint
require Pleroma.Constants
@@ -54,13 +56,87 @@ defmodule Pleroma.Web.ActivityPub.Builder do
{:ok, data, []}
end
+ defp unicode_emoji_react(_object, data, emoji) do
+ data
+ |> Map.put("content", emoji)
+ |> Map.put("type", "EmojiReact")
+ end
+
+ defp add_emoji_content(data, emoji, url) do
+ tag = [
+ %{
+ "id" => url,
+ "type" => "Emoji",
+ "name" => Emoji.maybe_quote(emoji),
+ "icon" => %{
+ "type" => "Image",
+ "url" => url
+ }
+ }
+ ]
+
+ data
+ |> Map.put("content", Emoji.maybe_quote(emoji))
+ |> Map.put("type", "EmojiReact")
+ |> Map.put("tag", tag)
+ end
+
+ defp remote_custom_emoji_react(
+ %{data: %{"reactions" => existing_reactions}},
+ data,
+ emoji
+ ) do
+ [emoji_code, instance] = String.split(Emoji.maybe_strip_name(emoji), "@")
+
+ matching_reaction =
+ Enum.find(
+ existing_reactions,
+ fn [name, _, url] ->
+ if url != nil do
+ url = URI.parse(url)
+ url.host == instance && name == emoji_code
+ end
+ end
+ )
+
+ if matching_reaction do
+ [name, _, url] = matching_reaction
+ add_emoji_content(data, name, url)
+ else
+ {:error, "Could not react"}
+ end
+ end
+
+ defp remote_custom_emoji_react(_object, _data, _emoji) do
+ {:error, "Could not react"}
+ end
+
+ defp local_custom_emoji_react(data, emoji) do
+ with %{file: path} = emojo <- Emoji.get(emoji) do
+ url = "#{Endpoint.url()}#{path}"
+ add_emoji_content(data, emojo.code, url)
+ else
+ _ -> {:error, "Emoji does not exist"}
+ end
+ end
+
+ defp custom_emoji_react(object, data, emoji) do
+ if String.contains?(emoji, "@") do
+ remote_custom_emoji_react(object, data, emoji)
+ else
+ local_custom_emoji_react(data, emoji)
+ end
+ end
+
@spec emoji_react(User.t(), Object.t(), String.t()) :: {:ok, map(), keyword()}
def emoji_react(actor, object, emoji) do
with {:ok, data, meta} <- object_action(actor, object) do
data =
- data
- |> Map.put("content", emoji)
- |> Map.put("type", "EmojiReact")
+ if Emoji.unicode?(emoji) do
+ unicode_emoji_react(object, data, emoji)
+ else
+ custom_emoji_react(object, data, emoji)
+ end
{:ok, data, meta}
end
@@ -142,6 +218,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
"tag" => Keyword.values(draft.tags) |> Enum.uniq()
}
|> add_in_reply_to(draft.in_reply_to)
+ |> add_quote(draft.quote_post)
|> Map.merge(draft.extra)
{:ok, data, []}
@@ -157,6 +234,16 @@ defmodule Pleroma.Web.ActivityPub.Builder do
end
end
+ defp add_quote(object, nil), do: object
+
+ defp add_quote(object, quote_post) do
+ with %Object{} = quote_object <- Object.normalize(quote_post, fetch: false) do
+ Map.put(object, "quoteUrl", quote_object.data["id"])
+ else
+ _ -> object
+ end
+ end
+
def chat_message(actor, recipient, content, opts \\ []) do
basic = %{
"id" => Utils.generate_object_id(),
@@ -261,7 +348,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
actor.ap_id == Relay.ap_id() ->
[actor.follower_address]
- public? and Visibility.is_local_public?(object) ->
+ public? and Visibility.local_public?(object) ->
[actor.follower_address, object.data["actor"], Utils.as_local_public()]
public? ->
@@ -289,7 +376,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
# Address the actor of the object, and our actor's follower collection if the post is public.
to =
- if Visibility.is_public?(object) do
+ if Visibility.public?(object) do
[actor.follower_address, object.data["actor"]]
else
[object.data["actor"]]
diff --git a/lib/pleroma/web/activity_pub/internal_fetch_actor.ex b/lib/pleroma/web/activity_pub/internal_fetch_actor.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/mrf.ex b/lib/pleroma/web/activity_pub/mrf.ex
old mode 100755
new mode 100644
index ff9f844..1071f8e
--- a/lib/pleroma/web/activity_pub/mrf.ex
+++ b/lib/pleroma/web/activity_pub/mrf.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2022 Pleroma Authors
+# Copyright © 2017-2023 Pleroma Authors
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF do
@@ -54,6 +54,8 @@ defmodule Pleroma.Web.ActivityPub.MRF do
@required_description_keys [:key, :related_policy]
def filter_one(policy, message) do
+ Code.ensure_loaded(policy)
+
should_plug_history? =
if function_exported?(policy, :history_awareness, 0) do
policy.history_awareness()
@@ -137,7 +139,16 @@ defmodule Pleroma.Web.ActivityPub.MRF do
@spec subdomains_regex([String.t()]) :: [Regex.t()]
def subdomains_regex(domains) when is_list(domains) do
- for domain <- domains, do: ~r(^#{String.replace(domain, "*.", "(.*\\.)*")}$)i
+ for domain <- domains do
+ try do
+ target = String.replace(domain, "*.", "(.*\\.)*")
+ ~r<^#{target}$>i
+ rescue
+ e ->
+ Logger.error("MRF: Invalid subdomain Regex: #{domain}")
+ reraise e, __STACKTRACE__
+ end
+ end
end
@spec subdomain_match?([Regex.t()], String.t()) :: boolean()
@@ -188,6 +199,8 @@ defmodule Pleroma.Web.ActivityPub.MRF do
def config_descriptions(policies) do
Enum.reduce(policies, @mrf_config_descriptions, fn policy, acc ->
+ Code.ensure_loaded(policy)
+
if function_exported?(policy, :config_description, 0) do
description =
@default_description
@@ -199,7 +212,7 @@ defmodule Pleroma.Web.ActivityPub.MRF do
if Enum.all?(@required_description_keys, &Map.has_key?(description, &1)) do
[description | acc]
else
- Logger.warn(
+ Logger.warning(
"#{policy} config description doesn't have one or all required keys #{inspect(@required_description_keys)}"
)
diff --git a/lib/pleroma/web/activity_pub/mrf/activity_expiration_policy.ex b/lib/pleroma/web/activity_pub/mrf/activity_expiration_policy.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex b/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex
old mode 100755
new mode 100644
index 97d75ec..df4ba81
--- a/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex
@@ -56,8 +56,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy do
nick_score + name_score + actor_type_score
end
- defp determine_if_followbot(_), do: 0.0
-
defp bot_allowed?(%{"object" => target}, bot_actor) do
%User{} = user = normalize_by_ap_id(target)
diff --git a/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex b/lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/mrf/drop_policy.ex b/lib/pleroma/web/activity_pub/mrf/drop_policy.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/mrf/emoji_policy.ex b/lib/pleroma/web/activity_pub/mrf/emoji_policy.ex
new file mode 100644
index 0000000..f884962
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/mrf/emoji_policy.ex
@@ -0,0 +1,281 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2023 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.MRF.EmojiPolicy do
+ require Pleroma.Constants
+
+ alias Pleroma.Object.Updater
+ alias Pleroma.Web.ActivityPub.MRF.Utils
+
+ @moduledoc "Reject or force-unlisted emojis with certain URLs or names"
+
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
+
+ defp config_remove_url do
+ Pleroma.Config.get([:mrf_emoji, :remove_url], [])
+ end
+
+ defp config_remove_shortcode do
+ Pleroma.Config.get([:mrf_emoji, :remove_shortcode], [])
+ end
+
+ defp config_unlist_url do
+ Pleroma.Config.get([:mrf_emoji, :federated_timeline_removal_url], [])
+ end
+
+ defp config_unlist_shortcode do
+ Pleroma.Config.get([:mrf_emoji, :federated_timeline_removal_shortcode], [])
+ end
+
+ @impl Pleroma.Web.ActivityPub.MRF.Policy
+ def history_awareness, do: :manual
+
+ @impl Pleroma.Web.ActivityPub.MRF.Policy
+ def filter(%{"type" => type, "object" => %{"type" => objtype} = object} = message)
+ when type in ["Create", "Update"] and objtype in Pleroma.Constants.status_object_types() do
+ with {:ok, object} <-
+ Updater.do_with_history(object, fn object ->
+ {:ok, process_remove(object, :url, config_remove_url())}
+ end),
+ {:ok, object} <-
+ Updater.do_with_history(object, fn object ->
+ {:ok, process_remove(object, :shortcode, config_remove_shortcode())}
+ end),
+ activity <- Map.put(message, "object", object),
+ activity <- maybe_delist(activity) do
+ {:ok, activity}
+ end
+ end
+
+ @impl Pleroma.Web.ActivityPub.MRF.Policy
+ def filter(%{"type" => type} = object) when type in Pleroma.Constants.actor_types() do
+ with object <- process_remove(object, :url, config_remove_url()),
+ object <- process_remove(object, :shortcode, config_remove_shortcode()) do
+ {:ok, object}
+ end
+ end
+
+ @impl Pleroma.Web.ActivityPub.MRF.Policy
+ def filter(%{"type" => "EmojiReact"} = object) do
+ with {:ok, _} <-
+ matched_emoji_checker(config_remove_url(), config_remove_shortcode()).(object) do
+ {:ok, object}
+ else
+ _ ->
+ {:reject, "[EmojiPolicy] Rejected for having disallowed emoji"}
+ end
+ end
+
+ @impl Pleroma.Web.ActivityPub.MRF.Policy
+ def filter(message) do
+ {:ok, message}
+ end
+
+ defp match_string?(string, pattern) when is_binary(pattern) do
+ string == pattern
+ end
+
+ defp match_string?(string, %Regex{} = pattern) do
+ String.match?(string, pattern)
+ end
+
+ defp match_any?(string, patterns) do
+ Enum.any?(patterns, &match_string?(string, &1))
+ end
+
+ defp url_from_tag(%{"icon" => %{"url" => url}}), do: url
+ defp url_from_tag(_), do: nil
+
+ defp url_from_emoji({_name, url}), do: url
+
+ defp shortcode_from_tag(%{"name" => name}) when is_binary(name), do: String.trim(name, ":")
+ defp shortcode_from_tag(_), do: nil
+
+ defp shortcode_from_emoji({name, _url}), do: name
+
+ defp process_remove(object, :url, patterns) do
+ process_remove_impl(object, &url_from_tag/1, &url_from_emoji/1, patterns)
+ end
+
+ defp process_remove(object, :shortcode, patterns) do
+ process_remove_impl(object, &shortcode_from_tag/1, &shortcode_from_emoji/1, patterns)
+ end
+
+ defp process_remove_impl(object, extract_from_tag, extract_from_emoji, patterns) do
+ object =
+ if object["tag"] do
+ Map.put(
+ object,
+ "tag",
+ Enum.filter(
+ object["tag"],
+ fn
+ %{"type" => "Emoji"} = tag ->
+ str = extract_from_tag.(tag)
+
+ if is_binary(str) do
+ not match_any?(str, patterns)
+ else
+ true
+ end
+
+ _ ->
+ true
+ end
+ )
+ )
+ else
+ object
+ end
+
+ object =
+ if object["emoji"] do
+ Map.put(
+ object,
+ "emoji",
+ object["emoji"]
+ |> Enum.reduce(%{}, fn {name, url} = emoji, acc ->
+ if not match_any?(extract_from_emoji.(emoji), patterns) do
+ Map.put(acc, name, url)
+ else
+ acc
+ end
+ end)
+ )
+ else
+ object
+ end
+
+ object
+ end
+
+ defp matched_emoji_checker(urls, shortcodes) do
+ fn object ->
+ if any_emoji_match?(object, &url_from_tag/1, &url_from_emoji/1, urls) or
+ any_emoji_match?(
+ object,
+ &shortcode_from_tag/1,
+ &shortcode_from_emoji/1,
+ shortcodes
+ ) do
+ {:matched, nil}
+ else
+ {:ok, %{}}
+ end
+ end
+ end
+
+ defp maybe_delist(%{"object" => object, "to" => to, "type" => "Create"} = activity) do
+ check = matched_emoji_checker(config_unlist_url(), config_unlist_shortcode())
+
+ should_delist? = fn object ->
+ with {:ok, _} <- Pleroma.Object.Updater.do_with_history(object, check) do
+ false
+ else
+ _ -> true
+ end
+ end
+
+ if Pleroma.Constants.as_public() in to and should_delist?.(object) do
+ to = List.delete(to, Pleroma.Constants.as_public())
+ cc = [Pleroma.Constants.as_public() | activity["cc"] || []]
+
+ activity
+ |> Map.put("to", to)
+ |> Map.put("cc", cc)
+ else
+ activity
+ end
+ end
+
+ defp maybe_delist(activity), do: activity
+
+ defp any_emoji_match?(object, extract_from_tag, extract_from_emoji, patterns) do
+ Kernel.||(
+ Enum.any?(
+ object["tag"] || [],
+ fn
+ %{"type" => "Emoji"} = tag ->
+ str = extract_from_tag.(tag)
+
+ if is_binary(str) do
+ match_any?(str, patterns)
+ else
+ false
+ end
+
+ _ ->
+ false
+ end
+ ),
+ (object["emoji"] || [])
+ |> Enum.any?(fn emoji -> match_any?(extract_from_emoji.(emoji), patterns) end)
+ )
+ end
+
+ @impl Pleroma.Web.ActivityPub.MRF.Policy
+ def describe do
+ mrf_emoji =
+ Pleroma.Config.get(:mrf_emoji, [])
+ |> Enum.map(fn {key, value} ->
+ {key, Enum.map(value, &Utils.describe_regex_or_string/1)}
+ end)
+ |> Enum.into(%{})
+
+ {:ok, %{mrf_emoji: mrf_emoji}}
+ end
+
+ @impl Pleroma.Web.ActivityPub.MRF.Policy
+ def config_description do
+ %{
+ key: :mrf_emoji,
+ related_policy: "Pleroma.Web.ActivityPub.MRF.EmojiPolicy",
+ label: "MRF Emoji",
+ description:
+ "Reject or force-unlisted emojis whose URLs or names match a keyword or [Regex](https://hexdocs.pm/elixir/Regex.html).",
+ children: [
+ %{
+ key: :remove_url,
+ type: {:list, :string},
+ description: """
+ A list of patterns which result in emoji whose URL matches being removed from the message. This will apply to statuses, emoji reactions, and user profiles.
+
+ Each pattern can be a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`.
+ """,
+ suggestions: ["https://example.org/foo.png", ~r/example.org\/foo/iu]
+ },
+ %{
+ key: :remove_shortcode,
+ type: {:list, :string},
+ description: """
+ A list of patterns which result in emoji whose shortcode matches being removed from the message. This will apply to statuses, emoji reactions, and user profiles.
+
+ Each pattern can be a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`.
+ """,
+ suggestions: ["foo", ~r/foo/iu]
+ },
+ %{
+ key: :federated_timeline_removal_url,
+ type: {:list, :string},
+ description: """
+ A list of patterns which result in message with emojis whose URLs match being removed from federated timelines (a.k.a unlisted). This will apply only to statuses.
+
+ Each pattern can be a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`.
+ """,
+ suggestions: ["https://example.org/foo.png", ~r/example.org\/foo/iu]
+ },
+ %{
+ key: :federated_timeline_removal_shortcode,
+ type: {:list, :string},
+ description: """
+ A list of patterns which result in message with emojis whose shortcodes match being removed from federated timelines (a.k.a unlisted). This will apply only to statuses.
+
+ Each pattern can be a string or [Regex](https://hexdocs.pm/elixir/Regex.html) in the format of `~r/PATTERN/`.
+ """,
+ suggestions: ["foo", ~r/foo/iu]
+ }
+ ]
+ }
+ end
+end
diff --git a/lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex b/lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/mrf/follow_bot_policy.ex b/lib/pleroma/web/activity_pub/mrf/follow_bot_policy.ex
old mode 100755
new mode 100644
index 5b6adbb..5a4a976
--- a/lib/pleroma/web/activity_pub/mrf/follow_bot_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/follow_bot_policy.ex
@@ -19,7 +19,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.FollowBotPolicy do
try_follow(follower, message)
else
nil ->
- Logger.warn(
+ Logger.warning(
"#{__MODULE__} skipped because of missing `:mrf_follow_bot, :follower_nickname` configuration, the :follower_nickname
account does not exist, or the account is not correctly configured as a bot."
)
diff --git a/lib/pleroma/web/activity_pub/mrf/force_bot_unlisted_policy.ex b/lib/pleroma/web/activity_pub/mrf/force_bot_unlisted_policy.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/mrf/force_mention.ex b/lib/pleroma/web/activity_pub/mrf/force_mention.ex
new file mode 100644
index 0000000..3853489
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/mrf/force_mention.ex
@@ -0,0 +1,59 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2024 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.MRF.ForceMention do
+ require Pleroma.Constants
+
+ alias Pleroma.Config
+ alias Pleroma.Object
+ alias Pleroma.User
+
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
+
+ defp get_author(url) do
+ with %Object{data: %{"actor" => actor}} <- Object.normalize(url, fetch: false),
+ %User{ap_id: ap_id, nickname: nickname} <- User.get_cached_by_ap_id(actor) do
+ %{"type" => "Mention", "href" => ap_id, "name" => "@#{nickname}"}
+ else
+ _ -> nil
+ end
+ end
+
+ defp prepend_author(tags, _, false), do: tags
+
+ defp prepend_author(tags, nil, _), do: tags
+
+ defp prepend_author(tags, url, _) do
+ actor = get_author(url)
+
+ if not is_nil(actor) do
+ [actor | tags]
+ else
+ tags
+ end
+ end
+
+ @impl true
+ def filter(%{"type" => "Create", "object" => %{"tag" => tag} = object} = activity) do
+ tag =
+ tag
+ |> prepend_author(
+ object["inReplyTo"],
+ Config.get([:mrf_force_mention, :mention_parent, true])
+ )
+ |> prepend_author(
+ object["quoteUrl"],
+ Config.get([:mrf_force_mention, :mention_quoted, true])
+ )
+ |> Enum.uniq()
+
+ {:ok, put_in(activity["object"]["tag"], tag)}
+ end
+
+ @impl true
+ def filter(object), do: {:ok, object}
+
+ @impl true
+ def describe, do: {:ok, %{}}
+end
diff --git a/lib/pleroma/web/activity_pub/mrf/force_mentions_in_content.ex b/lib/pleroma/web/activity_pub/mrf/force_mentions_in_content.ex
old mode 100755
new mode 100644
index 7022456..5532093
--- a/lib/pleroma/web/activity_pub/mrf/force_mentions_in_content.ex
+++ b/lib/pleroma/web/activity_pub/mrf/force_mentions_in_content.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2022 Pleroma Authors
+# Copyright © 2017-2023 Pleroma Authors
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.ForceMentionsInContent do
@@ -95,11 +95,13 @@ defmodule Pleroma.Web.ActivityPub.MRF.ForceMentionsInContent do
|> Enum.reject(&is_nil/1)
|> sort_replied_user(replied_to_user)
- explicitly_mentioned_uris = extract_mention_uris_from_content(content)
+ explicitly_mentioned_uris =
+ extract_mention_uris_from_content(content)
+ |> MapSet.new()
added_mentions =
- Enum.reduce(mention_users, "", fn %User{ap_id: uri} = user, acc ->
- unless uri in explicitly_mentioned_uris do
+ Enum.reduce(mention_users, "", fn %User{ap_id: ap_id, uri: uri} = user, acc ->
+ if MapSet.disjoint?(MapSet.new([ap_id, uri]), explicitly_mentioned_uris) do
acc <> Formatter.mention_from_user(user, %{mentions_format: :compact}) <> " "
else
acc
diff --git a/lib/pleroma/web/activity_pub/mrf/hashtag_policy.ex b/lib/pleroma/web/activity_pub/mrf/hashtag_policy.ex
old mode 100755
new mode 100644
index b73fd97..fdb9a9d
--- a/lib/pleroma/web/activity_pub/mrf/hashtag_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/hashtag_policy.ex
@@ -9,7 +9,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.HashtagPolicy do
alias Pleroma.Object
@moduledoc """
- Reject, TWKN-remove or Set-Sensitive messsages with specific hashtags (without the leading #)
+ Reject, TWKN-remove or Set-Sensitive messages with specific hashtags (without the leading #)
Note: This MRF Policy is always enabled, if you want to disable it you have to set empty lists.
"""
@@ -84,7 +84,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.HashtagPolicy do
if hashtags != [] do
with {:ok, message} <- check_reject(message, hashtags),
{:ok, message} <-
- (if "type" == "Create" do
+ (if type == "Create" do
check_ftl_removal(message, hashtags)
else
{:ok, message}
diff --git a/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex b/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/mrf/inline_quote_policy.ex b/lib/pleroma/web/activity_pub/mrf/inline_quote_policy.ex
new file mode 100644
index 0000000..b7a01c2
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/mrf/inline_quote_policy.ex
@@ -0,0 +1,77 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.MRF.InlineQuotePolicy do
+ @moduledoc "Force a quote line into the message content."
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
+
+ defp build_inline_quote(template, url) do
+ quote_line = String.replace(template, "{url}", "#{url}")
+
+ "
#{quote_line}"
+ end
+
+ defp has_inline_quote?(content, quote_url) do
+ cond do
+ # Does the quote URL exist in the content?
+ content =~ quote_url -> true
+ # Does the content already have a .quote-inline span?
+ content =~ "" -> true
+ # No inline quote found
+ true -> false
+ end
+ end
+
+ defp filter_object(%{"quoteUrl" => quote_url} = object) do
+ content = object["content"] || ""
+
+ if has_inline_quote?(content, quote_url) do
+ object
+ else
+ template = Pleroma.Config.get([:mrf_inline_quote, :template])
+
+ content =
+ if String.ends_with?(content, "
"),
+ do:
+ String.trim_trailing(content, "") <>
+ build_inline_quote(template, quote_url) <> "",
+ else: content <> build_inline_quote(template, quote_url)
+
+ Map.put(object, "content", content)
+ end
+ end
+
+ @impl true
+ def filter(%{"object" => %{"quoteUrl" => _} = object} = activity) do
+ {:ok, Map.put(activity, "object", filter_object(object))}
+ end
+
+ @impl true
+ def filter(object), do: {:ok, object}
+
+ @impl true
+ def describe, do: {:ok, %{}}
+
+ @impl Pleroma.Web.ActivityPub.MRF.Policy
+ def history_awareness, do: :auto
+
+ @impl true
+ def config_description do
+ %{
+ key: :mrf_inline_quote,
+ related_policy: "Pleroma.Web.ActivityPub.MRF.InlineQuotePolicy",
+ label: "MRF Inline Quote Policy",
+ description: "Force quote url to appear in post content.",
+ children: [
+ %{
+ key: :template,
+ type: :string,
+ description:
+ "The template to append to the post. `{url}` will be replaced with the actual link to the quoted post.",
+ suggestions: ["RT: {url}"]
+ }
+ ]
+ }
+ end
+end
diff --git a/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex b/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex
old mode 100755
new mode 100644
index 687ec6c..729da4e
--- a/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex
@@ -5,18 +5,17 @@
defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
require Pleroma.Constants
+ alias Pleroma.Web.ActivityPub.MRF.Utils
+
@moduledoc "Reject or Word-Replace messages with a keyword or regex"
@behaviour Pleroma.Web.ActivityPub.MRF.Policy
- defp string_matches?(string, _) when not is_binary(string) do
- false
- end
defp string_matches?(string, pattern) when is_binary(pattern) do
String.contains?(string, pattern)
end
- defp string_matches?(string, pattern) do
+ defp string_matches?(string, %Regex{} = pattern) do
String.match?(string, pattern)
end
@@ -128,7 +127,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
@impl true
def describe do
- # This horror is needed to convert regex sigils to strings
mrf_keyword =
Pleroma.Config.get(:mrf_keyword, [])
|> Enum.map(fn {key, value} ->
@@ -136,21 +134,12 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
Enum.map(value, fn
{pattern, replacement} ->
%{
- "pattern" =>
- if not is_binary(pattern) do
- inspect(pattern)
- else
- pattern
- end,
+ "pattern" => Utils.describe_regex_or_string(pattern),
"replacement" => replacement
}
pattern ->
- if not is_binary(pattern) do
- inspect(pattern)
- else
- pattern
- end
+ Utils.describe_regex_or_string(pattern)
end)}
end)
|> Enum.into(%{})
diff --git a/lib/pleroma/web/activity_pub/mrf/media_proxy_warming_policy.ex b/lib/pleroma/web/activity_pub/mrf/media_proxy_warming_policy.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/mrf/mention_policy.ex b/lib/pleroma/web/activity_pub/mrf/mention_policy.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/mrf/no_empty_policy.ex b/lib/pleroma/web/activity_pub/mrf/no_empty_policy.ex
old mode 100755
new mode 100644
index 855cda3..12bf4dd
--- a/lib/pleroma/web/activity_pub/mrf/no_empty_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/no_empty_policy.ex
@@ -10,9 +10,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.NoEmptyPolicy do
@impl true
def filter(%{"actor" => actor} = object) do
- with true <- is_local?(actor),
- true <- is_eligible_type?(object),
- true <- is_note?(object),
+ with true <- local?(actor),
+ true <- eligible_type?(object),
+ true <- note?(object),
false <- has_attachment?(object),
true <- only_mentions?(object) do
{:reject, "[NoEmptyPolicy]"}
@@ -24,7 +24,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.NoEmptyPolicy do
def filter(object), do: {:ok, object}
- defp is_local?(actor) do
+ defp local?(actor) do
if actor |> String.starts_with?("#{Endpoint.url()}") do
true
else
@@ -59,11 +59,11 @@ defmodule Pleroma.Web.ActivityPub.MRF.NoEmptyPolicy do
defp only_mentions?(_), do: false
- defp is_note?(%{"object" => %{"type" => "Note"}}), do: true
- defp is_note?(_), do: false
+ defp note?(%{"object" => %{"type" => "Note"}}), do: true
+ defp note?(_), do: false
- defp is_eligible_type?(%{"type" => type}) when type in ["Create", "Update"], do: true
- defp is_eligible_type?(_), do: false
+ defp eligible_type?(%{"type" => type}) when type in ["Create", "Update"], do: true
+ defp eligible_type?(_), do: false
@impl true
def describe, do: {:ok, %{}}
diff --git a/lib/pleroma/web/activity_pub/mrf/no_op_policy.ex b/lib/pleroma/web/activity_pub/mrf/no_op_policy.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex b/lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex b/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/mrf/object_age_policy.ex b/lib/pleroma/web/activity_pub/mrf/object_age_policy.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/mrf/pipeline_filtering.ex b/lib/pleroma/web/activity_pub/mrf/pipeline_filtering.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/mrf/policy.ex b/lib/pleroma/web/activity_pub/mrf/policy.ex
old mode 100755
new mode 100644
index 0234de4..1f34883
--- a/lib/pleroma/web/activity_pub/mrf/policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/policy.ex
@@ -3,8 +3,8 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.Policy do
- @callback filter(Map.t()) :: {:ok | :reject, Map.t()}
- @callback describe() :: {:ok | :error, Map.t()}
+ @callback filter(map()) :: {:ok | :reject, map()}
+ @callback describe() :: {:ok | :error, map()}
@callback config_description() :: %{
optional(:children) => [map()],
key: atom(),
diff --git a/lib/pleroma/web/activity_pub/mrf/quote_to_link_tag_policy.ex b/lib/pleroma/web/activity_pub/mrf/quote_to_link_tag_policy.ex
new file mode 100644
index 0000000..ac353f0
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/mrf/quote_to_link_tag_policy.ex
@@ -0,0 +1,49 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2023 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.MRF.QuoteToLinkTagPolicy do
+ @moduledoc "Force a Link tag for posts quoting another post. (may break outgoing federation of quote posts with older Pleroma versions)"
+ @behaviour Pleroma.Web.ActivityPub.MRF.Policy
+
+ alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
+
+ require Pleroma.Constants
+
+ @impl Pleroma.Web.ActivityPub.MRF.Policy
+ def filter(%{"object" => %{"quoteUrl" => _} = object} = activity) do
+ {:ok, Map.put(activity, "object", filter_object(object))}
+ end
+
+ @impl Pleroma.Web.ActivityPub.MRF.Policy
+ def filter(object), do: {:ok, object}
+
+ @impl Pleroma.Web.ActivityPub.MRF.Policy
+ def describe, do: {:ok, %{}}
+
+ @impl Pleroma.Web.ActivityPub.MRF.Policy
+ def history_awareness, do: :auto
+
+ defp filter_object(%{"quoteUrl" => quote_url} = object) do
+ tags = object["tag"] || []
+
+ if Enum.any?(tags, fn tag ->
+ CommonFixes.object_link_tag?(tag) and tag["href"] == quote_url
+ end) do
+ object
+ else
+ object
+ |> Map.put(
+ "tag",
+ tags ++
+ [
+ %{
+ "type" => "Link",
+ "mediaType" => Pleroma.Constants.activity_json_canonical_mime_type(),
+ "href" => quote_url
+ }
+ ]
+ )
+ end
+ end
+end
diff --git a/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex b/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/mrf/steal_emoji_policy.ex b/lib/pleroma/web/activity_pub/mrf/steal_emoji_policy.ex
old mode 100755
new mode 100644
index f66c379..fa6b595
--- a/lib/pleroma/web/activity_pub/mrf/steal_emoji_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/steal_emoji_policy.ex
@@ -34,14 +34,17 @@ defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicy do
|> Path.basename()
|> Path.extname()
- file_path = Path.join(emoji_dir_path, shortcode <> (extension || ".png"))
+ extension = if extension == "", do: ".png", else: extension
+
+ shortcode = Path.basename(shortcode)
+ file_path = Path.join(emoji_dir_path, shortcode <> extension)
case File.write(file_path, response.body) do
:ok ->
shortcode
e ->
- Logger.warn("MRF.StealEmojiPolicy: Failed to write to #{file_path}: #{inspect(e)}")
+ Logger.warning("MRF.StealEmojiPolicy: Failed to write to #{file_path}: #{inspect(e)}")
nil
end
else
@@ -53,7 +56,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicy do
end
else
e ->
- Logger.warn("MRF.StealEmojiPolicy: Failed to fetch #{url}: #{inspect(e)}")
+ Logger.warning("MRF.StealEmojiPolicy: Failed to fetch #{url}: #{inspect(e)}")
nil
end
end
@@ -76,6 +79,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.StealEmojiPolicy do
new_emojis =
foreign_emojis
|> Enum.reject(fn {shortcode, _url} -> shortcode in installed_emoji end)
+ |> Enum.reject(fn {shortcode, _url} -> String.contains?(shortcode, ["/", "\\"]) end)
|> Enum.filter(fn {shortcode, _url} ->
reject_emoji? =
[:mrf_steal_emoji, :rejected_shortcodes]
diff --git a/lib/pleroma/web/activity_pub/mrf/subchain_policy.ex b/lib/pleroma/web/activity_pub/mrf/subchain_policy.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/mrf/user_allow_list_policy.ex b/lib/pleroma/web/activity_pub/mrf/user_allow_list_policy.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/mrf/utils.ex b/lib/pleroma/web/activity_pub/mrf/utils.ex
new file mode 100644
index 0000000..f2dc9ee
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/mrf/utils.ex
@@ -0,0 +1,15 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2023 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.MRF.Utils do
+ @spec describe_regex_or_string(String.t() | Regex.t()) :: String.t()
+ def describe_regex_or_string(pattern) do
+ # This horror is needed to convert regex sigils to strings
+ if not is_binary(pattern) do
+ inspect(pattern)
+ else
+ pattern
+ end
+ end
+end
diff --git a/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex b/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex
old mode 100755
new mode 100644
index 5bcd6da..b3043b9
--- a/lib/pleroma/web/activity_pub/object_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validator.ex
@@ -21,7 +21,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
alias Pleroma.Web.ActivityPub.ObjectValidators.AnnounceValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.AnswerValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator
- alias Pleroma.Web.ActivityPub.ObjectValidators.AudioVideoValidator
+ alias Pleroma.Web.ActivityPub.ObjectValidators.AudioImageVideoValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.BlockValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.ChatMessageValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.CreateChatMessageValidator
@@ -102,7 +102,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
%{"type" => "Create", "object" => %{"type" => objtype} = object} = create_activity,
meta
)
- when objtype in ~w[Question Answer Audio Video Event Article Note Page] do
+ when objtype in ~w[Question Answer Audio Video Image Event Article Note Page] do
with {:ok, object_data} <- cast_and_apply_and_stringify_with_history(object),
meta = Keyword.put(meta, :object_data, object_data),
{:ok, create_activity} <-
@@ -115,13 +115,14 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
end
def validate(%{"type" => type} = object, meta)
- when type in ~w[Event Question Audio Video Article Note Page] do
+ when type in ~w[Event Question Audio Video Image Article Note Page] do
validator =
case type do
"Event" -> EventValidator
"Question" -> QuestionValidator
- "Audio" -> AudioVideoValidator
- "Video" -> AudioVideoValidator
+ "Audio" -> AudioImageVideoValidator
+ "Video" -> AudioImageVideoValidator
+ "Image" -> AudioImageVideoValidator
"Article" -> ArticleNotePageValidator
"Note" -> ArticleNotePageValidator
"Page" -> ArticleNotePageValidator
@@ -172,6 +173,9 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
{:object_validation, e} ->
e
+
+ {:error, %Ecto.Changeset{} = e} ->
+ {:error, e}
end
end
@@ -233,8 +237,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
AnswerValidator.cast_and_apply(object)
end
- def cast_and_apply(%{"type" => type} = object) when type in ~w[Audio Video] do
- AudioVideoValidator.cast_and_apply(object)
+ def cast_and_apply(%{"type" => type} = object) when type in ~w[Audio Image Video] do
+ AudioImageVideoValidator.cast_and_apply(object)
end
def cast_and_apply(%{"type" => "Event"} = object) do
diff --git a/lib/pleroma/web/activity_pub/object_validator/validating.ex b/lib/pleroma/web/activity_pub/object_validator/validating.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/object_validators/accept_reject_validator.ex b/lib/pleroma/web/activity_pub/object_validators/accept_reject_validator.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/object_validators/add_remove_validator.ex b/lib/pleroma/web/activity_pub/object_validators/add_remove_validator.ex
old mode 100755
new mode 100644
index 5202db7..db32595
--- a/lib/pleroma/web/activity_pub/object_validators/add_remove_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/add_remove_validator.ex
@@ -73,6 +73,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AddRemoveValidator do
end
defp maybe_refetch_user(%User{ap_id: ap_id}) do
- Pleroma.Web.ActivityPub.Transmogrifier.upgrade_user_from_ap_id(ap_id)
+ # Maybe it could use User.get_or_fetch_by_ap_id to avoid refreshing too often
+ User.fetch_by_ap_id(ap_id)
end
end
diff --git a/lib/pleroma/web/activity_pub/object_validators/announce_validator.ex b/lib/pleroma/web/activity_pub/object_validators/announce_validator.ex
old mode 100755
new mode 100644
index c2c7ba1..d021858
--- a/lib/pleroma/web/activity_pub/object_validators/announce_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/announce_validator.ex
@@ -82,7 +82,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnnounceValidator do
object when is_binary(object) <- get_field(cng, :object),
%User{} = actor <- User.get_cached_by_ap_id(actor),
%Object{} = object <- Object.get_cached_by_ap_id(object),
- false <- Visibility.is_public?(object) do
+ false <- Visibility.public?(object) do
same_actor = object.data["actor"] == actor.ap_id
recipients = get_field(cng, :to) ++ get_field(cng, :cc)
local_public = Utils.as_local_public()
diff --git a/lib/pleroma/web/activity_pub/object_validators/answer_validator.ex b/lib/pleroma/web/activity_pub/object_validators/answer_validator.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex b/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex
old mode 100755
new mode 100644
index 2670e3f..1b5b2e8
--- a/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex
@@ -84,6 +84,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do
|> fix_tag()
|> fix_replies()
|> fix_attachments()
+ |> CommonFixes.fix_quote_url()
|> Transmogrifier.fix_emoji()
|> Transmogrifier.fix_content_map()
end
diff --git a/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex b/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex
old mode 100755
new mode 100644
index 398020b..72975f3
--- a/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex
@@ -12,13 +12,13 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator do
@primary_key false
embedded_schema do
field(:id, :string)
- field(:type, :string)
+ field(:type, :string, default: "Link")
field(:mediaType, ObjectValidators.MIME, default: "application/octet-stream")
field(:name, :string)
field(:blurhash, :string)
embeds_many :url, UrlObjectValidator, primary_key: false do
- field(:type, :string)
+ field(:type, :string, default: "Link")
field(:href, ObjectValidators.Uri)
field(:mediaType, ObjectValidators.MIME, default: "application/octet-stream")
field(:width, :integer)
diff --git a/lib/pleroma/web/activity_pub/object_validators/audio_image_video_validator.ex b/lib/pleroma/web/activity_pub/object_validators/audio_image_video_validator.ex
new file mode 100644
index 0000000..65ac6bb
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/object_validators/audio_image_video_validator.ex
@@ -0,0 +1,126 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2022 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioImageVideoValidator do
+ use Ecto.Schema
+
+ alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
+ alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
+ alias Pleroma.Web.ActivityPub.Transmogrifier
+
+ import Ecto.Changeset
+
+ @primary_key false
+ @derive Jason.Encoder
+
+ embedded_schema do
+ quote do
+ unquote do
+ import Elixir.Pleroma.Web.ActivityPub.ObjectValidators.CommonFields
+ message_fields()
+ object_fields()
+ status_object_fields()
+ end
+ end
+ end
+
+ def cast_and_apply(data) do
+ data
+ |> cast_data
+ |> apply_action(:insert)
+ end
+
+ def cast_and_validate(data) do
+ data
+ |> cast_data()
+ |> validate_data()
+ end
+
+ def cast_data(data) do
+ %__MODULE__{}
+ |> changeset(data)
+ end
+
+ defp find_attachment(url) do
+ mpeg_url =
+ Enum.find(url, fn
+ %{"mediaType" => mime_type, "tag" => tags} when is_list(tags) ->
+ mime_type == "application/x-mpegURL"
+
+ _ ->
+ false
+ end)
+
+ url
+ |> Enum.concat(mpeg_url["tag"] || [])
+ |> Enum.find(fn
+ %{"mediaType" => mime_type} ->
+ String.starts_with?(mime_type, ["video/", "audio/", "image/"])
+
+ %{"mimeType" => mime_type} ->
+ String.starts_with?(mime_type, ["video/", "audio/", "image/"])
+
+ _ ->
+ false
+ end)
+ end
+
+ defp fix_url(%{"url" => url} = data) when is_list(url) do
+ attachment = find_attachment(url)
+
+ link_element =
+ Enum.find(url, fn
+ %{"mediaType" => "text/html"} -> true
+ %{"mimeType" => "text/html"} -> true
+ _ -> false
+ end)
+
+ data
+ |> Map.put("attachment", [attachment])
+ |> Map.put("url", link_element["href"])
+ end
+
+ defp fix_url(data), do: data
+
+ defp fix_content(%{"mediaType" => "text/markdown", "content" => content} = data)
+ when is_binary(content) do
+ content =
+ content
+ |> Pleroma.Formatter.markdown_to_html()
+ |> Pleroma.HTML.filter_tags()
+
+ Map.put(data, "content", content)
+ end
+
+ defp fix_content(data), do: data
+
+ defp fix(data) do
+ data
+ |> CommonFixes.fix_actor()
+ |> CommonFixes.fix_object_defaults()
+ |> CommonFixes.fix_quote_url()
+ |> Transmogrifier.fix_emoji()
+ |> fix_url()
+ |> fix_content()
+ end
+
+ def changeset(struct, data) do
+ data = fix(data)
+
+ struct
+ |> cast(data, __schema__(:fields) -- [:attachment, :tag])
+ |> cast_embed(:attachment, required: true)
+ |> cast_embed(:tag)
+ end
+
+ defp validate_data(data_cng) do
+ data_cng
+ |> validate_inclusion(:type, ~w[Audio Image Video])
+ |> validate_required([:id, :actor, :attributedTo, :type, :context])
+ |> CommonValidations.validate_any_presence([:cc, :to])
+ |> CommonValidations.validate_fields_match([:actor, :attributedTo])
+ |> CommonValidations.validate_actor_presence()
+ |> CommonValidations.validate_host_match()
+ end
+end
diff --git a/lib/pleroma/web/activity_pub/object_validators/audio_video_validator.ex b/lib/pleroma/web/activity_pub/object_validators/audio_video_validator.ex
deleted file mode 100755
index 671a7ef..0000000
--- a/lib/pleroma/web/activity_pub/object_validators/audio_video_validator.ex
+++ /dev/null
@@ -1,120 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2022 Pleroma Authors
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioVideoValidator do
- use Ecto.Schema
-
- alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
- alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
- alias Pleroma.Web.ActivityPub.Transmogrifier
-
- import Ecto.Changeset
-
- @primary_key false
- @derive Jason.Encoder
-
- embedded_schema do
- quote do
- unquote do
- import Elixir.Pleroma.Web.ActivityPub.ObjectValidators.CommonFields
- message_fields()
- object_fields()
- status_object_fields()
- end
- end
- end
-
- def cast_and_apply(data) do
- data
- |> cast_data
- |> apply_action(:insert)
- end
-
- def cast_and_validate(data) do
- data
- |> cast_data()
- |> validate_data()
- end
-
- def cast_data(data) do
- %__MODULE__{}
- |> changeset(data)
- end
-
- defp find_attachment(url) do
- mpeg_url =
- Enum.find(url, fn
- %{"mediaType" => mime_type, "tag" => tags} when is_list(tags) ->
- mime_type == "application/x-mpegURL"
-
- _ ->
- false
- end)
-
- url
- |> Enum.concat(mpeg_url["tag"] || [])
- |> Enum.find(fn
- %{"mediaType" => mime_type} -> String.starts_with?(mime_type, ["video/", "audio/"])
- %{"mimeType" => mime_type} -> String.starts_with?(mime_type, ["video/", "audio/"])
- _ -> false
- end)
- end
-
- defp fix_url(%{"url" => url} = data) when is_list(url) do
- attachment = find_attachment(url)
-
- link_element =
- Enum.find(url, fn
- %{"mediaType" => "text/html"} -> true
- %{"mimeType" => "text/html"} -> true
- _ -> false
- end)
-
- data
- |> Map.put("attachment", [attachment])
- |> Map.put("url", link_element["href"])
- end
-
- defp fix_url(data), do: data
-
- defp fix_content(%{"mediaType" => "text/markdown", "content" => content} = data)
- when is_binary(content) do
- content =
- content
- |> Pleroma.Formatter.markdown_to_html()
- |> Pleroma.HTML.filter_tags()
-
- Map.put(data, "content", content)
- end
-
- defp fix_content(data), do: data
-
- defp fix(data) do
- data
- |> CommonFixes.fix_actor()
- |> CommonFixes.fix_object_defaults()
- |> Transmogrifier.fix_emoji()
- |> fix_url()
- |> fix_content()
- end
-
- def changeset(struct, data) do
- data = fix(data)
-
- struct
- |> cast(data, __schema__(:fields) -- [:attachment, :tag])
- |> cast_embed(:attachment, required: true)
- |> cast_embed(:tag)
- end
-
- defp validate_data(data_cng) do
- data_cng
- |> validate_inclusion(:type, ["Audio", "Video"])
- |> validate_required([:id, :actor, :attributedTo, :type, :context])
- |> CommonValidations.validate_any_presence([:cc, :to])
- |> CommonValidations.validate_fields_match([:actor, :attributedTo])
- |> CommonValidations.validate_actor_presence()
- |> CommonValidations.validate_host_match()
- end
-end
diff --git a/lib/pleroma/web/activity_pub/object_validators/block_validator.ex b/lib/pleroma/web/activity_pub/object_validators/block_validator.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/object_validators/chat_message_validator.ex b/lib/pleroma/web/activity_pub/object_validators/chat_message_validator.ex
old mode 100755
new mode 100644
index efae48c..09e25be
--- a/lib/pleroma/web/activity_pub/object_validators/chat_message_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/chat_message_validator.ex
@@ -57,6 +57,11 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ChatMessageValidator do
|> Map.put("attachment", attachment)
end
+ def fix_attachment(%{"attachment" => attachment} = data) when attachment == [] do
+ data
+ |> Map.drop(["attachment"])
+ end
+
def fix_attachment(data), do: data
def changeset(struct, data) do
diff --git a/lib/pleroma/web/activity_pub/object_validators/common_fields.ex b/lib/pleroma/web/activity_pub/object_validators/common_fields.ex
old mode 100755
new mode 100644
index 7b60c13..1a5d026
--- a/lib/pleroma/web/activity_pub/object_validators/common_fields.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/common_fields.ex
@@ -27,7 +27,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFields do
end
end
- # All objects except Answer and CHatMessage
+ # All objects except Answer and ChatMessage
defmacro object_fields do
quote bind_quoted: binding() do
field(:content, :string)
@@ -57,8 +57,10 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFields do
field(:replies_count, :integer, default: 0)
field(:like_count, :integer, default: 0)
field(:announcement_count, :integer, default: 0)
+ field(:quotes_count, :integer, default: 0)
field(:inReplyTo, ObjectValidators.ObjectID)
- field(:url, ObjectValidators.Uri)
+ field(:quoteUrl, ObjectValidators.ObjectID)
+ field(:url, ObjectValidators.BareUri)
field(:likes, {:array, ObjectValidators.ObjectID}, default: [])
field(:announcements, {:array, ObjectValidators.ObjectID}, default: [])
diff --git a/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex b/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex
old mode 100755
new mode 100644
index add46d5..4699029
--- a/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/common_fixes.ex
@@ -4,12 +4,15 @@
defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
alias Pleroma.EctoType.ActivityPub.ObjectValidators
+ alias Pleroma.Maps
alias Pleroma.Object
alias Pleroma.Object.Containment
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.ActivityPub.Utils
+ require Pleroma.Constants
+
def cast_and_filter_recipients(message, field, follower_collection, field_fallback \\ []) do
{:ok, data} = ObjectValidators.Recipients.cast(message[field] || field_fallback)
@@ -22,6 +25,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
end
def fix_object_defaults(data) do
+ data = Maps.filter_empty_values(data)
+
context =
Utils.maybe_create_context(
data["context"] || data["conversation"] || data["inReplyTo"] || data["id"]
@@ -76,4 +81,48 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes do
Map.put(data, "to", to)
end
+
+ def fix_quote_url(%{"quoteUrl" => _quote_url} = data), do: data
+
+ # Fedibird
+ # https://github.com/fedibird/mastodon/commit/dbd7ae6cf58a92ec67c512296b4daaea0d01e6ac
+ def fix_quote_url(%{"quoteUri" => quote_url} = data) do
+ Map.put(data, "quoteUrl", quote_url)
+ end
+
+ # Old Fedibird (bug)
+ # https://github.com/fedibird/mastodon/issues/9
+ def fix_quote_url(%{"quoteURL" => quote_url} = data) do
+ Map.put(data, "quoteUrl", quote_url)
+ end
+
+ # Misskey fallback
+ def fix_quote_url(%{"_misskey_quote" => quote_url} = data) do
+ Map.put(data, "quoteUrl", quote_url)
+ end
+
+ def fix_quote_url(%{"tag" => [_ | _] = tags} = data) do
+ tag = Enum.find(tags, &object_link_tag?/1)
+
+ if not is_nil(tag) do
+ data
+ |> Map.put("quoteUrl", tag["href"])
+ else
+ data
+ end
+ end
+
+ def fix_quote_url(data), do: data
+
+ # https://codeberg.org/fediverse/fep/src/branch/main/fep/e232/fep-e232.md
+ def object_link_tag?(%{
+ "type" => "Link",
+ "mediaType" => media_type,
+ "href" => href
+ })
+ when media_type in Pleroma.Constants.activity_json_mime_types() and is_binary(href) do
+ true
+ end
+
+ def object_link_tag?(_), do: false
end
diff --git a/lib/pleroma/web/activity_pub/object_validators/common_validations.ex b/lib/pleroma/web/activity_pub/object_validators/common_validations.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/object_validators/create_chat_message_validator.ex b/lib/pleroma/web/activity_pub/object_validators/create_chat_message_validator.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/object_validators/create_generic_validator.ex b/lib/pleroma/web/activity_pub/object_validators/create_generic_validator.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/object_validators/delete_validator.ex b/lib/pleroma/web/activity_pub/object_validators/delete_validator.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex b/lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex
old mode 100755
new mode 100644
index 0858281..65ba047
--- a/lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex
@@ -5,8 +5,10 @@
defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
use Ecto.Schema
+ alias Pleroma.Emoji
alias Pleroma.Object
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
+ alias Pleroma.Web.ActivityPub.ObjectValidators.TagValidator
import Ecto.Changeset
import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
@@ -19,6 +21,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
import Elixir.Pleroma.Web.ActivityPub.ObjectValidators.CommonFields
message_fields()
activity_fields()
+ embeds_many(:tag, TagValidator)
end
end
@@ -43,7 +46,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
def changeset(struct, data) do
struct
- |> cast(data, __schema__(:fields))
+ |> cast(data, __schema__(:fields) -- [:tag])
+ |> cast_embed(:tag)
end
defp fix(data) do
@@ -53,12 +57,16 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
|> CommonFixes.fix_actor()
|> CommonFixes.fix_activity_addressing()
- with %Object{} = object <- Object.normalize(data["object"]) do
- data
- |> CommonFixes.fix_activity_context(object)
- |> CommonFixes.fix_object_action_recipients(object)
- else
- _ -> data
+ data = Map.put_new(data, "tag", [])
+
+ case Object.normalize(data["object"]) do
+ %Object{} = object ->
+ data
+ |> CommonFixes.fix_activity_context(object)
+ |> CommonFixes.fix_object_action_recipients(object)
+
+ _ ->
+ data
end
end
@@ -66,10 +74,10 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
new_emoji = Pleroma.Emoji.fully_qualify_emoji(emoji)
cond do
- Pleroma.Emoji.is_unicode_emoji?(emoji) ->
+ Pleroma.Emoji.unicode?(emoji) ->
data
- Pleroma.Emoji.is_unicode_emoji?(new_emoji) ->
+ Pleroma.Emoji.unicode?(new_emoji) ->
data |> Map.put("content", new_emoji)
true ->
@@ -82,11 +90,31 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
defp validate_emoji(cng) do
content = get_field(cng, :content)
- if Pleroma.Emoji.is_unicode_emoji?(content) do
+ if Emoji.unicode?(content) || Emoji.custom?(content) do
cng
else
cng
- |> add_error(:content, "must be a single character emoji")
+ |> add_error(:content, "is not a valid emoji")
+ end
+ end
+
+ defp maybe_validate_tag_presence(cng) do
+ content = get_field(cng, :content)
+
+ if Emoji.unicode?(content) do
+ cng
+ else
+ tag = get_field(cng, :tag)
+ emoji_name = Emoji.maybe_strip_name(content)
+
+ case tag do
+ [%{name: ^emoji_name, type: "Emoji", icon: %{url: _}}] ->
+ cng
+
+ _ ->
+ cng
+ |> add_error(:tag, "does not contain an Emoji tag")
+ end
end
end
@@ -97,5 +125,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
|> validate_actor_presence()
|> validate_object_presence()
|> validate_emoji()
+ |> maybe_validate_tag_presence()
end
end
diff --git a/lib/pleroma/web/activity_pub/object_validators/event_validator.ex b/lib/pleroma/web/activity_pub/object_validators/event_validator.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/object_validators/follow_validator.ex b/lib/pleroma/web/activity_pub/object_validators/follow_validator.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/object_validators/like_validator.ex b/lib/pleroma/web/activity_pub/object_validators/like_validator.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/object_validators/question_options_validator.ex b/lib/pleroma/web/activity_pub/object_validators/question_options_validator.ex
old mode 100755
new mode 100644
index 541945f..8d7f7b9
--- a/lib/pleroma/web/activity_pub/object_validators/question_options_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/question_options_validator.ex
@@ -14,10 +14,10 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.QuestionOptionsValidator do
embeds_one :replies, Replies, primary_key: false do
field(:totalItems, :integer)
- field(:type, :string)
+ field(:type, :string, default: "Collection")
end
- field(:type, :string)
+ field(:type, :string, default: "Note")
end
def changeset(struct, data) do
diff --git a/lib/pleroma/web/activity_pub/object_validators/question_validator.ex b/lib/pleroma/web/activity_pub/object_validators/question_validator.ex
old mode 100755
new mode 100644
index ce33051..7f9d4d6
--- a/lib/pleroma/web/activity_pub/object_validators/question_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/question_validator.ex
@@ -29,6 +29,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.QuestionValidator do
field(:closed, ObjectValidators.DateTime)
field(:voters, {:array, ObjectValidators.ObjectID}, default: [])
+ field(:nonAnonymous, :boolean)
embeds_many(:anyOf, QuestionOptionsValidator)
embeds_many(:oneOf, QuestionOptionsValidator)
end
@@ -62,6 +63,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.QuestionValidator do
data
|> CommonFixes.fix_actor()
|> CommonFixes.fix_object_defaults()
+ |> CommonFixes.fix_quote_url()
|> Transmogrifier.fix_emoji()
|> fix_closed()
end
diff --git a/lib/pleroma/web/activity_pub/object_validators/tag_validator.ex b/lib/pleroma/web/activity_pub/object_validators/tag_validator.ex
old mode 100755
new mode 100644
index 9f15f19..47cf7b4
--- a/lib/pleroma/web/activity_pub/object_validators/tag_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/tag_validator.ex
@@ -9,15 +9,20 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.TagValidator do
import Ecto.Changeset
+ require Pleroma.Constants
+
@primary_key false
embedded_schema do
# Common
field(:type, :string)
field(:name, :string)
- # Mention, Hashtag
+ # Mention, Hashtag, Link
field(:href, ObjectValidators.Uri)
+ # Link
+ field(:mediaType, :string)
+
# Emoji
embeds_one :icon, IconObjectValidator, primary_key: false do
field(:type, :string)
@@ -68,6 +73,19 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.TagValidator do
|> validate_required([:type, :name, :icon])
end
+ def changeset(struct, %{"type" => "Link"} = data) do
+ struct
+ |> cast(data, [:type, :name, :mediaType, :href])
+ |> validate_inclusion(:mediaType, Pleroma.Constants.activity_json_mime_types())
+ |> validate_required([:type, :href, :mediaType])
+ end
+
+ def changeset(struct, %{"type" => _} = data) do
+ struct
+ |> cast(data, [])
+ |> Map.put(:action, :ignore)
+ end
+
def icon_changeset(struct, data) do
struct
|> cast(data, [:type, :url])
diff --git a/lib/pleroma/web/activity_pub/object_validators/undo_validator.ex b/lib/pleroma/web/activity_pub/object_validators/undo_validator.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/object_validators/update_validator.ex b/lib/pleroma/web/activity_pub/object_validators/update_validator.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/pipeline.ex b/lib/pleroma/web/activity_pub/pipeline.ex
old mode 100755
new mode 100644
index ca8653a..40184bd
--- a/lib/pleroma/web/activity_pub/pipeline.ex
+++ b/lib/pleroma/web/activity_pub/pipeline.ex
@@ -62,7 +62,7 @@ defmodule Pleroma.Web.ActivityPub.Pipeline do
with {:ok, local} <- Keyword.fetch(meta, :local) do
do_not_federate = meta[:do_not_federate] || !config().get([:instance, :federating])
- if !do_not_federate and local and not Visibility.is_local_public?(activity) do
+ if !do_not_federate and local and not Visibility.local_public?(activity) do
activity =
if object = Keyword.get(meta, :object_data) do
%{activity | data: Map.put(activity.data, "object", object)}
diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex
old mode 100755
new mode 100644
index 6c1ba76..a42b484
--- a/lib/pleroma/web/activity_pub/publisher.ex
+++ b/lib/pleroma/web/activity_pub/publisher.ex
@@ -13,23 +13,60 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Relay
alias Pleroma.Web.ActivityPub.Transmogrifier
+ alias Pleroma.Workers.PublisherWorker
require Pleroma.Constants
import Pleroma.Web.ActivityPub.Visibility
- @behaviour Pleroma.Web.Federator.Publisher
-
require Logger
@moduledoc """
ActivityPub outgoing federation module.
"""
+ @doc """
+ Enqueue publishing a single activity.
+ """
+ @spec enqueue_one(map(), Keyword.t()) :: {:ok, %Oban.Job{}}
+ def enqueue_one(%{} = params, worker_args \\ []) do
+ PublisherWorker.enqueue(
+ "publish_one",
+ %{"params" => params},
+ worker_args
+ )
+ end
+
+ @doc """
+ Gathers a set of remote users given an IR envelope.
+ """
+ def remote_users(%User{id: user_id}, %{data: %{"to" => to} = data}) do
+ cc = Map.get(data, "cc", [])
+
+ bcc =
+ data
+ |> Map.get("bcc", [])
+ |> Enum.reduce([], fn ap_id, bcc ->
+ case Pleroma.List.get_by_ap_id(ap_id) do
+ %Pleroma.List{user_id: ^user_id} = list ->
+ {:ok, following} = Pleroma.List.get_following(list)
+ bcc ++ Enum.map(following, & &1.ap_id)
+
+ _ ->
+ bcc
+ end
+ end)
+
+ [to, cc, bcc]
+ |> Enum.concat()
+ |> Enum.map(&User.get_cached_by_ap_id/1)
+ |> Enum.filter(fn user -> user && !user.local end)
+ end
+
@doc """
Determine if an activity can be represented by running it through Transmogrifier.
"""
- def is_representable?(%Activity{} = activity) do
+ def representable?(%Activity{} = activity) do
with {:ok, _data} <- Transmogrifier.prepare_outgoing(activity.data) do
true
else
@@ -80,9 +117,27 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
result
else
- {_post_result, response} ->
+ {_post_result, %{status: code} = response} = e ->
+ unless params[:unreachable_since], do: Instances.set_unreachable(inbox)
+ Logger.metadata(activity: id, inbox: inbox, status: code)
+ Logger.error("Publisher failed to inbox #{inbox} with status #{code}")
+
+ case response do
+ %{status: 403} -> {:discard, :forbidden}
+ %{status: 404} -> {:discard, :not_found}
+ %{status: 410} -> {:discard, :not_found}
+ _ -> {:error, e}
+ end
+
+ {:error, :pool_full} ->
+ Logger.debug("Publisher snoozing worker job due to full connection pool")
+ {:snooze, 30}
+
+ e ->
unless params[:unreachable_since], do: Instances.set_unreachable(inbox)
- {:error, response}
+ Logger.metadata(activity: id, inbox: inbox)
+ Logger.error("Publisher failed to inbox #{inbox} #{inspect(e)}")
+ {:error, e}
end
end
@@ -103,22 +158,21 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
end
end
- defp should_federate?(inbox, public) do
- if public do
- true
- else
- %{host: host} = URI.parse(inbox)
+ def should_federate?(nil, _), do: false
+ def should_federate?(_, true), do: true
- quarantined_instances =
- Config.get([:instance, :quarantined_instances], [])
- |> Pleroma.Web.ActivityPub.MRF.instance_list_from_tuples()
- |> Pleroma.Web.ActivityPub.MRF.subdomains_regex()
+ def should_federate?(inbox, _) do
+ %{host: host} = URI.parse(inbox)
- !Pleroma.Web.ActivityPub.MRF.subdomain_match?(quarantined_instances, host)
- end
+ quarantined_instances =
+ Config.get([:instance, :quarantined_instances], [])
+ |> Pleroma.Web.ActivityPub.MRF.instance_list_from_tuples()
+ |> Pleroma.Web.ActivityPub.MRF.subdomains_regex()
+
+ !Pleroma.Web.ActivityPub.MRF.subdomain_match?(quarantined_instances, host)
end
- @spec recipients(User.t(), Activity.t()) :: list(User.t()) | []
+ @spec recipients(User.t(), Activity.t()) :: [[User.t()]]
defp recipients(actor, activity) do
followers =
if actor.follower_address in activity.recipients do
@@ -138,7 +192,10 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
[]
end
- Pleroma.Web.Federator.Publisher.remote_users(actor, activity) ++ followers ++ fetchers
+ mentioned = remote_users(actor, activity)
+ non_mentioned = (followers ++ fetchers) -- mentioned
+
+ [mentioned, non_mentioned]
end
defp get_cc_ap_ids(ap_id, recipients) do
@@ -192,45 +249,52 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
def publish(%User{} = actor, %{data: %{"bcc" => bcc}} = activity)
when is_list(bcc) and bcc != [] do
- public = is_public?(activity)
+ public = public?(activity)
{:ok, data} = Transmogrifier.prepare_outgoing(activity.data)
- recipients = recipients(actor, activity)
+ [priority_recipients, recipients] = recipients(actor, activity)
inboxes =
- recipients
- |> Enum.filter(&User.ap_enabled?/1)
- |> Enum.map(fn actor -> actor.inbox end)
- |> Enum.filter(fn inbox -> should_federate?(inbox, public) end)
- |> Instances.filter_reachable()
+ [priority_recipients, recipients]
+ |> Enum.map(fn recipients ->
+ recipients
+ |> Enum.map(fn %User{} = user ->
+ determine_inbox(activity, user)
+ end)
+ |> Enum.uniq()
+ |> Enum.filter(fn inbox -> should_federate?(inbox, public) end)
+ |> Instances.filter_reachable()
+ end)
Repo.checkout(fn ->
- Enum.each(inboxes, fn {inbox, unreachable_since} ->
- %User{ap_id: ap_id} = Enum.find(recipients, fn actor -> actor.inbox == inbox end)
-
- # Get all the recipients on the same host and add them to cc. Otherwise, a remote
- # instance would only accept a first message for the first recipient and ignore the rest.
- cc = get_cc_ap_ids(ap_id, recipients)
-
- json =
- data
- |> Map.put("cc", cc)
- |> Jason.encode!()
-
- Pleroma.Web.Federator.Publisher.enqueue_one(__MODULE__, %{
- inbox: inbox,
- json: json,
- actor_id: actor.id,
- id: activity.data["id"],
- unreachable_since: unreachable_since
- })
+ Enum.each(inboxes, fn inboxes ->
+ Enum.each(inboxes, fn {inbox, unreachable_since} ->
+ %User{ap_id: ap_id} = Enum.find(recipients, fn actor -> actor.inbox == inbox end)
+
+ # Get all the recipients on the same host and add them to cc. Otherwise, a remote
+ # instance would only accept a first message for the first recipient and ignore the rest.
+ cc = get_cc_ap_ids(ap_id, recipients)
+
+ json =
+ data
+ |> Map.put("cc", cc)
+ |> Jason.encode!()
+
+ __MODULE__.enqueue_one(%{
+ inbox: inbox,
+ json: json,
+ actor_id: actor.id,
+ id: activity.data["id"],
+ unreachable_since: unreachable_since
+ })
+ end)
end)
end)
end
# Publishes an activity to all relevant peers.
def publish(%User{} = actor, %Activity{} = activity) do
- public = is_public?(activity)
+ public = public?(activity)
if public && Config.get([:instance, :allow_relay]) do
Logger.debug(fn -> "Relaying #{activity.data["id"]} out" end)
@@ -240,26 +304,38 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
{:ok, data} = Transmogrifier.prepare_outgoing(activity.data)
json = Jason.encode!(data)
- recipients(actor, activity)
- |> Enum.filter(fn user -> User.ap_enabled?(user) end)
- |> Enum.map(fn %User{} = user ->
- determine_inbox(activity, user)
- end)
- |> Enum.uniq()
- |> Enum.filter(fn inbox -> should_federate?(inbox, public) end)
- |> Instances.filter_reachable()
- |> Enum.each(fn {inbox, unreachable_since} ->
- Pleroma.Web.Federator.Publisher.enqueue_one(
- __MODULE__,
- %{
- inbox: inbox,
- json: json,
- actor_id: actor.id,
- id: activity.data["id"],
- unreachable_since: unreachable_since
- }
- )
+ [priority_inboxes, inboxes] =
+ recipients(actor, activity)
+ |> Enum.map(fn recipients ->
+ recipients
+ |> Enum.map(fn %User{} = user ->
+ determine_inbox(activity, user)
+ end)
+ |> Enum.uniq()
+ |> Enum.filter(fn inbox -> should_federate?(inbox, public) end)
+ end)
+
+ inboxes = inboxes -- priority_inboxes
+
+ [{priority_inboxes, 0}, {inboxes, 1}]
+ |> Enum.each(fn {inboxes, priority} ->
+ inboxes
+ |> Instances.filter_reachable()
+ |> Enum.each(fn {inbox, unreachable_since} ->
+ __MODULE__.enqueue_one(
+ %{
+ inbox: inbox,
+ json: json,
+ actor_id: actor.id,
+ id: activity.data["id"],
+ unreachable_since: unreachable_since
+ },
+ priority: priority
+ )
+ end)
end)
+
+ :ok
end
def gather_webfinger_links(%User{} = user) do
diff --git a/lib/pleroma/web/activity_pub/relay.ex b/lib/pleroma/web/activity_pub/relay.ex
old mode 100755
new mode 100644
index 2010351..91a647f
--- a/lib/pleroma/web/activity_pub/relay.ex
+++ b/lib/pleroma/web/activity_pub/relay.ex
@@ -58,7 +58,7 @@ defmodule Pleroma.Web.ActivityPub.Relay do
@spec publish(any()) :: {:ok, Activity.t()} | {:error, any()}
def publish(%Activity{data: %{"type" => "Create"}} = activity) do
with %User{} = user <- get_actor(),
- true <- Visibility.is_public?(activity) do
+ true <- Visibility.public?(activity) do
CommonAPI.repeat(activity.id, user)
else
error -> format_error(error)
diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex
old mode 100755
new mode 100644
index fc5dec3..7421b8e
--- a/lib/pleroma/web/activity_pub/side_effects.ex
+++ b/lib/pleroma/web/activity_pub/side_effects.ex
@@ -197,6 +197,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
# - Increase replies count
# - Set up ActivityExpiration
# - Set up notifications
+ # - Index incoming posts for search (if needed)
@impl true
def handle(%{data: %{"type" => "Create"}} = activity, meta) do
with {:ok, object, meta} <- handle_object_creation(meta[:object_data], activity, meta),
@@ -209,6 +210,10 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
Object.increase_replies_count(in_reply_to)
end
+ if quote_url = object.data["quoteUrl"] do
+ Object.increase_quotes_count(quote_url)
+ end
+
reply_depth = (meta[:depth] || 0) + 1
# FIXME: Force inReplyTo to replies
@@ -222,9 +227,11 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
end
end
- ConcurrentLimiter.limit(Pleroma.Web.RichMedia.Helpers, fn ->
- Task.start(fn -> Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity) end)
- end)
+ Pleroma.Web.RichMedia.Card.get_by_activity(activity)
+
+ Pleroma.Search.add_to_index(Map.put(activity, :object, object))
+
+ Utils.maybe_handle_group_posts(activity)
meta =
meta
@@ -249,7 +256,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
Utils.add_announce_to_object(object, announced_object)
- if !User.is_internal_user?(user) do
+ if !User.internal?(user) do
Notification.create_notifications(object)
ap_streamer().stream_out(object)
@@ -285,6 +292,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
# - Reduce the user note count
# - Reduce the reply count
# - Stream out the activity
+ # - Removes posts from search index (if needed)
@impl true
def handle(%{data: %{"type" => "Delete", "object" => deleted_object}} = object, meta) do
deleted_object =
@@ -294,9 +302,9 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
result =
case deleted_object do
%Object{} ->
- with {:ok, deleted_object, _activity} <- Object.delete(deleted_object),
+ with {_, {:ok, deleted_object, _activity}} <- {:object, Object.delete(deleted_object)},
{_, actor} when is_binary(actor) <- {:actor, deleted_object.data["actor"]},
- %User{} = user <- User.get_cached_by_ap_id(actor) do
+ {_, %User{} = user} <- {:user, User.get_cached_by_ap_id(actor)} do
User.remove_pinned_object_id(user, deleted_object.data["id"])
{:ok, user} = ActivityPub.decrease_note_count_if_public(user, deleted_object)
@@ -305,6 +313,10 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
Object.decrease_replies_count(in_reply_to)
end
+ if quote_url = deleted_object.data["quoteUrl"] do
+ Object.decrease_quotes_count(quote_url)
+ end
+
MessageReference.delete_for_object(deleted_object)
ap_streamer().stream_out(object)
@@ -314,6 +326,17 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
{:actor, _} ->
@logger.error("The object doesn't have an actor: #{inspect(deleted_object)}")
:no_object_actor
+
+ {:user, _} ->
+ @logger.error(
+ "The object's actor could not be resolved to a user: #{inspect(deleted_object)}"
+ )
+
+ :no_object_user
+
+ {:object, _} ->
+ @logger.error("The object could not be deleted: #{inspect(deleted_object)}")
+ {:error, object}
end
%User{} ->
@@ -323,6 +346,11 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
end
if result == :ok do
+ # Only remove from index when deleting actual objects, not users or anything else
+ with %Pleroma.Object{} <- deleted_object do
+ Pleroma.Search.remove_from_index(deleted_object)
+ end
+
{:ok, object, meta}
else
{:error, result}
@@ -496,7 +524,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
end
def handle_object_creation(%{"type" => objtype} = object, _activity, meta)
- when objtype in ~w[Audio Video Event Article Note Page] do
+ when objtype in ~w[Audio Video Image Event Article Note Page] do
with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do
{:ok, object, meta}
end
@@ -550,7 +578,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
def handle_undoing(object), do: {:error, ["don't know how to handle", object]}
- @spec delete_object(Object.t()) :: :ok | {:error, Ecto.Changeset.t()}
+ @spec delete_object(Activity.t()) :: :ok | {:error, Ecto.Changeset.t()}
defp delete_object(object) do
with {:ok, _} <- Repo.delete(object), do: :ok
end
diff --git a/lib/pleroma/web/activity_pub/side_effects/handling.ex b/lib/pleroma/web/activity_pub/side_effects/handling.ex
old mode 100755
new mode 100644
index eb012f5..4751bb4
--- a/lib/pleroma/web/activity_pub/side_effects/handling.ex
+++ b/lib/pleroma/web/activity_pub/side_effects/handling.ex
@@ -4,5 +4,5 @@
defmodule Pleroma.Web.ActivityPub.SideEffects.Handling do
@callback handle(map(), keyword()) :: {:ok, map(), keyword()} | {:error, any()}
- @callback handle_after_transaction(map()) :: map()
+ @callback handle_after_transaction(keyword()) :: keyword()
end
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
old mode 100755
new mode 100644
index e4c04da..edfe73a
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -20,11 +20,9 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.Federator
- alias Pleroma.Workers.TransmogrifierWorker
import Ecto.Query
- require Logger
require Pleroma.Constants
@doc """
@@ -156,8 +154,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|> Map.put("context", replied_object.data["context"] || object["conversation"])
|> Map.drop(["conversation", "inReplyToAtomUri"])
else
- e ->
- Logger.warn("Couldn't fetch #{inspect(in_reply_to_id)}, error: #{inspect(e)}")
+ _ ->
object
end
else
@@ -167,6 +164,26 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
def fix_in_reply_to(object, _options), do: object
+ def fix_quote_url_and_maybe_fetch(object, options \\ []) do
+ quote_url =
+ case Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes.fix_quote_url(object) do
+ %{"quoteUrl" => quote_url} -> quote_url
+ _ -> nil
+ end
+
+ with {:quoting?, true} <- {:quoting?, not is_nil(quote_url)},
+ {:ok, quoted_object} <- get_obj_helper(quote_url, options),
+ %Activity{} <- Activity.get_create_by_object_ap_id(quoted_object.data["id"]) do
+ Map.put(object, "quoteUrl", quoted_object.data["id"])
+ else
+ {:quoting?, _} ->
+ object
+
+ _ ->
+ object
+ end
+ end
+
defp prepare_in_reply_to(in_reply_to) do
cond do
is_bitstring(in_reply_to) ->
@@ -447,7 +464,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
%{"type" => "Create", "object" => %{"type" => objtype, "id" => obj_id}} = data,
options
)
- when objtype in ~w{Question Answer ChatMessage Audio Video Event Article Note Page} do
+ when objtype in ~w{Question Answer ChatMessage Audio Video Event Article Note Page Image} do
fetch_options = Keyword.put(options, :depth, (options[:depth] || 0) + 1)
object =
@@ -455,6 +472,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|> strip_internal_fields()
|> fix_type(fetch_options)
|> fix_in_reply_to(fetch_options)
+ |> fix_quote_url_and_maybe_fetch(fetch_options)
data = Map.put(data, "object", object)
options = Keyword.put(options, :local, false)
@@ -629,6 +647,16 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
def set_reply_to_uri(obj), do: obj
+ @doc """
+ Fedibird compatibility
+ https://github.com/fedibird/mastodon/commit/dbd7ae6cf58a92ec67c512296b4daaea0d01e6ac
+ """
+ def set_quote_url(%{"quoteUrl" => quote_url} = object) when is_binary(quote_url) do
+ Map.put(object, "quoteUri", quote_url)
+ end
+
+ def set_quote_url(obj), do: obj
+
@doc """
Serialized Mastodon-compatible `replies` collection containing _self-replies_.
Based on Mastodon's ActivityPub::NoteSerializer#replies.
@@ -683,6 +711,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|> prepare_attachments
|> set_conversation
|> set_reply_to_uri
+ |> set_quote_url
|> set_replies
|> strip_internal_fields
|> strip_internal_tags
@@ -750,7 +779,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|> Object.normalize(fetch: false)
data =
- if Visibility.is_private?(object) && object.data["actor"] == ap_id do
+ if Visibility.private?(object) && object.data["actor"] == ap_id do
data |> Map.put("object", object |> Map.get(:data) |> prepare_object)
else
data |> maybe_fix_object_url
@@ -820,8 +849,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
relative_object do
Map.put(data, "object", external_url)
else
- {:fetch, e} ->
- Logger.error("Couldn't fetch #{object} #{inspect(e)}")
+ {:fetch, _} ->
data
_ ->
@@ -946,47 +974,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
defp strip_internal_tags(object), do: object
- def perform(:user_upgrade, user) do
- # we pass a fake user so that the followers collection is stripped away
- old_follower_address = User.ap_followers(%User{nickname: user.nickname})
-
- from(
- a in Activity,
- where: ^old_follower_address in a.recipients,
- update: [
- set: [
- recipients:
- fragment(
- "array_replace(?,?,?)",
- a.recipients,
- ^old_follower_address,
- ^user.follower_address
- )
- ]
- ]
- )
- |> Repo.update_all([])
- end
-
- def upgrade_user_from_ap_id(ap_id) do
- with %User{local: false} = user <- User.get_cached_by_ap_id(ap_id),
- {:ok, data} <- ActivityPub.fetch_and_prepare_user_from_ap_id(ap_id),
- {:ok, user} <- update_user(user, data) do
- {:ok, _pid} = Task.start(fn -> ActivityPub.pinned_fetch_task(user) end)
- TransmogrifierWorker.enqueue("user_upgrade", %{"user_id" => user.id})
- {:ok, user}
- else
- %User{} = user -> {:ok, user}
- e -> e
- end
- end
-
- defp update_user(user, data) do
- user
- |> User.remote_user_changeset(data)
- |> User.update_and_set_cache()
- end
-
def maybe_fix_user_url(%{"url" => url} = data) when is_map(url) do
Map.put(data, "url", url["href"])
end
diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex
old mode 100755
new mode 100644
index b898d6f..52cb64f
--- a/lib/pleroma/web/activity_pub/utils.ex
+++ b/lib/pleroma/web/activity_pub/utils.ex
@@ -7,6 +7,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
alias Ecto.UUID
alias Pleroma.Activity
alias Pleroma.Config
+ alias Pleroma.EctoType.ActivityPub.ObjectValidators.ObjectID
alias Pleroma.Maps
alias Pleroma.Notification
alias Pleroma.Object
@@ -31,7 +32,8 @@ defmodule Pleroma.Web.ActivityPub.Utils do
"Page",
"Question",
"Answer",
- "Audio"
+ "Audio",
+ "Image"
]
@strip_status_report_states ~w(closed resolved)
@supported_report_states ~w(open closed resolved)
@@ -165,7 +167,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
with true <- Config.get!([:instance, :federating]),
true <- type != "Block" || outgoing_blocks,
- false <- Visibility.is_local_public?(activity) do
+ false <- Visibility.local_public?(activity) do
Pleroma.Web.Federator.publish(activity)
end
@@ -275,7 +277,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
object_actor = User.get_cached_by_ap_id(object_actor_id)
to =
- if Visibility.is_public?(object) do
+ if Visibility.public?(object) do
[actor.follower_address, object.data["actor"]]
else
[object.data["actor"]]
@@ -325,21 +327,29 @@ defmodule Pleroma.Web.ActivityPub.Utils do
{:ok, Object.t()} | {:error, Ecto.Changeset.t()}
def add_emoji_reaction_to_object(
- %Activity{data: %{"content" => emoji, "actor" => actor}},
+ %Activity{data: %{"content" => emoji, "actor" => actor}} = activity,
object
) do
reactions = get_cached_emoji_reactions(object)
+ emoji = Pleroma.Emoji.maybe_strip_name(emoji)
+ url = maybe_emoji_url(emoji, activity)
new_reactions =
- case Enum.find_index(reactions, fn [candidate, _] -> emoji == candidate end) do
+ case Enum.find_index(reactions, fn [candidate, _, candidate_url] ->
+ if is_nil(candidate_url) do
+ emoji == candidate
+ else
+ url == candidate_url
+ end
+ end) do
nil ->
- reactions ++ [[emoji, [actor]]]
+ reactions ++ [[emoji, [actor], url]]
index ->
List.update_at(
reactions,
index,
- fn [emoji, users] -> [emoji, Enum.uniq([actor | users])] end
+ fn [emoji, users, url] -> [emoji, Enum.uniq([actor | users]), url] end
)
end
@@ -348,18 +358,40 @@ defmodule Pleroma.Web.ActivityPub.Utils do
update_element_in_object("reaction", new_reactions, object, count)
end
+ defp maybe_emoji_url(
+ name,
+ %Activity{
+ data: %{
+ "tag" => [
+ %{"type" => "Emoji", "name" => name, "icon" => %{"url" => url}}
+ ]
+ }
+ }
+ ),
+ do: url
+
+ defp maybe_emoji_url(_, _), do: nil
+
def emoji_count(reactions_list) do
- Enum.reduce(reactions_list, 0, fn [_, users], acc -> acc + length(users) end)
+ Enum.reduce(reactions_list, 0, fn [_, users, _], acc -> acc + length(users) end)
end
def remove_emoji_reaction_from_object(
- %Activity{data: %{"content" => emoji, "actor" => actor}},
+ %Activity{data: %{"content" => emoji, "actor" => actor}} = activity,
object
) do
+ emoji = Pleroma.Emoji.maybe_strip_name(emoji)
reactions = get_cached_emoji_reactions(object)
+ url = maybe_emoji_url(emoji, activity)
new_reactions =
- case Enum.find_index(reactions, fn [candidate, _] -> emoji == candidate end) do
+ case Enum.find_index(reactions, fn [candidate, _, candidate_url] ->
+ if is_nil(candidate_url) do
+ emoji == candidate
+ else
+ url == candidate_url
+ end
+ end) do
nil ->
reactions
@@ -367,9 +399,9 @@ defmodule Pleroma.Web.ActivityPub.Utils do
List.update_at(
reactions,
index,
- fn [emoji, users] -> [emoji, List.delete(users, actor)] end
+ fn [emoji, users, url] -> [emoji, List.delete(users, actor), url] end
)
- |> Enum.reject(fn [_, users] -> Enum.empty?(users) end)
+ |> Enum.reject(fn [_, users, _] -> Enum.empty?(users) end)
end
count = emoji_count(new_reactions)
@@ -377,11 +409,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
end
def get_cached_emoji_reactions(object) do
- if is_list(object.data["reactions"]) do
- object.data["reactions"]
- else
- []
- end
+ Object.get_emoji_reactions(object)
end
@spec add_like_to_object(Activity.t(), Object.t()) ::
@@ -489,17 +517,37 @@ defmodule Pleroma.Web.ActivityPub.Utils do
def get_latest_reaction(internal_activity_id, %{ap_id: ap_id}, emoji) do
%{data: %{"object" => object_ap_id}} = Activity.get_by_id(internal_activity_id)
+ emoji = Pleroma.Emoji.maybe_quote(emoji)
"EmojiReact"
|> Activity.Queries.by_type()
|> where(actor: ^ap_id)
- |> where([activity], fragment("?->>'content' = ?", activity.data, ^emoji))
+ |> custom_emoji_discriminator(emoji)
|> Activity.Queries.by_object_id(object_ap_id)
|> order_by([activity], fragment("? desc nulls last", activity.id))
|> limit(1)
|> Repo.one()
end
+ defp custom_emoji_discriminator(query, emoji) do
+ if String.contains?(emoji, "@") do
+ stripped = Pleroma.Emoji.maybe_strip_name(emoji)
+ [name, domain] = String.split(stripped, "@")
+ domain_pattern = "%/" <> domain <> "/%"
+ emoji_pattern = Pleroma.Emoji.maybe_quote(name)
+
+ query
+ |> where([activity], fragment("?->>'content' = ?
+ AND EXISTS (
+ SELECT FROM jsonb_array_elements(?->'tag') elem
+ WHERE elem->>'id' ILIKE ?
+ )", activity.data, ^emoji_pattern, activity.data, ^domain_pattern))
+ else
+ query
+ |> where([activity], fragment("?->>'content' = ?", activity.data, ^emoji))
+ end
+ end
+
#### Announce-related helpers
@doc """
@@ -728,10 +776,9 @@ defmodule Pleroma.Web.ActivityPub.Utils do
build_flag_object(object)
nil ->
- if %Object{} = object = Object.get_by_ap_id(id) do
- build_flag_object(object)
- else
- %{"id" => id, "deleted" => true}
+ case Object.get_by_ap_id(id) do
+ %Object{} = object -> build_flag_object(object)
+ _ -> %{"id" => id, "deleted" => true}
end
end
end
@@ -805,9 +852,11 @@ defmodule Pleroma.Web.ActivityPub.Utils do
[actor | reported_activities] = activity.data["object"]
stripped_activities =
- Enum.map(reported_activities, fn
- act when is_map(act) -> act["id"]
- act when is_binary(act) -> act
+ Enum.reduce(reported_activities, [], fn act, acc ->
+ case ObjectID.cast(act) do
+ {:ok, act} -> [act | acc]
+ _ -> acc
+ end
end)
new_data = put_in(activity.data, ["object"], [actor | stripped_activities])
@@ -885,4 +934,27 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|> where([a, object: o], fragment("(?)->>'type' = 'Answer'", o.data))
|> Repo.all()
end
+
+ def maybe_handle_group_posts(activity) do
+ poster = User.get_cached_by_ap_id(activity.actor)
+
+ mentions =
+ activity.data["to"]
+ |> Enum.filter(&(&1 != activity.actor))
+
+ mentioned_local_groups =
+ User.get_all_by_ap_id(mentions)
+ |> Enum.filter(fn user ->
+ user.actor_type == "Group" and
+ user.local and
+ not User.blocks?(user, poster)
+ end)
+
+ mentioned_local_groups
+ |> Enum.each(fn group ->
+ Pleroma.Web.CommonAPI.repeat(activity.id, group)
+ end)
+
+ :ok
+ end
end
diff --git a/lib/pleroma/web/activity_pub/views/object_view.ex b/lib/pleroma/web/activity_pub/views/object_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex
old mode 100755
new mode 100644
index f69fca0..937e4fd
--- a/lib/pleroma/web/activity_pub/views/user_view.ex
+++ b/lib/pleroma/web/activity_pub/views/user_view.ex
@@ -46,6 +46,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
"following" => "#{user.ap_id}/following",
"followers" => "#{user.ap_id}/followers",
"inbox" => "#{user.ap_id}/inbox",
+ "outbox" => "#{user.ap_id}/outbox",
"name" => "Pleroma",
"summary" =>
"An internal service actor for this Pleroma instance. No user-serviceable parts inside.",
@@ -66,8 +67,13 @@ defmodule Pleroma.Web.ActivityPub.UserView do
def render("user.json", %{user: %User{nickname: nil} = user}),
do: render("service.json", %{user: user})
- def render("user.json", %{user: %User{nickname: "internal." <> _} = user}),
- do: render("service.json", %{user: user}) |> Map.put("preferredUsername", user.nickname)
+ def render("user.json", %{user: %User{nickname: "internal." <> _} = user}) do
+ render("service.json", %{user: user})
+ |> Map.merge(%{
+ "preferredUsername" => user.nickname,
+ "webfinger" => "acct:#{User.full_nickname(user)}"
+ })
+ end
def render("user.json", %{user: user}) do
{:ok, _, public_key} = Keys.keys_from_pem(user.keys)
@@ -120,7 +126,8 @@ defmodule Pleroma.Web.ActivityPub.UserView do
"discoverable" => user.is_discoverable,
"capabilities" => capabilities,
"alsoKnownAs" => user.also_known_as,
- "vcard:bday" => birthday
+ "vcard:bday" => birthday,
+ "webfinger" => "acct:#{User.full_nickname(user)}"
}
|> Map.merge(maybe_make_image(&User.avatar_url/2, "icon", user))
|> Map.merge(maybe_make_image(&User.banner_url/2, "image", user))
diff --git a/lib/pleroma/web/activity_pub/visibility.ex b/lib/pleroma/web/activity_pub/visibility.ex
old mode 100755
new mode 100644
index 7c57f88..97fc7fa
--- a/lib/pleroma/web/activity_pub/visibility.ex
+++ b/lib/pleroma/web/activity_pub/visibility.ex
@@ -11,28 +11,28 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
require Pleroma.Constants
- @spec is_public?(Object.t() | Activity.t() | map()) :: boolean()
- def is_public?(%Object{data: %{"type" => "Tombstone"}}), do: false
- def is_public?(%Object{data: data}), do: is_public?(data)
- def is_public?(%Activity{data: %{"type" => "Move"}}), do: true
- def is_public?(%Activity{data: data}), do: is_public?(data)
- def is_public?(%{"directMessage" => true}), do: false
-
- def is_public?(data) do
+ @spec public?(Object.t() | Activity.t() | map()) :: boolean()
+ def public?(%Object{data: %{"type" => "Tombstone"}}), do: false
+ def public?(%Object{data: data}), do: public?(data)
+ def public?(%Activity{data: %{"type" => "Move"}}), do: true
+ def public?(%Activity{data: data}), do: public?(data)
+ def public?(%{"directMessage" => true}), do: false
+
+ def public?(data) do
Utils.label_in_message?(Pleroma.Constants.as_public(), data) or
Utils.label_in_message?(Utils.as_local_public(), data)
end
- def is_local_public?(%Object{data: data}), do: is_local_public?(data)
- def is_local_public?(%Activity{data: data}), do: is_local_public?(data)
+ def local_public?(%Object{data: data}), do: local_public?(data)
+ def local_public?(%Activity{data: data}), do: local_public?(data)
- def is_local_public?(data) do
+ def local_public?(data) do
Utils.label_in_message?(Utils.as_local_public(), data) and
not Utils.label_in_message?(Pleroma.Constants.as_public(), data)
end
- def is_private?(activity) do
- with false <- is_public?(activity),
+ def private?(activity) do
+ with false <- public?(activity),
%User{follower_address: follower_address} <-
User.get_cached_by_ap_id(activity.data["actor"]) do
follower_address in activity.data["to"]
@@ -41,20 +41,20 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
end
end
- def is_announceable?(activity, user, public \\ true) do
- is_public?(activity) ||
- (!public && is_private?(activity) && activity.data["actor"] == user.ap_id)
+ def announceable?(activity, user, public \\ true) do
+ public?(activity) ||
+ (!public && private?(activity) && activity.data["actor"] == user.ap_id)
end
- def is_direct?(%Activity{data: %{"directMessage" => true}}), do: true
- def is_direct?(%Object{data: %{"directMessage" => true}}), do: true
+ def direct?(%Activity{data: %{"directMessage" => true}}), do: true
+ def direct?(%Object{data: %{"directMessage" => true}}), do: true
- def is_direct?(activity) do
- !is_public?(activity) && !is_private?(activity)
+ def direct?(activity) do
+ !public?(activity) && !private?(activity)
end
- def is_list?(%{data: %{"listMessage" => _}}), do: true
- def is_list?(_), do: false
+ def list?(%{data: %{"listMessage" => _}}), do: true
+ def list?(_), do: false
@spec visible_for_user?(Object.t() | Activity.t() | nil, User.t() | nil) :: boolean()
def visible_for_user?(%Object{data: %{"type" => "Tombstone"}}, _), do: false
@@ -77,7 +77,7 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
when module in [Activity, Object] do
if restrict_unauthenticated_access?(message),
do: false,
- else: is_public?(message) and not is_local_public?(message)
+ else: public?(message) and not local_public?(message)
end
def visible_for_user?(%{__struct__: module} = message, user)
@@ -86,8 +86,8 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
y = [message.data["actor"]] ++ message.data["to"] ++ (message.data["cc"] || [])
user_is_local = user.local
- federatable = not is_local_public?(message)
- (is_public?(message) || Enum.any?(x, &(&1 in y))) and (user_is_local || federatable)
+ federatable = not local_public?(message)
+ (public?(message) || Enum.any?(x, &(&1 in y))) and (user_is_local || federatable)
end
def entire_thread_visible_for_user?(%Activity{} = activity, %User{} = user) do
diff --git a/lib/pleroma/web/admin_api/controllers/admin_api_controller.ex b/lib/pleroma/web/admin_api/controllers/admin_api_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/admin_api/controllers/announcement_controller.ex b/lib/pleroma/web/admin_api/controllers/announcement_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/admin_api/controllers/chat_controller.ex b/lib/pleroma/web/admin_api/controllers/chat_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/admin_api/controllers/config_controller.ex b/lib/pleroma/web/admin_api/controllers/config_controller.ex
old mode 100755
new mode 100644
index a03318c..2c9c272
--- a/lib/pleroma/web/admin_api/controllers/config_controller.ex
+++ b/lib/pleroma/web/admin_api/controllers/config_controller.ex
@@ -9,7 +9,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigController do
alias Pleroma.ConfigDB
alias Pleroma.Web.Plugs.OAuthScopesPlug
- plug(Pleroma.Web.ApiSpec.CastAndValidate)
+ plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
plug(OAuthScopesPlug, %{scopes: ["admin:write"]} when action == :update)
plug(
@@ -76,7 +76,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigController do
json(conn, translate_descriptions(descriptions))
end
- def show(conn, %{only_db: true}) do
+ def show(%{private: %{open_api_spex: %{params: %{only_db: true}}}} = conn, _) do
with :ok <- configurable_from_database() do
configs = Pleroma.Repo.all(ConfigDB)
@@ -128,7 +128,7 @@ defmodule Pleroma.Web.AdminAPI.ConfigController do
end
end
- def update(%{body_params: %{configs: configs}} = conn, _) do
+ def update(%{private: %{open_api_spex: %{body_params: %{configs: configs}}}} = conn, _) do
with :ok <- configurable_from_database() do
results =
configs
diff --git a/lib/pleroma/web/admin_api/controllers/fallback_controller.ex b/lib/pleroma/web/admin_api/controllers/fallback_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/admin_api/controllers/frontend_controller.ex b/lib/pleroma/web/admin_api/controllers/frontend_controller.ex
old mode 100755
new mode 100644
index b4dbb82..9e2ed4a
--- a/lib/pleroma/web/admin_api/controllers/frontend_controller.ex
+++ b/lib/pleroma/web/admin_api/controllers/frontend_controller.ex
@@ -18,13 +18,24 @@ defmodule Pleroma.Web.AdminAPI.FrontendController do
def index(conn, _params) do
installed = installed()
+ # FIrst get frontends from config,
+ # then add frontends that are installed but not in the config
frontends =
- [:frontends, :available]
- |> Config.get([])
+ Config.get([:frontends, :available], [])
|> Enum.map(fn {name, desc} ->
- Map.put(desc, "installed", name in installed)
+ desc
+ |> Map.put("installed", name in installed)
+ |> Map.put("installed_refs", installed_refs(name))
end)
+ frontends =
+ frontends ++
+ (installed
+ |> Enum.filter(fn n -> not Enum.any?(frontends, fn f -> f["name"] == n end) end)
+ |> Enum.map(fn name ->
+ %{"name" => name, "installed" => true, "installed_refs" => installed_refs(name)}
+ end))
+
render(conn, "index.json", frontends: frontends)
end
@@ -43,4 +54,12 @@ defmodule Pleroma.Web.AdminAPI.FrontendController do
[]
end
end
+
+ def installed_refs(name) do
+ if name in installed() do
+ File.ls!(Path.join(Pleroma.Frontend.dir(), name))
+ else
+ []
+ end
+ end
end
diff --git a/lib/pleroma/web/admin_api/controllers/instance_controller.ex b/lib/pleroma/web/admin_api/controllers/instance_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/admin_api/controllers/instance_document_controller.ex b/lib/pleroma/web/admin_api/controllers/instance_document_controller.ex
old mode 100755
new mode 100644
index 990a943..d76a959
--- a/lib/pleroma/web/admin_api/controllers/instance_document_controller.ex
+++ b/lib/pleroma/web/admin_api/controllers/instance_document_controller.ex
@@ -9,7 +9,7 @@ defmodule Pleroma.Web.AdminAPI.InstanceDocumentController do
alias Pleroma.Web.Plugs.InstanceStatic
alias Pleroma.Web.Plugs.OAuthScopesPlug
- plug(Pleroma.Web.ApiSpec.CastAndValidate)
+ plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
action_fallback(Pleroma.Web.AdminAPI.FallbackController)
@@ -18,7 +18,7 @@ defmodule Pleroma.Web.AdminAPI.InstanceDocumentController do
plug(OAuthScopesPlug, %{scopes: ["admin:read"]} when action == :show)
plug(OAuthScopesPlug, %{scopes: ["admin:write"]} when action in [:update, :delete])
- def show(conn, %{name: document_name}) do
+ def show(%{private: %{open_api_spex: %{params: %{name: document_name}}}} = conn, _) do
with {:ok, url} <- InstanceDocument.get(document_name),
{:ok, content} <- File.read(InstanceStatic.file_path(url)) do
conn
@@ -27,13 +27,18 @@ defmodule Pleroma.Web.AdminAPI.InstanceDocumentController do
end
end
- def update(%{body_params: %{file: file}} = conn, %{name: document_name}) do
+ def update(
+ %{
+ private: %{open_api_spex: %{body_params: %{file: file}, params: %{name: document_name}}}
+ } = conn,
+ _
+ ) do
with {:ok, url} <- InstanceDocument.put(document_name, file.path) do
json(conn, %{"url" => url})
end
end
- def delete(conn, %{name: document_name}) do
+ def delete(%{private: %{open_api_spex: %{params: %{name: document_name}}}} = conn, _) do
with :ok <- InstanceDocument.delete(document_name) do
json(conn, %{})
end
diff --git a/lib/pleroma/web/admin_api/controllers/invite_controller.ex b/lib/pleroma/web/admin_api/controllers/invite_controller.ex
old mode 100755
new mode 100644
index c5d759b..7e3020f
--- a/lib/pleroma/web/admin_api/controllers/invite_controller.ex
+++ b/lib/pleroma/web/admin_api/controllers/invite_controller.ex
@@ -13,7 +13,7 @@ defmodule Pleroma.Web.AdminAPI.InviteController do
require Logger
- plug(Pleroma.Web.ApiSpec.CastAndValidate)
+ plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
plug(OAuthScopesPlug, %{scopes: ["admin:read:invites"]} when action == :index)
plug(
@@ -33,14 +33,14 @@ defmodule Pleroma.Web.AdminAPI.InviteController do
end
@doc "Create an account registration invite token"
- def create(%{body_params: params} = conn, _) do
+ def create(%{private: %{open_api_spex: %{body_params: params}}} = conn, _) do
{:ok, invite} = UserInviteToken.create_invite(params)
render(conn, "show.json", invite: invite)
end
@doc "Revokes invite by token"
- def revoke(%{body_params: %{token: token}} = conn, _) do
+ def revoke(%{private: %{open_api_spex: %{body_params: %{token: token}}}} = conn, _) do
with {:ok, invite} <- UserInviteToken.find_by_token(token),
{:ok, updated_invite} = UserInviteToken.update_invite(invite, %{used: true}) do
render(conn, "show.json", invite: updated_invite)
@@ -51,7 +51,13 @@ defmodule Pleroma.Web.AdminAPI.InviteController do
end
@doc "Sends registration invite via email"
- def email(%{assigns: %{user: user}, body_params: %{email: email} = params} = conn, _) do
+ def email(
+ %{
+ assigns: %{user: user},
+ private: %{open_api_spex: %{body_params: %{email: email} = params}}
+ } = conn,
+ _
+ ) do
with {_, false} <- {:registrations_open, Config.get([:instance, :registrations_open])},
{_, true} <- {:invites_enabled, Config.get([:instance, :invites_enabled])},
{:ok, invite_token} <- UserInviteToken.create_invite(),
diff --git a/lib/pleroma/web/admin_api/controllers/media_proxy_cache_controller.ex b/lib/pleroma/web/admin_api/controllers/media_proxy_cache_controller.ex
old mode 100755
new mode 100644
index 4d53f54..8b43ea9
--- a/lib/pleroma/web/admin_api/controllers/media_proxy_cache_controller.ex
+++ b/lib/pleroma/web/admin_api/controllers/media_proxy_cache_controller.ex
@@ -11,7 +11,7 @@ defmodule Pleroma.Web.AdminAPI.MediaProxyCacheController do
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
- plug(Pleroma.Web.ApiSpec.CastAndValidate)
+ plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
plug(
OAuthScopesPlug,
@@ -27,7 +27,7 @@ defmodule Pleroma.Web.AdminAPI.MediaProxyCacheController do
defdelegate open_api_operation(action), to: Spec.MediaProxyCacheOperation
- def index(%{assigns: %{user: _}} = conn, params) do
+ def index(%{assigns: %{user: _}, private: %{open_api_spex: %{params: params}}} = conn, _) do
entries = fetch_entries(params)
urls = paginate_entries(entries, params.page, params.page_size)
@@ -59,12 +59,19 @@ defmodule Pleroma.Web.AdminAPI.MediaProxyCacheController do
Enum.slice(entries, offset, page_size)
end
- def delete(%{assigns: %{user: _}, body_params: %{urls: urls}} = conn, _) do
+ def delete(
+ %{assigns: %{user: _}, private: %{open_api_spex: %{body_params: %{urls: urls}}}} = conn,
+ _
+ ) do
MediaProxy.remove_from_banned_urls(urls)
json(conn, %{})
end
- def purge(%{assigns: %{user: _}, body_params: %{urls: urls, ban: ban}} = conn, _) do
+ def purge(
+ %{assigns: %{user: _}, private: %{open_api_spex: %{body_params: %{urls: urls, ban: ban}}}} =
+ conn,
+ _
+ ) do
MediaProxy.Invalidation.purge(urls)
if ban do
diff --git a/lib/pleroma/web/admin_api/controllers/o_auth_app_controller.ex b/lib/pleroma/web/admin_api/controllers/o_auth_app_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/admin_api/controllers/relay_controller.ex b/lib/pleroma/web/admin_api/controllers/relay_controller.ex
old mode 100755
new mode 100644
index 2e83fe1..1f36d3b
--- a/lib/pleroma/web/admin_api/controllers/relay_controller.ex
+++ b/lib/pleroma/web/admin_api/controllers/relay_controller.ex
@@ -11,7 +11,7 @@ defmodule Pleroma.Web.AdminAPI.RelayController do
require Logger
- plug(Pleroma.Web.ApiSpec.CastAndValidate)
+ plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
plug(
OAuthScopesPlug,
@@ -31,7 +31,13 @@ defmodule Pleroma.Web.AdminAPI.RelayController do
end
end
- def follow(%{assigns: %{user: admin}, body_params: %{relay_url: target}} = conn, _) do
+ def follow(
+ %{
+ assigns: %{user: admin},
+ private: %{open_api_spex: %{body_params: %{relay_url: target}}}
+ } = conn,
+ _
+ ) do
with {:ok, _message} <- Relay.follow(target) do
ModerationLog.insert_log(%{action: "relay_follow", actor: admin, target: target})
@@ -44,7 +50,13 @@ defmodule Pleroma.Web.AdminAPI.RelayController do
end
end
- def unfollow(%{assigns: %{user: admin}, body_params: %{relay_url: target} = params} = conn, _) do
+ def unfollow(
+ %{
+ assigns: %{user: admin},
+ private: %{open_api_spex: %{body_params: %{relay_url: target} = params}}
+ } = conn,
+ _
+ ) do
with {:ok, _message} <- Relay.unfollow(target, %{force: params[:force]}) do
ModerationLog.insert_log(%{action: "relay_unfollow", actor: admin, target: target})
diff --git a/lib/pleroma/web/admin_api/controllers/report_controller.ex b/lib/pleroma/web/admin_api/controllers/report_controller.ex
old mode 100755
new mode 100644
index 15cbbcc..89d8cc8
--- a/lib/pleroma/web/admin_api/controllers/report_controller.ex
+++ b/lib/pleroma/web/admin_api/controllers/report_controller.ex
@@ -18,7 +18,7 @@ defmodule Pleroma.Web.AdminAPI.ReportController do
require Logger
- plug(Pleroma.Web.ApiSpec.CastAndValidate)
+ plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
plug(OAuthScopesPlug, %{scopes: ["admin:read:reports"]} when action in [:index, :show])
plug(
@@ -31,13 +31,13 @@ defmodule Pleroma.Web.AdminAPI.ReportController do
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.Admin.ReportOperation
- def index(conn, params) do
+ def index(%{private: %{open_api_spex: %{params: params}}} = conn, _) do
reports = Utils.get_reports(params, params.page, params.page_size)
render(conn, "index.json", reports: reports)
end
- def show(conn, %{id: id}) do
+ def show(%{private: %{open_api_spex: %{params: %{id: id}}}} = conn, _) do
with %Activity{} = report <- Activity.get_report(id) do
render(conn, "show.json", Report.extract_report_info(report))
else
@@ -45,7 +45,13 @@ defmodule Pleroma.Web.AdminAPI.ReportController do
end
end
- def update(%{assigns: %{user: admin}, body_params: %{reports: reports}} = conn, _) do
+ def update(
+ %{
+ assigns: %{user: admin},
+ private: %{open_api_spex: %{body_params: %{reports: reports}}}
+ } = conn,
+ _
+ ) do
result =
Enum.map(reports, fn report ->
case CommonAPI.update_report_state(report.id, report.state) do
@@ -73,9 +79,13 @@ defmodule Pleroma.Web.AdminAPI.ReportController do
end
end
- def notes_create(%{assigns: %{user: user}, body_params: %{content: content}} = conn, %{
- id: report_id
- }) do
+ def notes_create(
+ %{
+ assigns: %{user: user},
+ private: %{open_api_spex: %{body_params: %{content: content}, params: %{id: report_id}}}
+ } = conn,
+ _
+ ) do
with {:ok, _} <- ReportNote.create(user.id, report_id, content),
report <- Activity.get_by_id_with_user_actor(report_id) do
ModerationLog.insert_log(%{
@@ -92,10 +102,20 @@ defmodule Pleroma.Web.AdminAPI.ReportController do
end
end
- def notes_delete(%{assigns: %{user: user}} = conn, %{
- id: note_id,
- report_id: report_id
- }) do
+ def notes_delete(
+ %{
+ assigns: %{user: user},
+ private: %{
+ open_api_spex: %{
+ params: %{
+ id: note_id,
+ report_id: report_id
+ }
+ }
+ }
+ } = conn,
+ _
+ ) do
with {:ok, note} <- ReportNote.destroy(note_id),
report <- Activity.get_by_id_with_user_actor(report_id) do
ModerationLog.insert_log(%{
diff --git a/lib/pleroma/web/admin_api/controllers/status_controller.ex b/lib/pleroma/web/admin_api/controllers/status_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/admin_api/controllers/user_controller.ex b/lib/pleroma/web/admin_api/controllers/user_controller.ex
old mode 100755
new mode 100644
index 7b4ee46..9ac2753
--- a/lib/pleroma/web/admin_api/controllers/user_controller.ex
+++ b/lib/pleroma/web/admin_api/controllers/user_controller.ex
@@ -18,7 +18,7 @@ defmodule Pleroma.Web.AdminAPI.UserController do
@users_page_size 50
- plug(Pleroma.Web.ApiSpec.CastAndValidate)
+ plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
plug(
OAuthScopesPlug,
@@ -51,13 +51,22 @@ defmodule Pleroma.Web.AdminAPI.UserController do
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.Admin.UserOperation
- def delete(conn, %{nickname: nickname}) do
+ def delete(%{private: %{open_api_spex: %{params: %{nickname: nickname}}}} = conn, _) do
conn
- |> Map.put(:body_params, %{nicknames: [nickname]})
- |> delete(%{})
+ |> do_deletes([nickname])
end
- def delete(%{assigns: %{user: admin}, body_params: %{nicknames: nicknames}} = conn, _) do
+ def delete(
+ %{
+ private: %{open_api_spex: %{body_params: %{nicknames: nicknames}}}
+ } = conn,
+ _
+ ) do
+ conn
+ |> do_deletes(nicknames)
+ end
+
+ defp do_deletes(%{assigns: %{user: admin}} = conn, nicknames) when is_list(nicknames) do
users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
Enum.each(users, fn user ->
@@ -77,9 +86,13 @@ defmodule Pleroma.Web.AdminAPI.UserController do
def follow(
%{
assigns: %{user: admin},
- body_params: %{
- follower: follower_nick,
- followed: followed_nick
+ private: %{
+ open_api_spex: %{
+ body_params: %{
+ follower: follower_nick,
+ followed: followed_nick
+ }
+ }
}
} = conn,
_
@@ -102,9 +115,13 @@ defmodule Pleroma.Web.AdminAPI.UserController do
def unfollow(
%{
assigns: %{user: admin},
- body_params: %{
- follower: follower_nick,
- followed: followed_nick
+ private: %{
+ open_api_spex: %{
+ body_params: %{
+ follower: follower_nick,
+ followed: followed_nick
+ }
+ }
}
} = conn,
_
@@ -124,7 +141,13 @@ defmodule Pleroma.Web.AdminAPI.UserController do
json(conn, "ok")
end
- def create(%{assigns: %{user: admin}, body_params: %{users: users}} = conn, _) do
+ def create(
+ %{
+ assigns: %{user: admin},
+ private: %{open_api_spex: %{body_params: %{users: users}}}
+ } = conn,
+ _
+ ) do
changesets =
users
|> Enum.map(fn %{nickname: nickname, email: email, password: password} ->
@@ -178,7 +201,13 @@ defmodule Pleroma.Web.AdminAPI.UserController do
end
end
- def show(%{assigns: %{user: admin}} = conn, %{nickname: nickname}) do
+ def show(
+ %{
+ assigns: %{user: admin},
+ private: %{open_api_spex: %{params: %{nickname: nickname}}}
+ } = conn,
+ _
+ ) do
with %User{} = user <- User.get_cached_by_nickname_or_id(nickname, for: admin) do
render(conn, "show.json", %{user: user})
else
@@ -186,7 +215,11 @@ defmodule Pleroma.Web.AdminAPI.UserController do
end
end
- def toggle_activation(%{assigns: %{user: admin}} = conn, %{nickname: nickname}) do
+ def toggle_activation(
+ %{assigns: %{user: admin}, private: %{open_api_spex: %{params: %{nickname: nickname}}}} =
+ conn,
+ _
+ ) do
user = User.get_cached_by_nickname(nickname)
{:ok, updated_user} = User.set_activation(user, !user.is_active)
@@ -202,7 +235,13 @@ defmodule Pleroma.Web.AdminAPI.UserController do
render(conn, "show.json", user: updated_user)
end
- def activate(%{assigns: %{user: admin}, body_params: %{nicknames: nicknames}} = conn, _) do
+ def activate(
+ %{
+ assigns: %{user: admin},
+ private: %{open_api_spex: %{body_params: %{nicknames: nicknames}}}
+ } = conn,
+ _
+ ) do
users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
{:ok, updated_users} = User.set_activation(users, true)
@@ -212,10 +251,16 @@ defmodule Pleroma.Web.AdminAPI.UserController do
action: "activate"
})
- render(conn, "index.json", users: Keyword.values(updated_users))
+ render(conn, "index.json", users: updated_users)
end
- def deactivate(%{assigns: %{user: admin}, body_params: %{nicknames: nicknames}} = conn, _) do
+ def deactivate(
+ %{
+ assigns: %{user: admin},
+ private: %{open_api_spex: %{body_params: %{nicknames: nicknames}}}
+ } = conn,
+ _
+ ) do
users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
{:ok, updated_users} = User.set_activation(users, false)
@@ -225,10 +270,16 @@ defmodule Pleroma.Web.AdminAPI.UserController do
action: "deactivate"
})
- render(conn, "index.json", users: Keyword.values(updated_users))
+ render(conn, "index.json", users: updated_users)
end
- def approve(%{assigns: %{user: admin}, body_params: %{nicknames: nicknames}} = conn, _) do
+ def approve(
+ %{
+ assigns: %{user: admin},
+ private: %{open_api_spex: %{body_params: %{nicknames: nicknames}}}
+ } = conn,
+ _
+ ) do
users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
{:ok, updated_users} = User.approve(users)
@@ -241,7 +292,13 @@ defmodule Pleroma.Web.AdminAPI.UserController do
render(conn, "index.json", users: updated_users)
end
- def suggest(%{assigns: %{user: admin}, body_params: %{nicknames: nicknames}} = conn, _) do
+ def suggest(
+ %{
+ assigns: %{user: admin},
+ private: %{open_api_spex: %{body_params: %{nicknames: nicknames}}}
+ } = conn,
+ _
+ ) do
users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
{:ok, updated_users} = User.set_suggestion(users, true)
@@ -254,7 +311,13 @@ defmodule Pleroma.Web.AdminAPI.UserController do
render(conn, "index.json", users: updated_users)
end
- def unsuggest(%{assigns: %{user: admin}, body_params: %{nicknames: nicknames}} = conn, _) do
+ def unsuggest(
+ %{
+ assigns: %{user: admin},
+ private: %{open_api_spex: %{body_params: %{nicknames: nicknames}}}
+ } = conn,
+ _
+ ) do
users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
{:ok, updated_users} = User.set_suggestion(users, false)
@@ -267,7 +330,7 @@ defmodule Pleroma.Web.AdminAPI.UserController do
render(conn, "index.json", users: updated_users)
end
- def index(conn, params) do
+ def index(%{private: %{open_api_spex: %{params: params}}} = conn, _) do
{page, page_size} = page_params(params)
filters = maybe_parse_filters(params[:filters])
diff --git a/lib/pleroma/web/admin_api/report.ex b/lib/pleroma/web/admin_api/report.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/admin_api/search.ex b/lib/pleroma/web/admin_api/search.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/admin_api/views/account_view.ex b/lib/pleroma/web/admin_api/views/account_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/admin_api/views/announcement_view.ex b/lib/pleroma/web/admin_api/views/announcement_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/admin_api/views/chat_view.ex b/lib/pleroma/web/admin_api/views/chat_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/admin_api/views/config_view.ex b/lib/pleroma/web/admin_api/views/config_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/admin_api/views/frontend_view.ex b/lib/pleroma/web/admin_api/views/frontend_view.ex
old mode 100755
new mode 100644
index 0ca3d67..ae40165
--- a/lib/pleroma/web/admin_api/views/frontend_view.ex
+++ b/lib/pleroma/web/admin_api/views/frontend_view.ex
@@ -15,7 +15,8 @@ defmodule Pleroma.Web.AdminAPI.FrontendView do
git: frontend["git"],
build_url: frontend["build_url"],
ref: frontend["ref"],
- installed: frontend["installed"]
+ installed: frontend["installed"],
+ installed_refs: frontend["installed_refs"]
}
end
end
diff --git a/lib/pleroma/web/admin_api/views/invite_view.ex b/lib/pleroma/web/admin_api/views/invite_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/admin_api/views/media_proxy_cache_view.ex b/lib/pleroma/web/admin_api/views/media_proxy_cache_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/admin_api/views/moderation_log_view.ex b/lib/pleroma/web/admin_api/views/moderation_log_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/admin_api/views/o_auth_app_view.ex b/lib/pleroma/web/admin_api/views/o_auth_app_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/admin_api/views/report_view.ex b/lib/pleroma/web/admin_api/views/report_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/admin_api/views/status_view.ex b/lib/pleroma/web/admin_api/views/status_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/admin_api/views/user_view.ex b/lib/pleroma/web/admin_api/views/user_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec.ex b/lib/pleroma/web/api_spec.ex
old mode 100755
new mode 100644
index cae4241..10d2215
--- a/lib/pleroma/web/api_spec.ex
+++ b/lib/pleroma/web/api_spec.ex
@@ -10,6 +10,14 @@ defmodule Pleroma.Web.ApiSpec do
@behaviour OpenApi
+ defp streaming_paths do
+ %{
+ "/api/v1/streaming" => %OpenApiSpex.PathItem{
+ get: Pleroma.Web.ApiSpec.StreamingOperation.streaming_operation()
+ }
+ }
+ end
+
@impl OpenApi
def spec(opts \\ []) do
%OpenApi{
@@ -35,7 +43,7 @@ defmodule Pleroma.Web.ApiSpec do
- [Mastodon API documentation](https://docs.joinmastodon.org/client/intro/)
- [Differences in Mastodon API responses from vanilla Mastodon](https://docs-develop.pleroma.social/backend/development/API/differences_in_mastoapi_responses/)
- Please report such occurences on our [issue tracker](https://git.pleroma.social/pleroma/pleroma/-/issues). Feel free to submit API questions or proposals there too!
+ Please report such occurrences on our [issue tracker](https://git.pleroma.social/pleroma/pleroma/-/issues). Feel free to submit API questions or proposals there too!
""",
# Strip environment from the version
version: Application.spec(:pleroma, :vsn) |> to_string() |> String.replace(~r/\+.*$/, ""),
@@ -45,7 +53,7 @@ defmodule Pleroma.Web.ApiSpec do
}
},
# populate the paths from a phoenix router
- paths: OpenApiSpex.Paths.from_router(Router),
+ paths: Map.merge(streaming_paths(), OpenApiSpex.Paths.from_router(Router)),
components: %OpenApiSpex.Components{
parameters: %{
"accountIdOrNickname" =>
@@ -86,16 +94,17 @@ defmodule Pleroma.Web.ApiSpec do
"tags" => [
"Chat administration",
"Emoji pack administration",
- "Frontend managment",
+ "Frontend management",
"Instance configuration",
"Instance documents",
"Invites",
"MediaProxy cache",
- "OAuth application managment",
+ "OAuth application management",
"Relays",
- "Report managment",
+ "Report management",
"Status administration",
- "User administration"
+ "User administration",
+ "Announcement management"
]
},
%{"name" => "Applications", "tags" => ["Applications", "Push subscriptions"]},
@@ -110,10 +119,12 @@ defmodule Pleroma.Web.ApiSpec do
"Follow requests",
"Mascot",
"Markers",
- "Notifications"
+ "Notifications",
+ "Filters",
+ "Settings"
]
},
- %{"name" => "Instance", "tags" => ["Custom emojis"]},
+ %{"name" => "Instance", "tags" => ["Custom emojis", "Instance misc"]},
%{"name" => "Messaging", "tags" => ["Chats", "Conversations"]},
%{
"name" => "Statuses",
@@ -125,10 +136,22 @@ defmodule Pleroma.Web.ApiSpec do
"Retrieve status information",
"Scheduled statuses",
"Search",
- "Status actions"
+ "Status actions",
+ "Media attachments",
+ "Bookmark folders"
]
},
- %{"name" => "Miscellaneous", "tags" => ["Emoji packs", "Reports", "Suggestions"]}
+ %{
+ "name" => "Miscellaneous",
+ "tags" => [
+ "Emoji packs",
+ "Reports",
+ "Suggestions",
+ "Announcements",
+ "Remote interaction",
+ "Others"
+ ]
+ }
]
}
}
diff --git a/lib/pleroma/web/api_spec/cast_and_validate.ex b/lib/pleroma/web/api_spec/cast_and_validate.ex
old mode 100755
new mode 100644
index add59eb..f3e8e09
--- a/lib/pleroma/web/api_spec/cast_and_validate.ex
+++ b/lib/pleroma/web/api_spec/cast_and_validate.ex
@@ -27,10 +27,12 @@ defmodule Pleroma.Web.ApiSpec.CastAndValidate do
@impl Plug
- def call(conn, %{operation_id: operation_id, render_error: render_error}) do
+ def call(conn, %{operation_id: operation_id, render_error: render_error} = opts) do
{spec, operation_lookup} = PutApiSpec.get_spec_and_operation_lookup(conn)
operation = operation_lookup[operation_id]
+ cast_opts = opts |> Map.take([:replace_params]) |> Map.to_list()
+
content_type =
case Conn.get_req_header(conn, "content-type") do
[header_value | _] ->
@@ -44,7 +46,7 @@ defmodule Pleroma.Web.ApiSpec.CastAndValidate do
conn = Conn.put_private(conn, :operation_id, operation_id)
- case cast_and_validate(spec, operation, conn, content_type, strict?()) do
+ case cast_and_validate(spec, operation, conn, content_type, strict?(), cast_opts) do
{:ok, conn} ->
conn
@@ -94,11 +96,11 @@ defmodule Pleroma.Web.ApiSpec.CastAndValidate do
def call(conn, opts), do: OpenApiSpex.Plug.CastAndValidate.call(conn, opts)
- defp cast_and_validate(spec, operation, conn, content_type, true = _strict) do
- OpenApiSpex.cast_and_validate(spec, operation, conn, content_type)
+ defp cast_and_validate(spec, operation, conn, content_type, true = _strict, cast_opts) do
+ OpenApiSpex.cast_and_validate(spec, operation, conn, content_type, cast_opts)
end
- defp cast_and_validate(spec, operation, conn, content_type, false = _strict) do
+ defp cast_and_validate(spec, operation, conn, content_type, false = _strict, cast_opts) do
case OpenApiSpex.cast_and_validate(spec, operation, conn, content_type) do
{:ok, conn} ->
{:ok, conn}
@@ -123,7 +125,7 @@ defmodule Pleroma.Web.ApiSpec.CastAndValidate do
end)
conn = %Conn{conn | query_params: query_params}
- OpenApiSpex.cast_and_validate(spec, operation, conn, content_type)
+ OpenApiSpex.cast_and_validate(spec, operation, conn, content_type, cast_opts)
end
end
diff --git a/lib/pleroma/web/api_spec/helpers.ex b/lib/pleroma/web/api_spec/helpers.ex
old mode 100755
new mode 100644
index f20a916..7257253
--- a/lib/pleroma/web/api_spec/helpers.ex
+++ b/lib/pleroma/web/api_spec/helpers.ex
@@ -62,7 +62,7 @@ defmodule Pleroma.Web.ApiSpec.Helpers do
Operation.parameter(
:with_relationships,
:query,
- BooleanLike,
+ BooleanLike.schema(),
"Embed relationships into accounts. **If this parameter is not set account's `pleroma.relationship` is going to be `null`.**"
)
end
diff --git a/lib/pleroma/web/api_spec/operations/account_operation.ex b/lib/pleroma/web/api_spec/operations/account_operation.ex
old mode 100755
new mode 100644
index aabe988..36025e4
--- a/lib/pleroma/web/api_spec/operations/account_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/account_operation.ex
@@ -122,22 +122,27 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
parameters:
[
%Reference{"$ref": "#/components/parameters/accountIdOrNickname"},
- Operation.parameter(:pinned, :query, BooleanLike, "Include only pinned statuses"),
+ Operation.parameter(
+ :pinned,
+ :query,
+ BooleanLike.schema(),
+ "Include only pinned statuses"
+ ),
Operation.parameter(:tagged, :query, :string, "With tag"),
Operation.parameter(
:only_media,
:query,
- BooleanLike,
+ BooleanLike.schema(),
"Include only statuses with media attached"
),
Operation.parameter(
:with_muted,
:query,
- BooleanLike,
+ BooleanLike.schema(),
"Include statuses from muted accounts."
),
- Operation.parameter(:exclude_reblogs, :query, BooleanLike, "Exclude reblogs"),
- Operation.parameter(:exclude_replies, :query, BooleanLike, "Exclude replies"),
+ Operation.parameter(:exclude_reblogs, :query, BooleanLike.schema(), "Exclude reblogs"),
+ Operation.parameter(:exclude_replies, :query, BooleanLike.schema(), "Exclude replies"),
Operation.parameter(
:exclude_visibilities,
:query,
@@ -147,7 +152,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
Operation.parameter(
:with_muted,
:query,
- BooleanLike,
+ BooleanLike.schema(),
"Include reactions from muted accounts."
)
] ++ pagination_params(),
@@ -347,7 +352,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
summary: "Endorse",
operationId: "AccountController.endorse",
security: [%{"oAuth" => ["follow", "write:accounts"]}],
- description: "Addds the given account to endorsed accounts list.",
+ description: "Adds the given account to endorsed accounts list.",
parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
responses: %{
200 => Operation.response("Relationship", "application/json", AccountRelationship),
@@ -452,7 +457,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
operationId: "AccountController.blocks",
description: "View your blocks. See also accounts/:id/{block,unblock}",
security: [%{"oAuth" => ["read:blocks"]}],
- parameters: pagination_params(),
+ parameters: [with_relationships_param() | pagination_params()],
responses: %{
200 => Operation.response("Accounts", "application/json", array_of_accounts())
}
@@ -461,7 +466,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
def lookup_operation do
%Operation{
- tags: ["Account lookup"],
+ tags: ["Retrieve account information"],
summary: "Find a user by nickname",
operationId: "AccountController.lookup",
parameters: [
diff --git a/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex b/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex
old mode 100755
new mode 100644
index 58a039e..49850e5
--- a/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex
@@ -17,7 +17,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.AnnouncementOperation do
def index_operation do
%Operation{
- tags: ["Announcement managment"],
+ tags: ["Announcement management"],
summary: "Retrieve a list of announcements",
operationId: "AdminAPI.AnnouncementController.index",
security: [%{"oAuth" => ["admin:read"]}],
@@ -46,7 +46,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.AnnouncementOperation do
def show_operation do
%Operation{
- tags: ["Announcement managment"],
+ tags: ["Announcement management"],
summary: "Display one announcement",
operationId: "AdminAPI.AnnouncementController.show",
security: [%{"oAuth" => ["admin:read"]}],
@@ -69,7 +69,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.AnnouncementOperation do
def delete_operation do
%Operation{
- tags: ["Announcement managment"],
+ tags: ["Announcement management"],
summary: "Delete one announcement",
operationId: "AdminAPI.AnnouncementController.delete",
security: [%{"oAuth" => ["admin:write"]}],
@@ -92,7 +92,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.AnnouncementOperation do
def create_operation do
%Operation{
- tags: ["Announcement managment"],
+ tags: ["Announcement management"],
summary: "Create one announcement",
operationId: "AdminAPI.AnnouncementController.create",
security: [%{"oAuth" => ["admin:write"]}],
@@ -107,7 +107,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.AnnouncementOperation do
def change_operation do
%Operation{
- tags: ["Announcement managment"],
+ tags: ["Announcement management"],
summary: "Change one announcement",
operationId: "AdminAPI.AnnouncementController.change",
security: [%{"oAuth" => ["admin:write"]}],
diff --git a/lib/pleroma/web/api_spec/operations/admin/chat_operation.ex b/lib/pleroma/web/api_spec/operations/admin/chat_operation.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/operations/admin/config_operation.ex b/lib/pleroma/web/api_spec/operations/admin/config_operation.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/operations/admin/frontend_operation.ex b/lib/pleroma/web/api_spec/operations/admin/frontend_operation.ex
old mode 100755
new mode 100644
index 4bfe5ac..e17881b
--- a/lib/pleroma/web/api_spec/operations/admin/frontend_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/admin/frontend_operation.ex
@@ -16,7 +16,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.FrontendOperation do
def index_operation do
%Operation{
- tags: ["Frontend managment"],
+ tags: ["Frontend management"],
summary: "Retrieve a list of available frontends",
operationId: "AdminAPI.FrontendController.index",
security: [%{"oAuth" => ["admin:read"]}],
@@ -29,7 +29,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.FrontendOperation do
def install_operation do
%Operation{
- tags: ["Frontend managment"],
+ tags: ["Frontend management"],
summary: "Install a frontend",
operationId: "AdminAPI.FrontendController.install",
security: [%{"oAuth" => ["admin:read"]}],
@@ -51,8 +51,9 @@ defmodule Pleroma.Web.ApiSpec.Admin.FrontendOperation do
name: %Schema{type: :string},
git: %Schema{type: :string, format: :uri, nullable: true},
build_url: %Schema{type: :string, format: :uri, nullable: true},
- ref: %Schema{type: :string},
- installed: %Schema{type: :boolean}
+ ref: %Schema{type: :string, nullable: true},
+ installed: %Schema{type: :boolean},
+ installed_refs: %Schema{type: :array, items: %Schema{type: :string}}
}
}
}
diff --git a/lib/pleroma/web/api_spec/operations/admin/instance_document_operation.ex b/lib/pleroma/web/api_spec/operations/admin/instance_document_operation.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/operations/admin/invite_operation.ex b/lib/pleroma/web/api_spec/operations/admin/invite_operation.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/operations/admin/media_proxy_cache_operation.ex b/lib/pleroma/web/api_spec/operations/admin/media_proxy_cache_operation.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/operations/admin/o_auth_app_operation.ex b/lib/pleroma/web/api_spec/operations/admin/o_auth_app_operation.ex
old mode 100755
new mode 100644
index 1a05aff..2b2496c
--- a/lib/pleroma/web/api_spec/operations/admin/o_auth_app_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/admin/o_auth_app_operation.ex
@@ -17,7 +17,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.OAuthAppOperation do
def index_operation do
%Operation{
summary: "Retrieve a list of OAuth applications",
- tags: ["OAuth application managment"],
+ tags: ["OAuth application management"],
operationId: "AdminAPI.OAuthAppController.index",
security: [%{"oAuth" => ["admin:write"]}],
parameters: [
@@ -69,7 +69,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.OAuthAppOperation do
def create_operation do
%Operation{
- tags: ["OAuth application managment"],
+ tags: ["OAuth application management"],
summary: "Create an OAuth application",
operationId: "AdminAPI.OAuthAppController.create",
requestBody: request_body("Parameters", create_request()),
@@ -84,7 +84,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.OAuthAppOperation do
def update_operation do
%Operation{
- tags: ["OAuth application managment"],
+ tags: ["OAuth application management"],
summary: "Update OAuth application",
operationId: "AdminAPI.OAuthAppController.update",
parameters: [id_param() | admin_api_params()],
@@ -102,7 +102,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.OAuthAppOperation do
def delete_operation do
%Operation{
- tags: ["OAuth application managment"],
+ tags: ["OAuth application management"],
summary: "Delete OAuth application",
operationId: "AdminAPI.OAuthAppController.delete",
parameters: [id_param() | admin_api_params()],
diff --git a/lib/pleroma/web/api_spec/operations/admin/relay_operation.ex b/lib/pleroma/web/api_spec/operations/admin/relay_operation.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/operations/admin/report_operation.ex b/lib/pleroma/web/api_spec/operations/admin/report_operation.ex
old mode 100755
new mode 100644
index 312e091..fbb6896
--- a/lib/pleroma/web/api_spec/operations/admin/report_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/admin/report_operation.ex
@@ -19,7 +19,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.ReportOperation do
def index_operation do
%Operation{
- tags: ["Report managment"],
+ tags: ["Report management"],
summary: "Retrieve a list of reports",
operationId: "AdminAPI.ReportController.index",
security: [%{"oAuth" => ["admin:read:reports"]}],
@@ -69,7 +69,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.ReportOperation do
def show_operation do
%Operation{
- tags: ["Report managment"],
+ tags: ["Report management"],
summary: "Retrieve a report",
operationId: "AdminAPI.ReportController.show",
parameters: [id_param() | admin_api_params()],
@@ -83,7 +83,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.ReportOperation do
def update_operation do
%Operation{
- tags: ["Report managment"],
+ tags: ["Report management"],
summary: "Change state of specified reports",
operationId: "AdminAPI.ReportController.update",
security: [%{"oAuth" => ["admin:write:reports"]}],
@@ -99,7 +99,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.ReportOperation do
def notes_create_operation do
%Operation{
- tags: ["Report managment"],
+ tags: ["Report management"],
summary: "Add a note to the report",
operationId: "AdminAPI.ReportController.notes_create",
parameters: [id_param() | admin_api_params()],
@@ -120,7 +120,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.ReportOperation do
def notes_delete_operation do
%Operation{
- tags: ["Report managment"],
+ tags: ["Report management"],
summary: "Delete note attached to the report",
operationId: "AdminAPI.ReportController.notes_delete",
parameters: [
@@ -141,7 +141,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.ReportOperation do
end
def id_param do
- Operation.parameter(:id, :path, FlakeID, "Report ID",
+ Operation.parameter(:id, :path, FlakeID.schema(), "Report ID",
example: "9umDrYheeY451cQnEe",
required: true
)
diff --git a/lib/pleroma/web/api_spec/operations/admin/status_operation.ex b/lib/pleroma/web/api_spec/operations/admin/status_operation.ex
old mode 100755
new mode 100644
index 229912d..17383f1
--- a/lib/pleroma/web/api_spec/operations/admin/status_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/admin/status_operation.ex
@@ -70,7 +70,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.StatusOperation do
def show_operation do
%Operation{
- tags: ["Status adminitration)"],
+ tags: ["Status administration"],
summary: "Get status",
operationId: "AdminAPI.StatusController.show",
parameters: [id_param() | admin_api_params()],
@@ -84,7 +84,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.StatusOperation do
def update_operation do
%Operation{
- tags: ["Status adminitration)"],
+ tags: ["Status administration"],
summary: "Change the scope of a status",
operationId: "AdminAPI.StatusController.update",
parameters: [id_param() | admin_api_params()],
@@ -99,7 +99,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.StatusOperation do
def delete_operation do
%Operation{
- tags: ["Status adminitration)"],
+ tags: ["Status administration"],
summary: "Delete status",
operationId: "AdminAPI.StatusController.delete",
parameters: [id_param() | admin_api_params()],
@@ -143,7 +143,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.StatusOperation do
}
},
tags: %Schema{type: :string},
- is_confirmed: %Schema{type: :string}
+ is_confirmed: %Schema{type: :boolean}
}
}
end
diff --git a/lib/pleroma/web/api_spec/operations/admin/user_operation.ex b/lib/pleroma/web/api_spec/operations/admin/user_operation.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/operations/announcement_operation.ex b/lib/pleroma/web/api_spec/operations/announcement_operation.ex
old mode 100755
new mode 100644
index 71be000..6f70319
--- a/lib/pleroma/web/api_spec/operations/announcement_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/announcement_operation.ex
@@ -15,7 +15,7 @@ defmodule Pleroma.Web.ApiSpec.AnnouncementOperation do
def index_operation do
%Operation{
- tags: ["Announcement"],
+ tags: ["Announcements"],
summary: "Retrieve a list of announcements",
operationId: "MastodonAPI.AnnouncementController.index",
security: [%{"oAuth" => []}],
@@ -28,7 +28,7 @@ defmodule Pleroma.Web.ApiSpec.AnnouncementOperation do
def mark_read_operation do
%Operation{
- tags: ["Announcement"],
+ tags: ["Announcements"],
summary: "Mark one announcement as read",
operationId: "MastodonAPI.AnnouncementController.mark_read",
security: [%{"oAuth" => ["write:accounts"]}],
diff --git a/lib/pleroma/web/api_spec/operations/app_operation.ex b/lib/pleroma/web/api_spec/operations/app_operation.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/operations/chat_operation.ex b/lib/pleroma/web/api_spec/operations/chat_operation.ex
old mode 100755
new mode 100644
index cf6a055..f56e57a
--- a/lib/pleroma/web/api_spec/operations/chat_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/chat_operation.ex
@@ -137,7 +137,12 @@ defmodule Pleroma.Web.ApiSpec.ChatOperation do
"Deprecated due to no support for pagination. Using [/api/v2/pleroma/chats](#operation/ChatController.index2) instead is recommended.",
operationId: "ChatController.index",
parameters: [
- Operation.parameter(:with_muted, :query, BooleanLike, "Include chats from muted users")
+ Operation.parameter(
+ :with_muted,
+ :query,
+ BooleanLike.schema(),
+ "Include chats from muted users"
+ )
],
responses: %{
200 => Operation.response("The chats of the user", "application/json", chats_response())
@@ -156,7 +161,12 @@ defmodule Pleroma.Web.ApiSpec.ChatOperation do
summary: "Retrieve list of chats",
operationId: "ChatController.index2",
parameters: [
- Operation.parameter(:with_muted, :query, BooleanLike, "Include chats from muted users")
+ Operation.parameter(
+ :with_muted,
+ :query,
+ BooleanLike.schema(),
+ "Include chats from muted users"
+ )
| pagination_params()
],
responses: %{
diff --git a/lib/pleroma/web/api_spec/operations/conversation_operation.ex b/lib/pleroma/web/api_spec/operations/conversation_operation.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/operations/custom_emoji_operation.ex b/lib/pleroma/web/api_spec/operations/custom_emoji_operation.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/operations/directory_operation.ex b/lib/pleroma/web/api_spec/operations/directory_operation.ex
old mode 100755
new mode 100644
index 55752fa..2eca176
--- a/lib/pleroma/web/api_spec/operations/directory_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/directory_operation.ex
@@ -17,7 +17,7 @@ defmodule Pleroma.Web.ApiSpec.DirectoryOperation do
def index_operation do
%Operation{
- tags: ["Directory"],
+ tags: ["Others"],
summary: "Profile directory",
operationId: "DirectoryController.index",
parameters:
@@ -29,7 +29,7 @@ defmodule Pleroma.Web.ApiSpec.DirectoryOperation do
"Order by recent activity or account creation",
required: nil
),
- Operation.parameter(:local, :query, BooleanLike, "Include local users only")
+ Operation.parameter(:local, :query, BooleanLike.schema(), "Include local users only")
] ++ pagination_params(),
responses: %{
200 =>
diff --git a/lib/pleroma/web/api_spec/operations/domain_block_operation.ex b/lib/pleroma/web/api_spec/operations/domain_block_operation.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/operations/emoji_reaction_operation.ex b/lib/pleroma/web/api_spec/operations/emoji_reaction_operation.ex
old mode 100755
new mode 100644
index 74341d6..8d6be89
--- a/lib/pleroma/web/api_spec/operations/emoji_reaction_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/emoji_reaction_operation.ex
@@ -21,7 +21,7 @@ defmodule Pleroma.Web.ApiSpec.EmojiReactionOperation do
summary:
"Get an object of emoji to account mappings with accounts that reacted to the post",
parameters: [
- Operation.parameter(:id, :path, FlakeID, "Status ID", required: true),
+ Operation.parameter(:id, :path, FlakeID.schema(), "Status ID", required: true),
Operation.parameter(:emoji, :path, :string, "Filter by a single unicode emoji",
required: nil
),
@@ -45,7 +45,7 @@ defmodule Pleroma.Web.ApiSpec.EmojiReactionOperation do
tags: ["Emoji reactions"],
summary: "React to a post with a unicode emoji",
parameters: [
- Operation.parameter(:id, :path, FlakeID, "Status ID", required: true),
+ Operation.parameter(:id, :path, FlakeID.schema(), "Status ID", required: true),
Operation.parameter(:emoji, :path, :string, "A single character unicode emoji",
required: true
)
@@ -64,7 +64,7 @@ defmodule Pleroma.Web.ApiSpec.EmojiReactionOperation do
tags: ["Emoji reactions"],
summary: "Remove a reaction to a post with a unicode emoji",
parameters: [
- Operation.parameter(:id, :path, FlakeID, "Status ID", required: true),
+ Operation.parameter(:id, :path, FlakeID.schema(), "Status ID", required: true),
Operation.parameter(:emoji, :path, :string, "A single character unicode emoji",
required: true
)
diff --git a/lib/pleroma/web/api_spec/operations/filter_operation.ex b/lib/pleroma/web/api_spec/operations/filter_operation.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/operations/follow_request_operation.ex b/lib/pleroma/web/api_spec/operations/follow_request_operation.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/operations/instance_operation.ex b/lib/pleroma/web/api_spec/operations/instance_operation.ex
old mode 100755
new mode 100644
index 3c4b504..b6c411c
--- a/lib/pleroma/web/api_spec/operations/instance_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/instance_operation.ex
@@ -13,7 +13,7 @@ defmodule Pleroma.Web.ApiSpec.InstanceOperation do
def show_operation do
%Operation{
- tags: ["Instance"],
+ tags: ["Instance misc"],
summary: "Retrieve instance information",
description: "Information about the server",
operationId: "InstanceController.show",
@@ -23,9 +23,21 @@ defmodule Pleroma.Web.ApiSpec.InstanceOperation do
}
end
+ def show2_operation do
+ %Operation{
+ tags: ["Instance misc"],
+ summary: "Retrieve instance information",
+ description: "Information about the server",
+ operationId: "InstanceController.show2",
+ responses: %{
+ 200 => Operation.response("Instance", "application/json", instance2())
+ }
+ }
+ end
+
def peers_operation do
%Operation{
- tags: ["Instance"],
+ tags: ["Instance misc"],
summary: "Retrieve list of known instances",
operationId: "InstanceController.peers",
responses: %{
@@ -38,6 +50,15 @@ defmodule Pleroma.Web.ApiSpec.InstanceOperation do
%Schema{
type: :object,
properties: %{
+ accounts: %Schema{
+ type: :object,
+ properties: %{
+ max_featured_tags: %Schema{
+ type: :integer,
+ description: "The maximum number of featured tags allowed for each account."
+ }
+ }
+ },
uri: %Schema{type: :string, description: "The domain name of the instance"},
title: %Schema{type: :string, description: "The title of the website"},
description: %Schema{
@@ -89,7 +110,7 @@ defmodule Pleroma.Web.ApiSpec.InstanceOperation do
languages: %Schema{
type: :array,
items: %Schema{type: :string},
- description: "Primary langauges of the website and its staff"
+ description: "Primary languages of the website and its staff"
},
registrations: %Schema{type: :boolean, description: "Whether registrations are enabled"},
# Extra (not present in Mastodon):
@@ -165,6 +186,184 @@ defmodule Pleroma.Web.ApiSpec.InstanceOperation do
}
end
+ defp instance2 do
+ %Schema{
+ type: :object,
+ properties: %{
+ domain: %Schema{type: :string, description: "The domain name of the instance"},
+ title: %Schema{type: :string, description: "The title of the website"},
+ version: %Schema{
+ type: :string,
+ description: "The version of Pleroma installed on the instance"
+ },
+ source_url: %Schema{
+ type: :string,
+ description: "The version of Pleroma installed on the instance"
+ },
+ description: %Schema{
+ type: :string,
+ description: "Admin-defined description of the Pleroma site"
+ },
+ usage: %Schema{
+ type: :object,
+ description: "Instance usage statistics",
+ properties: %{
+ users: %Schema{
+ type: :object,
+ description: "User count statistics",
+ properties: %{
+ active_month: %Schema{
+ type: :integer,
+ description: "Monthly active users"
+ }
+ }
+ }
+ }
+ },
+ email: %Schema{
+ type: :string,
+ description: "An email that may be contacted for any inquiries",
+ format: :email
+ },
+ urls: %Schema{
+ type: :object,
+ description: "URLs of interest for clients apps",
+ properties: %{}
+ },
+ stats: %Schema{
+ type: :object,
+ description: "Statistics about how much information the instance contains",
+ properties: %{
+ user_count: %Schema{
+ type: :integer,
+ description: "Users registered on this instance"
+ },
+ status_count: %Schema{
+ type: :integer,
+ description: "Statuses authored by users on instance"
+ },
+ domain_count: %Schema{
+ type: :integer,
+ description: "Domains federated with this instance"
+ }
+ }
+ },
+ thumbnail: %Schema{
+ type: :object,
+ properties: %{
+ url: %Schema{
+ type: :string,
+ description: "Banner image for the website",
+ nullable: true
+ }
+ }
+ },
+ languages: %Schema{
+ type: :array,
+ items: %Schema{type: :string},
+ description: "Primary languages of the website and its staff"
+ },
+ registrations: %Schema{
+ type: :object,
+ description: "Registrations-related configuration",
+ properties: %{
+ enabled: %Schema{
+ type: :boolean,
+ description: "Whether registrations are enabled"
+ },
+ approval_required: %Schema{
+ type: :boolean,
+ description: "Whether users need to be manually approved by admin"
+ }
+ }
+ },
+ configuration: %Schema{
+ type: :object,
+ description: "Instance configuration",
+ properties: %{
+ accounts: %Schema{
+ type: :object,
+ properties: %{
+ max_featured_tags: %Schema{
+ type: :integer,
+ description: "The maximum number of featured tags allowed for each account."
+ },
+ max_pinned_statuses: %Schema{
+ type: :integer,
+ description: "The maximum number of pinned statuses for each account."
+ }
+ }
+ },
+ urls: %Schema{
+ type: :object,
+ properties: %{
+ streaming: %Schema{
+ type: :string,
+ description: "Websockets address for push streaming"
+ }
+ }
+ },
+ statuses: %Schema{
+ type: :object,
+ description: "A map with poll limits for local statuses",
+ properties: %{
+ characters_reserved_per_url: %Schema{
+ type: :integer,
+ description:
+ "Each URL in a status will be assumed to be exactly this many characters."
+ },
+ max_characters: %Schema{
+ type: :integer,
+ description: "Posts character limit (CW/Subject included in the counter)"
+ },
+ max_media_attachments: %Schema{
+ type: :integer,
+ description: "Media attachment limit"
+ }
+ }
+ },
+ media_attachments: %Schema{
+ type: :object,
+ description: "A map with poll limits for media attachments",
+ properties: %{
+ image_size_limit: %Schema{
+ type: :integer,
+ description: "File size limit of uploaded images"
+ },
+ video_size_limit: %Schema{
+ type: :integer,
+ description: "File size limit of uploaded videos"
+ }
+ }
+ },
+ polls: %Schema{
+ type: :object,
+ description: "A map with poll limits for local polls",
+ properties: %{
+ max_options: %Schema{
+ type: :integer,
+ description: "Maximum number of options."
+ },
+ max_characters_per_option: %Schema{
+ type: :integer,
+ description: "Maximum number of characters per option."
+ },
+ min_expiration: %Schema{
+ type: :integer,
+ description: "Minimum expiration time (in seconds)."
+ },
+ max_expiration: %Schema{
+ type: :integer,
+ description: "Maximum expiration time (in seconds)."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ end
+
defp array_of_domains do
%Schema{
type: :array,
diff --git a/lib/pleroma/web/api_spec/operations/list_operation.ex b/lib/pleroma/web/api_spec/operations/list_operation.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/operations/marker_operation.ex b/lib/pleroma/web/api_spec/operations/marker_operation.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/operations/media_operation.ex b/lib/pleroma/web/api_spec/operations/media_operation.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/operations/notification_operation.ex b/lib/pleroma/web/api_spec/operations/notification_operation.ex
old mode 100755
new mode 100644
index 56aa129..757429d
--- a/lib/pleroma/web/api_spec/operations/notification_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/notification_operation.ex
@@ -62,7 +62,7 @@ defmodule Pleroma.Web.ApiSpec.NotificationOperation do
Operation.parameter(
:with_muted,
:query,
- BooleanLike,
+ BooleanLike.schema(),
"Include the notifications from muted users"
)
] ++ pagination_params(),
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_account_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_account_operation.ex
old mode 100755
new mode 100644
index 5375c5b..7340653
--- a/lib/pleroma/web/api_spec/operations/pleroma_account_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/pleroma_account_operation.ex
@@ -142,7 +142,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaAccountOperation do
end
defp id_param do
- Operation.parameter(:id, :path, FlakeID, "Account ID",
+ Operation.parameter(:id, :path, FlakeID.schema(), "Account ID",
example: "9umDrYheeY451cQnEe",
required: true
)
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_app_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_app_operation.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_backup_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_backup_operation.ex
old mode 100755
new mode 100644
index 45fa2b0..400f382
--- a/lib/pleroma/web/api_spec/operations/pleroma_backup_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/pleroma_backup_operation.ex
@@ -64,7 +64,13 @@ defmodule Pleroma.Web.ApiSpec.PleromaBackupOperation do
content_type: %Schema{type: :string},
file_name: %Schema{type: :string},
file_size: %Schema{type: :integer},
- processed: %Schema{type: :boolean}
+ processed: %Schema{type: :boolean, description: "whether this backup has succeeded"},
+ state: %Schema{
+ type: :string,
+ description: "the state of the backup",
+ enum: ["pending", "running", "complete", "failed"]
+ },
+ processed_number: %Schema{type: :integer, description: "the number of records processed"}
},
example: %{
"content_type" => "application/zip",
@@ -72,7 +78,9 @@ defmodule Pleroma.Web.ApiSpec.PleromaBackupOperation do
"https://cofe.fe:4000/media/backups/archive-foobar-20200908T164207-Yr7vuT5Wycv-sN3kSN2iJ0k-9pMo60j9qmvRCdDqIew.zip",
"file_size" => 4105,
"inserted_at" => "2020-09-08T16:42:07.000Z",
- "processed" => true
+ "processed" => true,
+ "state" => "complete",
+ "processed_number" => 20
}
}
end
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_bookmark_folder_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_bookmark_folder_operation.ex
new file mode 100644
index 0000000..eaa6831
--- /dev/null
+++ b/lib/pleroma/web/api_spec/operations/pleroma_bookmark_folder_operation.ex
@@ -0,0 +1,125 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2024 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.PleromaBookmarkFolderOperation do
+ alias OpenApiSpex.Operation
+ alias OpenApiSpex.Schema
+ alias Pleroma.Web.ApiSpec.Schemas.ApiError
+ alias Pleroma.Web.ApiSpec.Schemas.BookmarkFolder
+ alias Pleroma.Web.ApiSpec.Schemas.FlakeID
+
+ import Pleroma.Web.ApiSpec.Helpers
+
+ @spec open_api_operation(any()) :: any()
+ def open_api_operation(action) do
+ operation = String.to_existing_atom("#{action}_operation")
+ apply(__MODULE__, operation, [])
+ end
+
+ def index_operation do
+ %Operation{
+ tags: ["Bookmark folders"],
+ summary: "All bookmark folders",
+ security: [%{"oAuth" => ["read:bookmarks"]}],
+ operationId: "PleromaAPI.BookmarkFolderController.index",
+ responses: %{
+ 200 =>
+ Operation.response("Array of Bookmark Folders", "application/json", %Schema{
+ type: :array,
+ items: BookmarkFolder
+ })
+ }
+ }
+ end
+
+ def create_operation do
+ %Operation{
+ tags: ["Bookmark folders"],
+ summary: "Create a bookmark folder",
+ security: [%{"oAuth" => ["write:bookmarks"]}],
+ operationId: "PleromaAPI.BookmarkFolderController.create",
+ requestBody: request_body("Parameters", create_request(), required: true),
+ responses: %{
+ 200 => Operation.response("Bookmark Folder", "application/json", BookmarkFolder),
+ 422 => Operation.response("Error", "application/json", ApiError)
+ }
+ }
+ end
+
+ def update_operation do
+ %Operation{
+ tags: ["Bookmark folders"],
+ summary: "Update a bookmark folder",
+ security: [%{"oAuth" => ["write:bookmarks"]}],
+ operationId: "PleromaAPI.BookmarkFolderController.update",
+ parameters: [id_param()],
+ requestBody: request_body("Parameters", update_request(), required: true),
+ responses: %{
+ 200 => Operation.response("Bookmark Folder", "application/json", BookmarkFolder),
+ 403 => Operation.response("Forbidden", "application/json", ApiError),
+ 404 => Operation.response("Not Found", "application/json", ApiError),
+ 422 => Operation.response("Error", "application/json", ApiError)
+ }
+ }
+ end
+
+ def delete_operation do
+ %Operation{
+ tags: ["Bookmark folders"],
+ summary: "Delete a bookmark folder",
+ security: [%{"oAuth" => ["write:bookmarks"]}],
+ operationId: "PleromaAPI.BookmarkFolderController.delete",
+ parameters: [id_param()],
+ responses: %{
+ 200 => Operation.response("Bookmark Folder", "application/json", BookmarkFolder),
+ 403 => Operation.response("Forbidden", "application/json", ApiError),
+ 404 => Operation.response("Not Found", "application/json", ApiError)
+ }
+ }
+ end
+
+ defp create_request do
+ %Schema{
+ title: "BookmarkFolderCreateRequest",
+ type: :object,
+ properties: %{
+ name: %Schema{
+ type: :string,
+ description: "Folder name"
+ },
+ emoji: %Schema{
+ type: :string,
+ nullable: true,
+ description: "Folder emoji"
+ }
+ }
+ }
+ end
+
+ defp update_request do
+ %Schema{
+ title: "BookmarkFolderUpdateRequest",
+ type: :object,
+ properties: %{
+ name: %Schema{
+ type: :string,
+ nullable: true,
+ description: "Folder name"
+ },
+ emoji: %Schema{
+ type: :string,
+ nullable: true,
+ description: "Folder emoji"
+ }
+ }
+ }
+ end
+
+ def id_param do
+ Operation.parameter(:id, :path, FlakeID.schema(), "Bookmark Folder ID",
+ example: "9umDrYheeY451cQnEe",
+ required: true
+ )
+ end
+end
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_conversation_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_conversation_operation.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_emoji_file_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_emoji_file_operation.ex
old mode 100755
new mode 100644
index d09c1c1..b05bad1
--- a/lib/pleroma/web/api_spec/operations/pleroma_emoji_file_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/pleroma_emoji_file_operation.ex
@@ -133,7 +133,11 @@ defmodule Pleroma.Web.ApiSpec.PleromaEmojiFileOperation do
defp files_object do
%Schema{
type: :object,
- additionalProperties: %Schema{type: :string},
+ additionalProperties: %Schema{
+ type: :string,
+ description: "Filename of the emoji",
+ extensions: %{"x-additionalPropertiesName": "Emoji name"}
+ },
description: "Object with emoji names as keys and filenames as values"
}
end
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex
old mode 100755
new mode 100644
index 6add3ff..efa36ff
--- a/lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex
@@ -227,13 +227,29 @@ defmodule Pleroma.Web.ApiSpec.PleromaEmojiPackOperation do
defp emoji_packs_response do
Operation.response(
- "Object with pack names as keys and pack contents as values",
+ "Emoji packs and the count",
"application/json",
%Schema{
type: :object,
- additionalProperties: emoji_pack(),
+ properties: %{
+ packs: %Schema{
+ type: :object,
+ description: "Object with pack names as keys and pack contents as values",
+ additionalProperties: %Schema{
+ emoji_pack()
+ | extensions: %{"x-additionalPropertiesName": "Pack name"}
+ }
+ },
+ count: %Schema{
+ type: :integer,
+ description: "Number of emoji packs"
+ }
+ },
example: %{
- "emojos" => emoji_pack().example
+ "packs" => %{
+ "emojos" => emoji_pack().example
+ },
+ "count" => 1
}
}
)
@@ -274,7 +290,11 @@ defmodule Pleroma.Web.ApiSpec.PleromaEmojiPackOperation do
defp files_object do
%Schema{
type: :object,
- additionalProperties: %Schema{type: :string},
+ additionalProperties: %Schema{
+ type: :string,
+ description: "Filename",
+ extensions: %{"x-additionalPropertiesName": "Emoji name"}
+ },
description: "Object with emoji names as keys and filenames as values"
}
end
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_instances_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_instances_operation.ex
old mode 100755
new mode 100644
index 82db4e1..e9319f3
--- a/lib/pleroma/web/api_spec/operations/pleroma_instances_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/pleroma_instances_operation.ex
@@ -13,7 +13,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaInstancesOperation do
def show_operation do
%Operation{
- tags: ["Instance"],
+ tags: ["Instance misc"],
summary: "Retrieve federation status",
description: "Information about instances deemed unreachable by the server",
operationId: "PleromaInstances.show",
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_mascot_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_mascot_operation.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_notification_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_notification_operation.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_report_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_report_operation.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_scrobble_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_scrobble_operation.ex
old mode 100755
new mode 100644
index b6273bf..f595583
--- a/lib/pleroma/web/api_spec/operations/pleroma_scrobble_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/pleroma_scrobble_operation.ex
@@ -22,7 +22,8 @@ defmodule Pleroma.Web.ApiSpec.PleromaScrobbleOperation do
summary: "Creates a new Listen activity for an account",
security: [%{"oAuth" => ["write"]}],
operationId: "PleromaAPI.ScrobbleController.create",
- requestBody: request_body("Parameters", create_request(), requried: true),
+ deprecated: true,
+ requestBody: request_body("Parameters", create_request(), required: true),
responses: %{
200 => Operation.response("Scrobble", "application/json", scrobble())
}
@@ -34,6 +35,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaScrobbleOperation do
tags: ["Scrobbles"],
summary: "Requests a list of current and recent Listen activities for an account",
operationId: "PleromaAPI.ScrobbleController.index",
+ deprecated: true,
parameters: [
%Reference{"$ref": "#/components/parameters/accountIdOrNickname"} | pagination_params()
],
@@ -57,6 +59,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaScrobbleOperation do
album: %Schema{type: :string, description: "The album of the media playing"},
artist: %Schema{type: :string, description: "The artist of the media playing"},
length: %Schema{type: :integer, description: "The length of the media playing"},
+ externalLink: %Schema{type: :string, description: "A URL referencing the media playing"},
visibility: %Schema{
allOf: [VisibilityScope],
default: "public",
@@ -67,7 +70,8 @@ defmodule Pleroma.Web.ApiSpec.PleromaScrobbleOperation do
"title" => "Some Title",
"artist" => "Some Artist",
"album" => "Some Album",
- "length" => 180_000
+ "length" => 180_000,
+ "externalLink" => "https://www.last.fm/music/Some+Artist/_/Some+Title"
}
}
end
@@ -81,6 +85,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaScrobbleOperation do
title: %Schema{type: :string, description: "The title of the media playing"},
album: %Schema{type: :string, description: "The album of the media playing"},
artist: %Schema{type: :string, description: "The artist of the media playing"},
+ externalLink: %Schema{type: :string, description: "A URL referencing the media playing"},
length: %Schema{
type: :integer,
description: "The length of the media playing",
@@ -95,6 +100,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaScrobbleOperation do
"artist" => "Some Artist",
"album" => "Some Album",
"length" => 180_000,
+ "externalLink" => "https://www.last.fm/music/Some+Artist/_/Some+Title",
"created_at" => "2019-09-28T12:40:45.000Z"
}
}
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_settings_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_settings_operation.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_status_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_status_operation.ex
new file mode 100644
index 0000000..77c6049
--- /dev/null
+++ b/lib/pleroma/web/api_spec/operations/pleroma_status_operation.ex
@@ -0,0 +1,45 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2022 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.PleromaStatusOperation do
+ alias OpenApiSpex.Operation
+ alias Pleroma.Web.ApiSpec.Schemas.ApiError
+ alias Pleroma.Web.ApiSpec.Schemas.FlakeID
+ alias Pleroma.Web.ApiSpec.StatusOperation
+
+ import Pleroma.Web.ApiSpec.Helpers
+
+ def open_api_operation(action) do
+ operation = String.to_existing_atom("#{action}_operation")
+ apply(__MODULE__, operation, [])
+ end
+
+ def quotes_operation do
+ %Operation{
+ tags: ["Retrieve status information"],
+ summary: "Quoted by",
+ description: "View quotes for a given status",
+ operationId: "PleromaAPI.StatusController.quotes",
+ parameters: [id_param() | pagination_params()],
+ security: [%{"oAuth" => ["read:statuses"]}],
+ responses: %{
+ 200 =>
+ Operation.response(
+ "Array of Status",
+ "application/json",
+ StatusOperation.array_of_statuses()
+ ),
+ 403 => Operation.response("Forbidden", "application/json", ApiError),
+ 404 => Operation.response("Not Found", "application/json", ApiError)
+ }
+ }
+ end
+
+ def id_param do
+ Operation.parameter(:id, :path, FlakeID.schema(), "Status ID",
+ example: "9umDrYheeY451cQnEe",
+ required: true
+ )
+ end
+end
diff --git a/lib/pleroma/web/api_spec/operations/poll_operation.ex b/lib/pleroma/web/api_spec/operations/poll_operation.ex
old mode 100755
new mode 100644
index efd784f..6dd2517
--- a/lib/pleroma/web/api_spec/operations/poll_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/poll_operation.ex
@@ -47,7 +47,7 @@ defmodule Pleroma.Web.ApiSpec.PollOperation do
end
defp id_param do
- Operation.parameter(:id, :path, FlakeID, "Poll ID",
+ Operation.parameter(:id, :path, FlakeID.schema(), "Poll ID",
example: "123",
required: true
)
diff --git a/lib/pleroma/web/api_spec/operations/report_operation.ex b/lib/pleroma/web/api_spec/operations/report_operation.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/operations/scheduled_activity_operation.ex b/lib/pleroma/web/api_spec/operations/scheduled_activity_operation.ex
old mode 100755
new mode 100644
index 802d3b6..c7ed02f
--- a/lib/pleroma/web/api_spec/operations/scheduled_activity_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/scheduled_activity_operation.ex
@@ -88,7 +88,7 @@ defmodule Pleroma.Web.ApiSpec.ScheduledActivityOperation do
end
defp id_param do
- Operation.parameter(:id, :path, FlakeID, "Poll ID",
+ Operation.parameter(:id, :path, FlakeID.schema(), "Poll ID",
example: "123",
required: true
)
diff --git a/lib/pleroma/web/api_spec/operations/search_operation.ex b/lib/pleroma/web/api_spec/operations/search_operation.ex
old mode 100755
new mode 100644
index 1a7e49b..539743b
--- a/lib/pleroma/web/api_spec/operations/search_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/search_operation.ex
@@ -70,7 +70,7 @@ defmodule Pleroma.Web.ApiSpec.SearchOperation do
Operation.parameter(
:account_id,
:query,
- FlakeID,
+ FlakeID.schema(),
"If provided, statuses returned will be authored only by this account"
),
Operation.parameter(
@@ -116,7 +116,7 @@ defmodule Pleroma.Web.ApiSpec.SearchOperation do
Operation.parameter(
:account_id,
:query,
- FlakeID,
+ FlakeID.schema(),
"If provided, statuses returned will be authored only by this account"
),
Operation.parameter(
diff --git a/lib/pleroma/web/api_spec/operations/status_operation.ex b/lib/pleroma/web/api_spec/operations/status_operation.ex
old mode 100755
new mode 100644
index e921128..1717c68
--- a/lib/pleroma/web/api_spec/operations/status_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/status_operation.ex
@@ -39,7 +39,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
Operation.parameter(
:with_muted,
:query,
- BooleanLike,
+ BooleanLike.schema(),
"Include reactions from muted acccounts."
)
],
@@ -82,7 +82,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
Operation.parameter(
:with_muted,
:query,
- BooleanLike,
+ BooleanLike.schema(),
"Include reactions from muted acccounts."
)
],
@@ -256,6 +256,18 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
description: "Privately bookmark a status",
operationId: "StatusController.bookmark",
parameters: [id_param()],
+ requestBody:
+ request_body("Parameters", %Schema{
+ title: "StatusUpdateRequest",
+ type: :object,
+ properties: %{
+ folder_id: %Schema{
+ nullable: true,
+ allOf: [FlakeID],
+ description: "ID of bookmarks folder, if any"
+ }
+ }
+ }),
responses: %{
200 => status_response()
}
@@ -430,7 +442,15 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
summary: "Bookmarked statuses",
description: "Statuses the user has bookmarked",
operationId: "StatusController.bookmarks",
- parameters: pagination_params(),
+ parameters: [
+ Operation.parameter(
+ :folder_id,
+ :query,
+ FlakeID.schema(),
+ "If provided, only display bookmarks from given folder"
+ )
+ | pagination_params()
+ ],
security: [%{"oAuth" => ["read:bookmarks"]}],
responses: %{
200 => Operation.response("Array of Statuses", "application/json", array_of_statuses())
@@ -440,7 +460,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
def show_history_operation do
%Operation{
- tags: ["Retrieve status history"],
+ tags: ["Retrieve status information"],
summary: "Status history",
description: "View history of a status",
operationId: "StatusController.show_history",
@@ -457,7 +477,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
def show_source_operation do
%Operation{
- tags: ["Retrieve status source"],
+ tags: ["Retrieve status information"],
summary: "Status source",
description: "View source of a status",
operationId: "StatusController.show_source",
@@ -474,7 +494,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
def update_operation do
%Operation{
- tags: ["Update status"],
+ tags: ["Status actions"],
summary: "Update status",
description: "Change the content of a status",
operationId: "StatusController.update",
@@ -534,7 +554,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
format: :"date-time",
nullable: true,
description:
- "ISO 8601 Datetime at which to schedule a status. Providing this paramter will cause ScheduledStatus to be returned instead of Status. Must be at least 5 minutes in the future."
+ "ISO 8601 Datetime at which to schedule a status. Providing this parameter will cause ScheduledStatus to be returned instead of Status. Must be at least 5 minutes in the future."
},
language: %Schema{
type: :string,
@@ -546,7 +566,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
allOf: [BooleanLike],
nullable: true,
description:
- "If set to `true` the post won't be actually posted, but the status entitiy would still be rendered back. This could be useful for previewing rich text/custom emoji, for example"
+ "If set to `true` the post won't be actually posted, but the status entity would still be rendered back. This could be useful for previewing rich text/custom emoji, for example"
},
content_type: %Schema{
type: :string,
@@ -581,6 +601,11 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
type: :string,
description:
"Will reply to a given conversation, addressing only the people who are part of the recipient set of that conversation. Sets the visibility to `direct`."
+ },
+ quote_id: %Schema{
+ nullable: true,
+ allOf: [FlakeID],
+ description: "ID of the status being quoted, if any"
}
},
example: %{
@@ -680,7 +705,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
end
def id_param do
- Operation.parameter(:id, :path, FlakeID, "Status ID",
+ Operation.parameter(:id, :path, FlakeID.schema(), "Status ID",
example: "9umDrYheeY451cQnEe",
required: true
)
diff --git a/lib/pleroma/web/api_spec/operations/streaming_operation.ex b/lib/pleroma/web/api_spec/operations/streaming_operation.ex
new file mode 100644
index 0000000..b580bc2
--- /dev/null
+++ b/lib/pleroma/web/api_spec/operations/streaming_operation.ex
@@ -0,0 +1,464 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2022 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.StreamingOperation do
+ alias OpenApiSpex.Operation
+ alias OpenApiSpex.Response
+ alias OpenApiSpex.Schema
+ alias Pleroma.Web.ApiSpec.NotificationOperation
+ alias Pleroma.Web.ApiSpec.Schemas.Chat
+ alias Pleroma.Web.ApiSpec.Schemas.Conversation
+ alias Pleroma.Web.ApiSpec.Schemas.FlakeID
+ alias Pleroma.Web.ApiSpec.Schemas.Status
+
+ require Pleroma.Constants
+
+ @spec open_api_operation(atom) :: Operation.t()
+ def open_api_operation(action) do
+ operation = String.to_existing_atom("#{action}_operation")
+ apply(__MODULE__, operation, [])
+ end
+
+ @spec streaming_operation() :: Operation.t()
+ def streaming_operation do
+ %Operation{
+ tags: ["Timelines"],
+ summary: "Establish streaming connection",
+ description: """
+ Receive statuses in real-time via WebSocket.
+
+ You can specify the access token on the query string or through the `sec-websocket-protocol` header. Using
+ the query string to authenticate is considered unsafe and should not be used unless you have to (e.g. to maintain
+ your client's compatibility with Mastodon).
+
+ You may specify a stream on the query string. If you do so and you are connecting to a stream that requires logged-in users,
+ you must specify the access token at the time of the connection (i.e. via query string or header).
+
+ Otherwise, you have the option to authenticate after you have established the connection through client-sent events.
+
+ The "Request body" section below describes what events clients can send through WebSocket, and the "Responses" section
+ describes what events server will send through WebSocket.
+ """,
+ security: [%{"oAuth" => ["read:statuses", "read:notifications"]}],
+ operationId: "WebsocketHandler.streaming",
+ parameters:
+ [
+ Operation.parameter(:connection, :header, %Schema{type: :string}, "connection header",
+ required: true
+ ),
+ Operation.parameter(:upgrade, :header, %Schema{type: :string}, "upgrade header",
+ required: true
+ ),
+ Operation.parameter(
+ :"sec-websocket-key",
+ :header,
+ %Schema{type: :string},
+ "sec-websocket-key header",
+ required: true
+ ),
+ Operation.parameter(
+ :"sec-websocket-version",
+ :header,
+ %Schema{type: :string},
+ "sec-websocket-version header",
+ required: true
+ )
+ ] ++ stream_params() ++ access_token_params(),
+ requestBody: request_body("Client-sent events", client_sent_events()),
+ responses: %{
+ 101 => switching_protocols_response(),
+ 200 =>
+ Operation.response(
+ "Server-sent events",
+ "application/json",
+ server_sent_events()
+ )
+ }
+ }
+ end
+
+ defp stream_params do
+ stream_specifier()
+ |> Enum.map(fn {name, schema} ->
+ Operation.parameter(name, :query, schema, get_schema(schema).description)
+ end)
+ end
+
+ defp access_token_params do
+ [
+ Operation.parameter(:access_token, :query, token(), token().description),
+ Operation.parameter(:"sec-websocket-protocol", :header, token(), token().description)
+ ]
+ end
+
+ defp switching_protocols_response do
+ %Response{
+ description: "Switching protocols",
+ headers: %{
+ "connection" => %OpenApiSpex.Header{required: true},
+ "upgrade" => %OpenApiSpex.Header{required: true},
+ "sec-websocket-accept" => %OpenApiSpex.Header{required: true}
+ }
+ }
+ end
+
+ defp server_sent_events do
+ %Schema{
+ oneOf: [
+ update_event(),
+ status_update_event(),
+ notification_event(),
+ chat_update_event(),
+ follow_relationships_update_event(),
+ conversation_event(),
+ delete_event(),
+ pleroma_respond_event()
+ ]
+ }
+ end
+
+ defp stream do
+ %Schema{
+ type: :array,
+ title: "Stream",
+ description: """
+ The stream identifier.
+ The first item is the name of the stream. If the stream needs a differentiator, the second item will be the corresponding identifier.
+ Currently, for the following stream types, there is a second element in the array:
+
+ - `list`: The second element is the id of the list, as a string.
+ - `hashtag`: The second element is the name of the hashtag.
+ - `public:remote:media` and `public:remote`: The second element is the domain of the corresponding instance.
+ """,
+ maxItems: 2,
+ minItems: 1,
+ items: %Schema{type: :string},
+ example: ["hashtag", "mew"]
+ }
+ end
+
+ defp get_schema(%Schema{} = schema), do: schema
+ defp get_schema(schema), do: schema.schema
+
+ defp server_sent_event_helper(name, description, type, payload, opts \\ []) do
+ payload_type = Keyword.get(opts, :payload_type, :json)
+ has_stream = Keyword.get(opts, :has_stream, true)
+
+ stream_properties =
+ if has_stream do
+ %{stream: stream()}
+ else
+ %{}
+ end
+
+ stream_example = if has_stream, do: %{"stream" => get_schema(stream()).example}, else: %{}
+
+ stream_required = if has_stream, do: [:stream], else: []
+
+ payload_schema =
+ if payload_type == :json do
+ %Schema{
+ title: "Event payload",
+ description: "JSON-encoded string of #{get_schema(payload).title}",
+ allOf: [payload]
+ }
+ else
+ payload
+ end
+
+ payload_example =
+ if payload_type == :json do
+ get_schema(payload).example |> Jason.encode!()
+ else
+ get_schema(payload).example
+ end
+
+ %Schema{
+ type: :object,
+ title: name,
+ description: description,
+ required: [:event, :payload] ++ stream_required,
+ properties:
+ %{
+ event: %Schema{
+ title: "Event type",
+ description: "Type of the event.",
+ type: :string,
+ required: true,
+ enum: [type]
+ },
+ payload: payload_schema
+ }
+ |> Map.merge(stream_properties),
+ example:
+ %{
+ "event" => type,
+ "payload" => payload_example
+ }
+ |> Map.merge(stream_example)
+ }
+ end
+
+ defp update_event do
+ server_sent_event_helper("New status", "A newly-posted status.", "update", Status)
+ end
+
+ defp status_update_event do
+ server_sent_event_helper("Edit", "A status that was just edited", "status.update", Status)
+ end
+
+ defp notification_event do
+ server_sent_event_helper(
+ "Notification",
+ "A new notification.",
+ "notification",
+ NotificationOperation.notification()
+ )
+ end
+
+ defp follow_relationships_update_event do
+ server_sent_event_helper(
+ "Follow relationships update",
+ "An update to follow relationships.",
+ "pleroma:follow_relationships_update",
+ %Schema{
+ type: :object,
+ title: "Follow relationships update",
+ required: [:state, :follower, :following],
+ properties: %{
+ state: %Schema{
+ type: :string,
+ description: "Follow state of the relationship.",
+ enum: ["follow_pending", "follow_accept", "follow_reject", "unfollow"]
+ },
+ follower: %Schema{
+ type: :object,
+ description: "Information about the follower.",
+ required: [:id, :follower_count, :following_count],
+ properties: %{
+ id: FlakeID,
+ follower_count: %Schema{type: :integer},
+ following_count: %Schema{type: :integer}
+ }
+ },
+ following: %Schema{
+ type: :object,
+ description: "Information about the following person.",
+ required: [:id, :follower_count, :following_count],
+ properties: %{
+ id: FlakeID,
+ follower_count: %Schema{type: :integer},
+ following_count: %Schema{type: :integer}
+ }
+ }
+ },
+ example: %{
+ "state" => "follow_pending",
+ "follower" => %{
+ "id" => "someUser1",
+ "follower_count" => 1,
+ "following_count" => 1
+ },
+ "following" => %{
+ "id" => "someUser2",
+ "follower_count" => 1,
+ "following_count" => 1
+ }
+ }
+ }
+ )
+ end
+
+ defp chat_update_event do
+ server_sent_event_helper(
+ "Chat update",
+ "A new chat message.",
+ "pleroma:chat_update",
+ Chat
+ )
+ end
+
+ defp conversation_event do
+ server_sent_event_helper(
+ "Conversation update",
+ "An update about a conversation",
+ "conversation",
+ Conversation
+ )
+ end
+
+ defp delete_event do
+ server_sent_event_helper(
+ "Delete",
+ "A status that was just deleted.",
+ "delete",
+ %Schema{
+ type: :string,
+ title: "Status id",
+ description: "Id of the deleted status",
+ allOf: [FlakeID],
+ example: "some-opaque-id"
+ },
+ payload_type: :string,
+ has_stream: false
+ )
+ end
+
+ defp pleroma_respond_event do
+ server_sent_event_helper(
+ "Server response",
+ "A response to a client-sent event.",
+ "pleroma:respond",
+ %Schema{
+ type: :object,
+ title: "Results",
+ required: [:result, :type],
+ properties: %{
+ result: %Schema{
+ type: :string,
+ title: "Result of the request",
+ enum: ["success", "error", "ignored"]
+ },
+ error: %Schema{
+ type: :string,
+ title: "Error code",
+ description: "An error identifier. Only appears if `result` is `error`."
+ },
+ type: %Schema{
+ type: :string,
+ description: "Type of the request."
+ }
+ },
+ example: %{"result" => "success", "type" => "pleroma:authenticate"}
+ },
+ has_stream: false
+ )
+ end
+
+ defp client_sent_events do
+ %Schema{
+ oneOf: [
+ subscribe_event(),
+ unsubscribe_event(),
+ authenticate_event()
+ ]
+ }
+ end
+
+ defp request_body(description, schema, opts \\ []) do
+ %OpenApiSpex.RequestBody{
+ description: description,
+ content: %{
+ "application/json" => %OpenApiSpex.MediaType{
+ schema: schema,
+ example: opts[:example],
+ examples: opts[:examples]
+ }
+ }
+ }
+ end
+
+ defp client_sent_event_helper(name, description, type, properties, opts) do
+ required = opts[:required] || []
+
+ %Schema{
+ type: :object,
+ title: name,
+ required: [:type] ++ required,
+ description: description,
+ properties:
+ %{
+ type: %Schema{type: :string, enum: [type], description: "Type of the event."}
+ }
+ |> Map.merge(properties),
+ example: opts[:example]
+ }
+ end
+
+ defp subscribe_event do
+ client_sent_event_helper(
+ "Subscribe",
+ "Subscribe to a stream.",
+ "subscribe",
+ stream_specifier(),
+ required: [:stream],
+ example: %{"type" => "subscribe", "stream" => "list", "list" => "1"}
+ )
+ end
+
+ defp unsubscribe_event do
+ client_sent_event_helper(
+ "Unsubscribe",
+ "Unsubscribe from a stream.",
+ "unsubscribe",
+ stream_specifier(),
+ required: [:stream],
+ example: %{
+ "type" => "unsubscribe",
+ "stream" => "public:remote:media",
+ "instance" => "example.org"
+ }
+ )
+ end
+
+ defp authenticate_event do
+ client_sent_event_helper(
+ "Authenticate",
+ "Authenticate via an access token.",
+ "pleroma:authenticate",
+ %{
+ token: token()
+ },
+ required: [:token]
+ )
+ end
+
+ defp token do
+ %Schema{
+ type: :string,
+ description: "An OAuth access token with corresponding permissions.",
+ example: "some token"
+ }
+ end
+
+ defp stream_specifier do
+ %{
+ stream: %Schema{
+ type: :string,
+ description: "The name of the stream.",
+ enum:
+ Pleroma.Constants.public_streams() ++
+ [
+ "public:remote",
+ "public:remote:media",
+ "user",
+ "user:pleroma_chat",
+ "user:notification",
+ "direct",
+ "list",
+ "hashtag"
+ ]
+ },
+ list: %Schema{
+ type: :string,
+ title: "List id",
+ description: "The id of the list. Required when `stream` is `list`.",
+ example: "some-id"
+ },
+ tag: %Schema{
+ type: :string,
+ title: "Hashtag name",
+ description: "The name of the hashtag. Required when `stream` is `hashtag`.",
+ example: "mew"
+ },
+ instance: %Schema{
+ type: :string,
+ title: "Domain name",
+ description:
+ "Domain name of the instance. Required when `stream` is `public:remote` or `public:remote:media`.",
+ example: "example.org"
+ }
+ }
+ end
+end
diff --git a/lib/pleroma/web/api_spec/operations/subscription_operation.ex b/lib/pleroma/web/api_spec/operations/subscription_operation.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/operations/timeline_operation.ex b/lib/pleroma/web/api_spec/operations/timeline_operation.ex
old mode 100755
new mode 100644
index fbe3f76..f55e598
--- a/lib/pleroma/web/api_spec/operations/timeline_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/timeline_operation.ex
@@ -176,7 +176,12 @@ defmodule Pleroma.Web.ApiSpec.TimelineOperation do
end
defp with_muted_param do
- Operation.parameter(:with_muted, :query, BooleanLike, "Include activities by muted users")
+ Operation.parameter(
+ :with_muted,
+ :query,
+ BooleanLike.schema(),
+ "Include activities by muted users"
+ )
end
defp exclude_visibilities_param do
diff --git a/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex
old mode 100755
new mode 100644
index 29df03e..724d873
--- a/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex
@@ -17,7 +17,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
def emoji_operation do
%Operation{
- tags: ["Emojis"],
+ tags: ["Custom emojis"],
summary: "List all custom emojis",
operationId: "UtilController.emoji",
parameters: [],
@@ -30,7 +30,8 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
properties: %{
image_url: %Schema{type: :string},
tags: %Schema{type: :array, items: %Schema{type: :string}}
- }
+ },
+ extensions: %{"x-additionalPropertiesName": "Emoji name"}
},
example: %{
"firefox" => %{
@@ -45,7 +46,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
def frontend_configurations_operation do
%Operation{
- tags: ["Configuration"],
+ tags: ["Others"],
summary: "Dump frontend configurations",
operationId: "UtilController.frontend_configurations",
parameters: [],
@@ -53,7 +54,12 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
200 =>
Operation.response("List", "application/json", %Schema{
type: :object,
- additionalProperties: %Schema{type: :object}
+ additionalProperties: %Schema{
+ type: :object,
+ description:
+ "Opaque object representing the instance-wide configuration for the frontend",
+ extensions: %{"x-additionalPropertiesName": "Frontend name"}
+ }
})
}
}
@@ -81,7 +87,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
defp change_password_request do
%Schema{
title: "ChangePasswordRequest",
- description: "POST body for changing the account's passowrd",
+ description: "POST body for changing the account's password",
type: :object,
required: [:password, :new_password, :new_password_confirmation],
properties: %{
@@ -130,23 +136,23 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
}
end
- def update_notificaton_settings_operation do
+ def update_notification_settings_operation do
%Operation{
- tags: ["Accounts"],
+ tags: ["Settings"],
summary: "Update Notification Settings",
security: [%{"oAuth" => ["write:accounts"]}],
- operationId: "UtilController.update_notificaton_settings",
+ operationId: "UtilController.update_notification_settings",
parameters: [
Operation.parameter(
:block_from_strangers,
:query,
- BooleanLike,
+ BooleanLike.schema(),
"blocks notifications from accounts you do not follow"
),
Operation.parameter(
:hide_notification_contents,
:query,
- BooleanLike,
+ BooleanLike.schema(),
"removes the contents of a message from the push notification"
)
],
@@ -207,6 +213,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
%Operation{
summary: "Get a captcha",
operationId: "UtilController.captcha",
+ tags: ["Others"],
parameters: [],
responses: %{
200 => Operation.response("Success", "application/json", %Schema{type: :object})
@@ -356,7 +363,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
def healthcheck_operation do
%Operation{
- tags: ["Accounts"],
+ tags: ["Others"],
summary: "Quick status check on the instance",
security: [%{"oAuth" => ["write:accounts"]}],
operationId: "UtilController.healthcheck",
@@ -371,7 +378,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
def remote_subscribe_operation do
%Operation{
- tags: ["Accounts"],
+ tags: ["Remote interaction"],
summary: "Remote Subscribe",
operationId: "UtilController.remote_subscribe",
parameters: [],
@@ -381,7 +388,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
def remote_interaction_operation do
%Operation{
- tags: ["Accounts"],
+ tags: ["Remote interaction"],
summary: "Remote interaction",
operationId: "UtilController.remote_interaction",
requestBody: request_body("Parameters", remote_interaction_request(), required: true),
@@ -407,7 +414,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
def show_subscribe_form_operation do
%Operation{
- tags: ["Accounts"],
+ tags: ["Remote interaction"],
summary: "Show remote subscribe form",
operationId: "UtilController.show_subscribe_form",
parameters: [],
diff --git a/lib/pleroma/web/api_spec/operations/user_import_operation.ex b/lib/pleroma/web/api_spec/operations/user_import_operation.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/render_error.ex b/lib/pleroma/web/api_spec/render_error.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/schemas/account.ex b/lib/pleroma/web/api_spec/schemas/account.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/schemas/account_field.ex b/lib/pleroma/web/api_spec/schemas/account_field.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/schemas/account_relationship.ex b/lib/pleroma/web/api_spec/schemas/account_relationship.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/schemas/actor_type.ex b/lib/pleroma/web/api_spec/schemas/actor_type.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/schemas/announcement.ex b/lib/pleroma/web/api_spec/schemas/announcement.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/schemas/api_error.ex b/lib/pleroma/web/api_spec/schemas/api_error.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/schemas/app.ex b/lib/pleroma/web/api_spec/schemas/app.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/schemas/attachment.ex b/lib/pleroma/web/api_spec/schemas/attachment.ex
old mode 100755
new mode 100644
index 48634a1..2871b5f
--- a/lib/pleroma/web/api_spec/schemas/attachment.ex
+++ b/lib/pleroma/web/api_spec/schemas/attachment.ex
@@ -11,7 +11,7 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Attachment do
title: "Attachment",
description: "Represents a file or media attachment that can be added to a status.",
type: :object,
- requried: [:id, :url, :preview_url],
+ required: [:id, :url, :preview_url],
properties: %{
id: %Schema{type: :string, description: "The ID of the attachment in the database."},
url: %Schema{
diff --git a/lib/pleroma/web/api_spec/schemas/bookmark_folder.ex b/lib/pleroma/web/api_spec/schemas/bookmark_folder.ex
new file mode 100644
index 0000000..e8b4f43
--- /dev/null
+++ b/lib/pleroma/web/api_spec/schemas/bookmark_folder.ex
@@ -0,0 +1,26 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2024 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.Schemas.BookmarkFolder do
+ alias OpenApiSpex.Schema
+ alias Pleroma.Web.ApiSpec.Schemas.FlakeID
+
+ require OpenApiSpex
+
+ OpenApiSpex.schema(%{
+ title: "BookmarkFolder",
+ description: "Response schema for a bookmark folder",
+ type: :object,
+ properties: %{
+ id: FlakeID,
+ name: %Schema{type: :string, description: "Folder name"},
+ emoji: %Schema{type: :string, description: "Folder emoji", nullable: true}
+ },
+ example: %{
+ "id" => "9toJCu5YZW7O7gfvH6",
+ "name" => "Read later",
+ "emoji" => nil
+ }
+ })
+end
diff --git a/lib/pleroma/web/api_spec/schemas/boolean_like.ex b/lib/pleroma/web/api_spec/schemas/boolean_like.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/schemas/chat.ex b/lib/pleroma/web/api_spec/schemas/chat.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/schemas/chat_message.ex b/lib/pleroma/web/api_spec/schemas/chat_message.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/schemas/conversation.ex b/lib/pleroma/web/api_spec/schemas/conversation.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/schemas/emoji.ex b/lib/pleroma/web/api_spec/schemas/emoji.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/schemas/flake_id.ex b/lib/pleroma/web/api_spec/schemas/flake_id.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/schemas/list.ex b/lib/pleroma/web/api_spec/schemas/list.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/schemas/poll.ex b/lib/pleroma/web/api_spec/schemas/poll.ex
old mode 100755
new mode 100644
index 9157058..20cf5b0
--- a/lib/pleroma/web/api_spec/schemas/poll.ex
+++ b/lib/pleroma/web/api_spec/schemas/poll.ex
@@ -56,6 +56,15 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Poll do
}
},
description: "Possible answers for the poll."
+ },
+ pleroma: %Schema{
+ type: :object,
+ properties: %{
+ non_anonymous: %Schema{
+ type: :boolean,
+ description: "Can voters be publicly identified?"
+ }
+ }
}
},
example: %{
@@ -79,7 +88,10 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Poll do
votes_count: 4
}
],
- emojis: []
+ emojis: [],
+ pleroma: %{
+ non_anonymous: false
+ }
}
})
end
diff --git a/lib/pleroma/web/api_spec/schemas/push_subscription.ex b/lib/pleroma/web/api_spec/schemas/push_subscription.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/schemas/scheduled_status.ex b/lib/pleroma/web/api_spec/schemas/scheduled_status.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/schemas/status.ex b/lib/pleroma/web/api_spec/schemas/status.ex
old mode 100755
new mode 100644
index 698f117..6e537b5
--- a/lib/pleroma/web/api_spec/schemas/status.ex
+++ b/lib/pleroma/web/api_spec/schemas/status.ex
@@ -58,6 +58,10 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do
format: :uri,
description: "Preview thumbnail"
},
+ image_description: %Schema{
+ type: :string,
+ description: "Alternate text that describes what is in the thumbnail"
+ },
title: %Schema{type: :string, description: "Title of linked resource"},
description: %Schema{type: :string, description: "Description of preview"}
}
@@ -144,7 +148,11 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do
properties: %{
content: %Schema{
type: :object,
- additionalProperties: %Schema{type: :string},
+ additionalProperties: %Schema{
+ type: :string,
+ description: "Alternate representation in the MIME type specified",
+ extensions: %{"x-additionalPropertiesName": "MIME type"}
+ },
description:
"A map consisting of alternate representations of the `content` property with the key being it's mimetype. Currently the only alternate representation supported is `text/plain`"
},
@@ -189,13 +197,41 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do
nullable: true,
description: "The `acct` property of User entity for replied user (if any)"
},
+ quote: %Schema{
+ allOf: [%OpenApiSpex.Reference{"$ref": "#/components/schemas/Status"}],
+ nullable: true,
+ description: "Quoted status (if any)"
+ },
+ quote_id: %Schema{
+ nullable: true,
+ allOf: [FlakeID],
+ description: "ID of the status being quoted, if any"
+ },
+ quote_url: %Schema{
+ type: :string,
+ format: :uri,
+ nullable: true,
+ description: "URL of the quoted status"
+ },
+ quote_visible: %Schema{
+ type: :boolean,
+ description: "`true` if the quoted post is visible to the user"
+ },
+ quotes_count: %Schema{
+ type: :integer,
+ description: "How many statuses quoted this status"
+ },
local: %Schema{
type: :boolean,
description: "`true` if the post was made on the local instance"
},
spoiler_text: %Schema{
type: :object,
- additionalProperties: %Schema{type: :string},
+ additionalProperties: %Schema{
+ type: :string,
+ description: "Alternate representation in the MIME type specified",
+ extensions: %{"x-additionalPropertiesName": "MIME type"}
+ },
description:
"A map consisting of alternate representations of the `spoiler_text` property with the key being it's mimetype. Currently the only alternate representation supported is `text/plain`."
},
@@ -339,7 +375,8 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do
"in_reply_to_account_acct" => nil,
"local" => true,
"spoiler_text" => %{"text/plain" => ""},
- "thread_muted" => false
+ "thread_muted" => false,
+ "quotes_count" => 0
},
"poll" => nil,
"reblog" => nil,
diff --git a/lib/pleroma/web/api_spec/schemas/tag.ex b/lib/pleroma/web/api_spec/schemas/tag.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/schemas/visibility_scope.ex b/lib/pleroma/web/api_spec/schemas/visibility_scope.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/api_spec/scopes/compiler.ex b/lib/pleroma/web/api_spec/scopes/compiler.ex
new file mode 100644
index 0000000..162edc9
--- /dev/null
+++ b/lib/pleroma/web/api_spec/scopes/compiler.ex
@@ -0,0 +1,82 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2023 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.Scopes.Compiler do
+ defmacro __before_compile__(_env) do
+ strings = __MODULE__.extract_all_scopes()
+
+ quote do
+ def placeholder do
+ unquote do
+ Enum.map(
+ strings,
+ fn string ->
+ quote do
+ Pleroma.Web.Gettext.dgettext_noop(
+ "oauth_scopes",
+ unquote(string)
+ )
+ end
+ end
+ )
+ end
+ end
+ end
+ end
+
+ def extract_all_scopes do
+ extract_all_scopes_from(Pleroma.Web.ApiSpec.spec())
+ end
+
+ def extract_all_scopes_from(specs) do
+ specs.paths
+ |> Enum.reduce([], fn
+ {_path, %{} = path_item}, acc ->
+ extract_routes(path_item)
+ |> Enum.flat_map(fn operation -> process_operation(operation) end)
+ |> Kernel.++(acc)
+
+ {_, _}, acc ->
+ acc
+ end)
+ |> Enum.uniq()
+ end
+
+ defp extract_routes(path_item) do
+ path_item
+ |> Map.from_struct()
+ |> Enum.map(fn {_method, path_item} -> path_item end)
+ |> Enum.filter(fn
+ %OpenApiSpex.Operation{} = _operation -> true
+ _ -> false
+ end)
+ end
+
+ defp process_operation(operation) do
+ operation.security
+ |> Kernel.||([])
+ |> Enum.flat_map(fn
+ %{"oAuth" => scopes} -> process_scopes(scopes)
+ _ -> []
+ end)
+ end
+
+ defp process_scopes(scopes) do
+ scopes
+ |> Enum.flat_map(fn scope ->
+ process_scope(scope)
+ end)
+ end
+
+ def process_scope(scope) do
+ hierarchy = String.split(scope, ":")
+
+ {_, list} =
+ Enum.reduce(hierarchy, {"", []}, fn comp, {cur, list} ->
+ {cur <> comp <> ":", [cur <> comp | list]}
+ end)
+
+ list
+ end
+end
diff --git a/lib/pleroma/web/api_spec/scopes/translator.ex b/lib/pleroma/web/api_spec/scopes/translator.ex
new file mode 100644
index 0000000..54eea35
--- /dev/null
+++ b/lib/pleroma/web/api_spec/scopes/translator.ex
@@ -0,0 +1,10 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2023 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.Scopes.Translator do
+ require Pleroma.Web.ApiSpec.Scopes.Compiler
+ require Pleroma.Web.Gettext
+
+ @before_compile Pleroma.Web.ApiSpec.Scopes.Compiler
+end
diff --git a/lib/pleroma/web/auth/authenticator.ex b/lib/pleroma/web/auth/authenticator.ex
old mode 100755
new mode 100644
index a0bd154..01bf157
--- a/lib/pleroma/web/auth/authenticator.ex
+++ b/lib/pleroma/web/auth/authenticator.ex
@@ -5,7 +5,7 @@
defmodule Pleroma.Web.Auth.Authenticator do
@callback get_user(Plug.Conn.t()) :: {:ok, user :: struct()} | {:error, any()}
@callback create_from_registration(Plug.Conn.t(), registration :: struct()) ::
- {:ok, User.t()} | {:error, any()}
+ {:ok, Pleroma.User.t()} | {:error, any()}
@callback get_registration(Plug.Conn.t()) :: {:ok, registration :: struct()} | {:error, any()}
@callback handle_error(Plug.Conn.t(), any()) :: any()
@callback auth_template() :: String.t() | nil
diff --git a/lib/pleroma/web/auth/helpers.ex b/lib/pleroma/web/auth/helpers.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/auth/ldap_authenticator.ex b/lib/pleroma/web/auth/ldap_authenticator.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/auth/pleroma_authenticator.ex b/lib/pleroma/web/auth/pleroma_authenticator.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/auth/totp_authenticator.ex b/lib/pleroma/web/auth/totp_authenticator.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/auth/wrapper_authenticator.ex b/lib/pleroma/web/auth/wrapper_authenticator.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/channels/user_socket.ex b/lib/pleroma/web/channels/user_socket.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/common_api.ex b/lib/pleroma/web/common_api.ex
old mode 100755
new mode 100644
index 44eb000..27e82ec
--- a/lib/pleroma/web/common_api.ex
+++ b/lib/pleroma/web/common_api.ex
@@ -154,7 +154,7 @@ defmodule Pleroma.Web.CommonAPI do
def delete(activity_id, user) do
with {_, %Activity{data: %{"object" => _, "type" => "Create"}} = activity} <-
- {:find_activity, Activity.get_by_id(activity_id)},
+ {:find_activity, Activity.get_by_id(activity_id, filter: [])},
{_, %Object{} = object, _} <-
{:find_object, Object.normalize(activity, fetch: false), activity},
true <- User.privileged?(user, :messages_delete) || user.ap_id == object.data["actor"],
@@ -372,7 +372,7 @@ defmodule Pleroma.Web.CommonAPI do
do: visibility in ~w(public unlisted)
def public_announce?(object, _) do
- Visibility.is_public?(object)
+ Visibility.public?(object)
end
def get_visibility(_, _, %Participation{}), do: {"direct", "direct"}
@@ -500,12 +500,12 @@ defmodule Pleroma.Web.CommonAPI do
end
defp activity_is_public(activity) do
- with false <- Visibility.is_public?(activity) do
+ with false <- Visibility.public?(activity) do
{:error, :visibility_error}
end
end
- @spec unpin(String.t(), User.t()) :: {:ok, User.t()} | {:error, term()}
+ @spec unpin(String.t(), User.t()) :: {:ok, Activity.t()} | {:error, term()}
def unpin(id, user) do
with %Activity{} = activity <- create_activity_by_id(id),
{:ok, unpin_data, _} <- Builder.unpin(user, activity.object),
@@ -550,7 +550,7 @@ defmodule Pleroma.Web.CommonAPI do
remove_mute(user, activity)
else
{what, result} = error ->
- Logger.warn(
+ Logger.warning(
"CommonAPI.remove_mute/2 failed. #{what}: #{result}, user_id: #{user_id}, activity_id: #{activity_id}"
)
@@ -595,7 +595,7 @@ defmodule Pleroma.Web.CommonAPI do
end
def update_report_state(activity_id, state) do
- with %Activity{} = activity <- Activity.get_by_id(activity_id) do
+ with %Activity{} = activity <- Activity.get_by_id(activity_id, filter: []) do
Utils.update_report_state(activity, state)
else
nil -> {:error, :not_found}
diff --git a/lib/pleroma/web/common_api/activity_draft.ex b/lib/pleroma/web/common_api/activity_draft.ex
old mode 100755
new mode 100644
index 63ed48a..bc46a8a
--- a/lib/pleroma/web/common_api/activity_draft.ex
+++ b/lib/pleroma/web/common_api/activity_draft.ex
@@ -7,10 +7,14 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do
alias Pleroma.Conversation.Participation
alias Pleroma.Object
alias Pleroma.Web.ActivityPub.Builder
+ alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.CommonAPI.Utils
import Pleroma.Web.Gettext
+ import Pleroma.Web.Utils.Guards, only: [not_empty_string: 1]
+
+ @type t :: %__MODULE__{}
defstruct valid?: true,
errors: [],
@@ -22,6 +26,7 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do
attachments: [],
in_reply_to: nil,
in_reply_to_conversation: nil,
+ quote_post: nil,
visibility: nil,
expires_at: nil,
extra: nil,
@@ -53,7 +58,9 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do
|> poll()
|> with_valid(&in_reply_to/1)
|> with_valid(&in_reply_to_conversation/1)
+ |> with_valid("e_post/1)
|> with_valid(&visibility/1)
+ |> with_valid("ing_visibility/1)
|> content()
|> with_valid(&to_and_cc/1)
|> with_valid(&context/1)
@@ -78,7 +85,7 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do
defp listen_object(draft) do
object =
draft.params
- |> Map.take([:album, :artist, :title, :length])
+ |> Map.take([:album, :artist, :title, :length, :externalLink])
|> Map.new(fn {key, value} -> {to_string(key), value} end)
|> Map.put("type", "Audio")
|> Map.put("to", draft.to)
@@ -132,6 +139,18 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do
defp in_reply_to(draft), do: draft
+ defp quote_post(%{params: %{quote_id: id}} = draft) when not_empty_string(id) do
+ case Activity.get_by_id_with_object(id) do
+ %Activity{} = activity ->
+ %__MODULE__{draft | quote_post: activity}
+
+ _ ->
+ draft
+ end
+ end
+
+ defp quote_post(draft), do: draft
+
defp in_reply_to_conversation(draft) do
in_reply_to_conversation = Participation.get(draft.params[:in_reply_to_conversation_id])
%__MODULE__{draft | in_reply_to_conversation: in_reply_to_conversation}
@@ -147,6 +166,29 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do
end
end
+ defp can_quote?(_draft, _object, visibility) when visibility in ~w(public unlisted local) do
+ true
+ end
+
+ defp can_quote?(draft, object, "private") do
+ draft.user.ap_id == object.data["actor"]
+ end
+
+ defp can_quote?(_, _, _) do
+ false
+ end
+
+ defp quoting_visibility(%{quote_post: %Activity{}} = draft) do
+ with %Object{} = object <- Object.normalize(draft.quote_post, fetch: false),
+ true <- can_quote?(draft, object, Visibility.get_visibility(object)) do
+ draft
+ else
+ _ -> add_error(draft, dgettext("errors", "Cannot quote private message"))
+ end
+ end
+
+ defp quoting_visibility(draft), do: draft
+
defp expires_at(draft) do
case CommonAPI.check_expiry_date(draft.params[:expires_in]) do
{:ok, expires_at} -> %__MODULE__{draft | expires_at: expires_at}
@@ -164,12 +206,15 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do
end
end
- defp content(draft) do
+ defp content(%{mentions: mentions} = draft) do
{content_html, mentioned_users, tags} = Utils.make_content_html(draft)
+ mentioned_ap_ids =
+ Enum.map(mentioned_users, fn {_, mentioned_user} -> mentioned_user.ap_id end)
+
mentions =
- mentioned_users
- |> Enum.map(fn {_, mentioned_user} -> mentioned_user.ap_id end)
+ mentions
+ |> Kernel.++(mentioned_ap_ids)
|> Utils.get_addressed_users(draft.params[:to])
%__MODULE__{draft | content_html: content_html, mentions: mentions, tags: tags}
diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex
old mode 100755
new mode 100644
index 6410815..52c08f0
--- a/lib/pleroma/web/common_api/utils.ex
+++ b/lib/pleroma/web/common_api/utils.ex
@@ -59,7 +59,8 @@ defmodule Pleroma.Web.CommonAPI.Utils do
end
defp get_attachment(media_id, user) do
- with %Object{data: _data} = object <- Repo.get(Object, media_id),
+ with %Object{data: data} = object <- Repo.get(Object, media_id),
+ %{"type" => type} when type in Pleroma.Constants.upload_object_types() <- data,
:ok <- Object.authorize_access(object, user) do
object
else
@@ -108,7 +109,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
def get_to_and_cc(%{visibility: "direct"} = draft) do
# If the OP is a DM already, add the implicit actor.
- if draft.in_reply_to && Visibility.is_direct?(draft.in_reply_to) do
+ if draft.in_reply_to && Visibility.direct?(draft.in_reply_to) do
{Enum.uniq([draft.in_reply_to.data["actor"] | draft.mentions]), []}
else
{draft.mentions, []}
@@ -150,6 +151,8 @@ defmodule Pleroma.Web.CommonAPI.Utils do
when is_list(options) do
limits = Config.get([:instance, :poll_limits])
+ options = options |> Enum.uniq()
+
with :ok <- validate_poll_expiration(expires_in, limits),
:ok <- validate_poll_options_amount(options, limits),
:ok <- validate_poll_options_length(options, limits) do
@@ -185,10 +188,15 @@ defmodule Pleroma.Web.CommonAPI.Utils do
end
defp validate_poll_options_amount(options, %{max_options: max_options}) do
- if Enum.count(options) > max_options do
- {:error, "Poll can't contain more than #{max_options} options"}
- else
- :ok
+ cond do
+ Enum.count(options) < 2 ->
+ {:error, "Poll must contain at least 2 options"}
+
+ Enum.count(options) > max_options ->
+ {:error, "Poll can't contain more than #{max_options} options"}
+
+ true ->
+ :ok
end
end
@@ -313,13 +321,13 @@ defmodule Pleroma.Web.CommonAPI.Utils do
format_asctime(date)
else
_e ->
- Logger.warn("Date #{date} in wrong format, must be ISO 8601")
+ Logger.warning("Date #{date} in wrong format, must be ISO 8601")
""
end
end
def date_to_asctime(date) do
- Logger.warn("Date #{date} in wrong format, must be ISO 8601")
+ Logger.warning("Date #{date} in wrong format, must be ISO 8601")
""
end
diff --git a/lib/pleroma/web/controller_helper.ex b/lib/pleroma/web/controller_helper.ex
old mode 100755
new mode 100644
index 0c7fc17..1caf0f7
--- a/lib/pleroma/web/controller_helper.ex
+++ b/lib/pleroma/web/controller_helper.ex
@@ -20,7 +20,7 @@ defmodule Pleroma.Web.ControllerHelper do
|> json(json)
end
- @spec fetch_integer_param(map(), String.t(), integer() | nil) :: integer() | nil
+ @spec fetch_integer_param(map(), String.t() | atom(), integer() | nil) :: integer() | nil
def fetch_integer_param(params, name, default \\ nil) do
params
|> Map.get(name, default)
@@ -53,10 +53,15 @@ defmodule Pleroma.Web.ControllerHelper do
end
end
+ # TODO: Only fetch the params from open_api_spex when everything is converted
@id_keys Pagination.page_keys() -- ["limit", "order"]
defp build_pagination_fields(conn, min_id, max_id, extra_params) do
params =
- conn.params
+ if Map.has_key?(conn.private, :open_api_spex) do
+ get_in(conn, [Access.key(:private), Access.key(:open_api_spex), Access.key(:params)])
+ else
+ conn.params
+ end
|> Map.drop(Map.keys(conn.path_params) |> Enum.map(&String.to_existing_atom/1))
|> Map.merge(extra_params)
|> Map.drop(@id_keys)
@@ -85,18 +90,15 @@ defmodule Pleroma.Web.ControllerHelper do
end
end
- def assign_account_by_id(conn, _) do
- case Pleroma.User.get_cached_by_id(conn.params.id) do
+ def assign_account_by_id(%{private: %{open_api_spex: %{params: %{id: id}}}} = conn, _) do
+ case Pleroma.User.get_cached_by_id(id) do
%Pleroma.User{} = account -> assign(conn, :account, account)
nil -> Pleroma.Web.MastodonAPI.FallbackController.call(conn, {:error, :not_found}) |> halt()
end
end
def try_render(conn, target, params) when is_binary(target) do
- case render(conn, target, params) do
- nil -> render_error(conn, :not_implemented, "Can't display this activity")
- res -> res
- end
+ render(conn, target, params)
end
def try_render(conn, _, _) do
diff --git a/lib/pleroma/web/embed_controller.ex b/lib/pleroma/web/embed_controller.ex
old mode 100755
new mode 100644
index 8b9f0a0..2ca4501
--- a/lib/pleroma/web/embed_controller.ex
+++ b/lib/pleroma/web/embed_controller.ex
@@ -11,12 +11,10 @@ defmodule Pleroma.Web.EmbedController do
alias Pleroma.Web.ActivityPub.Visibility
- plug(:put_layout, :embed)
-
def show(conn, %{"id" => id}) do
with %Activity{local: true} = activity <-
Activity.get_by_id_with_object(id),
- true <- Visibility.is_public?(activity.object) do
+ true <- Visibility.public?(activity.object) do
{:ok, author} = User.get_or_fetch(activity.object.data["actor"])
conn
diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex
old mode 100755
new mode 100644
index d8d40cc..2e21049
--- a/lib/pleroma/web/endpoint.ex
+++ b/lib/pleroma/web/endpoint.ex
@@ -9,7 +9,31 @@ defmodule Pleroma.Web.Endpoint do
alias Pleroma.Config
- socket("/socket", Pleroma.Web.UserSocket)
+ socket("/api/v1/streaming", Pleroma.Web.MastodonAPI.WebsocketHandler,
+ longpoll: false,
+ websocket: [
+ path: "/",
+ compress: false,
+ error_handler: {Pleroma.Web.MastodonAPI.WebsocketHandler, :handle_error, []},
+ fullsweep_after: 20
+ ]
+ )
+
+ socket("/socket", Pleroma.Web.UserSocket,
+ websocket: [
+ path: "/websocket",
+ serializer: [
+ {Phoenix.Socket.V1.JSONSerializer, "~> 1.0.0"},
+ {Phoenix.Socket.V2.JSONSerializer, "~> 2.0.0"}
+ ],
+ timeout: 60_000,
+ transport_log: false,
+ compress: false,
+ fullsweep_after: 20
+ ],
+ longpoll: false
+ )
+
socket("/live", Phoenix.LiveView.Socket)
plug(Plug.Telemetry, event_prefix: [:phoenix, :endpoint])
@@ -19,7 +43,8 @@ defmodule Pleroma.Web.Endpoint do
plug(Pleroma.Web.Plugs.HTTPSecurityPlug)
plug(Pleroma.Web.Plugs.UploadedMedia)
- @static_cache_control "public, no-cache"
+ @static_cache_control "public, max-age=1209600"
+ @static_cache_disabled "public, no-cache"
# InstanceStatic needs to be before Plug.Static to be able to override shipped-static files
# If you're adding new paths to `only:` you'll need to configure them in InstanceStatic as well
@@ -30,22 +55,32 @@ defmodule Pleroma.Web.Endpoint do
from: :pleroma,
only: ["emoji", "images"],
gzip: true,
- cache_control_for_etags: "public, max-age=1209600",
+ cache_control_for_etags: @static_cache_control,
headers: %{
- "cache-control" => "public, max-age=1209600"
+ "cache-control" => @static_cache_control
}
)
plug(Pleroma.Web.Plugs.InstanceStatic,
at: "/",
gzip: true,
- cache_control_for_etags: @static_cache_control,
+ cache_control_for_etags: @static_cache_disabled,
headers: %{
- "cache-control" => @static_cache_control
+ "cache-control" => @static_cache_disabled
+ }
+ )
+
+ plug(Pleroma.Web.Plugs.FrontendStatic,
+ at: "/",
+ frontend_type: :primary,
+ only: ["index.html"],
+ gzip: true,
+ cache_control_for_etags: @static_cache_disabled,
+ headers: %{
+ "cache-control" => @static_cache_disabled
}
)
- # Careful! No `only` restriction here, as we don't know what frontends contain.
plug(Pleroma.Web.Plugs.FrontendStatic,
at: "/",
frontend_type: :primary,
@@ -62,9 +97,9 @@ defmodule Pleroma.Web.Endpoint do
at: "/pleroma/admin",
frontend_type: :admin,
gzip: true,
- cache_control_for_etags: @static_cache_control,
+ cache_control_for_etags: @static_cache_disabled,
headers: %{
- "cache-control" => @static_cache_control
+ "cache-control" => @static_cache_disabled
}
)
@@ -79,9 +114,9 @@ defmodule Pleroma.Web.Endpoint do
only: Pleroma.Constants.static_only_files(),
# credo:disable-for-previous-line Credo.Check.Readability.MaxLineLength
gzip: true,
- cache_control_for_etags: @static_cache_control,
+ cache_control_for_etags: @static_cache_disabled,
headers: %{
- "cache-control" => @static_cache_control
+ "cache-control" => @static_cache_disabled
}
)
@@ -101,13 +136,10 @@ defmodule Pleroma.Web.Endpoint do
plug(Plug.Logger, log: :debug)
plug(Plug.Parsers,
- parsers: [
- :urlencoded,
- {:multipart, length: {Config, :get, [[:instance, :upload_limit]]}},
- :json
- ],
+ parsers: [:urlencoded, Pleroma.Web.Multipart, :json],
pass: ["*/*"],
json_decoder: Jason,
+ # Note: this is compile-time only, won't work for database-config
length: Config.get([:instance, :upload_limit]),
body_reader: {Pleroma.Web.Plugs.DigestPlug, :read_body, []}
)
@@ -141,47 +173,6 @@ defmodule Pleroma.Web.Endpoint do
plug(Pleroma.Web.Plugs.RemoteIp)
- defmodule Instrumenter do
- use Prometheus.PhoenixInstrumenter
- end
-
- defmodule PipelineInstrumenter do
- use Prometheus.PlugPipelineInstrumenter
- end
-
- defmodule MetricsExporter do
- use Prometheus.PlugExporter
- end
-
- defmodule MetricsExporterCaller do
- @behaviour Plug
-
- def init(opts), do: opts
-
- def call(conn, opts) do
- prometheus_config = Application.get_env(:prometheus, MetricsExporter, [])
- ip_whitelist = List.wrap(prometheus_config[:ip_whitelist])
-
- cond do
- !prometheus_config[:enabled] ->
- conn
-
- ip_whitelist != [] and
- !Enum.find(ip_whitelist, fn ip ->
- Pleroma.Helpers.InetHelper.parse_address(ip) == {:ok, conn.remote_ip}
- end) ->
- conn
-
- true ->
- MetricsExporter.call(conn, opts)
- end
- end
- end
-
- plug(PipelineInstrumenter)
-
- plug(MetricsExporterCaller)
-
plug(Pleroma.Web.Router)
@doc """
diff --git a/lib/pleroma/web/fallback/legacy_pleroma_api_rerouter_plug.ex b/lib/pleroma/web/fallback/legacy_pleroma_api_rerouter_plug.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/fallback/redirect_controller.ex b/lib/pleroma/web/fallback/redirect_controller.ex
old mode 100755
new mode 100644
index 1a86f7a..4a0885f
--- a/lib/pleroma/web/fallback/redirect_controller.ex
+++ b/lib/pleroma/web/fallback/redirect_controller.ex
@@ -17,10 +17,28 @@ defmodule Pleroma.Web.Fallback.RedirectController do
|> json(%{error: "Not implemented"})
end
+ def add_generated_metadata(page_content, extra \\ "") do
+ title = "#{Pleroma.Config.get([:instance, :name])}"
+ favicon = ""
+ manifest = ""
+
+ page_content
+ |> String.replace(
+ "",
+ title <> favicon <> manifest <> extra
+ )
+ end
+
def redirector(conn, _params, code \\ 200) do
+ {:ok, index_content} = File.read(index_file_path())
+
+ response =
+ index_content
+ |> add_generated_metadata()
+
conn
|> put_resp_content_type("text/html")
- |> send_file(code, index_file_path())
+ |> send_resp(code, response)
end
def redirector_with_meta(conn, %{"maybe_nickname_or_id" => maybe_nickname_or_id} = params) do
@@ -34,14 +52,12 @@ defmodule Pleroma.Web.Fallback.RedirectController do
def redirector_with_meta(conn, params) do
{:ok, index_content} = File.read(index_file_path())
-
tags = build_tags(conn, params)
preloads = preload_data(conn, params)
- title = "#{Pleroma.Config.get([:instance, :name])}"
response =
index_content
- |> String.replace("", tags <> preloads <> title)
+ |> add_generated_metadata(tags <> preloads)
conn
|> put_resp_content_type("text/html")
@@ -55,11 +71,10 @@ defmodule Pleroma.Web.Fallback.RedirectController do
def redirector_with_preload(conn, params) do
{:ok, index_content} = File.read(index_file_path())
preloads = preload_data(conn, params)
- title = "#{Pleroma.Config.get([:instance, :name])}"
response =
index_content
- |> String.replace("", preloads <> title)
+ |> add_generated_metadata(preloads)
conn
|> put_resp_content_type("text/html")
diff --git a/lib/pleroma/web/federator.ex b/lib/pleroma/web/federator.ex
old mode 100755
new mode 100644
index 318b6cb..1f2c383
--- a/lib/pleroma/web/federator.ex
+++ b/lib/pleroma/web/federator.ex
@@ -6,10 +6,9 @@ defmodule Pleroma.Web.Federator do
alias Pleroma.Activity
alias Pleroma.Object.Containment
alias Pleroma.User
- alias Pleroma.Web.ActivityPub.ActivityPub
+ alias Pleroma.Web.ActivityPub.Publisher
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.ActivityPub.Utils
- alias Pleroma.Web.Federator.Publisher
alias Pleroma.Workers.PublisherWorker
alias Pleroma.Workers.ReceiverWorker
@@ -36,6 +35,17 @@ defmodule Pleroma.Web.Federator do
end
# Client API
+ def incoming_ap_doc(%{params: params, req_headers: req_headers}) do
+ ReceiverWorker.enqueue(
+ "incoming_ap_doc",
+ %{"req_headers" => req_headers, "params" => params, "timeout" => :timer.seconds(20)},
+ priority: 2
+ )
+ end
+
+ def incoming_ap_doc(%{"type" => "Delete"} = params) do
+ ReceiverWorker.enqueue("incoming_ap_doc", %{"params" => params}, priority: 3)
+ end
def incoming_ap_doc(params) do
ReceiverWorker.enqueue("incoming_ap_doc", %{"params" => params})
@@ -58,10 +68,8 @@ defmodule Pleroma.Web.Federator do
# Job Worker Callbacks
- @spec perform(atom(), module(), any()) :: {:ok, any()} | {:error, any()}
- def perform(:publish_one, module, params) do
- apply(module, :publish_one, [params])
- end
+ @spec perform(atom(), any()) :: {:ok, any()} | {:error, any()}
+ def perform(:publish_one, params), do: Publisher.publish_one(params)
def perform(:publish, activity) do
Logger.debug(fn -> "Running publish for #{activity.data["id"]}" end)
@@ -80,7 +88,7 @@ defmodule Pleroma.Web.Federator do
# NOTE: we use the actor ID to do the containment, this is fine because an
# actor shouldn't be acting on objects outside their own AP server.
- with {_, {:ok, _user}} <- {:actor, ap_enabled_actor(actor)},
+ with {_, {:ok, _user}} <- {:actor, User.get_or_fetch_by_ap_id(actor)},
nil <- Activity.normalize(params["id"]),
{_, :ok} <-
{:correct_origin?, Containment.contain_origin_from_id(actor, params)},
@@ -110,14 +118,4 @@ defmodule Pleroma.Web.Federator do
{:error, e}
end
end
-
- def ap_enabled_actor(id) do
- user = User.get_cached_by_ap_id(id)
-
- if User.ap_enabled?(user) do
- {:ok, user}
- else
- ActivityPub.make_user_from_ap_id(id)
- end
- end
end
diff --git a/lib/pleroma/web/federator/publisher.ex b/lib/pleroma/web/federator/publisher.ex
deleted file mode 100755
index a45796e..0000000
--- a/lib/pleroma/web/federator/publisher.ex
+++ /dev/null
@@ -1,109 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2022 Pleroma Authors
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.Federator.Publisher do
- alias Pleroma.Activity
- alias Pleroma.Config
- alias Pleroma.User
- alias Pleroma.Workers.PublisherWorker
-
- require Logger
-
- @moduledoc """
- Defines the contract used by federation implementations to publish messages to
- their peers.
- """
-
- @doc """
- Determine whether an activity can be relayed using the federation module.
- """
- @callback is_representable?(Pleroma.Activity.t()) :: boolean()
-
- @doc """
- Relays an activity to a specified peer, determined by the parameters. The
- parameters used are controlled by the federation module.
- """
- @callback publish_one(Map.t()) :: {:ok, Map.t()} | {:error, any()}
-
- @doc """
- Enqueue publishing a single activity.
- """
- @spec enqueue_one(module(), Map.t()) :: :ok
- def enqueue_one(module, %{} = params) do
- PublisherWorker.enqueue(
- "publish_one",
- %{"module" => to_string(module), "params" => params}
- )
- end
-
- @doc """
- Relays an activity to all specified peers.
- """
- @callback publish(User.t(), Activity.t()) :: :ok | {:error, any()}
-
- @spec publish(User.t(), Activity.t()) :: :ok
- def publish(%User{} = user, %Activity{} = activity) do
- Config.get([:instance, :federation_publisher_modules])
- |> Enum.each(fn module ->
- if module.is_representable?(activity) do
- Logger.debug("Publishing #{activity.data["id"]} using #{inspect(module)}")
- module.publish(user, activity)
- end
- end)
-
- :ok
- end
-
- @doc """
- Gathers links used by an outgoing federation module for WebFinger output.
- """
- @callback gather_webfinger_links(User.t()) :: list()
-
- @spec gather_webfinger_links(User.t()) :: list()
- def gather_webfinger_links(%User{} = user) do
- Config.get([:instance, :federation_publisher_modules])
- |> Enum.reduce([], fn module, links ->
- links ++ module.gather_webfinger_links(user)
- end)
- end
-
- @doc """
- Gathers nodeinfo protocol names supported by the federation module.
- """
- @callback gather_nodeinfo_protocol_names() :: list()
-
- @spec gather_nodeinfo_protocol_names() :: list()
- def gather_nodeinfo_protocol_names do
- Config.get([:instance, :federation_publisher_modules])
- |> Enum.reduce([], fn module, links ->
- links ++ module.gather_nodeinfo_protocol_names()
- end)
- end
-
- @doc """
- Gathers a set of remote users given an IR envelope.
- """
- def remote_users(%User{id: user_id}, %{data: %{"to" => to} = data}) do
- cc = Map.get(data, "cc", [])
-
- bcc =
- data
- |> Map.get("bcc", [])
- |> Enum.reduce([], fn ap_id, bcc ->
- case Pleroma.List.get_by_ap_id(ap_id) do
- %Pleroma.List{user_id: ^user_id} = list ->
- {:ok, following} = Pleroma.List.get_following(list)
- bcc ++ Enum.map(following, & &1.ap_id)
-
- _ ->
- bcc
- end
- end)
-
- [to, cc, bcc]
- |> Enum.concat()
- |> Enum.map(&User.get_cached_by_ap_id/1)
- |> Enum.filter(fn user -> user && !user.local end)
- end
-end
diff --git a/lib/pleroma/web/federator/publishing.ex b/lib/pleroma/web/federator/publishing.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/feed/feed_view.ex b/lib/pleroma/web/feed/feed_view.ex
old mode 100755
new mode 100644
index 034722e..e1ee33d
--- a/lib/pleroma/web/feed/feed_view.ex
+++ b/lib/pleroma/web/feed/feed_view.ex
@@ -132,7 +132,7 @@ defmodule Pleroma.Web.Feed.FeedView do
|> safe_to_string()
end
- @spec to_rfc3339(String.t() | NativeDateTime.t()) :: String.t()
+ @spec to_rfc3339(String.t() | NaiveDateTime.t()) :: String.t()
def to_rfc3339(date) when is_binary(date) do
date
|> Timex.parse!("{ISO:Extended}")
@@ -145,7 +145,7 @@ defmodule Pleroma.Web.Feed.FeedView do
|> Timex.format!("{RFC3339}")
end
- @spec to_rfc2822(String.t() | DateTime.t() | NativeDateTime.t()) :: String.t()
+ @spec to_rfc2822(String.t() | DateTime.t() | NaiveDateTime.t()) :: String.t()
def to_rfc2822(datestr) when is_binary(datestr) do
datestr
|> Timex.parse!("{ISO:Extended}")
diff --git a/lib/pleroma/web/feed/tag_controller.ex b/lib/pleroma/web/feed/tag_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/feed/user_controller.ex b/lib/pleroma/web/feed/user_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/gettext.ex b/lib/pleroma/web/gettext.ex
old mode 100755
new mode 100644
index 5ef49d8..1fa3f97
--- a/lib/pleroma/web/gettext.ex
+++ b/lib/pleroma/web/gettext.ex
@@ -85,12 +85,12 @@ defmodule Pleroma.Web.Gettext do
Process.get({Pleroma.Web.Gettext, :locales}, [])
end
- def is_locale_list(locales) do
+ def locale_list?(locales) do
Enum.all?(locales, &is_binary/1)
end
def put_locales(locales) do
- if is_locale_list(locales) do
+ if locale_list?(locales) do
Process.put({Pleroma.Web.Gettext, :locales}, Enum.uniq(locales))
Gettext.put_locale(Enum.at(locales, 0, Gettext.get_locale()))
:ok
diff --git a/lib/pleroma/web/instance_document.ex b/lib/pleroma/web/instance_document.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mailer/subscription_controller.ex b/lib/pleroma/web/mailer/subscription_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/manifest_controller.ex b/lib/pleroma/web/manifest_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
old mode 100755
new mode 100644
index ea6e593..9226a2d
--- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
@@ -30,7 +30,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
alias Pleroma.Web.TwitterAPI.TwitterAPI
alias Pleroma.Web.Utils.Params
- plug(Pleroma.Web.ApiSpec.CastAndValidate)
+ plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
plug(:skip_auth when action in [:create, :lookup])
@@ -92,7 +92,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
plug(
RateLimiter,
- [name: :relation_id_action, params: [:id, :uri]] when action in @relationship_actions
+ [name: :relation_id_action, params: ["id", "uri"]] when action in @relationship_actions
)
plug(RateLimiter, [name: :relations_actions] when action in @relationship_actions)
@@ -104,7 +104,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.AccountOperation
@doc "POST /api/v1/accounts"
- def create(%{assigns: %{app: app}, body_params: params} = conn, _params) do
+ def create(
+ %{assigns: %{app: app}, private: %{open_api_spex: %{body_params: params}}} = conn,
+ _params
+ ) do
with :ok <- validate_email_param(params),
:ok <- TwitterAPI.validate_captcha(app, params),
{:ok, user} <- TwitterAPI.register_user(params),
@@ -168,7 +171,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
end
@doc "PATCH /api/v1/accounts/update_credentials"
- def update_credentials(%{assigns: %{user: user}, body_params: params} = conn, _params) do
+ def update_credentials(
+ %{assigns: %{user: user}, private: %{open_api_spex: %{body_params: params}}} = conn,
+ _params
+ ) do
params =
params
|> Enum.filter(fn {_, value} -> not is_nil(value) end)
@@ -235,7 +241,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
# So we first build the normal local changeset, then apply it to the
# user data, but don't persist it. With this, we generate the object
# data for our update activity. We feed this and the changeset as meta
- # inforation into the pipeline, where they will be properly updated and
+ # information into the pipeline, where they will be properly updated and
# federated.
with changeset <- User.update_changeset(user, user_params),
{:ok, unpersisted_user} <- Ecto.Changeset.apply_action(changeset, :update),
@@ -263,24 +269,36 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
{:error, %Ecto.Changeset{errors: [background: {"file is too large", _}]}} ->
render_error(conn, :request_entity_too_large, "File is too large")
+ {:error, %Ecto.Changeset{errors: [{:bio, {_, _}} | _]}} ->
+ render_error(conn, :request_entity_too_large, "Bio is too long")
+
+ {:error, %Ecto.Changeset{errors: [{:name, {_, _}} | _]}} ->
+ render_error(conn, :request_entity_too_large, "Name is too long")
+
+ {:error, %Ecto.Changeset{errors: [{:fields, {"invalid", _}} | _]}} ->
+ render_error(conn, :request_entity_too_large, "One or more field entries are too long")
+
+ {:error, %Ecto.Changeset{errors: [{:fields, {_, _}} | _]}} ->
+ render_error(conn, :request_entity_too_large, "Too many field entries")
+
_e ->
render_error(conn, :forbidden, "Invalid request")
end
end
defp normalize_fields_attributes(fields) do
- if Enum.all?(fields, &is_tuple/1) do
- Enum.map(fields, fn {_, v} -> v end)
- else
- Enum.map(fields, fn
- %{} = field -> %{"name" => field.name, "value" => field.value}
- field -> field
- end)
- end
+ if(Enum.all?(fields, &is_tuple/1), do: Enum.map(fields, fn {_, v} -> v end), else: fields)
+ |> Enum.map(fn
+ %{} = field -> %{"name" => field.name, "value" => field.value}
+ field -> field
+ end)
end
@doc "GET /api/v1/accounts/relationships"
- def relationships(%{assigns: %{user: user}} = conn, %{id: id}) do
+ def relationships(
+ %{assigns: %{user: user}, private: %{open_api_spex: %{params: %{id: id}}}} = conn,
+ _
+ ) do
targets = User.get_all_by_ids(List.wrap(id))
render(conn, "relationships.json", user: user, targets: targets)
@@ -290,7 +308,13 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
def relationships(%{assigns: %{user: _user}} = conn, _), do: json(conn, [])
@doc "GET /api/v1/accounts/:id"
- def show(%{assigns: %{user: for_user}} = conn, %{id: nickname_or_id} = params) do
+ def show(
+ %{
+ assigns: %{user: for_user},
+ private: %{open_api_spex: %{params: %{id: nickname_or_id} = params}}
+ } = conn,
+ _params
+ ) do
with %User{} = user <- User.get_cached_by_nickname_or_id(nickname_or_id, for: for_user),
:visible <- User.visible_for(user, for_user) do
render(conn, "show.json",
@@ -304,7 +328,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
end
@doc "GET /api/v1/accounts/:id/statuses"
- def statuses(%{assigns: %{user: reading_user}} = conn, params) do
+ def statuses(
+ %{assigns: %{user: reading_user}, private: %{open_api_spex: %{params: params}}} = conn,
+ _params
+ ) do
with %User{} = user <- User.get_cached_by_nickname_or_id(params.id, for: reading_user),
:visible <- User.visible_for(user, reading_user) do
params =
@@ -339,7 +366,11 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
end
@doc "GET /api/v1/accounts/:id/followers"
- def followers(%{assigns: %{user: for_user, account: user}} = conn, params) do
+ def followers(
+ %{assigns: %{user: for_user, account: user}, private: %{open_api_spex: %{params: params}}} =
+ conn,
+ _params
+ ) do
params =
params
|> Enum.map(fn {key, value} -> {to_string(key), value} end)
@@ -364,7 +395,11 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
end
@doc "GET /api/v1/accounts/:id/following"
- def following(%{assigns: %{user: for_user, account: user}} = conn, params) do
+ def following(
+ %{assigns: %{user: for_user, account: user}, private: %{open_api_spex: %{params: params}}} =
+ conn,
+ _params
+ ) do
params =
params
|> Enum.map(fn {key, value} -> {to_string(key), value} end)
@@ -402,7 +437,13 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
{:error, "Can not follow yourself"}
end
- def follow(%{body_params: params, assigns: %{user: follower, account: followed}} = conn, _) do
+ def follow(
+ %{
+ assigns: %{user: follower, account: followed},
+ private: %{open_api_spex: %{body_params: params}}
+ } = conn,
+ _
+ ) do
with {:ok, follower} <- MastodonAPI.follow(follower, followed, params) do
render(conn, "relationship.json", user: follower, target: followed)
else
@@ -422,7 +463,13 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
end
@doc "POST /api/v1/accounts/:id/mute"
- def mute(%{assigns: %{user: muter, account: muted}, body_params: params} = conn, _params) do
+ def mute(
+ %{
+ assigns: %{user: muter, account: muted},
+ private: %{open_api_spex: %{body_params: params}}
+ } = conn,
+ _params
+ ) do
params =
params
|> Map.put_new(:duration, Map.get(params, :expires_in, 0))
@@ -463,7 +510,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
@doc "POST /api/v1/accounts/:id/note"
def note(
- %{assigns: %{user: noter, account: target}, body_params: %{comment: comment}} = conn,
+ %{
+ assigns: %{user: noter, account: target},
+ private: %{open_api_spex: %{body_params: %{comment: comment}}}
+ } = conn,
_params
) do
with {:ok, _user_note} <- UserNote.create(noter, target, comment) do
@@ -504,7 +554,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
end
@doc "POST /api/v1/follows"
- def follow_by_uri(%{body_params: %{uri: uri}} = conn, _) do
+ def follow_by_uri(%{private: %{open_api_spex: %{body_params: %{uri: uri}}}} = conn, _) do
case User.get_cached_by_nickname(uri) do
%User{} = user ->
conn
@@ -543,11 +593,16 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
conn
|> add_link_headers(users)
- |> render("index.json", users: users, for: user, as: :user)
+ |> render("index.json",
+ users: users,
+ for: user,
+ as: :user,
+ embed_relationships: embed_relationships?(params)
+ )
end
@doc "GET /api/v1/accounts/lookup"
- def lookup(conn, %{acct: nickname} = _params) do
+ def lookup(%{private: %{open_api_spex: %{params: %{acct: nickname}}}} = conn, _params) do
with %User{} = user <- User.get_by_nickname(nickname) do
render(conn, "show.json",
user: user,
diff --git a/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex b/lib/pleroma/web/mastodon_api/controllers/announcement_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/controllers/app_controller.ex b/lib/pleroma/web/mastodon_api/controllers/app_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex b/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/controllers/conversation_controller.ex b/lib/pleroma/web/mastodon_api/controllers/conversation_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/controllers/custom_emoji_controller.ex b/lib/pleroma/web/mastodon_api/controllers/custom_emoji_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/controllers/directory_controller.ex b/lib/pleroma/web/mastodon_api/controllers/directory_controller.ex
old mode 100755
new mode 100644
index 253f06c..f894259
--- a/lib/pleroma/web/mastodon_api/controllers/directory_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/directory_controller.ex
@@ -15,7 +15,7 @@ defmodule Pleroma.Web.MastodonAPI.DirectoryController do
plug(Pleroma.Web.ApiSpec.CastAndValidate)
- plug(:skip_auth when action == "index")
+ plug(:skip_auth when action == :index)
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.DirectoryOperation
diff --git a/lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex b/lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex
old mode 100755
new mode 100644
index b2e347e..4615794
--- a/lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex
@@ -8,7 +8,7 @@ defmodule Pleroma.Web.MastodonAPI.DomainBlockController do
alias Pleroma.User
alias Pleroma.Web.Plugs.OAuthScopesPlug
- plug(Pleroma.Web.ApiSpec.CastAndValidate)
+ plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.DomainBlockOperation
plug(
@@ -27,23 +27,31 @@ defmodule Pleroma.Web.MastodonAPI.DomainBlockController do
end
@doc "POST /api/v1/domain_blocks"
- def create(%{assigns: %{user: blocker}, body_params: %{domain: domain}} = conn, _params) do
+ def create(
+ %{assigns: %{user: blocker}, private: %{open_api_spex: %{body_params: %{domain: domain}}}} =
+ conn,
+ _params
+ ) do
User.block_domain(blocker, domain)
json(conn, %{})
end
- def create(%{assigns: %{user: blocker}} = conn, %{domain: domain}) do
+ def create(%{assigns: %{user: blocker}} = conn, %{"domain" => domain}) do
User.block_domain(blocker, domain)
json(conn, %{})
end
@doc "DELETE /api/v1/domain_blocks"
- def delete(%{assigns: %{user: blocker}, body_params: %{domain: domain}} = conn, _params) do
+ def delete(
+ %{assigns: %{user: blocker}, private: %{open_api_spex: %{body_params: %{domain: domain}}}} =
+ conn,
+ _params
+ ) do
User.unblock_domain(blocker, domain)
json(conn, %{})
end
- def delete(%{assigns: %{user: blocker}} = conn, %{domain: domain}) do
+ def delete(%{assigns: %{user: blocker}} = conn, %{"domain" => domain}) do
User.unblock_domain(blocker, domain)
json(conn, %{})
end
diff --git a/lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex b/lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/controllers/filter_controller.ex b/lib/pleroma/web/mastodon_api/controllers/filter_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex b/lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex
old mode 100755
new mode 100644
index ba6d074..6eee55d
--- a/lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex
@@ -9,7 +9,7 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestController do
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.Plugs.OAuthScopesPlug
- plug(Pleroma.Web.ApiSpec.CastAndValidate)
+ plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
plug(:assign_follower when action != :index)
action_fallback(:errors)
@@ -44,7 +44,7 @@ defmodule Pleroma.Web.MastodonAPI.FollowRequestController do
end
end
- defp assign_follower(%{params: %{id: id}} = conn, _) do
+ defp assign_follower(%{private: %{open_api_spex: %{params: %{id: id}}}} = conn, _) do
case User.get_cached_by_id(id) do
%User{} = follower -> assign(conn, :follower, follower)
nil -> Pleroma.Web.MastodonAPI.FallbackController.call(conn, {:error, :not_found}) |> halt()
diff --git a/lib/pleroma/web/mastodon_api/controllers/instance_controller.ex b/lib/pleroma/web/mastodon_api/controllers/instance_controller.ex
old mode 100755
new mode 100644
index 6410e87..3e66490
--- a/lib/pleroma/web/mastodon_api/controllers/instance_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/instance_controller.ex
@@ -7,7 +7,7 @@ defmodule Pleroma.Web.MastodonAPI.InstanceController do
plug(Pleroma.Web.ApiSpec.CastAndValidate)
- plug(:skip_auth when action in [:show, :peers])
+ plug(:skip_auth when action in [:show, :show2, :peers])
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.InstanceOperation
@@ -16,6 +16,11 @@ defmodule Pleroma.Web.MastodonAPI.InstanceController do
render(conn, "show.json")
end
+ @doc "GET /api/v2/instance"
+ def show2(conn, _params) do
+ render(conn, "show2.json")
+ end
+
@doc "GET /api/v1/instance/peers"
def peers(conn, _params) do
json(conn, Pleroma.Stats.get_peers())
diff --git a/lib/pleroma/web/mastodon_api/controllers/list_controller.ex b/lib/pleroma/web/mastodon_api/controllers/list_controller.ex
old mode 100755
new mode 100644
index 2117aae..3bfc365
--- a/lib/pleroma/web/mastodon_api/controllers/list_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/list_controller.ex
@@ -11,7 +11,7 @@ defmodule Pleroma.Web.MastodonAPI.ListController do
@oauth_read_actions [:index, :show, :list_accounts]
- plug(Pleroma.Web.ApiSpec.CastAndValidate)
+ plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
plug(:list_by_id_and_user when action not in [:index, :create])
plug(OAuthScopesPlug, %{scopes: ["read:lists"]} when action in @oauth_read_actions)
plug(OAuthScopesPlug, %{scopes: ["write:lists"]} when action not in @oauth_read_actions)
@@ -21,25 +21,33 @@ defmodule Pleroma.Web.MastodonAPI.ListController do
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.ListOperation
# GET /api/v1/lists
- def index(%{assigns: %{user: user}} = conn, opts) do
- lists = Pleroma.List.for_user(user, opts)
+ def index(%{assigns: %{user: user}, private: %{open_api_spex: %{params: params}}} = conn, _) do
+ lists = Pleroma.List.for_user(user, params)
render(conn, "index.json", lists: lists)
end
# POST /api/v1/lists
- def create(%{assigns: %{user: user}, body_params: %{title: title}} = conn, _) do
+ def create(
+ %{assigns: %{user: user}, private: %{open_api_spex: %{body_params: %{title: title}}}} =
+ conn,
+ _
+ ) do
with {:ok, %Pleroma.List{} = list} <- Pleroma.List.create(title, user) do
render(conn, "show.json", list: list)
end
end
- # GET /api/v1/lists/:id
+ # GET /api/v1/lists/:idOB
def show(%{assigns: %{list: list}} = conn, _) do
render(conn, "show.json", list: list)
end
# PUT /api/v1/lists/:id
- def update(%{assigns: %{list: list}, body_params: %{title: title}} = conn, _) do
+ def update(
+ %{assigns: %{list: list}, private: %{open_api_spex: %{body_params: %{title: title}}}} =
+ conn,
+ _
+ ) do
with {:ok, list} <- Pleroma.List.rename(list, title) do
render(conn, "show.json", list: list)
end
@@ -62,7 +70,13 @@ defmodule Pleroma.Web.MastodonAPI.ListController do
end
# POST /api/v1/lists/:id/accounts
- def add_to_list(%{assigns: %{list: list}, body_params: %{account_ids: account_ids}} = conn, _) do
+ def add_to_list(
+ %{
+ assigns: %{list: list},
+ private: %{open_api_spex: %{body_params: %{account_ids: account_ids}}}
+ } = conn,
+ _
+ ) do
Enum.each(account_ids, fn account_id ->
with %User{} = followed <- User.get_cached_by_id(account_id) do
Pleroma.List.follow(list, followed)
@@ -74,9 +88,22 @@ defmodule Pleroma.Web.MastodonAPI.ListController do
# DELETE /api/v1/lists/:id/accounts
def remove_from_list(
- %{assigns: %{list: list}, params: %{account_ids: account_ids}} = conn,
+ %{
+ private: %{open_api_spex: %{params: %{account_ids: account_ids}}}
+ } = conn,
_
) do
+ do_remove_from_list(conn, account_ids)
+ end
+
+ def remove_from_list(
+ %{private: %{open_api_spex: %{body_params: %{account_ids: account_ids}}}} = conn,
+ _
+ ) do
+ do_remove_from_list(conn, account_ids)
+ end
+
+ defp do_remove_from_list(%{assigns: %{list: list}} = conn, account_ids) do
Enum.each(account_ids, fn account_id ->
with %User{} = followed <- User.get_cached_by_id(account_id) do
Pleroma.List.unfollow(list, followed)
@@ -86,11 +113,10 @@ defmodule Pleroma.Web.MastodonAPI.ListController do
json(conn, %{})
end
- def remove_from_list(%{body_params: params} = conn, _) do
- remove_from_list(%{conn | params: params}, %{})
- end
-
- defp list_by_id_and_user(%{assigns: %{user: user}, params: %{id: id}} = conn, _) do
+ defp list_by_id_and_user(
+ %{assigns: %{user: user}, private: %{open_api_spex: %{params: %{id: id}}}} = conn,
+ _
+ ) do
case Pleroma.List.get(id, user) do
%Pleroma.List{} = list -> assign(conn, :list, list)
nil -> conn |> render_error(:not_found, "List not found") |> halt()
diff --git a/lib/pleroma/web/mastodon_api/controllers/marker_controller.ex b/lib/pleroma/web/mastodon_api/controllers/marker_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/controllers/media_controller.ex b/lib/pleroma/web/mastodon_api/controllers/media_controller.ex
old mode 100755
new mode 100644
index 7d9a63c..056bad8
--- a/lib/pleroma/web/mastodon_api/controllers/media_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/media_controller.ex
@@ -12,7 +12,7 @@ defmodule Pleroma.Web.MastodonAPI.MediaController do
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
plug(Majic.Plug, [pool: Pleroma.MajicPool] when action in [:create, :create2])
- plug(Pleroma.Web.ApiSpec.CastAndValidate)
+ plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
plug(OAuthScopesPlug, %{scopes: ["read:media"]} when action == :show)
plug(OAuthScopesPlug, %{scopes: ["write:media"]} when action != :show)
@@ -20,7 +20,11 @@ defmodule Pleroma.Web.MastodonAPI.MediaController do
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.MediaOperation
@doc "POST /api/v1/media"
- def create(%{assigns: %{user: user}, body_params: %{file: file} = data} = conn, _) do
+ def create(
+ %{assigns: %{user: user}, private: %{open_api_spex: %{body_params: %{file: file} = data}}} =
+ conn,
+ _
+ ) do
with {:ok, object} <-
ActivityPub.upload(
file,
@@ -36,7 +40,11 @@ defmodule Pleroma.Web.MastodonAPI.MediaController do
def create(_conn, _data), do: {:error, :bad_request}
@doc "POST /api/v2/media"
- def create2(%{assigns: %{user: user}, body_params: %{file: file} = data} = conn, _) do
+ def create2(
+ %{assigns: %{user: user}, private: %{open_api_spex: %{body_params: %{file: file} = data}}} =
+ conn,
+ _
+ ) do
with {:ok, object} <-
ActivityPub.upload(
file,
@@ -54,7 +62,15 @@ defmodule Pleroma.Web.MastodonAPI.MediaController do
def create2(_conn, _data), do: {:error, :bad_request}
@doc "PUT /api/v1/media/:id"
- def update(%{assigns: %{user: user}, body_params: %{description: description}} = conn, %{id: id}) do
+ def update(
+ %{
+ assigns: %{user: user},
+ private: %{
+ open_api_spex: %{body_params: %{description: description}, params: %{id: id}}
+ }
+ } = conn,
+ _
+ ) do
with %Object{} = object <- Object.get_by_id(id),
:ok <- Object.authorize_access(object, user),
{:ok, %Object{data: data}} <- Object.update_data(object, %{"name" => description}) do
@@ -67,7 +83,7 @@ defmodule Pleroma.Web.MastodonAPI.MediaController do
def update(conn, data), do: show(conn, data)
@doc "GET /api/v1/media/:id"
- def show(%{assigns: %{user: user}} = conn, %{id: id}) do
+ def show(%{assigns: %{user: user}, private: %{open_api_spex: %{params: %{id: id}}}} = conn, _) do
with %Object{data: data, id: object_id} = object <- Object.get_by_id(id),
:ok <- Object.authorize_access(object, user) do
attachment_data = Map.put(data, "id", object_id)
diff --git a/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex b/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex
old mode 100755
new mode 100644
index a490e83..e305aea
--- a/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex
@@ -13,7 +13,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationController do
@oauth_read_actions [:show, :index]
- plug(Pleroma.Web.ApiSpec.CastAndValidate)
+ plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
plug(
OAuthScopesPlug,
@@ -24,8 +24,20 @@ defmodule Pleroma.Web.MastodonAPI.NotificationController do
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.NotificationOperation
+ @default_notification_types ~w{
+ mention
+ follow
+ follow_request
+ reblog
+ favourite
+ move
+ pleroma:emoji_reaction
+ poll
+ update
+ }
+
# GET /api/v1/notifications
- def index(conn, %{account_id: account_id} = params) do
+ def index(%{private: %{open_api_spex: %{params: %{account_id: account_id} = params}}} = conn, _) do
case Pleroma.User.get_cached_by_id(account_id) do
%{ap_id: account_ap_id} ->
params =
@@ -33,7 +45,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationController do
|> Map.delete(:account_id)
|> Map.put(:account_ap_id, account_ap_id)
- index(conn, params)
+ do_get_notifications(conn, params)
_ ->
conn
@@ -42,18 +54,11 @@ defmodule Pleroma.Web.MastodonAPI.NotificationController do
end
end
- @default_notification_types ~w{
- mention
- follow
- follow_request
- reblog
- favourite
- move
- pleroma:emoji_reaction
- poll
- update
- }
- def index(%{assigns: %{user: user}} = conn, params) do
+ def index(%{private: %{open_api_spex: %{params: params}}} = conn, _) do
+ do_get_notifications(conn, params)
+ end
+
+ defp do_get_notifications(%{assigns: %{user: user}} = conn, params) do
params =
Map.new(params, fn {k, v} -> {to_string(k), v} end)
|> Map.put_new("types", Map.get(params, :include_types, @default_notification_types))
@@ -69,7 +74,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationController do
end
# GET /api/v1/notifications/:id
- def show(%{assigns: %{user: user}} = conn, %{id: id}) do
+ def show(%{assigns: %{user: user}, private: %{open_api_spex: %{params: %{id: id}}}} = conn, _) do
with {:ok, notification} <- Notification.get(user, id) do
render(conn, "show.json", notification: notification, for: user)
else
@@ -88,8 +93,20 @@ defmodule Pleroma.Web.MastodonAPI.NotificationController do
# POST /api/v1/notifications/:id/dismiss
- def dismiss(%{assigns: %{user: user}} = conn, %{id: id} = _params) do
- with {:ok, _notif} <- Notification.dismiss(user, id) do
+ def dismiss(%{private: %{open_api_spex: %{params: %{id: id}}}} = conn, _) do
+ do_dismiss(conn, id)
+ end
+
+ # POST /api/v1/notifications/dismiss (deprecated)
+ def dismiss_via_body(
+ %{private: %{open_api_spex: %{body_params: %{id: id}}}} = conn,
+ _
+ ) do
+ do_dismiss(conn, id)
+ end
+
+ defp do_dismiss(%{assigns: %{user: user}} = conn, notification_id) do
+ with {:ok, _notif} <- Notification.dismiss(user, notification_id) do
json(conn, %{})
else
{:error, reason} ->
@@ -99,13 +116,11 @@ defmodule Pleroma.Web.MastodonAPI.NotificationController do
end
end
- # POST /api/v1/notifications/dismiss (deprecated)
- def dismiss_via_body(%{body_params: params} = conn, _) do
- dismiss(conn, params)
- end
-
# DELETE /api/v1/notifications/destroy_multiple
- def destroy_multiple(%{assigns: %{user: user}} = conn, %{ids: ids} = _params) do
+ def destroy_multiple(
+ %{assigns: %{user: user}, private: %{open_api_spex: %{params: %{ids: ids}}}} = conn,
+ _
+ ) do
Notification.destroy_multiple(user, ids)
json(conn, %{})
end
diff --git a/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex b/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex
old mode 100755
new mode 100644
index 002c210..b074ee4
--- a/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex
@@ -15,7 +15,7 @@ defmodule Pleroma.Web.MastodonAPI.PollController do
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
- plug(Pleroma.Web.ApiSpec.CastAndValidate)
+ plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
plug(
OAuthScopesPlug,
@@ -29,7 +29,7 @@ defmodule Pleroma.Web.MastodonAPI.PollController do
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
@doc "GET /api/v1/polls/:id"
- def show(%{assigns: %{user: user}} = conn, %{id: id}) do
+ def show(%{assigns: %{user: user}, private: %{open_api_spex: %{params: %{id: id}}}} = conn, _) do
with %Object{} = object <- Object.get_by_id_and_maybe_refetch(id, interval: 60),
%Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]),
true <- Visibility.visible_for_user?(activity, user) do
@@ -41,7 +41,13 @@ defmodule Pleroma.Web.MastodonAPI.PollController do
end
@doc "POST /api/v1/polls/:id/votes"
- def vote(%{assigns: %{user: user}, body_params: %{choices: choices}} = conn, %{id: id}) do
+ def vote(
+ %{
+ assigns: %{user: user},
+ private: %{open_api_spex: %{body_params: %{choices: choices}, params: %{id: id}}}
+ } = conn,
+ _
+ ) do
with %Object{data: %{"type" => "Question"}} = object <- Object.get_by_id(id),
%Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]),
true <- Visibility.visible_for_user?(activity, user),
diff --git a/lib/pleroma/web/mastodon_api/controllers/report_controller.ex b/lib/pleroma/web/mastodon_api/controllers/report_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/controllers/scheduled_activity_controller.ex b/lib/pleroma/web/mastodon_api/controllers/scheduled_activity_controller.ex
old mode 100755
new mode 100644
index 0392fce..1b7095e
--- a/lib/pleroma/web/mastodon_api/controllers/scheduled_activity_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/scheduled_activity_controller.ex
@@ -13,7 +13,7 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityController do
@oauth_read_actions [:show, :index]
- plug(Pleroma.Web.ApiSpec.CastAndValidate)
+ plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
plug(OAuthScopesPlug, %{scopes: ["read:statuses"]} when action in @oauth_read_actions)
plug(OAuthScopesPlug, %{scopes: ["write:statuses"]} when action not in @oauth_read_actions)
plug(:assign_scheduled_activity when action != :index)
@@ -23,7 +23,7 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityController do
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.ScheduledActivityOperation
@doc "GET /api/v1/scheduled_statuses"
- def index(%{assigns: %{user: user}} = conn, params) do
+ def index(%{assigns: %{user: user}, private: %{open_api_spex: %{params: params}}} = conn, _) do
params = Map.new(params, fn {key, value} -> {to_string(key), value} end)
with scheduled_activities <- MastodonAPI.get_scheduled_activities(user, params) do
@@ -39,7 +39,13 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityController do
end
@doc "PUT /api/v1/scheduled_statuses/:id"
- def update(%{assigns: %{scheduled_activity: scheduled_activity}, body_params: params} = conn, _) do
+ def update(
+ %{
+ assigns: %{scheduled_activity: scheduled_activity},
+ private: %{open_api_spex: %{body_params: params}}
+ } = conn,
+ _
+ ) do
with {:ok, scheduled_activity} <- ScheduledActivity.update(scheduled_activity, params) do
render(conn, "show.json", scheduled_activity: scheduled_activity)
end
@@ -52,7 +58,10 @@ defmodule Pleroma.Web.MastodonAPI.ScheduledActivityController do
end
end
- defp assign_scheduled_activity(%{assigns: %{user: user}, params: %{id: id}} = conn, _) do
+ defp assign_scheduled_activity(
+ %{assigns: %{user: user}, private: %{open_api_spex: %{params: %{id: id}}}} = conn,
+ _
+ ) do
case ScheduledActivity.get(user, id) do
%ScheduledActivity{} = activity -> assign(conn, :scheduled_activity, activity)
nil -> Pleroma.Web.MastodonAPI.FallbackController.call(conn, {:error, :not_found}) |> halt()
diff --git a/lib/pleroma/web/mastodon_api/controllers/search_controller.ex b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex
old mode 100755
new mode 100644
index 5e6e047..628aa31
--- a/lib/pleroma/web/mastodon_api/controllers/search_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex
@@ -5,7 +5,6 @@
defmodule Pleroma.Web.MastodonAPI.SearchController do
use Pleroma.Web, :controller
- alias Pleroma.Activity
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.ControllerHelper
@@ -19,7 +18,7 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do
@search_limit 40
- plug(Pleroma.Web.ApiSpec.CastAndValidate)
+ plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
# Note: Mastodon doesn't allow unauthenticated access (requires read:accounts / read:search)
plug(OAuthScopesPlug, %{scopes: ["read:search"], fallback: :proceed_unauthenticated})
@@ -30,7 +29,11 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do
defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.SearchOperation
- def account_search(%{assigns: %{user: user}} = conn, %{q: query} = params) do
+ def account_search(
+ %{assigns: %{user: user}, private: %{open_api_spex: %{params: %{q: query} = params}}} =
+ conn,
+ _
+ ) do
accounts = User.search(query, search_options(params, user))
conn
@@ -45,7 +48,12 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do
def search2(conn, params), do: do_search(:v2, conn, params)
def search(conn, params), do: do_search(:v1, conn, params)
- defp do_search(version, %{assigns: %{user: user}} = conn, %{q: query} = params) do
+ defp do_search(
+ version,
+ %{assigns: %{user: user}, private: %{open_api_spex: %{params: %{q: query} = params}}} =
+ conn,
+ _
+ ) do
query = String.trim(query)
options = search_options(params, user)
timeout = Keyword.get(Repo.config(), :timeout, 15_000)
@@ -100,7 +108,7 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do
end
defp resource_search(_, "statuses", query, options) do
- statuses = with_fallback(fn -> Activity.search(options[:for_user], query, options) end)
+ statuses = with_fallback(fn -> Pleroma.Search.search(query, options) end)
StatusView.render("index.json",
activities: statuses,
@@ -148,7 +156,7 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do
tags
end
- Pleroma.Pagination.paginate(tags, options)
+ Pleroma.Pagination.paginate_list(tags, options)
end
defp add_joined_tag(tags) do
diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex
old mode 100755
new mode 100644
index e594ea4..83e1bee
--- a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex
@@ -12,6 +12,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
alias Pleroma.Activity
alias Pleroma.Bookmark
+ alias Pleroma.BookmarkFolder
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.ScheduledActivity
@@ -25,7 +26,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
alias Pleroma.Web.Plugs.OAuthScopesPlug
alias Pleroma.Web.Plugs.RateLimiter
- plug(Pleroma.Web.ApiSpec.CastAndValidate)
+ plug(Pleroma.Web.ApiSpec.CastAndValidate, replace_params: false)
plug(:skip_public_check when action in [:index, :show])
@@ -37,7 +38,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
when action in [
:index,
:show,
- :card,
:context,
:show_history,
:show_source
@@ -110,7 +110,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
`ids` query param is required
"""
- def index(%{assigns: %{user: user}} = conn, %{ids: ids} = params) do
+ def index(
+ %{assigns: %{user: user}, private: %{open_api_spex: %{params: %{ids: ids} = params}}} =
+ conn,
+ _
+ ) do
limit = 100
activities =
@@ -134,7 +138,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
def create(
%{
assigns: %{user: user},
- body_params: %{status: _, scheduled_at: scheduled_at} = params
+ private: %{
+ open_api_spex: %{body_params: %{status: _, scheduled_at: scheduled_at} = params}
+ }
} = conn,
_
)
@@ -156,7 +162,13 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
else
{:far_enough, _} ->
params = Map.drop(params, [:scheduled_at])
- create(%Plug.Conn{conn | body_params: params}, %{})
+
+ put_in(
+ conn,
+ [Access.key(:private), Access.key(:open_api_spex), Access.key(:body_params)],
+ params
+ )
+ |> do_create
error ->
error
@@ -164,7 +176,35 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
end
# Creates a regular status
- def create(%{assigns: %{user: user}, body_params: %{status: _} = params} = conn, _) do
+ def create(
+ %{
+ private: %{open_api_spex: %{body_params: %{status: _}}}
+ } = conn,
+ _
+ ) do
+ do_create(conn)
+ end
+
+ def create(
+ %{
+ assigns: %{user: _user},
+ private: %{open_api_spex: %{body_params: %{media_ids: _} = params}}
+ } = conn,
+ _
+ ) do
+ params = Map.put(params, :status, "")
+
+ put_in(
+ conn,
+ [Access.key(:private), Access.key(:open_api_spex), Access.key(:body_params)],
+ params
+ )
+ |> do_create
+ end
+
+ defp do_create(
+ %{assigns: %{user: user}, private: %{open_api_spex: %{body_params: params}}} = conn
+ ) do
params =
Map.put(params, :in_reply_to_status_id, params[:in_reply_to_id])
|> put_application(conn)
@@ -189,13 +229,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
end
end
- def create(%{assigns: %{user: _user}, body_params: %{media_ids: _} = params} = conn, _) do
- params = Map.put(params, :status, "")
- create(%Plug.Conn{conn | body_params: params}, %{})
- end
-
@doc "GET /api/v1/statuses/:id/history"
- def show_history(%{assigns: assigns} = conn, %{id: id} = params) do
+ def show_history(
+ %{assigns: assigns, private: %{open_api_spex: %{params: %{id: id} = params}}} = conn,
+ _
+ ) do
with user = assigns[:user],
%Activity{} = activity <- Activity.get_by_id_with_object(id),
true <- Visibility.visible_for_user?(activity, user) do
@@ -211,7 +249,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
end
@doc "GET /api/v1/statuses/:id/source"
- def show_source(%{assigns: assigns} = conn, %{id: id} = _params) do
+ def show_source(%{assigns: assigns, private: %{open_api_spex: %{params: %{id: id}}}} = conn, _) do
with user = assigns[:user],
%Activity{} = activity <- Activity.get_by_id_with_object(id),
true <- Visibility.visible_for_user?(activity, user) do
@@ -225,7 +263,13 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
end
@doc "PUT /api/v1/statuses/:id"
- def update(%{assigns: %{user: user}, body_params: body_params} = conn, %{id: id} = params) do
+ def update(
+ %{
+ assigns: %{user: user},
+ private: %{open_api_spex: %{body_params: body_params, params: %{id: id} = params}}
+ } = conn,
+ _
+ ) do
with {_, %Activity{}} = {_, activity} <- {:activity, Activity.get_by_id_with_object(id)},
{_, true} <- {:visible, Visibility.visible_for_user?(activity, user)},
{_, true} <- {:is_create, activity.data["type"] == "Create"},
@@ -248,7 +292,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
end
@doc "GET /api/v1/statuses/:id"
- def show(%{assigns: %{user: user}} = conn, %{id: id} = params) do
+ def show(
+ %{assigns: %{user: user}, private: %{open_api_spex: %{params: %{id: id} = params}}} =
+ conn,
+ _
+ ) do
with %Activity{} = activity <- Activity.get_by_id_with_object(id),
true <- Visibility.visible_for_user?(activity, user) do
try_render(conn, "show.json",
@@ -263,7 +311,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
end
@doc "DELETE /api/v1/statuses/:id"
- def delete(%{assigns: %{user: user}} = conn, %{id: id}) do
+ def delete(%{assigns: %{user: user}, private: %{open_api_spex: %{params: %{id: id}}}} = conn, _) do
with %Activity{} = activity <- Activity.get_by_id_with_object(id),
{:ok, %Activity{}} <- CommonAPI.delete(id, user) do
try_render(conn, "show.json",
@@ -278,7 +326,13 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
end
@doc "POST /api/v1/statuses/:id/reblog"
- def reblog(%{assigns: %{user: user}, body_params: params} = conn, %{id: ap_id_or_id}) do
+ def reblog(
+ %{
+ assigns: %{user: user},
+ private: %{open_api_spex: %{body_params: params, params: %{id: ap_id_or_id}}}
+ } = conn,
+ _
+ ) do
with {:ok, announce} <- CommonAPI.repeat(ap_id_or_id, user, params),
%Activity{} = announce <- Activity.normalize(announce.data) do
try_render(conn, "show.json", %{activity: announce, for: user, as: :activity})
@@ -286,7 +340,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
end
@doc "POST /api/v1/statuses/:id/unreblog"
- def unreblog(%{assigns: %{user: user}} = conn, %{id: activity_id}) do
+ def unreblog(
+ %{assigns: %{user: user}, private: %{open_api_spex: %{params: %{id: activity_id}}}} =
+ conn,
+ _
+ ) do
with {:ok, _unannounce} <- CommonAPI.unrepeat(activity_id, user),
%Activity{} = activity <- Activity.get_by_id(activity_id) do
try_render(conn, "show.json", %{activity: activity, for: user, as: :activity})
@@ -294,7 +352,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
end
@doc "POST /api/v1/statuses/:id/favourite"
- def favourite(%{assigns: %{user: user}} = conn, %{id: activity_id}) do
+ def favourite(
+ %{assigns: %{user: user}, private: %{open_api_spex: %{params: %{id: activity_id}}}} =
+ conn,
+ _
+ ) do
with {:ok, _fav} <- CommonAPI.favorite(user, activity_id),
%Activity{} = activity <- Activity.get_by_id(activity_id) do
try_render(conn, "show.json", activity: activity, for: user, as: :activity)
@@ -302,7 +364,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
end
@doc "POST /api/v1/statuses/:id/unfavourite"
- def unfavourite(%{assigns: %{user: user}} = conn, %{id: activity_id}) do
+ def unfavourite(
+ %{assigns: %{user: user}, private: %{open_api_spex: %{params: %{id: activity_id}}}} =
+ conn,
+ _
+ ) do
with {:ok, _unfav} <- CommonAPI.unfavorite(activity_id, user),
%Activity{} = activity <- Activity.get_by_id(activity_id) do
try_render(conn, "show.json", activity: activity, for: user, as: :activity)
@@ -310,7 +376,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
end
@doc "POST /api/v1/statuses/:id/pin"
- def pin(%{assigns: %{user: user}} = conn, %{id: ap_id_or_id}) do
+ def pin(
+ %{assigns: %{user: user}, private: %{open_api_spex: %{params: %{id: ap_id_or_id}}}} =
+ conn,
+ _
+ ) do
with {:ok, activity} <- CommonAPI.pin(ap_id_or_id, user) do
try_render(conn, "show.json", activity: activity, for: user, as: :activity)
else
@@ -329,24 +399,43 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
end
@doc "POST /api/v1/statuses/:id/unpin"
- def unpin(%{assigns: %{user: user}} = conn, %{id: ap_id_or_id}) do
+ def unpin(
+ %{assigns: %{user: user}, private: %{open_api_spex: %{params: %{id: ap_id_or_id}}}} =
+ conn,
+ _
+ ) do
with {:ok, activity} <- CommonAPI.unpin(ap_id_or_id, user) do
try_render(conn, "show.json", activity: activity, for: user, as: :activity)
end
end
@doc "POST /api/v1/statuses/:id/bookmark"
- def bookmark(%{assigns: %{user: user}} = conn, %{id: id}) do
+ def bookmark(
+ %{
+ assigns: %{user: user},
+ private: %{open_api_spex: %{body_params: body_params, params: %{id: id}}}
+ } = conn,
+ _
+ ) do
with %Activity{} = activity <- Activity.get_by_id_with_object(id),
%User{} = user <- User.get_cached_by_nickname(user.nickname),
true <- Visibility.visible_for_user?(activity, user),
- {:ok, _bookmark} <- Bookmark.create(user.id, activity.id) do
+ folder_id <- Map.get(body_params, :folder_id, nil),
+ folder_id <-
+ if(folder_id && BookmarkFolder.belongs_to_user?(folder_id, user.id),
+ do: folder_id,
+ else: nil
+ ),
+ {:ok, _bookmark} <- Bookmark.create(user.id, activity.id, folder_id) do
try_render(conn, "show.json", activity: activity, for: user, as: :activity)
end
end
@doc "POST /api/v1/statuses/:id/unbookmark"
- def unbookmark(%{assigns: %{user: user}} = conn, %{id: id}) do
+ def unbookmark(
+ %{assigns: %{user: user}, private: %{open_api_spex: %{params: %{id: id}}}} = conn,
+ _
+ ) do
with %Activity{} = activity <- Activity.get_by_id_with_object(id),
%User{} = user <- User.get_cached_by_nickname(user.nickname),
true <- Visibility.visible_for_user?(activity, user),
@@ -356,7 +445,13 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
end
@doc "POST /api/v1/statuses/:id/mute"
- def mute_conversation(%{assigns: %{user: user}, body_params: params} = conn, %{id: id}) do
+ def mute_conversation(
+ %{
+ assigns: %{user: user},
+ private: %{open_api_spex: %{body_params: params, params: %{id: id}}}
+ } = conn,
+ _
+ ) do
with %Activity{} = activity <- Activity.get_by_id(id),
{:ok, activity} <- CommonAPI.add_mute(user, activity, params) do
try_render(conn, "show.json", activity: activity, for: user, as: :activity)
@@ -364,27 +459,24 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
end
@doc "POST /api/v1/statuses/:id/unmute"
- def unmute_conversation(%{assigns: %{user: user}} = conn, %{id: id}) do
+ def unmute_conversation(
+ %{
+ assigns: %{user: user},
+ private: %{open_api_spex: %{params: %{id: id}}}
+ } = conn,
+ _
+ ) do
with %Activity{} = activity <- Activity.get_by_id(id),
{:ok, activity} <- CommonAPI.remove_mute(user, activity) do
try_render(conn, "show.json", activity: activity, for: user, as: :activity)
end
end
- @doc "GET /api/v1/statuses/:id/card"
- @deprecated "https://github.com/tootsuite/mastodon/pull/11213"
- def card(%{assigns: %{user: user}} = conn, %{id: status_id}) do
- with %Activity{} = activity <- Activity.get_by_id(status_id),
- true <- Visibility.visible_for_user?(activity, user) do
- data = Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
- render(conn, "card.json", data)
- else
- _ -> render_error(conn, :not_found, "Record not found")
- end
- end
-
@doc "GET /api/v1/statuses/:id/favourited_by"
- def favourited_by(%{assigns: %{user: user}} = conn, %{id: id}) do
+ def favourited_by(
+ %{assigns: %{user: user}, private: %{open_api_spex: %{params: %{id: id}}}} = conn,
+ _
+ ) do
with true <- Pleroma.Config.get([:instance, :show_reactions]),
%Activity{} = activity <- Activity.get_by_id_with_object(id),
{:visible, true} <- {:visible, Visibility.visible_for_user?(activity, user)},
@@ -405,7 +497,10 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
end
@doc "GET /api/v1/statuses/:id/reblogged_by"
- def reblogged_by(%{assigns: %{user: user}} = conn, %{id: id}) do
+ def reblogged_by(
+ %{assigns: %{user: user}, private: %{open_api_spex: %{params: %{id: id}}}} = conn,
+ _
+ ) do
with %Activity{} = activity <- Activity.get_by_id_with_object(id),
{:visible, true} <- {:visible, Visibility.visible_for_user?(activity, user)},
%Object{data: %{"announcements" => announces, "id" => ap_id}} <-
@@ -437,7 +532,10 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
end
@doc "GET /api/v1/statuses/:id/context"
- def context(%{assigns: %{user: user}} = conn, %{id: id}) do
+ def context(
+ %{assigns: %{user: user}, private: %{open_api_spex: %{params: %{id: id}}}} = conn,
+ _
+ ) do
with %Activity{} = activity <- Activity.get_by_id(id) do
activities =
ActivityPub.fetch_activities_for_context(activity.data["context"], %{
@@ -451,7 +549,10 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
end
@doc "GET /api/v1/favourites"
- def favourites(%{assigns: %{user: %User{} = user}} = conn, params) do
+ def favourites(
+ %{assigns: %{user: %User{} = user}, private: %{open_api_spex: %{params: params}}} = conn,
+ _
+ ) do
activities = ActivityPub.fetch_favourites(user, params)
conn
@@ -464,12 +565,13 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
end
@doc "GET /api/v1/bookmarks"
- def bookmarks(%{assigns: %{user: user}} = conn, params) do
+ def bookmarks(%{assigns: %{user: user}, private: %{open_api_spex: %{params: params}}} = conn, _) do
user = User.get_cached_by_id(user.id)
+ folder_id = Map.get(params, :folder_id)
bookmarks =
user.id
- |> Bookmark.for_user_query()
+ |> Bookmark.for_user_query(folder_id)
|> Pleroma.Pagination.fetch_paginated(params)
activities =
diff --git a/lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex b/lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/controllers/suggestion_controller.ex b/lib/pleroma/web/mastodon_api/controllers/suggestion_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api.ex b/lib/pleroma/web/mastodon_api/mastodon_api.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex
old mode 100755
new mode 100644
index cc3e358..267c3e3
--- a/lib/pleroma/web/mastodon_api/views/account_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/account_view.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2022 Pleroma Authors
+# Copyright © 2017-2023 Pleroma Authors
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.AccountView do
@@ -194,6 +194,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
end
defp do_render("show.json", %{user: user} = opts) do
+ self = opts[:for] == user
+
user = User.sanitize_html(user, User.html_filter_policy(opts[:for]))
display_name = user.name || user.nickname
@@ -203,16 +205,16 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
header_static = User.banner_url(user) |> MediaProxy.preview_url(static: true)
following_count =
- if !user.hide_follows_count or !user.hide_follows or opts[:for] == user,
+ if !user.hide_follows_count or !user.hide_follows or self,
do: user.following_count,
else: 0
followers_count =
- if !user.hide_followers_count or !user.hide_followers or opts[:for] == user,
+ if !user.hide_followers_count or !user.hide_followers or self,
do: user.follower_count,
else: 0
- bot = user.actor_type == "Service"
+ bot = bot?(user)
emojis =
Enum.map(user.emoji, fn {shortcode, raw_url} ->
@@ -249,6 +251,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
nil
end
+ last_status_at =
+ user.last_status_at &&
+ user.last_status_at |> NaiveDateTime.to_date() |> Date.to_iso8601()
+
%{
id: to_string(user.id),
username: username_from_nickname(user.nickname),
@@ -277,7 +283,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
actor_type: user.actor_type
}
},
- last_status_at: user.last_status_at,
+ last_status_at: last_status_at,
# Pleroma extensions
# Note: it's insecure to output :email but fully-qualified nickname may serve as safe stub
@@ -464,4 +470,12 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
defp image_url(%{"url" => [%{"href" => href} | _]}), do: href
defp image_url(_), do: nil
+
+ defp bot?(user) do
+ # Because older and/or Mastodon clients may not recognize a Group actor properly,
+ # and currently the group actor can only boost things, we should let these clients
+ # think groups are bots.
+ # See https://git.pleroma.social/pleroma/pleroma-meta/-/issues/14
+ user.actor_type == "Service" || user.actor_type == "Group"
+ end
end
diff --git a/lib/pleroma/web/mastodon_api/views/announcement_view.ex b/lib/pleroma/web/mastodon_api/views/announcement_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/views/app_view.ex b/lib/pleroma/web/mastodon_api/views/app_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/views/conversation_view.ex b/lib/pleroma/web/mastodon_api/views/conversation_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/views/custom_emoji_view.ex b/lib/pleroma/web/mastodon_api/views/custom_emoji_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/views/filter_view.ex b/lib/pleroma/web/mastodon_api/views/filter_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/views/follow_request_view.ex b/lib/pleroma/web/mastodon_api/views/follow_request_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/views/instance_view.ex b/lib/pleroma/web/mastodon_api/views/instance_view.ex
old mode 100755
new mode 100644
index abf7f29..890dd39
--- a/lib/pleroma/web/mastodon_api/views/instance_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/instance_view.ex
@@ -13,12 +13,11 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
def render("show.json", _) do
instance = Config.get(:instance)
- %{
- uri: Pleroma.Web.Endpoint.url(),
- title: Keyword.get(instance, :name),
+ common_information(instance)
+ |> Map.merge(%{
+ uri: Pleroma.Web.WebFinger.host(),
description: Keyword.get(instance, :description),
short_description: Keyword.get(instance, :short_description),
- version: "#{@mastodon_api_level} (compatible; #{Pleroma.Application.named_version()})",
email: Keyword.get(instance, :email),
urls: %{
streaming_api: Pleroma.Web.Endpoint.websocket_url()
@@ -27,9 +26,10 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
thumbnail:
URI.merge(Pleroma.Web.Endpoint.url(), Keyword.get(instance, :instance_thumbnail))
|> to_string,
- languages: Keyword.get(instance, :languages, ["en"]),
registrations: Keyword.get(instance, :registrations_open),
approval_required: Keyword.get(instance, :account_approval_required),
+ contact_account: contact_account(Keyword.get(instance, :contact_username)),
+ configuration: configuration(),
# Extra (not present in Mastodon):
max_toot_chars: Keyword.get(instance, :limit),
max_media_attachments: Keyword.get(instance, :max_media_attachments),
@@ -41,19 +41,47 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
background_image: Pleroma.Web.Endpoint.url() <> Keyword.get(instance, :background_image),
shout_limit: Config.get([:shout, :limit]),
description_limit: Keyword.get(instance, :description_limit),
- pleroma: %{
- metadata: %{
- account_activation_required: Keyword.get(instance, :account_activation_required),
- features: features(),
- federation: federation(),
- fields_limits: fields_limits(),
- post_formats: Config.get([:instance, :allowed_post_formats]),
- birthday_required: Config.get([:instance, :birthday_required]),
- birthday_min_age: Config.get([:instance, :birthday_min_age])
- },
- stats: %{mau: Pleroma.User.active_user_count()},
- vapid_public_key: Keyword.get(Pleroma.Web.Push.vapid_config(), :public_key)
- }
+ chat_limit: Keyword.get(instance, :chat_limit),
+ pleroma: pleroma_configuration(instance)
+ })
+ end
+
+ def render("show2.json", _) do
+ instance = Config.get(:instance)
+
+ common_information(instance)
+ |> Map.merge(%{
+ domain: Pleroma.Web.WebFinger.host(),
+ source_url: Pleroma.Application.repository(),
+ description: Keyword.get(instance, :short_description),
+ usage: %{users: %{active_month: Pleroma.User.active_user_count()}},
+ thumbnail: %{
+ url:
+ URI.merge(Pleroma.Web.Endpoint.url(), Keyword.get(instance, :instance_thumbnail))
+ |> to_string
+ },
+ configuration: configuration2(),
+ registrations: %{
+ enabled: Keyword.get(instance, :registrations_open),
+ approval_required: Keyword.get(instance, :account_approval_required),
+ message: nil,
+ url: nil
+ },
+ contact: %{
+ email: Keyword.get(instance, :email),
+ account: contact_account(Keyword.get(instance, :contact_username))
+ },
+ # Extra (not present in Mastodon):
+ pleroma: pleroma_configuration2(instance)
+ })
+ end
+
+ defp common_information(instance) do
+ %{
+ title: Keyword.get(instance, :name),
+ version: "#{@mastodon_api_level} (compatible; #{Pleroma.Application.named_version()})",
+ languages: Keyword.get(instance, :languages, ["en"]),
+ rules: []
}
end
@@ -69,6 +97,7 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
"multifetch",
"pleroma:api/v1/notifications:include_types_filter",
"editing",
+ "quote_posting",
if Config.get([:activitypub, :blockers_visible]) do
"blockers_visible"
end,
@@ -92,6 +121,7 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
"safe_dm_mentions"
end,
"pleroma_emoji_reactions",
+ "pleroma_custom_emoji_reactions",
"pleroma_chat_messages",
if Config.get([:instance, :show_reactions]) do
"exposable_reactions"
@@ -99,7 +129,9 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
if Config.get([:instance, :profile_directory]) do
"profile_directory"
end,
- "pleroma:get:main/ostatus"
+ "pleroma:get:main/ostatus",
+ "pleroma:group_actors",
+ "pleroma:bookmark_folders"
]
|> Enum.filter(& &1)
end
@@ -131,7 +163,7 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
|> Map.put(:enabled, Config.get([:instance, :federating]))
end
- def fields_limits do
+ defp fields_limits do
%{
max_fields: Config.get([:instance, :max_account_fields]),
max_remote_fields: Config.get([:instance, :max_remote_account_fields]),
@@ -139,4 +171,94 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
value_length: Config.get([:instance, :account_field_value_length])
}
end
+
+ defp contact_account(nil), do: nil
+
+ defp contact_account("@" <> username) do
+ contact_account(username)
+ end
+
+ defp contact_account(username) do
+ user = Pleroma.User.get_cached_by_nickname(username)
+
+ if user do
+ Pleroma.Web.MastodonAPI.AccountView.render("show.json", %{user: user, for: nil})
+ else
+ nil
+ end
+ end
+
+ defp configuration do
+ %{
+ accounts: %{
+ max_featured_tags: 0
+ },
+ statuses: %{
+ max_characters: Config.get([:instance, :limit]),
+ max_media_attachments: Config.get([:instance, :max_media_attachments])
+ },
+ media_attachments: %{
+ image_size_limit: Config.get([:instance, :upload_limit]),
+ video_size_limit: Config.get([:instance, :upload_limit]),
+ supported_mime_types: ["application/octet-stream"]
+ },
+ polls: %{
+ max_options: Config.get([:instance, :poll_limits, :max_options]),
+ max_characters_per_option: Config.get([:instance, :poll_limits, :max_option_chars]),
+ min_expiration: Config.get([:instance, :poll_limits, :min_expiration]),
+ max_expiration: Config.get([:instance, :poll_limits, :max_expiration])
+ }
+ }
+ end
+
+ defp configuration2 do
+ configuration()
+ |> put_in([:accounts, :max_pinned_statuses], Config.get([:instance, :max_pinned_statuses], 0))
+ |> put_in([:statuses, :characters_reserved_per_url], 0)
+ |> Map.merge(%{
+ urls: %{
+ streaming: Pleroma.Web.Endpoint.websocket_url(),
+ status: Config.get([:instance, :status_page])
+ },
+ vapid: %{
+ public_key: Keyword.get(Pleroma.Web.Push.vapid_config(), :public_key)
+ }
+ })
+ end
+
+ defp pleroma_configuration(instance) do
+ %{
+ metadata: %{
+ account_activation_required: Keyword.get(instance, :account_activation_required),
+ features: features(),
+ federation: federation(),
+ fields_limits: fields_limits(),
+ post_formats: Config.get([:instance, :allowed_post_formats]),
+ birthday_required: Config.get([:instance, :birthday_required]),
+ birthday_min_age: Config.get([:instance, :birthday_min_age])
+ },
+ stats: %{mau: Pleroma.User.active_user_count()},
+ vapid_public_key: Keyword.get(Pleroma.Web.Push.vapid_config(), :public_key)
+ }
+ end
+
+ defp pleroma_configuration2(instance) do
+ configuration = pleroma_configuration(instance)
+
+ configuration
+ |> Map.merge(%{
+ metadata:
+ configuration.metadata
+ |> Map.merge(%{
+ avatar_upload_limit: Keyword.get(instance, :avatar_upload_limit),
+ background_upload_limit: Keyword.get(instance, :background_upload_limit),
+ banner_upload_limit: Keyword.get(instance, :banner_upload_limit),
+ background_image:
+ Pleroma.Web.Endpoint.url() <> Keyword.get(instance, :background_image),
+ chat_limit: Keyword.get(instance, :chat_limit),
+ description_limit: Keyword.get(instance, :description_limit),
+ shout_limit: Config.get([:shout, :limit])
+ })
+ })
+ end
end
diff --git a/lib/pleroma/web/mastodon_api/views/list_view.ex b/lib/pleroma/web/mastodon_api/views/list_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/views/marker_view.ex b/lib/pleroma/web/mastodon_api/views/marker_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/views/media_view.ex b/lib/pleroma/web/mastodon_api/views/media_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/views/notification_view.ex b/lib/pleroma/web/mastodon_api/views/notification_view.ex
old mode 100755
new mode 100644
index b5b5b23..2a51f37
--- a/lib/pleroma/web/mastodon_api/views/notification_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/notification_view.ex
@@ -17,6 +17,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
alias Pleroma.Web.MastodonAPI.AccountView
alias Pleroma.Web.MastodonAPI.NotificationView
alias Pleroma.Web.MastodonAPI.StatusView
+ alias Pleroma.Web.MediaProxy
alias Pleroma.Web.PleromaAPI.Chat.MessageReferenceView
defp object_id_for(%{data: %{"object" => %{"id" => id}}}) when is_binary(id), do: id
@@ -145,7 +146,9 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
end
defp put_emoji(response, activity) do
- Map.put(response, :emoji, activity.data["content"])
+ response
+ |> Map.put(:emoji, activity.data["content"])
+ |> Map.put(:emoji_url, MediaProxy.url(Pleroma.Emoji.emoji_url(activity.data)))
end
defp put_chat_message(response, activity, reading_user, opts) do
diff --git a/lib/pleroma/web/mastodon_api/views/poll_view.ex b/lib/pleroma/web/mastodon_api/views/poll_view.ex
old mode 100755
new mode 100644
index 34e2387..1e3c9f3
--- a/lib/pleroma/web/mastodon_api/views/poll_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/poll_view.ex
@@ -21,7 +21,10 @@ defmodule Pleroma.Web.MastodonAPI.PollView do
votes_count: votes_count,
voters_count: voters_count(object),
options: options,
- emojis: Pleroma.Web.MastodonAPI.StatusView.build_emojis(object.data["emoji"])
+ emojis: Pleroma.Web.MastodonAPI.StatusView.build_emojis(object.data["emoji"]),
+ pleroma: %{
+ non_anonymous: object.data["nonAnonymous"] || false
+ }
}
if params[:for] do
diff --git a/lib/pleroma/web/mastodon_api/views/report_view.ex b/lib/pleroma/web/mastodon_api/views/report_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex b/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
old mode 100755
new mode 100644
index 0a8c98b..c945290
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -21,6 +21,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
alias Pleroma.Web.MastodonAPI.StatusView
alias Pleroma.Web.MediaProxy
alias Pleroma.Web.PleromaAPI.EmojiReactionController
+ alias Pleroma.Web.RichMedia.Card
import Pleroma.Web.ActivityPub.Visibility, only: [get_visibility: 1, visible_for_user?: 2]
@@ -29,9 +30,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
# pagination is restricted to 40 activities at a time
defp fetch_rich_media_for_activities(activities) do
Enum.each(activities, fn activity ->
- spawn(fn ->
- Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity)
- end)
+ spawn(fn -> Card.get_by_activity(activity) end)
end)
end
@@ -57,6 +56,27 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
end)
end
+ defp get_quoted_activities([]), do: %{}
+
+ defp get_quoted_activities(activities) do
+ activities
+ |> Enum.map(fn
+ %{data: %{"type" => "Create"}} = activity ->
+ object = Object.normalize(activity, fetch: false)
+ object && object.data["quoteUrl"] != "" && object.data["quoteUrl"]
+
+ _ ->
+ nil
+ end)
+ |> Enum.filter(& &1)
+ |> Activity.create_by_object_ap_id_with_object()
+ |> Repo.all()
+ |> Enum.reduce(%{}, fn activity, acc ->
+ object = Object.normalize(activity, fetch: false)
+ if object, do: Map.put(acc, object.data["id"], activity), else: acc
+ end)
+ end
+
# DEPRECATED This field seems to be a left-over from the StatusNet era.
# If your application uses `pleroma.conversation_id`: this field is deprecated.
# It is currently stubbed instead by doing a CRC32 of the context, and
@@ -92,11 +112,10 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
# To do: check AdminAPIControllerTest on the reasons behind nil activities in the list
activities = Enum.filter(opts.activities, & &1)
- # Start fetching rich media before doing anything else, so that later calls to get the cards
- # only block for timeout in the worst case, as opposed to
- # length(activities_with_links) * timeout
+ # Start prefetching rich media before doing anything else
fetch_rich_media_for_activities(activities)
replied_to_activities = get_replied_to_activities(activities)
+ quoted_activities = get_quoted_activities(activities)
parent_activities =
activities
@@ -129,6 +148,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
opts =
opts
|> Map.put(:replied_to_activities, replied_to_activities)
+ |> Map.put(:quoted_activities, quoted_activities)
|> Map.put(:parent_activities, parent_activities)
|> Map.put(:relationships, relationships_opt)
@@ -161,7 +181,14 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
favorited = opts[:for] && opts[:for].ap_id in (object.data["likes"] || [])
- bookmarked = Activity.get_bookmark(reblogged_parent_activity, opts[:for]) != nil
+ bookmark = Activity.get_bookmark(reblogged_parent_activity, opts[:for])
+
+ bookmark_folder =
+ if bookmark != nil do
+ bookmark.folder_id
+ else
+ nil
+ end
mentions =
activity.recipients
@@ -190,7 +217,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
favourites_count: 0,
reblogged: reblogged?(reblogged_parent_activity, opts[:for]),
favourited: present?(favorited),
- bookmarked: present?(bookmarked),
+ bookmarked: present?(bookmark),
muted: false,
pinned: pinned?,
sensitive: false,
@@ -204,7 +231,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
emojis: [],
pleroma: %{
local: activity.local,
- pinned_at: pinned_at
+ pinned_at: pinned_at,
+ bookmark_folder: bookmark_folder
}
}
end
@@ -241,7 +269,14 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
favorited = opts[:for] && opts[:for].ap_id in (object.data["likes"] || [])
- bookmarked = Activity.get_bookmark(activity, opts[:for]) != nil
+ bookmark = Activity.get_bookmark(activity, opts[:for])
+
+ bookmark_folder =
+ if bookmark != nil do
+ bookmark.folder_id
+ else
+ nil
+ end
client_posted_this_activity = opts[:for] && user.id == opts[:for].id
@@ -277,7 +312,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
end
reply_to = get_reply_to(activity, opts)
-
reply_to_user = reply_to && CommonAPI.get_user(reply_to.data["actor"])
history_len =
@@ -290,6 +324,22 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
# Here the implicit index of the current content is 0
chrono_order = history_len - 1
+ quote_activity = get_quote(activity, opts)
+
+ quote_id =
+ case quote_activity do
+ %Activity{id: id} -> id
+ _ -> nil
+ end
+
+ quote_post =
+ if visible_for_user?(quote_activity, opts[:for]) and opts[:show_quote] != false do
+ quote_rendering_opts = Map.merge(opts, %{activity: quote_activity, show_quote: false})
+ render("show.json", quote_rendering_opts)
+ else
+ nil
+ end
+
content =
object
|> render_content()
@@ -311,7 +361,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
summary = object.data["summary"] || ""
- card = render("card.json", Pleroma.Web.RichMedia.Helpers.fetch_data_for_activity(activity))
+ card =
+ case Card.get_by_activity(activity) do
+ %Card{} = result -> render("card.json", result)
+ _ -> nil
+ end
url =
if user.local do
@@ -334,14 +388,14 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
end
emoji_reactions =
- object.data
- |> Map.get("reactions", [])
+ object
+ |> Object.get_emoji_reactions()
|> EmojiReactionController.filter_allowed_users(
opts[:for],
Map.get(opts, :with_muted, false)
)
- |> Stream.map(fn {emoji, users} ->
- build_emoji_map(emoji, users, opts[:for])
+ |> Stream.map(fn {emoji, users, url} ->
+ build_emoji_map(emoji, users, url, opts[:for])
end)
|> Enum.to_list()
@@ -380,7 +434,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
favourites_count: like_count,
reblogged: reblogged?(activity, opts[:for]),
favourited: present?(favorited),
- bookmarked: present?(bookmarked),
+ bookmarked: present?(bookmark),
muted: muted,
pinned: pinned?,
sensitive: sensitive,
@@ -398,6 +452,10 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
conversation_id: get_context_id(activity),
context: object.data["context"],
in_reply_to_account_acct: reply_to_user && reply_to_user.nickname,
+ quote: quote_post,
+ quote_id: quote_id,
+ quote_url: object.data["quoteUrl"],
+ quote_visible: visible_for_user?(quote_activity, opts[:for]),
content: %{"text/plain" => content_plaintext},
spoiler_text: %{"text/plain" => summary},
expires_at: expires_at,
@@ -405,7 +463,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
thread_muted: thread_muted?,
emoji_reactions: emoji_reactions,
parent_visible: visible_for_user?(reply_to, opts[:for]),
- pinned_at: pinned_at
+ pinned_at: pinned_at,
+ quotes_count: object.data["quotesCount"] || 0,
+ bookmark_folder: bookmark_folder
}
}
end
@@ -508,37 +568,30 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
}
end
- def render("card.json", %{rich_media: rich_media, page_url: page_url}) do
- page_url_data = URI.parse(page_url)
-
- page_url_data =
- if is_binary(rich_media["url"]) do
- URI.merge(page_url_data, URI.parse(rich_media["url"]))
- else
- page_url_data
- end
+ def render("card.json", %Card{fields: rich_media}) do
+ page_url_data = URI.parse(rich_media["url"])
page_url = page_url_data |> to_string
- image_url_data =
- if is_binary(rich_media["image"]) do
- URI.parse(rich_media["image"])
- else
- nil
- end
-
- image_url = build_image_url(image_url_data, page_url_data)
+ image_url = proxied_url(rich_media["image"], page_url_data)
+ audio_url = proxied_url(rich_media["audio"], page_url_data)
+ video_url = proxied_url(rich_media["video"], page_url_data)
%{
type: "link",
provider_name: page_url_data.host,
provider_url: page_url_data.scheme <> "://" <> page_url_data.host,
url: page_url,
- image: image_url |> MediaProxy.url(),
+ image: image_url,
+ image_description: rich_media["image:alt"] || "",
title: rich_media["title"] || "",
description: rich_media["description"] || "",
pleroma: %{
- opengraph: rich_media
+ opengraph:
+ rich_media
+ |> Maps.put_if_present("image", image_url)
+ |> Maps.put_if_present("audio", audio_url)
+ |> Maps.put_if_present("video", video_url)
}
}
end
@@ -633,6 +686,25 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
end
end
+ def get_quote(activity, %{quoted_activities: quoted_activities}) do
+ object = Object.normalize(activity, fetch: false)
+
+ with nil <- quoted_activities[object.data["quoteUrl"]] do
+ # For when a quote post is inside an Announce
+ Activity.get_create_by_object_ap_id_with_object(object.data["quoteUrl"])
+ end
+ end
+
+ def get_quote(%{data: %{"object" => _object}} = activity, _) do
+ object = Object.normalize(activity, fetch: false)
+
+ if object.data["quoteUrl"] && object.data["quoteUrl"] != "" do
+ Activity.get_create_by_object_ap_id(object.data["quoteUrl"])
+ else
+ nil
+ end
+ end
+
def render_content(%{data: %{"name" => name}} = object) when not is_nil(name) and name != "" do
url = object.data["url"] || object.data["id"]
@@ -702,11 +774,13 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
end
end
- defp build_emoji_map(emoji, users, current_user) do
+ defp build_emoji_map(emoji, users, url, current_user) do
%{
- name: emoji,
+ name: Pleroma.Web.PleromaAPI.EmojiReactionView.emoji_name(emoji, url),
count: length(users),
- me: !!(current_user && current_user.ap_id in users)
+ url: MediaProxy.url(url),
+ me: !!(current_user && current_user.ap_id in users),
+ account_ids: Enum.map(users, fn user -> User.get_cached_by_ap_id(user).id end)
}
end
@@ -733,8 +807,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
URI.merge(page_url_data, image_url_data) |> to_string
end
- defp build_image_url(_, _), do: nil
-
defp get_source_text(%{"content" => content} = _source) do
content
end
@@ -754,4 +826,12 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
defp get_source_content_type(_source) do
Utils.get_content_type(nil)
end
+
+ defp proxied_url(url, page_url_data) do
+ if is_binary(url) do
+ build_image_url(URI.parse(url), page_url_data) |> MediaProxy.url()
+ else
+ nil
+ end
+ end
end
diff --git a/lib/pleroma/web/mastodon_api/views/subscription_view.ex b/lib/pleroma/web/mastodon_api/views/subscription_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/views/suggestion_view.ex b/lib/pleroma/web/mastodon_api/views/suggestion_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/views/timeline_view.ex b/lib/pleroma/web/mastodon_api/views/timeline_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mastodon_api/websocket_handler.ex b/lib/pleroma/web/mastodon_api/websocket_handler.ex
old mode 100755
new mode 100644
index 8844410..bb27d80
--- a/lib/pleroma/web/mastodon_api/websocket_handler.ex
+++ b/lib/pleroma/web/mastodon_api/websocket_handler.ex
@@ -9,124 +9,128 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
alias Pleroma.User
alias Pleroma.Web.OAuth.Token
alias Pleroma.Web.Streamer
+ alias Pleroma.Web.StreamerView
- @behaviour :cowboy_websocket
+ @behaviour Phoenix.Socket.Transport
# Client ping period.
@tick :timer.seconds(30)
- # Cowboy timeout period.
- @timeout :timer.seconds(60)
- # Hibernate every X messages
- @hibernate_every 100
-
- def init(%{qs: qs} = req, state) do
- with params <- Enum.into(:cow_qs.parse_qs(qs), %{}),
- sec_websocket <- :cowboy_req.header("sec-websocket-protocol", req, nil),
- access_token <- Map.get(params, "access_token"),
- {:ok, user, oauth_token} <- authenticate_request(access_token, sec_websocket),
- {:ok, topic} <- Streamer.get_topic(params["stream"], user, oauth_token, params) do
- req =
- if sec_websocket do
- :cowboy_req.set_resp_header("sec-websocket-protocol", sec_websocket, req)
+
+ @impl Phoenix.Socket.Transport
+ def child_spec(_opts), do: :ignore
+
+ # This only prepares the connection and is not in the process yet
+ @impl Phoenix.Socket.Transport
+ def connect(%{params: params} = transport_info) do
+ with access_token <- Map.get(params, "access_token"),
+ {:ok, user, oauth_token} <- authenticate_request(access_token),
+ {:ok, topic} <-
+ Streamer.get_topic(params["stream"], user, oauth_token, params) do
+ topics =
+ if topic do
+ [topic]
else
- req
+ []
end
- {:cowboy_websocket, req,
- %{user: user, topic: topic, oauth_token: oauth_token, count: 0, timer: nil},
- %{idle_timeout: @timeout}}
+ state = %{
+ user: user,
+ topics: topics,
+ oauth_token: oauth_token,
+ count: 0,
+ timer: nil
+ }
+
+ {:ok, state}
else
{:error, :bad_topic} ->
- Logger.debug("#{__MODULE__} bad topic #{inspect(req)}")
- req = :cowboy_req.reply(404, req)
- {:ok, req, state}
+ Logger.debug("#{__MODULE__} bad topic #{inspect(transport_info)}")
+
+ {:error, :bad_topic}
{:error, :unauthorized} ->
- Logger.debug("#{__MODULE__} authentication error: #{inspect(req)}")
- req = :cowboy_req.reply(401, req)
- {:ok, req, state}
+ Logger.debug("#{__MODULE__} authentication error: #{inspect(transport_info)}")
+ {:error, :unauthorized}
end
end
- def websocket_init(state) do
- Logger.debug(
- "#{__MODULE__} accepted websocket connection for user #{(state.user || %{id: "anonymous"}).id}, topic #{state.topic}"
- )
+ # All subscriptions/links and messages cannot be created
+ # until the processed is launched with init/1
+ @impl Phoenix.Socket.Transport
+ def init(state) do
+ Enum.each(state.topics, fn topic -> Streamer.add_socket(topic, state.oauth_token) end)
- Streamer.add_socket(state.topic, state.oauth_token)
- {:ok, %{state | timer: timer()}}
- end
+ Process.send_after(self(), :ping, @tick)
- # Client's Pong frame.
- def websocket_handle(:pong, state) do
- if state.timer, do: Process.cancel_timer(state.timer)
- {:ok, %{state | timer: timer()}}
+ {:ok, state}
end
- # We only receive pings for now
- def websocket_handle(:ping, state), do: {:ok, state}
+ @impl Phoenix.Socket.Transport
+ def handle_in({text, [opcode: :text]}, state) do
+ with {:ok, %{} = event} <- Jason.decode(text) do
+ handle_client_event(event, state)
+ else
+ _ ->
+ Logger.error("#{__MODULE__} received non-JSON event: #{inspect(text)}")
+ {:ok, state}
+ end
+ end
- def websocket_handle(frame, state) do
+ def handle_in(frame, state) do
Logger.error("#{__MODULE__} received frame: #{inspect(frame)}")
{:ok, state}
end
- def websocket_info({:render_with_user, view, template, item}, state) do
+ @impl Phoenix.Socket.Transport
+ def handle_info({:render_with_user, view, template, item, topic}, state) do
user = %User{} = User.get_cached_by_ap_id(state.user.ap_id)
unless Streamer.filtered_by_user?(user, item) do
- websocket_info({:text, view.render(template, item, user)}, %{state | user: user})
+ message = view.render(template, item, user, topic)
+ {:push, {:text, message}, %{state | user: user}}
else
{:ok, state}
end
end
- def websocket_info({:text, message}, state) do
- # If the websocket processed X messages, force an hibernate/GC.
- # We don't hibernate at every message to balance CPU usage/latency with RAM usage.
- if state.count > @hibernate_every do
- {:reply, {:text, message}, %{state | count: 0}, :hibernate}
- else
- {:reply, {:text, message}, %{state | count: state.count + 1}}
- end
+ def handle_info({:text, text}, state) do
+ {:push, {:text, text}, state}
end
- # Ping tick. We don't re-queue a timer there, it is instead queued when :pong is received.
- # As we hibernate there, reset the count to 0.
- # If the client misses :pong, Cowboy will automatically timeout the connection after
- # `@idle_timeout`.
- def websocket_info(:tick, state) do
- {:reply, :ping, %{state | timer: nil, count: 0}, :hibernate}
+ def handle_info(:ping, state) do
+ Process.send_after(self(), :ping, @tick)
+
+ {:push, {:ping, ""}, state}
end
- def websocket_info(:close, state) do
- {:stop, state}
+ def handle_info(:close, state) do
+ {:stop, {:closed, 'connection closed by server'}, state}
end
- # State can be `[]` only in case we terminate before switching to websocket,
- # we already log errors for these cases in `init/1`, so just do nothing here
- def terminate(_reason, _req, []), do: :ok
+ def handle_info(msg, state) do
+ Logger.debug("#{__MODULE__} received info: #{inspect(msg)}")
+
+ {:ok, state}
+ end
- def terminate(reason, _req, state) do
+ @impl Phoenix.Socket.Transport
+ def terminate(reason, state) do
Logger.debug(
- "#{__MODULE__} terminating websocket connection for user #{(state.user || %{id: "anonymous"}).id}, topic #{state.topic || "?"}: #{inspect(reason)}"
+ "#{__MODULE__} terminating websocket connection for user #{(state.user || %{id: "anonymous"}).id}, topics #{state.topics || "?"}: #{inspect(reason)})"
)
- Streamer.remove_socket(state.topic)
+ Enum.each(state.topics, fn topic -> Streamer.remove_socket(topic) end)
:ok
end
# Public streams without authentication.
- defp authenticate_request(nil, nil) do
+ defp authenticate_request(nil) do
{:ok, nil, nil}
end
# Authenticated streams.
- defp authenticate_request(access_token, sec_websocket) do
- token = access_token || sec_websocket
-
- with true <- is_bitstring(token),
- oauth_token = %Token{user_id: user_id} <- Repo.get_by(Token, token: token),
+ defp authenticate_request(access_token) do
+ with oauth_token = %Token{user_id: user_id} <- Repo.get_by(Token, token: access_token),
user = %User{} <- User.get_cached_by_id(user_id) do
{:ok, user, oauth_token}
else
@@ -134,7 +138,110 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
end
end
- defp timer do
- Process.send_after(self(), :tick, @tick)
+ defp handle_client_event(%{"type" => "subscribe", "stream" => _topic} = params, state) do
+ with {_, {:ok, topic}} <-
+ {:topic, Streamer.get_topic(params["stream"], state.user, state.oauth_token, params)},
+ {_, false} <- {:subscribed, topic in state.topics} do
+ Streamer.add_socket(topic, state.oauth_token)
+
+ message =
+ StreamerView.render("pleroma_respond.json", %{type: "subscribe", result: "success"})
+
+ {:reply, :ok, {:text, message}, %{state | topics: [topic | state.topics]}}
+ else
+ {:subscribed, true} ->
+ message =
+ StreamerView.render("pleroma_respond.json", %{type: "subscribe", result: "ignored"})
+
+ {:reply, :error, {:text, message}, state}
+
+ {:topic, {:error, error}} ->
+ message =
+ StreamerView.render("pleroma_respond.json", %{
+ type: "subscribe",
+ result: "error",
+ error: error
+ })
+
+ {:reply, :error, {:text, message}, state}
+ end
+ end
+
+ defp handle_client_event(%{"type" => "unsubscribe", "stream" => _topic} = params, state) do
+ with {_, {:ok, topic}} <-
+ {:topic, Streamer.get_topic(params["stream"], state.user, state.oauth_token, params)},
+ {_, true} <- {:subscribed, topic in state.topics} do
+ Streamer.remove_socket(topic)
+
+ message =
+ StreamerView.render("pleroma_respond.json", %{type: "unsubscribe", result: "success"})
+
+ {:reply, :ok, {:text, message}, %{state | topics: List.delete(state.topics, topic)}}
+ else
+ {:subscribed, false} ->
+ message =
+ StreamerView.render("pleroma_respond.json", %{type: "unsubscribe", result: "ignored"})
+
+ {:reply, :error, {:text, message}, state}
+
+ {:topic, {:error, error}} ->
+ message =
+ StreamerView.render("pleroma_respond.json", %{
+ type: "unsubscribe",
+ result: "error",
+ error: error
+ })
+
+ {:reply, :error, {:text, message}, state}
+ end
+ end
+
+ defp handle_client_event(
+ %{"type" => "pleroma:authenticate", "token" => access_token} = _params,
+ state
+ ) do
+ with {:auth, nil, nil} <- {:auth, state.user, state.oauth_token},
+ {:ok, user, oauth_token} <- authenticate_request(access_token) do
+ message =
+ StreamerView.render("pleroma_respond.json", %{
+ type: "pleroma:authenticate",
+ result: "success"
+ })
+
+ {:reply, :ok, {:text, message}, %{state | user: user, oauth_token: oauth_token}}
+ else
+ {:auth, _, _} ->
+ message =
+ StreamerView.render("pleroma_respond.json", %{
+ type: "pleroma:authenticate",
+ result: "error",
+ error: :already_authenticated
+ })
+
+ {:reply, :error, {:text, message}, state}
+
+ _ ->
+ message =
+ StreamerView.render("pleroma_respond.json", %{
+ type: "pleroma:authenticate",
+ result: "error",
+ error: :unauthorized
+ })
+
+ {:reply, :error, {:text, message}, state}
+ end
+ end
+
+ defp handle_client_event(params, state) do
+ Logger.error("#{__MODULE__} received unknown event: #{inspect(params)}")
+ {:ok, state}
+ end
+
+ def handle_error(conn, :unauthorized) do
+ Plug.Conn.send_resp(conn, 401, "Unauthorized")
+ end
+
+ def handle_error(conn, _reason) do
+ Plug.Conn.send_resp(conn, 404, "Not Found")
end
end
diff --git a/lib/pleroma/web/media_proxy.ex b/lib/pleroma/web/media_proxy.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/media_proxy/invalidation.ex b/lib/pleroma/web/media_proxy/invalidation.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/media_proxy/invalidation/http.ex b/lib/pleroma/web/media_proxy/invalidation/http.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/media_proxy/invalidation/script.ex b/lib/pleroma/web/media_proxy/invalidation/script.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/media_proxy/media_proxy_controller.ex b/lib/pleroma/web/media_proxy/media_proxy_controller.ex
old mode 100755
new mode 100644
index bda5b36..c11484e
--- a/lib/pleroma/web/media_proxy/media_proxy_controller.ex
+++ b/lib/pleroma/web/media_proxy/media_proxy_controller.ex
@@ -56,7 +56,7 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyController do
media_proxy_url = MediaProxy.url(url)
with {:ok, %{status: status} = head_response} when status in 200..299 <-
- Pleroma.HTTP.request("HEAD", media_proxy_url, [], [], pool: :media) do
+ Pleroma.HTTP.request(:head, media_proxy_url, "", [], pool: :media) do
content_type = Tesla.get_header(head_response, "content-type")
content_length = Tesla.get_header(head_response, "content-length")
content_length = content_length && String.to_integer(content_length)
diff --git a/lib/pleroma/web/metadata.ex b/lib/pleroma/web/metadata.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/metadata/player_view.ex b/lib/pleroma/web/metadata/player_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/metadata/providers/feed.ex b/lib/pleroma/web/metadata/providers/feed.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/metadata/providers/open_graph.ex b/lib/pleroma/web/metadata/providers/open_graph.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/metadata/providers/provider.ex b/lib/pleroma/web/metadata/providers/provider.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/metadata/providers/rel_me.ex b/lib/pleroma/web/metadata/providers/rel_me.ex
old mode 100755
new mode 100644
index f0bee85..eabd8cb
--- a/lib/pleroma/web/metadata/providers/rel_me.ex
+++ b/lib/pleroma/web/metadata/providers/rel_me.ex
@@ -8,12 +8,20 @@ defmodule Pleroma.Web.Metadata.Providers.RelMe do
@impl Provider
def build_tags(%{user: user}) do
- bio_tree = Floki.parse_fragment!(user.bio)
+ profile_tree =
+ user.bio
+ |> append_fields_tag(user.fields)
+ |> Floki.parse_fragment!()
- (Floki.attribute(bio_tree, "link[rel~=me]", "href") ++
- Floki.attribute(bio_tree, "a[rel~=me]", "href"))
+ (Floki.attribute(profile_tree, "link[rel~=me]", "href") ++
+ Floki.attribute(profile_tree, "a[rel~=me]", "href"))
|> Enum.map(fn link ->
{:link, [rel: "me", href: link], []}
end)
end
+
+ defp append_fields_tag(bio, fields) do
+ fields
+ |> Enum.reduce(bio, fn %{"value" => v}, res -> res <> v end)
+ end
end
diff --git a/lib/pleroma/web/metadata/providers/restrict_indexing.ex b/lib/pleroma/web/metadata/providers/restrict_indexing.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/metadata/providers/twitter_card.ex b/lib/pleroma/web/metadata/providers/twitter_card.ex
old mode 100755
new mode 100644
index 2dac22e..426022c
--- a/lib/pleroma/web/metadata/providers/twitter_card.ex
+++ b/lib/pleroma/web/metadata/providers/twitter_card.ex
@@ -76,9 +76,10 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCard do
{:meta, [name: "twitter:card", content: "summary_large_image"], []},
{:meta,
[
- name: "twitter:player",
+ name: "twitter:image",
content: MediaProxy.url(url["href"])
- ], []}
+ ], []},
+ {:meta, [name: "twitter:image:alt", content: truncate(attachment["name"])], []}
| acc
]
|> maybe_add_dimensions(url)
@@ -130,4 +131,12 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCard do
metadata
end
end
+
+ defp truncate(nil), do: ""
+
+ defp truncate(text) do
+ # truncate to 420 characters
+ # see https://developer.twitter.com/en/docs/twitter-for-websites/cards/overview/markup
+ Pleroma.Formatter.truncate(text, 420)
+ end
end
diff --git a/lib/pleroma/web/metadata/utils.ex b/lib/pleroma/web/metadata/utils.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/mongoose_im/mongoose_im_controller.ex b/lib/pleroma/web/mongoose_im/mongoose_im_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/multipart.ex b/lib/pleroma/web/multipart.ex
new file mode 100644
index 0000000..e24bb14
--- /dev/null
+++ b/lib/pleroma/web/multipart.ex
@@ -0,0 +1,22 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2023 Pleroma Authors
+# SPDX-License-Identifier: AGPL-3.0-only
+
+#
+defmodule Pleroma.Web.Multipart do
+ @multipart Plug.Parsers.MULTIPART
+
+ def init(opts) do
+ opts
+ end
+
+ def parse(conn, "multipart", subtype, headers, opts) do
+ length = Pleroma.Config.get([:instance, :upload_limit])
+ opts = @multipart.init([length: length] ++ opts)
+ @multipart.parse(conn, "multipart", subtype, headers, opts)
+ end
+
+ def parse(conn, _type, _subtype, _headers, _opts) do
+ {:next, conn}
+ end
+end
diff --git a/lib/pleroma/web/nodeinfo/nodeinfo.ex b/lib/pleroma/web/nodeinfo/nodeinfo.ex
old mode 100755
new mode 100644
index 9e27ac2..4d5a9a5
--- a/lib/pleroma/web/nodeinfo/nodeinfo.ex
+++ b/lib/pleroma/web/nodeinfo/nodeinfo.ex
@@ -6,7 +6,7 @@ defmodule Pleroma.Web.Nodeinfo.Nodeinfo do
alias Pleroma.Config
alias Pleroma.Stats
alias Pleroma.User
- alias Pleroma.Web.Federator.Publisher
+ alias Pleroma.Web.ActivityPub.Publisher
alias Pleroma.Web.MastodonAPI.InstanceView
# returns a nodeinfo 2.0 map, since 2.1 just adds a repository field
diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/o_auth.ex b/lib/pleroma/web/o_auth.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/o_auth/app.ex b/lib/pleroma/web/o_auth/app.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/o_auth/authorization.ex b/lib/pleroma/web/o_auth/authorization.ex
old mode 100755
new mode 100644
index 593d2d6..22e5bfc
--- a/lib/pleroma/web/o_auth/authorization.ex
+++ b/lib/pleroma/web/o_auth/authorization.ex
@@ -28,7 +28,7 @@ defmodule Pleroma.Web.OAuth.Authorization do
end
@spec create_authorization(App.t(), User.t() | %{}, [String.t()] | nil) ::
- {:ok, Authorization.t()} | {:error, Changeset.t()}
+ {:ok, Authorization.t()} | {:error, Ecto.Changeset.t()}
def create_authorization(%App{} = app, %User{} = user, scopes \\ nil) do
%{
scopes: scopes || app.scopes,
@@ -39,7 +39,7 @@ defmodule Pleroma.Web.OAuth.Authorization do
|> Repo.insert()
end
- @spec create_changeset(map()) :: Changeset.t()
+ @spec create_changeset(map()) :: Ecto.Changeset.t()
def create_changeset(attrs \\ %{}) do
%Authorization{}
|> cast(attrs, [:user_id, :app_id, :scopes, :valid_until])
@@ -58,7 +58,7 @@ defmodule Pleroma.Web.OAuth.Authorization do
put_change(changeset, :valid_until, NaiveDateTime.add(NaiveDateTime.utc_now(), lifespan))
end
- @spec use_changeset(Authtorizatiton.t(), map()) :: Changeset.t()
+ @spec use_changeset(Authorization.t(), map()) :: Ecto.Changeset.t()
def use_changeset(%Authorization{} = auth, params) do
auth
|> cast(params, [:used])
@@ -66,7 +66,7 @@ defmodule Pleroma.Web.OAuth.Authorization do
end
@spec use_token(Authorization.t()) ::
- {:ok, Authorization.t()} | {:error, Changeset.t()} | {:error, String.t()}
+ {:ok, Authorization.t()} | {:error, Ecto.Changeset.t()} | {:error, String.t()}
def use_token(%Authorization{used: false, valid_until: valid_until} = auth) do
if NaiveDateTime.diff(NaiveDateTime.utc_now(), valid_until) < 0 do
Repo.update(use_changeset(auth, %{used: true}))
diff --git a/lib/pleroma/web/o_auth/fallback_controller.ex b/lib/pleroma/web/o_auth/fallback_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/o_auth/mfa_controller.ex b/lib/pleroma/web/o_auth/mfa_controller.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/o_auth/mfa_view.ex b/lib/pleroma/web/o_auth/mfa_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/o_auth/o_auth_controller.ex b/lib/pleroma/web/o_auth/o_auth_controller.ex
old mode 100755
new mode 100644
index c1fb4f3..47b0321
--- a/lib/pleroma/web/o_auth/o_auth_controller.ex
+++ b/lib/pleroma/web/o_auth/o_auth_controller.ex
@@ -310,7 +310,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do
after_token_exchange(conn, %{token: token})
else
_error ->
- handle_token_exchange_error(conn, :invalid_credentails)
+ handle_token_exchange_error(conn, :invalid_credentials)
end
end
@@ -610,13 +610,8 @@ defmodule Pleroma.Web.OAuth.OAuthController do
end
end
- @spec validate_scopes(App.t(), map() | list()) ::
+ @spec validate_scopes(App.t(), list()) ::
{:ok, list()} | {:error, :missing_scopes | :unsupported_scopes}
- defp validate_scopes(%App{} = app, params) when is_map(params) do
- requested_scopes = Scopes.fetch_scopes(params, app.scopes)
- validate_scopes(app, requested_scopes)
- end
-
defp validate_scopes(%App{} = app, requested_scopes) when is_list(requested_scopes) do
Scopes.validate(requested_scopes, app.scopes)
end
diff --git a/lib/pleroma/web/o_auth/o_auth_view.ex b/lib/pleroma/web/o_auth/o_auth_view.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/o_auth/scopes.ex b/lib/pleroma/web/o_auth/scopes.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/o_auth/token.ex b/lib/pleroma/web/o_auth/token.ex
old mode 100755
new mode 100644
index 26de7bb..a5ad2e9
--- a/lib/pleroma/web/o_auth/token.ex
+++ b/lib/pleroma/web/o_auth/token.ex
@@ -56,7 +56,8 @@ defmodule Pleroma.Web.OAuth.Token do
|> Repo.find_resource()
end
- @spec exchange_token(App.t(), Authorization.t()) :: {:ok, Token.t()} | {:error, Changeset.t()}
+ @spec exchange_token(App.t(), Authorization.t()) ::
+ {:ok, Token.t()} | {:error, Ecto.Changeset.t()}
def exchange_token(app, auth) do
with {:ok, auth} <- Authorization.use_token(auth),
true <- auth.app_id == app.id do
@@ -95,7 +96,7 @@ defmodule Pleroma.Web.OAuth.Token do
|> validate_required([:valid_until])
end
- @spec create(App.t(), User.t(), map()) :: {:ok, Token} | {:error, Changeset.t()}
+ @spec create(App.t(), User.t(), map()) :: {:ok, Token} | {:error, Ecto.Changeset.t()}
def create(%App{} = app, %User{} = user, attrs \\ %{}) do
with {:ok, token} <- do_create(app, user, attrs) do
if Pleroma.Config.get([:oauth2, :clean_expired_tokens]) do
@@ -137,9 +138,9 @@ defmodule Pleroma.Web.OAuth.Token do
|> Repo.all()
end
- def is_expired?(%__MODULE__{valid_until: valid_until}) do
+ def expired?(%__MODULE__{valid_until: valid_until}) do
NaiveDateTime.diff(NaiveDateTime.utc_now(), valid_until) > 0
end
- def is_expired?(_), do: false
+ def expired?(_), do: false
end
diff --git a/lib/pleroma/web/o_auth/token/query.ex b/lib/pleroma/web/o_auth/token/query.ex
old mode 100755
new mode 100644
index 4a4d2d3..6853ec8
--- a/lib/pleroma/web/o_auth/token/query.ex
+++ b/lib/pleroma/web/o_auth/token/query.ex
@@ -9,10 +9,10 @@ defmodule Pleroma.Web.OAuth.Token.Query do
import Ecto.Query, only: [from: 2]
- @type query :: Ecto.Queryable.t() | Token.t()
-
alias Pleroma.Web.OAuth.Token
+ @type query :: Ecto.Queryable.t() | Token.t()
+
@spec get_by_refresh_token(query, String.t()) :: query
def get_by_refresh_token(query \\ Token, refresh_token) do
from(q in query, where: q.refresh_token == ^refresh_token)
diff --git a/lib/pleroma/web/o_auth/token/strategy/refresh_token.ex b/lib/pleroma/web/o_auth/token/strategy/refresh_token.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/o_auth/token/strategy/revoke.ex b/lib/pleroma/web/o_auth/token/strategy/revoke.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/o_auth/token/utils.ex b/lib/pleroma/web/o_auth/token/utils.ex
old mode 100755
new mode 100644
diff --git a/lib/pleroma/web/o_status/o_status_controller.ex b/lib/pleroma/web/o_status/o_status_controller.ex
old mode 100755
new mode 100644
index ea4994b..ee7ef4a
--- a/lib/pleroma/web/o_status/o_status_controller.ex
+++ b/lib/pleroma/web/o_status/o_status_controller.ex
@@ -37,7 +37,7 @@ defmodule Pleroma.Web.OStatus.OStatusController do
with id <- Endpoint.url() <> conn.request_path,
{_, %Activity{} = activity} <-
{:activity, Activity.get_create_by_object_ap_id_with_object(id)},
- {_, true} <- {:public?, Visibility.is_public?(activity)} do
+ {_, true} <- {:public?, Visibility.public?(activity)} do
redirect(conn, to: "/notice/#{activity.id}")
else
reason when reason in [{:public?, false}, {:activity, nil}] ->
@@ -56,7 +56,7 @@ defmodule Pleroma.Web.OStatus.OStatusController do
def activity(conn, _params) do
with id <- Endpoint.url() <> conn.request_path,
{_, %Activity{} = activity} <- {:activity, Activity.normalize(id)},
- {_, true} <- {:public?, Visibility.is_public?(activity)} do
+ {_, true} <- {:public?, Visibility.public?(activity)} do
redirect(conn, to: "/notice/#{activity.id}")
else
reason when reason in [{:public?, false}, {:activity, nil}] ->
@@ -69,7 +69,7 @@ defmodule Pleroma.Web.OStatus.OStatusController do
def notice(%{assigns: %{format: format}} = conn, %{"id" => id}) do
with {_, %Activity{} = activity} <- {:activity, Activity.get_by_id_with_object(id)},
- {_, true} <- {:public?, Visibility.is_public?(activity)},
+ {_, true} <- {:public?, Visibility.public?(activity)},
%User{} = user <- User.get_cached_by_ap_id(activity.data["actor"]) do
cond do
format in ["json", "activity+json"] ->
@@ -106,13 +106,12 @@ defmodule Pleroma.Web.OStatus.OStatusController do
# Returns an HTML embedded