diff --git a/.circleci/config.yml b/.circleci/config.yml index cb45d00e..d332ec13 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -167,7 +167,7 @@ jobs: - image: circleci/node:8.15.0-stretch steps: - *attach_workspace - - run: ./bin/retry yarn test:jest + - run: ./bin/retry yarn test:jest # : todo : check-i18n: <<: *defaults diff --git a/.eslintrc.js b/.eslintrc.js index f2113e44..e5b812a1 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -5,7 +5,6 @@ module.exports = { browser: true, node: true, es6: true, - jest: true, }, globals: { @@ -199,8 +198,6 @@ module.exports = { { devDependencies: [ 'config/webpack/**', - 'app/javascript/gabsocial/test_setup.js', - 'app/javascript/**/__tests__/**', ], }, ], diff --git a/app/controllers/about_controller.rb b/app/controllers/about_controller.rb index 37c49e92..7cf6068f 100644 --- a/app/controllers/about_controller.rb +++ b/app/controllers/about_controller.rb @@ -13,19 +13,11 @@ class AboutController < ApplicationController end end - def more; end - def terms; end - def privacy; end - def investors; end - def dmca; end - def sales; end - private def new_user User.new.tap do |user| user.build_account - user.build_invite_request end end diff --git a/app/controllers/account_follow_controller.rb b/app/controllers/account_follow_controller.rb deleted file mode 100644 index 185a355f..00000000 --- a/app/controllers/account_follow_controller.rb +++ /dev/null @@ -1,12 +0,0 @@ -# frozen_string_literal: true - -class AccountFollowController < ApplicationController - include AccountControllerConcern - - before_action :authenticate_user! - - def create - FollowService.new.call(current_user.account, @account.acct) - redirect_to account_path(@account) - end -end diff --git a/app/controllers/account_unfollow_controller.rb b/app/controllers/account_unfollow_controller.rb deleted file mode 100644 index 378ec86d..00000000 --- a/app/controllers/account_unfollow_controller.rb +++ /dev/null @@ -1,12 +0,0 @@ -# frozen_string_literal: true - -class AccountUnfollowController < ApplicationController - include AccountControllerConcern - - before_action :authenticate_user! - - def create - UnfollowService.new.call(current_user.account, @account) - redirect_to account_path(@account) - end -end diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb deleted file mode 100644 index a5a17f28..00000000 --- a/app/controllers/accounts_controller.rb +++ /dev/null @@ -1,135 +0,0 @@ -# frozen_string_literal: true - -class AccountsController < ReactController - PAGE_SIZE = 20 - - include AccountControllerConcern - - before_action :set_cache_headers - - def show - respond_to do |format| - format.html do - mark_cacheable! unless user_signed_in? - return process(:react) - end - - format.atom do - mark_cacheable! - - @entries = @account.stream_entries.where(hidden: false).with_includes.paginate_by_max_id(PAGE_SIZE, params[:max_id], params[:since_id]) - render xml: OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.feed(@account, @entries.reject { |entry| entry.status.nil? })) - end - - format.rss do - mark_cacheable! - - @statuses = cache_collection(default_statuses.without_reblogs.without_replies.limit(PAGE_SIZE), Status) - render xml: RSS::AccountSerializer.render(@account, @statuses) - end - - format.json do - mark_cacheable! - - render_cached_json(['activitypub', 'actor', @account], content_type: 'application/activity+json') do - ActiveModelSerializers::SerializableResource.new(@account, serializer: ActivityPub::ActorSerializer, adapter: ActivityPub::Adapter) - end - end - end - end - - private - - def show_pinned_statuses? - [replies_requested?, media_requested?, tag_requested?, params[:max_id].present?, params[:min_id].present?].none? - end - - def filtered_statuses - default_statuses.tap do |statuses| - statuses.merge!(hashtag_scope) if tag_requested? - statuses.merge!(only_media_scope) if media_requested? - statuses.merge!(no_replies_scope) unless replies_requested? - statuses.merge!(only_replies_scope) unless comments_only_requested? - end - end - - def default_statuses - @account.statuses.where(visibility: [:public, :unlisted]) - end - - def only_media_scope - Status.where(id: account_media_status_ids) - end - - def account_media_status_ids - @account.media_attachments.attached.reorder(nil).select(:status_id).distinct - end - - def no_replies_scope - Status.without_replies - end - - def only_replies_scope - Status.only_replies - end - - def hashtag_scope - tag = Tag.find_normalized(params[:tag]) - - if tag - Status.tagged_with(tag.id) - else - Status.none - end - end - - def username_param - params[:username] - end - - def older_url - pagination_url(max_id: @statuses.last.id) - end - - def newer_url - pagination_url(min_id: @statuses.first.id) - end - - def pagination_url(max_id: nil, min_id: nil) - if tag_requested? - short_account_tag_url(@account, params[:tag], max_id: max_id, min_id: min_id) - elsif media_requested? - short_account_media_url(@account, max_id: max_id, min_id: min_id) - elsif replies_requested? - short_account_with_replies_url(@account, max_id: max_id, min_id: min_id) - elsif comments_only_requested? - short_account_comments_only_url(@account, max_id: max_id, min_id: min_id) - else - short_account_url(@account, max_id: max_id, min_id: min_id) - end - end - - def media_requested? - request.path.ends_with?('/media') - end - - def replies_requested? - request.path.ends_with?('/with_replies') - end - - def comments_only_requested? - request.path.ends_with?('/comments_only') - end - - def tag_requested? - request.path.ends_with?(Addressable::URI.parse("/tagged/#{params[:tag]}").normalize) - end - - def filtered_status_page(params) - if params[:min_id].present? - filtered_statuses.paginate_by_min_id(PAGE_SIZE, params[:min_id]).reverse - else - filtered_statuses.paginate_by_max_id(PAGE_SIZE, params[:max_id], params[:since_id]).to_a - end - end -end diff --git a/app/controllers/admin/accounts_controller.rb b/app/controllers/admin/accounts_controller.rb index 9e17d789..a48806a6 100644 --- a/app/controllers/admin/accounts_controller.rb +++ b/app/controllers/admin/accounts_controller.rb @@ -2,8 +2,8 @@ module Admin class AccountsController < BaseController - before_action :set_account, only: [:show, :subscribe, :unsubscribe, :redownload, :remove_avatar, :remove_header, :enable, :unsilence, :unsuspend, :memorialize, :approve, :reject, :verify, :unverify, :add_donor_badge, :remove_donor_badge, :add_investor_badge, :remove_investor_badge, :edit_pro, :save_pro, :edit, :update] - before_action :require_remote_account!, only: [:subscribe, :unsubscribe, :redownload] + before_action :set_account, only: [:show, :redownload, :remove_avatar, :remove_header, :enable, :unsilence, :unsuspend, :memorialize, :approve, :reject, :verify, :unverify, :add_donor_badge, :remove_donor_badge, :add_investor_badge, :remove_investor_badge, :edit_pro, :save_pro, :edit, :update] + before_action :require_remote_account!, only: [:redownload] before_action :require_local_account!, only: [:enable, :memorialize, :approve, :reject] def index @@ -19,18 +19,6 @@ module Admin @warnings = @account.targeted_account_warnings.latest.custom end - def subscribe - authorize @account, :subscribe? - Pubsubhubbub::SubscribeWorker.perform_async(@account.id) - redirect_to admin_account_path(@account.id) - end - - def unsubscribe - authorize @account, :unsubscribe? - Pubsubhubbub::UnsubscribeWorker.perform_async(@account.id) - redirect_to admin_account_path(@account.id) - end - def memorialize authorize @account, :memorialize? @account.memorialize! @@ -134,9 +122,6 @@ module Admin def redownload authorize @account, :redownload? - @account.update!(last_webfingered_at: nil) - ResolveAccountService.new.call(@account) - redirect_to admin_account_path(@account.id) end diff --git a/app/controllers/admin/custom_emojis_controller.rb b/app/controllers/admin/custom_emojis_controller.rb index f7769916..051f4146 100644 --- a/app/controllers/admin/custom_emojis_controller.rb +++ b/app/controllers/admin/custom_emojis_controller.rb @@ -51,23 +51,6 @@ module Admin redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params) end - def copy - authorize @custom_emoji, :copy? - - emoji = CustomEmoji.find_or_initialize_by(domain: nil, - shortcode: @custom_emoji.shortcode) - emoji.image = @custom_emoji.image - - if emoji.save - log_action :create, emoji - flash[:notice] = I18n.t('admin.custom_emojis.copied_msg') - else - flash[:alert] = I18n.t('admin.custom_emojis.copy_failed_msg') - end - - redirect_to admin_custom_emojis_path(page: params[:page], **@filter_params) - end - def enable authorize @custom_emoji, :enable? @custom_emoji.update!(disabled: false) diff --git a/app/controllers/admin/dashboard_controller.rb b/app/controllers/admin/dashboard_controller.rb index 44f20213..fd7c9d6f 100644 --- a/app/controllers/admin/dashboard_controller.rb +++ b/app/controllers/admin/dashboard_controller.rb @@ -8,11 +8,7 @@ module Admin @registrations_week = Redis.current.get("activity:accounts:local:#{current_week}") || 0 @logins_week = Redis.current.pfcount("activity:logins:#{current_week}") @interactions_week = Redis.current.get("activity:interactions:#{current_week}") || 0 - @relay_enabled = Relay.enabled.exists? @single_user_mode = Rails.configuration.x.single_user_mode - @registrations_enabled = Setting.registrations_mode != 'none' - @deletions_enabled = Setting.open_deletion - @invites_enabled = Setting.min_invite_role == 'user' @search_enabled = Chewy.enabled? @version = GabSocial::Version.to_s @database_version = ActiveRecord::Base.connection.execute('SELECT VERSION()').first['version'].match(/\A(?:PostgreSQL |)([^\s]+).*\z/)[1] @@ -27,9 +23,6 @@ module Admin @saml_enabled = ENV['SAML_ENABLED'] == 'true' @pam_enabled = ENV['PAM_ENABLED'] == 'true' @hidden_service = ENV['ALLOW_ACCESS_TO_HIDDEN_SERVICE'] == 'true' - @trending_hashtags = TrendingTags.get(7) - @profile_directory = Setting.profile_directory - @timeline_preview = Setting.timeline_preview end private diff --git a/app/controllers/admin/domain_blocks_controller.rb b/app/controllers/admin/domain_blocks_controller.rb deleted file mode 100644 index 71597763..00000000 --- a/app/controllers/admin/domain_blocks_controller.rb +++ /dev/null @@ -1,59 +0,0 @@ -# frozen_string_literal: true - -module Admin - class DomainBlocksController < BaseController - before_action :set_domain_block, only: [:show, :destroy] - - def new - authorize :domain_block, :create? - @domain_block = DomainBlock.new(domain: params[:_domain]) - end - - def create - authorize :domain_block, :create? - - @domain_block = DomainBlock.new(resource_params) - existing_domain_block = resource_params[:domain].present? ? DomainBlock.find_by(domain: resource_params[:domain]) : nil - - if existing_domain_block.present? && !@domain_block.stricter_than?(existing_domain_block) - @domain_block.save - flash[:alert] = I18n.t('admin.domain_blocks.existing_domain_block_html', name: existing_domain_block.domain, unblock_url: admin_domain_block_path(existing_domain_block)).html_safe # rubocop:disable Rails/OutputSafety - @domain_block.errors[:domain].clear - render :new - else - if existing_domain_block.present? - @domain_block = existing_domain_block - @domain_block.update(resource_params) - end - if @domain_block.save - DomainBlockWorker.perform_async(@domain_block.id) - log_action :create, @domain_block - redirect_to admin_instances_path(limited: '1'), notice: I18n.t('admin.domain_blocks.created_msg') - else - render :new - end - end - end - - def show - authorize @domain_block, :show? - end - - def destroy - authorize @domain_block, :destroy? - UnblockDomainService.new.call(@domain_block) - log_action :destroy, @domain_block - redirect_to admin_instances_path(limited: '1'), notice: I18n.t('admin.domain_blocks.destroyed_msg') - end - - private - - def set_domain_block - @domain_block = DomainBlock.find(params[:id]) - end - - def resource_params - params.require(:domain_block).permit(:domain, :severity, :reject_media, :reject_reports) - end - end -end diff --git a/app/controllers/admin/instances_controller.rb b/app/controllers/admin/instances_controller.rb deleted file mode 100644 index 6dd659a3..00000000 --- a/app/controllers/admin/instances_controller.rb +++ /dev/null @@ -1,44 +0,0 @@ -# frozen_string_literal: true - -module Admin - class InstancesController < BaseController - def index - authorize :instance, :index? - - @instances = ordered_instances - end - - def show - authorize :instance, :show? - - @instance = Instance.new(Account.by_domain_accounts.find_by(domain: params[:id]) || DomainBlock.find_by!(domain: params[:id])) - @following_count = Follow.where(account: Account.where(domain: params[:id])).count - @followers_count = Follow.where(target_account: Account.where(domain: params[:id])).count - @reports_count = Report.where(target_account: Account.where(domain: params[:id])).count - @blocks_count = Block.where(target_account: Account.where(domain: params[:id])).count - @available = DeliveryFailureTracker.available?(Account.select(:shared_inbox_url).where(domain: params[:id]).first&.shared_inbox_url) - @media_storage = MediaAttachment.where(account: Account.where(domain: params[:id])).sum(:file_file_size) - @domain_block = DomainBlock.find_by(domain: params[:id]) - end - - private - - def filtered_instances - InstanceFilter.new(filter_params).results - end - - def paginated_instances - filtered_instances.page(params[:page]) - end - - helper_method :paginated_instances - - def ordered_instances - paginated_instances.map { |resource| Instance.new(resource) } - end - - def filter_params - params.permit(:limited, :by_domain) - end - end -end diff --git a/app/controllers/admin/invites_controller.rb b/app/controllers/admin/invites_controller.rb deleted file mode 100644 index 44a8eec7..00000000 --- a/app/controllers/admin/invites_controller.rb +++ /dev/null @@ -1,53 +0,0 @@ -# frozen_string_literal: true - -module Admin - class InvitesController < BaseController - def index - authorize :invite, :index? - - @invites = filtered_invites.includes(user: :account).page(params[:page]) - @invite = Invite.new - end - - def create - authorize :invite, :create? - - @invite = Invite.new(resource_params) - @invite.user = current_user - - if @invite.save - redirect_to admin_invites_path - else - @invites = Invite.page(params[:page]) - render :index - end - end - - def destroy - @invite = Invite.find(params[:id]) - authorize @invite, :destroy? - @invite.expire! - redirect_to admin_invites_path - end - - def deactivate_all - authorize :invite, :deactivate_all? - Invite.available.in_batches.update_all(expires_at: Time.now.utc) - redirect_to admin_invites_path - end - - private - - def resource_params - params.require(:invite).permit(:max_uses, :expires_in) - end - - def filtered_invites - InviteFilter.new(filter_params).results - end - - def filter_params - params.permit(:available, :expired) - end - end -end diff --git a/app/controllers/admin/pending_accounts_controller.rb b/app/controllers/admin/pending_accounts_controller.rb deleted file mode 100644 index b62a9bc8..00000000 --- a/app/controllers/admin/pending_accounts_controller.rb +++ /dev/null @@ -1,52 +0,0 @@ -# frozen_string_literal: true - -module Admin - class PendingAccountsController < BaseController - before_action :set_accounts, only: :index - - def index - @form = Form::AccountBatch.new - end - - def batch - @form = Form::AccountBatch.new(form_account_batch_params.merge(current_account: current_account, action: action_from_button)) - @form.save - rescue ActionController::ParameterMissing - flash[:alert] = I18n.t('admin.accounts.no_account_selected') - ensure - redirect_to admin_pending_accounts_path(current_params) - end - - def approve_all - Form::AccountBatch.new(current_account: current_account, account_ids: User.pending.pluck(:account_id), action: 'approve').save - redirect_to admin_pending_accounts_path(current_params) - end - - def reject_all - Form::AccountBatch.new(current_account: current_account, account_ids: User.pending.pluck(:account_id), action: 'reject').save - redirect_to admin_pending_accounts_path(current_params) - end - - private - - def set_accounts - @accounts = Account.joins(:user).merge(User.pending.recent).includes(user: :invite_request).page(params[:page]) - end - - def form_account_batch_params - params.require(:form_account_batch).permit(:action, account_ids: []) - end - - def action_from_button - if params[:approve] - 'approve' - elsif params[:reject] - 'reject' - end - end - - def current_params - params.slice(:page).permit(:page) - end - end -end diff --git a/app/controllers/admin/relays_controller.rb b/app/controllers/admin/relays_controller.rb deleted file mode 100644 index 1b02d3c3..00000000 --- a/app/controllers/admin/relays_controller.rb +++ /dev/null @@ -1,58 +0,0 @@ -# frozen_string_literal: true - -module Admin - class RelaysController < BaseController - before_action :set_relay, except: [:index, :new, :create] - - def index - authorize :relay, :update? - @relays = Relay.all - end - - def new - authorize :relay, :update? - @relay = Relay.new(inbox_url: Relay::PRESET_RELAY) - end - - def create - authorize :relay, :update? - - @relay = Relay.new(resource_params) - - if @relay.save - @relay.enable! - redirect_to admin_relays_path - else - render action: :new - end - end - - def destroy - authorize :relay, :update? - @relay.destroy - redirect_to admin_relays_path - end - - def enable - authorize :relay, :update? - @relay.enable! - redirect_to admin_relays_path - end - - def disable - authorize :relay, :update? - @relay.disable! - redirect_to admin_relays_path - end - - private - - def set_relay - @relay = Relay.find(params[:id]) - end - - def resource_params - params.require(:relay).permit(:inbox_url) - end - end -end diff --git a/app/controllers/admin/subscriptions_controller.rb b/app/controllers/admin/subscriptions_controller.rb deleted file mode 100644 index 40500ef4..00000000 --- a/app/controllers/admin/subscriptions_controller.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -module Admin - class SubscriptionsController < BaseController - def index - authorize :subscription, :index? - @subscriptions = ordered_subscriptions.page(requested_page) - end - - private - - def ordered_subscriptions - Subscription.order(id: :desc).includes(:account) - end - - def requested_page - params[:page].to_i - end - end -end diff --git a/app/controllers/admin/tags_controller.rb b/app/controllers/admin/tags_controller.rb deleted file mode 100644 index e9f4f2cf..00000000 --- a/app/controllers/admin/tags_controller.rb +++ /dev/null @@ -1,44 +0,0 @@ -# frozen_string_literal: true - -module Admin - class TagsController < BaseController - before_action :set_tags, only: :index - before_action :set_tag, except: :index - before_action :set_filter_params - - def index - authorize :tag, :index? - end - - def hide - authorize @tag, :hide? - @tag.account_tag_stat.update!(hidden: true) - redirect_to admin_tags_path(@filter_params) - end - - def unhide - authorize @tag, :unhide? - @tag.account_tag_stat.update!(hidden: false) - redirect_to admin_tags_path(@filter_params) - end - - private - - def set_tags - @tags = Tag.discoverable - @tags.merge!(Tag.hidden) if filter_params[:hidden] - end - - def set_tag - @tag = Tag.find(params[:id]) - end - - def set_filter_params - @filter_params = filter_params.to_hash.symbolize_keys - end - - def filter_params - params.permit(:hidden) - end - end -end diff --git a/app/controllers/api/base_controller.rb b/app/controllers/api/base_controller.rb index e8b2872c..260909cc 100644 --- a/app/controllers/api/base_controller.rb +++ b/app/controllers/api/base_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class Api::BaseController < ApplicationController - DEFAULT_STATUSES_LIMIT = 20 + DEFAULT_STATUSES_LIMIT = 18 DEFAULT_ACCOUNTS_LIMIT = 40 include RateLimitHeaders @@ -77,8 +77,6 @@ class Api::BaseController < ApplicationController # : todo : when figure out email/catpcha, put this back # elsif !current_user.confirmed? # render json: { error: 'Your login is missing a confirmed e-mail address' }, status: 403 - elsif !current_user.approved? - render json: { error: 'Your login is currently pending approval' }, status: 403 else set_user_activity end diff --git a/app/controllers/api/oembed_controller.rb b/app/controllers/api/oembed_controller.rb index 37a163cd..72b75f91 100644 --- a/app/controllers/api/oembed_controller.rb +++ b/app/controllers/api/oembed_controller.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true class Api::OEmbedController < Api::BaseController - respond_to :json def show @status = status_finder.status diff --git a/app/controllers/api/proofs_controller.rb b/app/controllers/api/proofs_controller.rb index a84ad201..5720e27b 100644 --- a/app/controllers/api/proofs_controller.rb +++ b/app/controllers/api/proofs_controller.rb @@ -3,7 +3,6 @@ class Api::ProofsController < Api::BaseController before_action :set_account before_action :set_provider - before_action :check_account_approval before_action :check_account_suspension def index @@ -20,10 +19,6 @@ class Api::ProofsController < Api::BaseController @account = Account.find_local!(params[:username]) end - def check_account_approval - not_found if @account.user_pending? - end - def check_account_suspension gone if @account.suspended? end diff --git a/app/controllers/api/push_controller.rb b/app/controllers/api/push_controller.rb deleted file mode 100644 index e04d1912..00000000 --- a/app/controllers/api/push_controller.rb +++ /dev/null @@ -1,73 +0,0 @@ -# frozen_string_literal: true - -class Api::PushController < Api::BaseController - include SignatureVerification - - def update - response, status = process_push_request - render plain: response, status: status - end - - private - - def process_push_request - case hub_mode - when 'subscribe' - Pubsubhubbub::SubscribeService.new.call(account_from_topic, hub_callback, hub_secret, hub_lease_seconds, verified_domain) - when 'unsubscribe' - Pubsubhubbub::UnsubscribeService.new.call(account_from_topic, hub_callback) - else - ["Unknown mode: #{hub_mode}", 422] - end - end - - def hub_mode - params['hub.mode'] - end - - def hub_topic - params['hub.topic'] - end - - def hub_callback - params['hub.callback'] - end - - def hub_lease_seconds - params['hub.lease_seconds'] - end - - def hub_secret - params['hub.secret'] - end - - def account_from_topic - if hub_topic.present? && local_domain? && account_feed_path? - Account.find_local(hub_topic_params[:username]) - end - end - - def hub_topic_params - @_hub_topic_params ||= Rails.application.routes.recognize_path(hub_topic_uri.path) - end - - def hub_topic_uri - @_hub_topic_uri ||= Addressable::URI.parse(hub_topic).normalize - end - - def local_domain? - TagManager.instance.web_domain?(hub_topic_domain) - end - - def verified_domain - return signed_request_account.domain if signed_request_account - end - - def hub_topic_domain - hub_topic_uri.host + (hub_topic_uri.port ? ":#{hub_topic_uri.port}" : '') - end - - def account_feed_path? - hub_topic_params[:controller] == 'accounts' && hub_topic_params[:action] == 'show' && hub_topic_params[:format] == 'atom' - end -end diff --git a/app/controllers/api/salmon_controller.rb b/app/controllers/api/salmon_controller.rb deleted file mode 100644 index ac5f3268..00000000 --- a/app/controllers/api/salmon_controller.rb +++ /dev/null @@ -1,37 +0,0 @@ -# frozen_string_literal: true - -class Api::SalmonController < Api::BaseController - include SignatureVerification - - before_action :set_account - respond_to :txt - - def update - if verify_payload? - process_salmon - head 202 - elsif payload.present? - render plain: signature_verification_failure_reason, status: 401 - else - head 400 - end - end - - private - - def set_account - @account = Account.find(params[:id]) - end - - def payload - @_payload ||= request.body.read - end - - def verify_payload? - payload.present? && VerifySalmonService.new.call(payload) - end - - def process_salmon - SalmonWorker.perform_async(@account.id, payload.force_encoding('UTF-8')) - end -end diff --git a/app/controllers/api/subscriptions_controller.rb b/app/controllers/api/subscriptions_controller.rb deleted file mode 100644 index 89007f3d..00000000 --- a/app/controllers/api/subscriptions_controller.rb +++ /dev/null @@ -1,51 +0,0 @@ -# frozen_string_literal: true - -class Api::SubscriptionsController < Api::BaseController - before_action :set_account - respond_to :txt - - def show - if subscription.valid?(params['hub.topic']) - @account.update(subscription_expires_at: future_expires) - render plain: encoded_challenge, status: 200 - else - head 404 - end - end - - def update - if subscription.verify(body, request.headers['HTTP_X_HUB_SIGNATURE']) - ProcessingWorker.perform_async(@account.id, body.force_encoding('UTF-8')) - end - - head 200 - end - - private - - def subscription - @_subscription ||= @account.subscription( - api_subscription_url(@account.id) - ) - end - - def body - @_body ||= request.body.read - end - - def encoded_challenge - HTMLEntities.new.encode(params['hub.challenge']) - end - - def future_expires - Time.now.utc + lease_seconds_or_default - end - - def lease_seconds_or_default - (params['hub.lease_seconds'] || 1.day).to_i.seconds - end - - def set_account - @account = Account.find(params[:id]) - end -end diff --git a/app/controllers/api/v1/account_by_username_controller.rb b/app/controllers/api/v1/account_by_username_controller.rb index 5246f800..63a34353 100644 --- a/app/controllers/api/v1/account_by_username_controller.rb +++ b/app/controllers/api/v1/account_by_username_controller.rb @@ -5,8 +5,6 @@ class Api::V1::AccountByUsernameController < EmptyController before_action :check_account_suspension before_action :check_account_local - respond_to :json - def show render json: @account, serializer: REST::AccountSerializer end diff --git a/app/controllers/api/v1/accounts/credentials_controller.rb b/app/controllers/api/v1/accounts/credentials_controller.rb index 4659fdb5..0fb7d3ca 100644 --- a/app/controllers/api/v1/accounts/credentials_controller.rb +++ b/app/controllers/api/v1/accounts/credentials_controller.rb @@ -14,7 +14,6 @@ class Api::V1::Accounts::CredentialsController < Api::BaseController @account = current_account UpdateAccountService.new.call(@account, account_params, raise_error: true) UserSettingsDecorator.new(current_user).update(user_settings_params) if user_settings_params - ActivityPub::UpdateDistributionWorker.perform_async(@account.id) render json: @account, serializer: REST::CredentialAccountSerializer end diff --git a/app/controllers/api/v1/accounts/follower_accounts_controller.rb b/app/controllers/api/v1/accounts/follower_accounts_controller.rb index 2dabb839..c85db5f7 100644 --- a/app/controllers/api/v1/accounts/follower_accounts_controller.rb +++ b/app/controllers/api/v1/accounts/follower_accounts_controller.rb @@ -5,8 +5,6 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController before_action :set_account after_action :insert_pagination_headers - respond_to :json - def index @accounts = load_accounts render json: @accounts, each_serializer: REST::AccountSerializer diff --git a/app/controllers/api/v1/accounts/following_accounts_controller.rb b/app/controllers/api/v1/accounts/following_accounts_controller.rb index 44e89804..6d0247e3 100644 --- a/app/controllers/api/v1/accounts/following_accounts_controller.rb +++ b/app/controllers/api/v1/accounts/following_accounts_controller.rb @@ -5,8 +5,6 @@ class Api::V1::Accounts::FollowingAccountsController < Api::BaseController before_action :set_account after_action :insert_pagination_headers - respond_to :json - def index @accounts = load_accounts render json: @accounts, each_serializer: REST::AccountSerializer @@ -25,6 +23,7 @@ class Api::V1::Accounts::FollowingAccountsController < Api::BaseController end def hide_results? + # : todo : where tf is this? (@account.user_hides_network? && current_account.id != @account.id) || (current_account && @account.blocking?(current_account)) end diff --git a/app/controllers/api/v1/accounts/identity_proofs_controller.rb b/app/controllers/api/v1/accounts/identity_proofs_controller.rb deleted file mode 100644 index dee28977..00000000 --- a/app/controllers/api/v1/accounts/identity_proofs_controller.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -class Api::V1::Accounts::IdentityProofsController < Api::BaseController - before_action :set_account - - respond_to :json - - def index - @proofs = @account.identity_proofs.active - render json: @proofs, each_serializer: REST::IdentityProofSerializer - end - - private - - def set_account - @account = Account.find(params[:account_id]) - end -end diff --git a/app/controllers/api/v1/accounts/lists_controller.rb b/app/controllers/api/v1/accounts/lists_controller.rb index 72392453..ccb751f8 100644 --- a/app/controllers/api/v1/accounts/lists_controller.rb +++ b/app/controllers/api/v1/accounts/lists_controller.rb @@ -5,8 +5,6 @@ class Api::V1::Accounts::ListsController < Api::BaseController before_action :require_user! before_action :set_account - respond_to :json - def index @lists = @account.lists.where(account: current_account) render json: @lists, each_serializer: REST::ListSerializer diff --git a/app/controllers/api/v1/accounts/pins_controller.rb b/app/controllers/api/v1/accounts/pins_controller.rb deleted file mode 100644 index 0a0239c4..00000000 --- a/app/controllers/api/v1/accounts/pins_controller.rb +++ /dev/null @@ -1,32 +0,0 @@ -# frozen_string_literal: true - -class Api::V1::Accounts::PinsController < Api::BaseController - include Authorization - - before_action -> { doorkeeper_authorize! :write, :'write:accounts' } - before_action :require_user! - before_action :set_account - - respond_to :json - - def create - AccountPin.create!(account: current_account, target_account: @account) - render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships_presenter - end - - def destroy - pin = AccountPin.find_by(account: current_account, target_account: @account) - pin&.destroy! - render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships_presenter - end - - private - - def set_account - @account = Account.find(params[:account_id]) - end - - def relationships_presenter - AccountRelationshipsPresenter.new([@account.id], current_user.account_id) - end -end diff --git a/app/controllers/api/v1/accounts/relationships_controller.rb b/app/controllers/api/v1/accounts/relationships_controller.rb index ab8a0461..1d3992a2 100644 --- a/app/controllers/api/v1/accounts/relationships_controller.rb +++ b/app/controllers/api/v1/accounts/relationships_controller.rb @@ -4,8 +4,6 @@ class Api::V1::Accounts::RelationshipsController < Api::BaseController before_action -> { doorkeeper_authorize! :read, :'read:follows' } before_action :require_user! - respond_to :json - def index accounts = Account.where(id: account_ids).select('id') # .where doesn't guarantee that our results are in the same order diff --git a/app/controllers/api/v1/accounts/search_controller.rb b/app/controllers/api/v1/accounts/search_controller.rb deleted file mode 100644 index 4217b527..00000000 --- a/app/controllers/api/v1/accounts/search_controller.rb +++ /dev/null @@ -1,26 +0,0 @@ -# frozen_string_literal: true - -class Api::V1::Accounts::SearchController < Api::BaseController - before_action -> { doorkeeper_authorize! :read, :'read:accounts' } - before_action :require_user! - - respond_to :json - - def show - @accounts = account_search - render json: @accounts, each_serializer: REST::AccountSerializer - end - - private - - def account_search - AccountSearchService.new.call( - params[:q], - current_account, - limit: limit_param(DEFAULT_ACCOUNTS_LIMIT), - resolve: truthy_param?(:resolve), - following: truthy_param?(:following), - offset: params[:offset] - ) - end -end diff --git a/app/controllers/api/v1/accounts/statuses_controller.rb b/app/controllers/api/v1/accounts/statuses_controller.rb index 76b857a4..b4563d28 100644 --- a/app/controllers/api/v1/accounts/statuses_controller.rb +++ b/app/controllers/api/v1/accounts/statuses_controller.rb @@ -5,11 +5,12 @@ class Api::V1::Accounts::StatusesController < Api::BaseController before_action :set_account after_action :insert_pagination_headers - respond_to :json - def index @statuses = load_statuses - render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id) + render json: @statuses, + each_serializer: REST::StatusSerializer, + account_id: params[:account_id], + relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id) end private diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb index b0c62778..09ae8701 100644 --- a/app/controllers/api/v1/accounts_controller.rb +++ b/app/controllers/api/v1/accounts_controller.rb @@ -10,9 +10,6 @@ class Api::V1::AccountsController < Api::BaseController before_action :require_user!, except: [:show, :create] before_action :set_account, except: [:create] before_action :check_account_suspension, only: [:show] - before_action :check_enabled_registrations, only: [:create] - - respond_to :json def show render json: @account, serializer: REST::AccountSerializer @@ -78,12 +75,4 @@ class Api::V1::AccountsController < Api::BaseController def account_params params.permit(:username, :email, :password, :agreement, :locale) end - - def check_enabled_registrations - forbidden if single_user_mode? || !allowed_registrations? - end - - def allowed_registrations? - Setting.registrations_mode != 'none' - end end diff --git a/app/controllers/api/v1/apps/credentials_controller.rb b/app/controllers/api/v1/apps/credentials_controller.rb index 8b63d049..0475b2d4 100644 --- a/app/controllers/api/v1/apps/credentials_controller.rb +++ b/app/controllers/api/v1/apps/credentials_controller.rb @@ -3,8 +3,6 @@ class Api::V1::Apps::CredentialsController < Api::BaseController before_action -> { doorkeeper_authorize! :read } - respond_to :json - def show render json: doorkeeper_token.application, serializer: REST::ApplicationSerializer, fields: %i(name website vapid_key) end diff --git a/app/controllers/api/v1/blocks_controller.rb b/app/controllers/api/v1/blocks_controller.rb index 4cff04ca..a2baeef9 100644 --- a/app/controllers/api/v1/blocks_controller.rb +++ b/app/controllers/api/v1/blocks_controller.rb @@ -5,8 +5,6 @@ class Api::V1::BlocksController < Api::BaseController before_action :require_user! after_action :insert_pagination_headers - respond_to :json - def index @accounts = load_accounts render json: @accounts, each_serializer: REST::AccountSerializer diff --git a/app/controllers/api/v1/bookmarks_controller.rb b/app/controllers/api/v1/bookmarks_controller.rb index b3ef2fd9..f6aed818 100644 --- a/app/controllers/api/v1/bookmarks_controller.rb +++ b/app/controllers/api/v1/bookmarks_controller.rb @@ -5,8 +5,6 @@ class Api::V1::BookmarksController < Api::BaseController before_action :require_user! after_action :insert_pagination_headers - respond_to :json - def index @statuses = [] if current_account.is_pro diff --git a/app/controllers/api/v1/conversations_controller.rb b/app/controllers/api/v1/conversations_controller.rb deleted file mode 100644 index b19f27eb..00000000 --- a/app/controllers/api/v1/conversations_controller.rb +++ /dev/null @@ -1,71 +0,0 @@ -# frozen_string_literal: true - -class Api::V1::ConversationsController < Api::BaseController - LIMIT = 20 - - before_action -> { doorkeeper_authorize! :read, :'read:statuses' }, only: :index - before_action -> { doorkeeper_authorize! :write, :'write:conversations' }, except: :index - before_action :require_user! - before_action :set_conversation, except: :index - after_action :insert_pagination_headers, only: :index - - respond_to :json - - def index - @conversations = paginated_conversations - render json: @conversations, each_serializer: REST::ConversationSerializer - end - - def read - @conversation.update!(unread: false) - render json: @conversation, serializer: REST::ConversationSerializer - end - - def destroy - @conversation.destroy! - render_empty - end - - private - - def set_conversation - @conversation = AccountConversation.where(account: current_account).find(params[:id]) - end - - def paginated_conversations - AccountConversation.where(account: current_account) - .paginate_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id)) - end - - def insert_pagination_headers - set_pagination_headers(next_path, prev_path) - end - - def next_path - if records_continue? - api_v1_conversations_url pagination_params(max_id: pagination_max_id) - end - end - - def prev_path - unless @conversations.empty? - api_v1_conversations_url pagination_params(min_id: pagination_since_id) - end - end - - def pagination_max_id - @conversations.last.last_status_id - end - - def pagination_since_id - @conversations.first.last_status_id - end - - def records_continue? - @conversations.size == limit_param(LIMIT) - end - - def pagination_params(core_params) - params.slice(:limit).permit(:limit).merge(core_params) - end -end diff --git a/app/controllers/api/v1/custom_emojis_controller.rb b/app/controllers/api/v1/custom_emojis_controller.rb index 3589d1e3..ef9d6f96 100644 --- a/app/controllers/api/v1/custom_emojis_controller.rb +++ b/app/controllers/api/v1/custom_emojis_controller.rb @@ -1,8 +1,10 @@ # frozen_string_literal: true class Api::V1::CustomEmojisController < EmptyController + def index - data = ActiveModelSerializers::SerializableResource.new(CustomEmoji.local.where(disabled: false), each_serializer: REST::CustomEmojiSerializer) + data = ActiveModelSerializers::SerializableResource.new(CustomEmoji.local, each_serializer: REST::CustomEmojiSerializer) render json: data.to_json, content_type: 'application/json' end + end diff --git a/app/controllers/api/v1/domain_blocks_controller.rb b/app/controllers/api/v1/domain_blocks_controller.rb deleted file mode 100644 index af9e7a20..00000000 --- a/app/controllers/api/v1/domain_blocks_controller.rb +++ /dev/null @@ -1,78 +0,0 @@ -# frozen_string_literal: true - -class Api::V1::DomainBlocksController < Api::BaseController - BLOCK_LIMIT = 100 - - before_action -> { doorkeeper_authorize! :follow, :'read:blocks' }, only: :show - before_action -> { doorkeeper_authorize! :follow, :'write:blocks' }, except: :show - before_action :require_user! - after_action :insert_pagination_headers, only: :show - - respond_to :json - - def show - @blocks = load_domain_blocks - render json: @blocks.map(&:domain) - end - - def create - current_account.block_domain!(domain_block_params[:domain]) - AfterAccountDomainBlockWorker.perform_async(current_account.id, domain_block_params[:domain]) - render_empty - end - - def destroy - current_account.unblock_domain!(domain_block_params[:domain]) - render_empty - end - - private - - def load_domain_blocks - account_domain_blocks.paginate_by_max_id( - limit_param(BLOCK_LIMIT), - params[:max_id], - params[:since_id] - ) - end - - def account_domain_blocks - current_account.domain_blocks - end - - def insert_pagination_headers - set_pagination_headers(next_path, prev_path) - end - - def next_path - if records_continue? - api_v1_domain_blocks_url pagination_params(max_id: pagination_max_id) - end - end - - def prev_path - unless @blocks.empty? - api_v1_domain_blocks_url pagination_params(since_id: pagination_since_id) - end - end - - def pagination_max_id - @blocks.last.id - end - - def pagination_since_id - @blocks.first.id - end - - def records_continue? - @blocks.size == limit_param(BLOCK_LIMIT) - end - - def pagination_params(core_params) - params.slice(:limit).permit(:limit).merge(core_params) - end - - def domain_block_params - params.permit(:domain) - end -end diff --git a/app/controllers/api/v1/endorsements_controller.rb b/app/controllers/api/v1/endorsements_controller.rb deleted file mode 100644 index 2770c7ae..00000000 --- a/app/controllers/api/v1/endorsements_controller.rb +++ /dev/null @@ -1,72 +0,0 @@ -# frozen_string_literal: true - -class Api::V1::EndorsementsController < Api::BaseController - before_action -> { doorkeeper_authorize! :read, :'read:accounts' } - before_action :require_user! - after_action :insert_pagination_headers - - respond_to :json - - def index - @accounts = load_accounts - render json: @accounts, each_serializer: REST::AccountSerializer - end - - private - - def load_accounts - if unlimited? - endorsed_accounts.all - else - endorsed_accounts.paginate_by_max_id( - limit_param(DEFAULT_ACCOUNTS_LIMIT), - params[:max_id], - params[:since_id] - ) - end - end - - def endorsed_accounts - current_account.endorsed_accounts.includes(:account_stat) - end - - def insert_pagination_headers - set_pagination_headers(next_path, prev_path) - end - - def next_path - return if unlimited? - - if records_continue? - api_v1_endorsements_url pagination_params(max_id: pagination_max_id) - end - end - - def prev_path - return if unlimited? - - unless @accounts.empty? - api_v1_endorsements_url pagination_params(since_id: pagination_since_id) - end - end - - def pagination_max_id - @accounts.last.id - end - - def pagination_since_id - @accounts.first.id - end - - def records_continue? - @accounts.size == limit_param(DEFAULT_ACCOUNTS_LIMIT) - end - - def pagination_params(core_params) - params.slice(:limit).permit(:limit).merge(core_params) - end - - def unlimited? - params[:limit] == '0' - end -end diff --git a/app/controllers/api/v1/favourites_controller.rb b/app/controllers/api/v1/favourites_controller.rb index db827f9d..3e242905 100644 --- a/app/controllers/api/v1/favourites_controller.rb +++ b/app/controllers/api/v1/favourites_controller.rb @@ -5,8 +5,6 @@ class Api::V1::FavouritesController < Api::BaseController before_action :require_user! after_action :insert_pagination_headers - respond_to :json - def index @statuses = load_statuses render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id) diff --git a/app/controllers/api/v1/filters_controller.rb b/app/controllers/api/v1/filters_controller.rb index e5ebaff4..b0ace3af 100644 --- a/app/controllers/api/v1/filters_controller.rb +++ b/app/controllers/api/v1/filters_controller.rb @@ -7,8 +7,6 @@ class Api::V1::FiltersController < Api::BaseController before_action :set_filters, only: :index before_action :set_filter, only: [:show, :update, :destroy] - respond_to :json - def index render json: @filters, each_serializer: REST::FilterSerializer end diff --git a/app/controllers/api/v1/follows_controller.rb b/app/controllers/api/v1/follows_controller.rb index 5420c053..5eaf06b3 100644 --- a/app/controllers/api/v1/follows_controller.rb +++ b/app/controllers/api/v1/follows_controller.rb @@ -4,18 +4,11 @@ class Api::V1::FollowsController < Api::BaseController before_action -> { doorkeeper_authorize! :follow, :'write:follows' } before_action :require_user! - respond_to :json - def create raise ActiveRecord::RecordNotFound if follow_params[:uri].blank? @account = FollowService.new.call(current_user.account, target_uri).try(:target_account) - if @account.nil? - username, domain = target_uri.split('@') - @account = Account.find_remote!(username, domain) - end - render json: @account, serializer: REST::AccountSerializer end diff --git a/app/controllers/api/v1/gab_trends_controller.rb b/app/controllers/api/v1/gab_trends_controller.rb deleted file mode 100644 index 166403bb..00000000 --- a/app/controllers/api/v1/gab_trends_controller.rb +++ /dev/null @@ -1,91 +0,0 @@ -# frozen_string_literal: true - -class Api::V1::GabTrendsController < EmptyController - def index - if Rails.env != 'development' - render json: nil - end - - type = params[:type] - if type == 'feed' - body = Redis.current.get("gabtrends:feed") - - if body.nil? || body.empty? - Request.new(:get, "https://trends.gab.com/trend-feed/json").perform do |res| - Rails.logger.debug "GabTrendsController: #{type} endpoint res code: #{res.code.to_s}" - if res.code == 200 - body = res.body_with_limit - Redis.current.set("gabtrends:feed", body) - Redis.current.expire("gabtrends:feed", 1.hour.seconds) - render json: body - else - render json: nil - end - end - else - render json: body - end - elsif type == 'partner' - body = Redis.current.get("gabtrends:partner") - - if body.nil? || body.empty? - Request.new(:get, "https://trends.gab.com/partner").perform do |res| - Rails.logger.debug "GabTrendsController: #{type} endpoint res code: #{res.code.to_s}" - if res.code == 200 - body = res.body_with_limit - Redis.current.set("gabtrends:partner", body) - Redis.current.expire("gabtrends:partner", 1.minute.seconds) - render json: body - else - render json: nil - end - end - else - render json: body - end - elsif type == 'news' - body = Redis.current.get("gabtrends:news") - - if body.nil? || body.empty? - Request.new(:get, "https://news.gab.com/feed/json").perform do |res| - Rails.logger.debug "GabTrendsController: #{type} endpoint res code: #{res.code.to_s}" - if res.code == 200 - body = res.body_with_limit - Redis.current.set("gabtrends:news", body) - Redis.current.expire("gabtrends:news", 1.minute.seconds) - render json: body - else - render json: nil - end - end - else - render json: body - end - elsif type == 'rss' - body = Redis.current.get("gabtrends:feeds") - - if body.nil? || body.empty? - Request.new(:get, "https://trends.gab.com/feed/#{params[:feedId]}?fmt=json&p=#{params[:page]}").perform do |res| - Rails.logger.debug "GabTrendsController: #{type} endpoint res code: #{res.code.to_s}" - if res.code == 200 - body = res.body_with_limit - Redis.current.set("gabtrends:news", body) - Redis.current.expire("gabtrends:news", 1.minute.seconds) - render json: body - else - render json: nil - end - end - else - render json: body - end - else - raise GabSocial::NotPermittedError - end - - rescue HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError, HTTP::Error - Rails.logger.debug "Error fetching gabtrends feed: #{type}" - render json: nil - end - -end diff --git a/app/controllers/api/v1/groups/password_controller.rb b/app/controllers/api/v1/groups/password_controller.rb index d0804077..ba8ed772 100644 --- a/app/controllers/api/v1/groups/password_controller.rb +++ b/app/controllers/api/v1/groups/password_controller.rb @@ -7,8 +7,6 @@ class Api::V1::Groups::PasswordController < Api::BaseController before_action :require_user! before_action :set_group - respond_to :json - def create authorize @group, :join? diff --git a/app/controllers/api/v1/groups/pins_controller.rb b/app/controllers/api/v1/groups/pins_controller.rb index ce66e0bc..051897f3 100644 --- a/app/controllers/api/v1/groups/pins_controller.rb +++ b/app/controllers/api/v1/groups/pins_controller.rb @@ -8,8 +8,6 @@ class Api::V1::Groups::PinsController < Api::BaseController before_action :set_group before_action :set_status - respond_to :json - def create authorize @group, :update? @@ -17,6 +15,10 @@ class Api::V1::Groups::PinsController < Api::BaseController render json: @status, serializer: REST::StatusSerializer end + def show + # is status pinned by user of group? + end + def destroy authorize @group, :update? diff --git a/app/controllers/api/v1/groups/relationships_controller.rb b/app/controllers/api/v1/groups/relationships_controller.rb index 884c5916..3bbad6aa 100644 --- a/app/controllers/api/v1/groups/relationships_controller.rb +++ b/app/controllers/api/v1/groups/relationships_controller.rb @@ -4,8 +4,6 @@ class Api::V1::Groups::RelationshipsController < Api::BaseController before_action -> { doorkeeper_authorize! :read, :'read:groups' } before_action :require_user! - respond_to :json - def index groups = Group.where(id: group_ids, is_archived: false).select('id') # .where doesn't guarantee that our results are in the same order diff --git a/app/controllers/api/v1/media_controller.rb b/app/controllers/api/v1/media_controller.rb index 659ddf90..8ad3c602 100644 --- a/app/controllers/api/v1/media_controller.rb +++ b/app/controllers/api/v1/media_controller.rb @@ -7,8 +7,6 @@ class Api::V1::MediaController < Api::BaseController include ObfuscateFilename obfuscate_filename :file - respond_to :json - def create @media = current_account.media_attachments.create!(account: current_account, file: media_params[:file], description: media_params[:description], focus: media_params[:focus]) render json: @media, serializer: REST::MediaAttachmentSerializer diff --git a/app/controllers/api/v1/mutes_controller.rb b/app/controllers/api/v1/mutes_controller.rb index df6c8e86..65439fe9 100644 --- a/app/controllers/api/v1/mutes_controller.rb +++ b/app/controllers/api/v1/mutes_controller.rb @@ -5,8 +5,6 @@ class Api::V1::MutesController < Api::BaseController before_action :require_user! after_action :insert_pagination_headers - respond_to :json - def index @accounts = load_accounts render json: @accounts, each_serializer: REST::AccountSerializer diff --git a/app/controllers/api/v1/notifications_controller.rb b/app/controllers/api/v1/notifications_controller.rb index a3152942..727f693b 100644 --- a/app/controllers/api/v1/notifications_controller.rb +++ b/app/controllers/api/v1/notifications_controller.rb @@ -1,14 +1,12 @@ # frozen_string_literal: true class Api::V1::NotificationsController < Api::BaseController - before_action -> { doorkeeper_authorize! :read, :'read:notifications' }, except: [:clear, :dismiss, :mark_read] - before_action -> { doorkeeper_authorize! :write, :'write:notifications' }, only: [:clear, :dismiss, :mark_read] + before_action -> { doorkeeper_authorize! :read, :'read:notifications' }, except: [:clear, :mark_read] + before_action -> { doorkeeper_authorize! :write, :'write:notifications' }, only: [:clear, :mark_read] before_action :require_user! before_action :set_filter_params after_action :insert_pagination_headers, only: :index - respond_to :json - DEFAULT_NOTIFICATIONS_LIMIT = 20 def index @@ -26,11 +24,6 @@ class Api::V1::NotificationsController < Api::BaseController render_empty end - def dismiss - current_account.notifications.find_by!(id: params[:id]).destroy! - render_empty - end - def mark_read current_account.notifications.find(params[:id]).mark_read! render_empty diff --git a/app/controllers/api/v1/polls/votes_controller.rb b/app/controllers/api/v1/polls/votes_controller.rb index aac094c1..b4e4a68b 100644 --- a/app/controllers/api/v1/polls/votes_controller.rb +++ b/app/controllers/api/v1/polls/votes_controller.rb @@ -7,8 +7,6 @@ class Api::V1::Polls::VotesController < Api::BaseController before_action :require_user! before_action :set_poll - respond_to :json - def create VoteService.new.call(current_account, @poll, vote_params[:choices]) render json: @poll, serializer: REST::PollSerializer diff --git a/app/controllers/api/v1/polls_controller.rb b/app/controllers/api/v1/polls_controller.rb index 4f4a6858..f5a1dc38 100644 --- a/app/controllers/api/v1/polls_controller.rb +++ b/app/controllers/api/v1/polls_controller.rb @@ -3,11 +3,8 @@ class Api::V1::PollsController < Api::BaseController before_action -> { authorize_if_got_token! :read, :'read:statuses' }, only: :show - respond_to :json - def show @poll = Poll.attached.find(params[:id]) - ActivityPub::FetchRemotePollService.new.call(@poll, current_account) if user_signed_in? && @poll.possibly_stale? render json: @poll, serializer: REST::PollSerializer, include_results: true end end diff --git a/app/controllers/api/v1/preferences_controller.rb b/app/controllers/api/v1/preferences_controller.rb index 077d39f5..1640a822 100644 --- a/app/controllers/api/v1/preferences_controller.rb +++ b/app/controllers/api/v1/preferences_controller.rb @@ -4,8 +4,6 @@ class Api::V1::PreferencesController < Api::BaseController before_action -> { doorkeeper_authorize! :read, :'read:accounts' } before_action :require_user! - respond_to :json - def index render json: current_account, serializer: REST::PreferencesSerializer end diff --git a/app/controllers/api/v1/push/subscriptions_controller.rb b/app/controllers/api/v1/push/subscriptions_controller.rb deleted file mode 100644 index 1b658f87..00000000 --- a/app/controllers/api/v1/push/subscriptions_controller.rb +++ /dev/null @@ -1,56 +0,0 @@ -# frozen_string_literal: true - -class Api::V1::Push::SubscriptionsController < Api::BaseController - before_action -> { doorkeeper_authorize! :push } - before_action :require_user! - before_action :set_web_push_subscription - - def create - @web_subscription&.destroy! - - @web_subscription = ::Web::PushSubscription.create!( - endpoint: subscription_params[:endpoint], - key_p256dh: subscription_params[:keys][:p256dh], - key_auth: subscription_params[:keys][:auth], - data: data_params, - user_id: current_user.id, - access_token_id: doorkeeper_token.id - ) - - render json: @web_subscription, serializer: REST::WebPushSubscriptionSerializer - end - - def show - raise ActiveRecord::RecordNotFound if @web_subscription.nil? - - render json: @web_subscription, serializer: REST::WebPushSubscriptionSerializer - end - - def update - raise ActiveRecord::RecordNotFound if @web_subscription.nil? - - @web_subscription.update!(data: data_params) - - render json: @web_subscription, serializer: REST::WebPushSubscriptionSerializer - end - - def destroy - @web_subscription&.destroy! - render_empty - end - - private - - def set_web_push_subscription - @web_subscription = ::Web::PushSubscription.find_by(access_token_id: doorkeeper_token.id) - end - - def subscription_params - params.require(:subscription).permit(:endpoint, keys: [:auth, :p256dh]) - end - - def data_params - return {} if params[:data].blank? - params.require(:data).permit(alerts: [:follow, :favourite, :reblog, :mention, :poll]) - end -end diff --git a/app/controllers/api/v1/reports_controller.rb b/app/controllers/api/v1/reports_controller.rb index e182a9c6..4b477a0f 100644 --- a/app/controllers/api/v1/reports_controller.rb +++ b/app/controllers/api/v1/reports_controller.rb @@ -4,8 +4,6 @@ class Api::V1::ReportsController < Api::BaseController before_action -> { doorkeeper_authorize! :write, :'write:reports' }, only: [:create] before_action :require_user! - respond_to :json - def create @report = ReportService.new.call( current_account, diff --git a/app/controllers/api/v1/search_controller.rb b/app/controllers/api/v1/search_controller.rb index daa7ba81..bb81ed9f 100644 --- a/app/controllers/api/v1/search_controller.rb +++ b/app/controllers/api/v1/search_controller.rb @@ -1,9 +1,7 @@ # frozen_string_literal: true -class Api::V1::SearchController < Api::BaseController - RESULTS_LIMIT = 100 - - respond_to :json +class Api::V1::SearchController < EmptyController + RESULTS_LIMIT = 25 def index @search = Search.new(search_results) diff --git a/app/controllers/api/v1/shop_controller.rb b/app/controllers/api/v1/shop_controller.rb deleted file mode 100644 index 32984e53..00000000 --- a/app/controllers/api/v1/shop_controller.rb +++ /dev/null @@ -1,36 +0,0 @@ -# frozen_string_literal: true - -class Api::V1::ShopController < EmptyController - def index - if Rails.env != 'development' - render json: nil - end - - type = params[:type] - if type == 'featured_products' - body = Redis.current.get("gabstore:featuredproducts") - - if body.nil? || body.empty? - Request.new(:get, "https://shop.dissenter.com/product/group/json").perform do |res| - Rails.logger.debug "ShopController dissenter products endpoint res code: #{res.code.to_s}" - if res.code == 200 - body = res.body_with_limit - Redis.current.set("gabstore:featuredproducts", body) - Redis.current.expire("gabstore:featuredproducts", 15.minutes.seconds) - render json: body - else - render json: nil - end - end - else - render json: body - end - else - raise GabSocial::NotPermittedError - end - rescue HTTP::TimeoutError, HTTP::ConnectionError, OpenSSL::SSL::SSLError, HTTP::Error - Rails.logger.debug "Error fetching dissenter shop: #{type}" - render json: nil - end - -end diff --git a/app/controllers/api/v1/statuses/bookmarks_controller.rb b/app/controllers/api/v1/statuses/bookmarks_controller.rb index 6dbb74c7..8a5625ed 100644 --- a/app/controllers/api/v1/statuses/bookmarks_controller.rb +++ b/app/controllers/api/v1/statuses/bookmarks_controller.rb @@ -6,8 +6,6 @@ class Api::V1::Statuses::BookmarksController < Api::BaseController before_action -> { doorkeeper_authorize! :write, :'write:bookmarks' } before_action :require_user! - respond_to :json - def create if current_user.account.is_pro @status = bookmarked_status @@ -17,6 +15,10 @@ class Api::V1::Statuses::BookmarksController < Api::BaseController end end + def show + # is status bookmarked by user? + end + def destroy if current_user.account.is_pro @status = requested_status diff --git a/app/controllers/api/v1/statuses/favourites_controller.rb b/app/controllers/api/v1/statuses/favourites_controller.rb index 2ee4beb7..4f52942f 100644 --- a/app/controllers/api/v1/statuses/favourites_controller.rb +++ b/app/controllers/api/v1/statuses/favourites_controller.rb @@ -6,11 +6,10 @@ class Api::V1::Statuses::FavouritesController < Api::BaseController before_action -> { doorkeeper_authorize! :write, :'write:favourites' } before_action :require_user! - respond_to :json - def create @status = favourited_status - render json: @status, serializer: REST::StatusSerializer + puts "tilly -- status: " + @status.inspect + render json: @status, serializer: REST::StatusStatSerializer end def destroy @@ -19,7 +18,7 @@ class Api::V1::Statuses::FavouritesController < Api::BaseController UnfavouriteWorker.perform_async(current_user.account_id, @status.id) - render json: @status, serializer: REST::StatusSerializer, unfavourite: true, relationships: StatusRelationshipsPresenter.new([@status], current_user&.account_id, favourites_map: @favourites_map) + render json: @status, serializer: REST::StatusStatSerializer, unfavourite: true, relationships: StatusRelationshipsPresenter.new([@status], current_user&.account_id, favourites_map: @favourites_map) end private diff --git a/app/controllers/api/v1/statuses/mutes_controller.rb b/app/controllers/api/v1/statuses/mutes_controller.rb deleted file mode 100644 index 3a1c49d6..00000000 --- a/app/controllers/api/v1/statuses/mutes_controller.rb +++ /dev/null @@ -1,41 +0,0 @@ -# frozen_string_literal: true - -class Api::V1::Statuses::MutesController < Api::BaseController - include Authorization - - before_action -> { doorkeeper_authorize! :write, :'write:mutes' } - before_action :require_user! - before_action :set_status - before_action :set_conversation - - respond_to :json - - def create - current_account.mute_conversation!(@conversation) - @mutes_map = { @conversation.id => true } - - render json: @status, serializer: REST::StatusSerializer - end - - def destroy - current_account.unmute_conversation!(@conversation) - @mutes_map = { @conversation.id => false } - - render json: @status, serializer: REST::StatusSerializer - end - - private - - def set_status - @status = Status.find(params[:status_id]) - authorize @status, :show? - rescue GabSocial::NotPermittedError - # Reraise in order to get a 404 instead of a 403 error code - raise ActiveRecord::RecordNotFound - end - - def set_conversation - @conversation = @status.conversation - raise GabSocial::ValidationError if @conversation.nil? - end -end diff --git a/app/controllers/api/v1/statuses/pins_controller.rb b/app/controllers/api/v1/statuses/pins_controller.rb index f9f135d8..fba194da 100644 --- a/app/controllers/api/v1/statuses/pins_controller.rb +++ b/app/controllers/api/v1/statuses/pins_controller.rb @@ -7,13 +7,15 @@ class Api::V1::Statuses::PinsController < Api::BaseController before_action :require_user! before_action :set_status - respond_to :json - def create StatusPin.create!(account: current_account, status: @status) render json: @status, serializer: REST::StatusSerializer end + def show + # is status pinned by user? + end + def destroy pin = StatusPin.find_by(account: current_account, status: @status) diff --git a/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb b/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb index 7a267bf4..f897650d 100644 --- a/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb +++ b/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb @@ -1,14 +1,12 @@ # frozen_string_literal: true -class Api::V1::Statuses::RebloggedByAccountsController < Api::BaseController +class Api::V1::Statuses::RepostedByAccountsController < Api::BaseController include Authorization before_action -> { authorize_if_got_token! :read, :'read:accounts' } before_action :set_status after_action :insert_pagination_headers - respond_to :json - def index @accounts = load_accounts render json: @accounts, each_serializer: REST::AccountSerializer @@ -38,13 +36,13 @@ class Api::V1::Statuses::RebloggedByAccountsController < Api::BaseController def next_path if records_continue? - api_v1_status_reblogged_by_index_url pagination_params(max_id: pagination_max_id) + api_v1_status_reposted_by_index_url pagination_params(max_id: pagination_max_id) end end def prev_path unless @accounts.empty? - api_v1_status_reblogged_by_index_url pagination_params(since_id: pagination_since_id) + api_v1_status_reposted_by_index_url pagination_params(since_id: pagination_since_id) end end diff --git a/app/controllers/api/v1/statuses/reblogs_controller.rb b/app/controllers/api/v1/statuses/reblogs_controller.rb index bb5b6a4a..fe492fd0 100644 --- a/app/controllers/api/v1/statuses/reblogs_controller.rb +++ b/app/controllers/api/v1/statuses/reblogs_controller.rb @@ -6,8 +6,6 @@ class Api::V1::Statuses::ReblogsController < Api::BaseController before_action -> { doorkeeper_authorize! :write, :'write:statuses' } before_action :require_user! - respond_to :json - def create if !current_user.account.local? || !status_for_reblog.local return render json: { error: 'Invalid action' }, status: 422 diff --git a/app/controllers/api/v1/statuses_controller.rb b/app/controllers/api/v1/statuses_controller.rb index 5f42befd..a84b5d30 100644 --- a/app/controllers/api/v1/statuses_controller.rb +++ b/app/controllers/api/v1/statuses_controller.rb @@ -3,13 +3,12 @@ class Api::V1::StatusesController < Api::BaseController include Authorization + # : todo : disable all oauth everything before_action -> { authorize_if_got_token! :read, :'read:statuses' }, except: [:create, :update, :destroy] before_action -> { doorkeeper_authorize! :write, :'write:statuses' }, only: [:create, :update, :destroy] before_action :require_user!, except: [:show, :comments, :context, :card] before_action :set_status, only: [:show, :comments, :context, :card, :update, :revisions] - respond_to :json - # This API was originally unlimited, pagination cannot be introduced without # breaking backwards-compatibility. Arbitrarily high number to cover most # conversations as quasi-unlimited, it would be too much work to render more @@ -126,7 +125,6 @@ class Api::V1::StatusesController < Api::BaseController media_ids: [], poll: [ :multiple, - :hide_totals, :expires_in, options: [], ], diff --git a/app/controllers/api/v1/streaming_controller.rb b/app/controllers/api/v1/streaming_controller.rb index 66b812e7..da918610 100644 --- a/app/controllers/api/v1/streaming_controller.rb +++ b/app/controllers/api/v1/streaming_controller.rb @@ -1,8 +1,6 @@ # frozen_string_literal: true class Api::V1::StreamingController < Api::BaseController - respond_to :json - def index if Rails.configuration.x.streaming_api_base_url != request.host uri = URI.parse(request.url) diff --git a/app/controllers/api/v1/suggestions_controller.rb b/app/controllers/api/v1/suggestions_controller.rb index 7f0eda60..6ebec322 100644 --- a/app/controllers/api/v1/suggestions_controller.rb +++ b/app/controllers/api/v1/suggestions_controller.rb @@ -6,13 +6,11 @@ class Api::V1::SuggestionsController < Api::BaseController before_action -> { doorkeeper_authorize! :read } before_action :require_user! - respond_to :json - def index type = params[:type] if type == 'related' - count = truthy_param?(:unlimited) ? 80 : 10 + count = truthy_param?(:unlimited) ? PotentialFriendshipTracker::MAX_ITEMS : 10 @accounts = PotentialFriendshipTracker.get(current_account.id, limit: count) render json: @accounts, each_serializer: REST::AccountSerializer elsif type == 'verified' diff --git a/app/controllers/api/v1/timelines/explore_controller.rb b/app/controllers/api/v1/timelines/explore_controller.rb index 00b89b7e..a4fe635d 100644 --- a/app/controllers/api/v1/timelines/explore_controller.rb +++ b/app/controllers/api/v1/timelines/explore_controller.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class Api::V1::Timelines::ExploreController < Api::BaseController +class Api::V1::Timelines::ExploreController < EmptyController before_action :set_sort_type before_action :set_statuses @@ -45,110 +45,7 @@ class Api::V1::Timelines::ExploreController < Api::BaseController end def explore_statuses - statuses = nil - - date_limit = 30.days.ago - top_order = 'status_stats.favourites_count DESC, status_stats.reblogs_count DESC, status_stats.replies_count DESC' - - if @sort_type == 'hot' - # : todo : - # unique groups - # unique users - date_limit = 8.hours.ago - elsif @sort_type == 'top_today' - date_limit = 24.hours.ago - elsif @sort_type == 'top_weekly' - date_limit = 7.days.ago - elsif @sort_type == 'top_monthly' - date_limit = 30.days.ago - elsif @sort_type == 'top_yearly' - date_limit = 1.year.ago - end - - if current_account - if @sort_type == 'newest' - statuses = Status.with_public_visibility.where( - reply: false - ).paginate_by_id( - limit_param(DEFAULT_STATUSES_LIMIT), - params_slice(:max_id, :since_id) - ).reject { |status| FeedManager.instance.filter?(:home, status, current_account.id) } - elsif @sort_type == 'recent' - statuses = Status.with_public_visibility.where( - reply: false - ).joins(:status_stat).where( - 'status_stats.replies_count > 0 OR status_stats.reblogs_count > 0 OR status_stats.favourites_count > 0' - ).order('status_stats.updated_at DESC').paginate_by_id( - limit_param(DEFAULT_STATUSES_LIMIT), - params_slice(:max_id, :since_id) - ).reject { |status| FeedManager.instance.filter?(:home, status, current_account.id) } - elsif ['top_today', 'top_weekly', 'top_monthly', 'top_yearly', 'top_all_time', 'hot'].include? @sort_type - if @sort_type == 'top_all_time' - statuses = Status.unscoped.with_public_visibility.where( - reply: false - ).joins(:status_stat).order(top_order).paginate_by_id( - limit_param(DEFAULT_STATUSES_LIMIT), - params_slice(:max_id, :since_id) - ).reject { |status| FeedManager.instance.filter?(:home, status, current_account.id) } - elsif @sort_type == 'hot' - statuses = Status.unscoped.with_public_visibility.where( - reply: false - ).where( - 'statuses.created_at > ?', date_limit - ).joins(:status_stat).order(top_order).paginate_by_id( - limit_param(DEFAULT_STATUSES_LIMIT), - params_slice(:max_id, :since_id) - ).reject { |status| FeedManager.instance.filter?(:home, status, current_account.id) } - else - statuses = Status.unscoped.with_public_visibility.where( - reply: false - ).where( - 'statuses.created_at > ?', date_limit - ).joins(:status_stat).order(top_order).paginate_by_id( - limit_param(DEFAULT_STATUSES_LIMIT), - params_slice(:max_id, :since_id) - ).reject { |status| FeedManager.instance.filter?(:home, status, current_account.id) } - end - end - else - if @sort_type == 'newest' - statuses = Status.with_public_visibility.where( - reply: false - ).paginate_by_id( - limit_param(DEFAULT_STATUSES_LIMIT), - params_slice(:max_id, :since_id) - ) - elsif @sort_type == 'recent' - statuses = Status.with_public_visibility.where( - reply: false - ).joins(:status_stat).where( - 'status_stats.replies_count > 0 OR status_stats.reblogs_count > 0 OR status_stats.favourites_count > 0' - ).order('status_stats.updated_at DESC').paginate_by_id( - limit_param(DEFAULT_STATUSES_LIMIT), - params_slice(:max_id, :since_id) - ) - elsif ['top_today', 'top_weekly', 'top_monthly', 'top_yearly', 'top_all_time', 'hot'].include? @sort_type - if @sort_type == 'top_all_time' - statuses = Status.unscoped.with_public_visibility.where( - reply: false - ).joins(:status_stat).order(top_order).paginate_by_id( - limit_param(DEFAULT_STATUSES_LIMIT), - params_slice(:max_id, :since_id) - ) - else - statuses = Status.unscoped.with_public_visibility.where( - reply: false - ).where( - 'statuses.created_at > ?', date_limit - ).joins(:status_stat).order(top_order).paginate_by_id( - limit_param(DEFAULT_STATUSES_LIMIT), - params_slice(:max_id, :since_id) - ) - end - end - end - - statuses + SortingQueryBuilder.new.call(@sort_type, params[:max_id]) end def insert_pagination_headers diff --git a/app/controllers/api/v1/timelines/group_collection_controller.rb b/app/controllers/api/v1/timelines/group_collection_controller.rb index b08d0c90..780638b7 100644 --- a/app/controllers/api/v1/timelines/group_collection_controller.rb +++ b/app/controllers/api/v1/timelines/group_collection_controller.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class Api::V1::Timelines::GroupCollectionController < Api::BaseController +class Api::V1::Timelines::GroupCollectionController < EmptyController before_action :set_collection_type before_action :set_sort_type before_action :set_statuses @@ -61,8 +61,6 @@ class Api::V1::Timelines::GroupCollectionController < Api::BaseController end def group_collection_statuses - statuses = nil - @groupIds = [] if @collection_type == 'featured' @groupIds = FetchGroupsService.new.call("featured") @@ -72,98 +70,7 @@ class Api::V1::Timelines::GroupCollectionController < Api::BaseController return [] end - date_limit = 30.days.ago - top_order = 'status_stats.favourites_count DESC, status_stats.reblogs_count DESC, status_stats.replies_count DESC' - - if @sort_type == 'hot' - # : todo : - # unique groups - # unique users - date_limit = 8.hours.ago - elsif @sort_type == 'top_today' - date_limit = 24.hours.ago - elsif @sort_type == 'top_weekly' - date_limit = 7.days.ago - elsif @sort_type == 'top_monthly' - date_limit = 30.days.ago - elsif @sort_type == 'top_yearly' - date_limit = 1.year.ago - end - - if current_account - if @sort_type == 'newest' - statuses = Status.where( - group: @groupIds, reply: false - ).paginate_by_id( - limit_param(DEFAULT_STATUSES_LIMIT), - params_slice(:max_id, :since_id, :min_id) - ).reject { |status| FeedManager.instance.filter?(:home, status, current_account.id) } - elsif @sort_type == 'recent' - statuses = Status.where( - group: @groupIds, reply: false - ).joins(:status_stat).where( - 'status_stats.replies_count > 0 OR status_stats.reblogs_count > 0 OR status_stats.favourites_count > 0' - ).order('status_stats.updated_at DESC').paginate_by_id( - limit_param(DEFAULT_STATUSES_LIMIT), - params_slice(:max_id, :since_id, :min_id) - ).reject { |status| FeedManager.instance.filter?(:home, status, current_account.id) } - elsif ['top_today', 'top_weekly', 'top_monthly', 'top_yearly', 'top_all_time', 'hot'].include? @sort_type - if @sort_type == 'top_all_time' - statuses = Status.unscoped.where( - group: @groupIds, reply: false - ).joins(:status_stat).order(top_order) - .paginate_by_id( - limit_param(DEFAULT_STATUSES_LIMIT), - params_slice(:max_id, :since_id, :min_id) - ).reject { |status| FeedManager.instance.filter?(:home, status, current_account.id) } - else - statuses = Status.unscoped.where( - group: @groupIds, reply: false - ).where( - 'statuses.created_at > ?', date_limit - ).joins(:status_stat).order(top_order).paginate_by_id( - limit_param(DEFAULT_STATUSES_LIMIT), - params_slice(:max_id, :since_id, :min_id) - ).reject { |status| FeedManager.instance.filter?(:home, status, current_account.id) } - end - end - else - if @sort_type == 'newest' - statuses = Status.where( - group: @groupIds, reply: false - ).paginate_by_id(limit_param(DEFAULT_STATUSES_LIMIT), params_slice(:max_id, :since_id, :min_id)) - elsif @sort_type == 'recent' - statuses = Status.where( - group: @groupIds, reply: false - ).joins(:status_stat).where( - 'status_stats.replies_count > 0 OR status_stats.reblogs_count > 0 OR status_stats.favourites_count > 0' - ).order('status_stats.updated_at DESC').paginate_by_id( - limit_param(DEFAULT_STATUSES_LIMIT), - params_slice(:max_id, :since_id, :min_id) - ) - elsif ['top_today', 'top_weekly', 'top_monthly', 'top_yearly', 'top_all_time', 'hot'].include? @sort_type - if @sort_type == 'top_all_time' - statuses = Status.unscoped.where( - group: @groupIds, reply: false - ).joins(:status_stat).order(top_order) - .paginate_by_id( - limit_param(DEFAULT_STATUSES_LIMIT), - params_slice(:max_id, :since_id, :min_id) - ) - else - statuses = Status.unscoped.where( - group: @groupIds, reply: false - ).where( - 'statuses.created_at > ?', date_limit - ).joins(:status_stat).order(top_order).paginate_by_id( - limit_param(DEFAULT_STATUSES_LIMIT), - params_slice(:max_id, :since_id, :min_id) - ) - end - end - end - - statuses + SortingQueryBuilder.new.call(@sort_type, params[:max_id], @groupIds) end def insert_pagination_headers diff --git a/app/controllers/api/v1/timelines/group_controller.rb b/app/controllers/api/v1/timelines/group_controller.rb index e9c870a2..01e0a31b 100644 --- a/app/controllers/api/v1/timelines/group_controller.rb +++ b/app/controllers/api/v1/timelines/group_controller.rb @@ -13,6 +13,7 @@ class Api::V1::Timelines::GroupController < Api::BaseController if current_user render json: @statuses, each_serializer: REST::StatusSerializer, + group_id: params[:id], relationships: StatusRelationshipsPresenter.new(@statuses, current_user.account_id, group_id: @group.id) else render json: @statuses, each_serializer: REST::StatusSerializer @@ -50,103 +51,7 @@ class Api::V1::Timelines::GroupController < Api::BaseController end def group_statuses - statuses = nil - - date_limit = 30.days.ago - top_order = 'status_stats.favourites_count DESC, status_stats.reblogs_count DESC, status_stats.replies_count DESC' - - if @sort_type == 'hot' - # : todo : - # unique groups - # unique users - date_limit = 8.hours.ago - elsif @sort_type == 'top_today' - date_limit = 24.hours.ago - elsif @sort_type == 'top_weekly' - date_limit = 7.days.ago - elsif @sort_type == 'top_monthly' - date_limit = 30.days.ago - elsif @sort_type == 'top_yearly' - date_limit = 1.year.ago - end - - if current_account - if @sort_type == 'newest' - statuses = Status.where( - group: @group, reply: false - ).paginate_by_id( - limit_param(DEFAULT_STATUSES_LIMIT), - params_slice(:max_id, :since_id, :min_id) - ).reject { |status| FeedManager.instance.filter?(:home, status, current_account.id) } - elsif @sort_type == 'recent' - statuses = Status.where( - group: @group, reply: false - ).joins(:status_stat).where( - 'status_stats.replies_count > 0 OR status_stats.reblogs_count > 0 OR status_stats.favourites_count > 0' - ).order('status_stats.updated_at DESC').paginate_by_id( - limit_param(DEFAULT_STATUSES_LIMIT), - params_slice(:max_id, :since_id, :min_id) - ).reject { |status| FeedManager.instance.filter?(:home, status, current_account.id) } - elsif ['top_today', 'top_weekly', 'top_monthly', 'top_yearly', 'top_all_time', 'hot'].include? @sort_type - if @sort_type == 'top_all_time' - statuses = Status.unscoped.where( - group: @group, reply: false - ).joins(:status_stat).order(top_order) - .paginate_by_id( - limit_param(DEFAULT_STATUSES_LIMIT), - params_slice(:max_id, :since_id, :min_id) - ).reject { |status| FeedManager.instance.filter?(:home, status, current_account.id) } - else - statuses = Status.unscoped.where( - group: @group, reply: false - ).where( - 'statuses.created_at > ?', date_limit - ).joins(:status_stat).order(top_order).paginate_by_id( - limit_param(DEFAULT_STATUSES_LIMIT), - params_slice(:max_id, :since_id, :min_id) - ).reject { |status| FeedManager.instance.filter?(:home, status, current_account.id) } - end - end - else - if @sort_type == 'newest' - statuses = Status.where( - group: @group, reply: false - ).paginate_by_id( - limit_param(DEFAULT_STATUSES_LIMIT), - params_slice(:max_id, :since_id, :min_id) - ) - elsif @sort_type == 'recent' - statuses = Status.where( - group: @group, reply: false - ).joins(:status_stat).where( - 'status_stats.replies_count > 0 OR status_stats.reblogs_count > 0 OR status_stats.favourites_count > 0' - ).order('status_stats.updated_at DESC').paginate_by_id( - limit_param(DEFAULT_STATUSES_LIMIT), - params_slice(:max_id, :since_id, :min_id) - ) - elsif ['top_today', 'top_weekly', 'top_monthly', 'top_yearly', 'top_all_time', 'hot'].include? @sort_type - if @sort_type == 'top_all_time' - statuses = Status.unscoped.where( - group: @group, reply: false - ).joins(:status_stat).order(top_order) - .paginate_by_id( - limit_param(DEFAULT_STATUSES_LIMIT), - params_slice(:max_id, :since_id, :min_id) - ) - else - statuses = Status.unscoped.where( - group: @group, reply: false - ).where( - 'statuses.created_at > ?', date_limit - ).joins(:status_stat).order(top_order).paginate_by_id( - limit_param(DEFAULT_STATUSES_LIMIT), - params_slice(:max_id, :since_id, :min_id) - ) - end - end - end - - statuses + SortingQueryBuilder.new.call(@sort_type, params[:max_id], @group) end def insert_pagination_headers diff --git a/app/controllers/api/v1/timelines/home_controller.rb b/app/controllers/api/v1/timelines/home_controller.rb index 748799a6..28fb06a5 100644 --- a/app/controllers/api/v1/timelines/home_controller.rb +++ b/app/controllers/api/v1/timelines/home_controller.rb @@ -5,8 +5,6 @@ class Api::V1::Timelines::HomeController < Api::BaseController before_action :require_user!, only: [:show] after_action :insert_pagination_headers, unless: -> { @statuses.empty? } - respond_to :json - def show @statuses = load_statuses render json: @statuses, diff --git a/app/controllers/api/v1/timelines/preview_card_controller.rb b/app/controllers/api/v1/timelines/preview_card_controller.rb index 8f0d15c2..4734ea2a 100644 --- a/app/controllers/api/v1/timelines/preview_card_controller.rb +++ b/app/controllers/api/v1/timelines/preview_card_controller.rb @@ -10,6 +10,7 @@ class Api::V1::Timelines::PreviewCardController < Api::BaseController def show render json: @statuses, each_serializer: REST::StatusSerializer, + preview_card_id: params[:id], relationships: StatusRelationshipsPresenter.new(@statuses, current_user.account_id) end diff --git a/app/controllers/api/v1/timelines/pro_controller.rb b/app/controllers/api/v1/timelines/pro_controller.rb index 89abc4f1..97691a88 100644 --- a/app/controllers/api/v1/timelines/pro_controller.rb +++ b/app/controllers/api/v1/timelines/pro_controller.rb @@ -4,8 +4,6 @@ class Api::V1::Timelines::ProController < Api::BaseController before_action :require_user!, only: [:show] after_action :insert_pagination_headers, unless: -> { @statuses.empty? } - respond_to :json - def show @statuses = load_statuses render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id) diff --git a/app/controllers/api/v1/timelines/public_controller.rb b/app/controllers/api/v1/timelines/public_controller.rb deleted file mode 100644 index a6d1e8ee..00000000 --- a/app/controllers/api/v1/timelines/public_controller.rb +++ /dev/null @@ -1,67 +0,0 @@ -# frozen_string_literal: true - -class Api::V1::Timelines::PublicController < Api::BaseController - before_action :require_user!, only: [:show] - before_action :require_admin! - after_action :insert_pagination_headers, unless: -> { @statuses.empty? } - - respond_to :json - - def show - @statuses = load_statuses - render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id) - end - - private - - def load_statuses - cached_public_statuses - end - - def cached_public_statuses - cache_collection public_statuses, Status - end - - def public_statuses - statuses = public_timeline_statuses.paginate_by_id( - limit_param(DEFAULT_STATUSES_LIMIT), - params_slice(:max_id, :since_id, :min_id) - ) - - if truthy_param?(:only_media) - # `SELECT DISTINCT id, updated_at` is too slow, so pluck ids at first, and then select id, updated_at with ids. - status_ids = statuses.joins(:media_attachments).distinct(:id).pluck(:id) - statuses.where(id: status_ids) - else - statuses - end - end - - def public_timeline_statuses - Status.as_public_timeline(current_account) - end - - def insert_pagination_headers - set_pagination_headers(next_path, prev_path) - end - - def pagination_params(core_params) - params.slice(:limit, :only_media).permit(:limit, :only_media).merge(core_params) - end - - def next_path - api_v1_timelines_public_url pagination_params(max_id: pagination_max_id) - end - - def prev_path - api_v1_timelines_public_url pagination_params(min_id: pagination_since_id) - end - - def pagination_max_id - @statuses.last.id - end - - def pagination_since_id - @statuses.first.id - end -end diff --git a/app/controllers/api/v1/timelines/tag_controller.rb b/app/controllers/api/v1/timelines/tag_controller.rb index 777be45f..4e89a112 100644 --- a/app/controllers/api/v1/timelines/tag_controller.rb +++ b/app/controllers/api/v1/timelines/tag_controller.rb @@ -5,11 +5,11 @@ class Api::V1::Timelines::TagController < Api::BaseController before_action :require_user!, only: [:show] after_action :insert_pagination_headers, unless: -> { @statuses.empty? } - respond_to :json - def show @statuses = tagged_statuses - render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id) + render json: @statuses, + each_serializer: REST::StatusSerializer, + relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id) end private diff --git a/app/controllers/api/web/embeds_controller.rb b/app/controllers/api/web/embeds_controller.rb index a62b1af4..9f58ff8f 100644 --- a/app/controllers/api/web/embeds_controller.rb +++ b/app/controllers/api/web/embeds_controller.rb @@ -1,8 +1,6 @@ # frozen_string_literal: true class Api::Web::EmbedsController < Api::Web::BaseController - respond_to :json - def create status = StatusFinder.new(params[:url]).status render json: status, serializer: OEmbedSerializer, width: 400 diff --git a/app/controllers/api/web/push_subscriptions_controller.rb b/app/controllers/api/web/push_subscriptions_controller.rb index d8153e08..07c4aa56 100644 --- a/app/controllers/api/web/push_subscriptions_controller.rb +++ b/app/controllers/api/web/push_subscriptions_controller.rb @@ -1,8 +1,6 @@ # frozen_string_literal: true class Api::Web::PushSubscriptionsController < Api::Web::BaseController - respond_to :json - before_action :require_user! def create diff --git a/app/controllers/api/web/settings_controller.rb b/app/controllers/api/web/settings_controller.rb index e3178bf4..3d65e46e 100644 --- a/app/controllers/api/web/settings_controller.rb +++ b/app/controllers/api/web/settings_controller.rb @@ -1,8 +1,6 @@ # frozen_string_literal: true class Api::Web::SettingsController < Api::Web::BaseController - respond_to :json - before_action :require_user! def update diff --git a/app/controllers/auth/omniauth_callbacks_controller.rb b/app/controllers/auth/omniauth_callbacks_controller.rb deleted file mode 100644 index bbf63bed..00000000 --- a/app/controllers/auth/omniauth_callbacks_controller.rb +++ /dev/null @@ -1,33 +0,0 @@ -# frozen_string_literal: true - -class Auth::OmniauthCallbacksController < Devise::OmniauthCallbacksController - skip_before_action :verify_authenticity_token - - def self.provides_callback_for(provider) - provider_id = provider.to_s.chomp '_oauth2' - - define_method provider do - @user = User.find_for_oauth(request.env['omniauth.auth'], current_user) - - if @user.persisted? - sign_in_and_redirect @user, event: :authentication - set_flash_message(:notice, :success, kind: provider_id.capitalize) if is_navigational_format? - else - session["devise.#{provider}_data"] = request.env['omniauth.auth'] - redirect_to new_user_registration_url - end - end - end - - Devise.omniauth_configs.each_key do |provider| - provides_callback_for provider - end - - def after_sign_in_path_for(resource) - if resource.email_verified? - root_path - else - finish_signup_path - end - end -end diff --git a/app/controllers/auth/registrations_controller.rb b/app/controllers/auth/registrations_controller.rb index b1f322f1..ccd9b473 100644 --- a/app/controllers/auth/registrations_controller.rb +++ b/app/controllers/auth/registrations_controller.rb @@ -3,9 +3,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController layout :determine_layout - before_action :set_invite, only: [:new, :create] before_action :set_challenge, only: [:new] - before_action :check_enabled_registrations, only: [:new, :create] before_action :configure_sign_up_params, only: [:create] before_action :set_sessions, only: [:edit, :update] before_action :set_instance_presenter, only: [:new, :create, :update] @@ -41,7 +39,6 @@ class Auth::RegistrationsController < Devise::RegistrationsController super(hash) resource.locale = I18n.locale - resource.invite_code = params[:invite_code] if resource.invite_code.blank? resource.agreement = true resource.current_sign_in_ip = request.remote_ip @@ -50,7 +47,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController def configure_sign_up_params devise_parameter_sanitizer.permit(:sign_up) do |u| - u.permit({ account_attributes: [:username], invite_request_attributes: [:text] }, :email, :password, :password_confirmation, :invite_code) + u.permit({ account_attributes: [:username] }, :email, :password, :password_confirmation) end end @@ -58,16 +55,6 @@ class Auth::RegistrationsController < Devise::RegistrationsController new_user_session_path end - def after_sign_in_path_for(_resource) - set_invite - - if @invite&.autofollow? - short_account_path(@invite.user.account) - else - super - end - end - def after_inactive_sign_up_path_for(_resource) new_user_session_path end @@ -76,22 +63,6 @@ class Auth::RegistrationsController < Devise::RegistrationsController edit_user_registration_path end - def check_enabled_registrations - redirect_to root_path if single_user_mode? || !allowed_registrations? - end - - def allowed_registrations? - Setting.registrations_mode != 'none' || @invite&.valid_for_use? - end - - def invite_code - if params[:user] - params[:user][:invite_code] - else - params[:invite_code] - end - end - private def set_instance_presenter @@ -102,11 +73,6 @@ class Auth::RegistrationsController < Devise::RegistrationsController @body_classes = %w(edit update).include?(action_name) ? 'admin' : '' end - def set_invite - invite = invite_code.present? ? Invite.find_by(code: invite_code) : nil - @invite = invite&.valid_for_use? ? invite : nil - end - def set_challenge @challenge_add_1 = rand(0...9) @challenge_add_2 = rand(0...9) diff --git a/app/controllers/authorize_interactions_controller.rb b/app/controllers/authorize_interactions_controller.rb deleted file mode 100644 index 5c308260..00000000 --- a/app/controllers/authorize_interactions_controller.rb +++ /dev/null @@ -1,66 +0,0 @@ -# frozen_string_literal: true - -class AuthorizeInteractionsController < ApplicationController - include Authorization - - layout 'modal' - - before_action :authenticate_user! - before_action :set_body_classes - before_action :set_resource - - def show - if @resource.is_a?(Account) - render :show - elsif @resource.is_a?(Status) - redirect_to web_url("statuses/#{@resource.id}") - else - render :error - end - end - - def create - if @resource.is_a?(Account) && FollowService.new.call(current_account, @resource) - render :success - else - render :error - end - rescue ActiveRecord::RecordNotFound, GabSocial::NotPermittedError - render :error - end - - private - - def set_resource - @resource = located_resource || render(:error) - authorize(@resource, :show?) if @resource.is_a?(Status) - end - - def located_resource - if uri_param_is_url? - ResolveURLService.new.call(uri_param) - else - account_from_remote_follow - end - end - - def account_from_remote_follow - ResolveAccountService.new.call(uri_param) - end - - def uri_param_is_url? - parsed_uri.path && %w(http https).include?(parsed_uri.scheme) - end - - def parsed_uri - Addressable::URI.parse(uri_param).normalize - end - - def uri_param - params[:uri] || params.fetch(:acct, '').gsub(/\Aacct:/, '') - end - - def set_body_classes - @body_classes = 'modal-layout' - end -end diff --git a/app/controllers/concerns/account_controller_concern.rb b/app/controllers/concerns/account_controller_concern.rb index d17560d1..5b93831a 100644 --- a/app/controllers/concerns/account_controller_concern.rb +++ b/app/controllers/concerns/account_controller_concern.rb @@ -7,10 +7,8 @@ module AccountControllerConcern included do before_action :set_account - before_action :check_account_approval before_action :check_account_suspension before_action :set_instance_presenter - before_action :set_link_headers end private @@ -23,51 +21,10 @@ module AccountControllerConcern @instance_presenter = InstancePresenter.new end - def set_link_headers - return if !@account.local? # TODO: Handle remote users - - response.headers['Link'] = LinkHeader.new( - [ - webfinger_account_link, - atom_account_url_link, - actor_url_link, - ] - ) - end - def username_param params[:account_username] end - def webfinger_account_link - [ - webfinger_account_url, - [%w(rel lrdd), %w(type application/xrd+xml)], - ] - end - - def atom_account_url_link - [ - account_url(@account, format: 'atom'), - [%w(rel alternate), %w(type application/atom+xml)], - ] - end - - def actor_url_link - [ - ActivityPub::TagManager.instance.uri_for(@account), - [%w(rel alternate), %w(type application/activity+json)], - ] - end - - def webfinger_account_url - webfinger_url(resource: @account.to_webfinger_s) - end - - def check_account_approval - not_found if @account.user_pending? - end - def check_account_suspension if @account.suspended? skip_session! diff --git a/app/controllers/concerns/signature_verification.rb b/app/controllers/concerns/signature_verification.rb index 90a57197..fb2166ff 100644 --- a/app/controllers/concerns/signature_verification.rb +++ b/app/controllers/concerns/signature_verification.rb @@ -43,7 +43,7 @@ module SignatureVerification return end - account = account_from_key_id(signature_params['keyId']) + account = nil if account.nil? @signature_verification_failure_reason = "Public key not found for key #{signature_params['keyId']}" @@ -56,7 +56,7 @@ module SignatureVerification return account unless verify_signature(account, signature, compare_signed_string).nil? - account = stoplight_wrap_request { account.possibly_stale? ? account.refresh! : account_refresh_key(account) } + account = nil if account.nil? @signature_verification_failure_reason = "Public key not found for key #{signature_params['keyId']}" @@ -122,27 +122,4 @@ module SignatureVerification signature_params['signature'].blank? end - def account_from_key_id(key_id) - if key_id.start_with?('acct:') - stoplight_wrap_request { ResolveAccountService.new.call(key_id.gsub(/\Aacct:/, '')) } - elsif !ActivityPub::TagManager.instance.local_uri?(key_id) - account = ActivityPub::TagManager.instance.uri_to_resource(key_id, Account) - account ||= stoplight_wrap_request { ActivityPub::FetchRemoteKeyService.new.call(key_id, id: false) } - account - end - end - - def stoplight_wrap_request(&block) - Stoplight("source:#{request.remote_ip}", &block) - .with_fallback { nil } - .with_threshold(1) - .with_cool_off_time(5.minutes.seconds) - .with_error_handler { |error, handle| error.is_a?(HTTP::Error) ? handle.call(error) : raise(error) } - .run - end - - def account_refresh_key(account) - return if account.local? || !account.activitypub? - ActivityPub::FetchRemoteAccountService.new.call(account.uri, only_key: true) - end end diff --git a/app/controllers/directories_controller.rb b/app/controllers/directories_controller.rb deleted file mode 100644 index 59490767..00000000 --- a/app/controllers/directories_controller.rb +++ /dev/null @@ -1,43 +0,0 @@ -# frozen_string_literal: true - -class DirectoriesController < ApplicationController - layout 'public' - - before_action :check_enabled - before_action :set_instance_presenter - before_action :set_tag, only: :show - before_action :set_tags - before_action :set_accounts - - def index - render :index - end - - def show - render :index - end - - private - - def check_enabled - return not_found unless Setting.profile_directory - end - - def set_tag - @tag = Tag.discoverable.find_by!(name: params[:id].downcase) - end - - def set_tags - @tags = Tag.discoverable.limit(30).reject { |tag| tag.cached_sample_accounts.empty? } - end - - def set_accounts - @accounts = Account.discoverable.by_recent_status.page(params[:page]).per(40).tap do |query| - query.merge!(Account.tagged_with(@tag.id)) if @tag - end - end - - def set_instance_presenter - @instance_presenter = InstancePresenter.new - end -end diff --git a/app/controllers/downloads_controller.rb b/app/controllers/downloads_controller.rb deleted file mode 100644 index 946c7ded..00000000 --- a/app/controllers/downloads_controller.rb +++ /dev/null @@ -1,8 +0,0 @@ -# frozen_string_literal: true - -class DownloadsController < ApplicationController - layout 'public' - - before_action :check_enabled - -end \ No newline at end of file diff --git a/app/controllers/emojis_controller.rb b/app/controllers/emojis_controller.rb deleted file mode 100644 index 5d306e60..00000000 --- a/app/controllers/emojis_controller.rb +++ /dev/null @@ -1,24 +0,0 @@ -# frozen_string_literal: true - -class EmojisController < ApplicationController - before_action :set_emoji - before_action :set_cache_headers - - def show - respond_to do |format| - format.json do - skip_session! - - render_cached_json(['activitypub', 'emoji', @emoji], content_type: 'application/activity+json') do - ActiveModelSerializers::SerializableResource.new(@emoji, serializer: ActivityPub::EmojiSerializer, adapter: ActivityPub::Adapter) - end - end - end - end - - private - - def set_emoji - @emoji = CustomEmoji.local.find(params[:id]) - end -end diff --git a/app/controllers/follower_accounts_controller.rb b/app/controllers/follower_accounts_controller.rb deleted file mode 100644 index ff7c6b5b..00000000 --- a/app/controllers/follower_accounts_controller.rb +++ /dev/null @@ -1,65 +0,0 @@ -# frozen_string_literal: true - -class FollowerAccountsController < ApplicationController - include AccountControllerConcern - - before_action :set_cache_headers - - def index - respond_to do |format| - format.html do - mark_cacheable! unless user_signed_in? - - next if @account.user_hides_network? - - follows - @relationships = AccountRelationshipsPresenter.new(follows.map(&:account_id), current_user.account_id) if user_signed_in? - end - - format.json do - raise GabSocial::NotPermittedError if params[:page].present? && @account.user_hides_network? - - if params[:page].blank? - skip_session! - expires_in 3.minutes, public: true - end - - render json: collection_presenter, - serializer: ActivityPub::CollectionSerializer, - adapter: ActivityPub::Adapter, - content_type: 'application/activity+json' - end - end - end - - private - - def follows - @follows ||= Follow.where(target_account: @account).recent.page(params[:page]).per(FOLLOW_PER_PAGE).preload(:account) - end - - def page_url(page) - account_followers_url(@account, page: page) unless page.nil? - end - - def collection_presenter - if params[:page].present? - ActivityPub::CollectionPresenter.new( - id: account_followers_url(@account, page: params.fetch(:page, 1)), - type: :ordered, - size: @account.followers_count, - items: follows.map { |f| ActivityPub::TagManager.instance.uri_for(f.account) }, - part_of: account_followers_url(@account), - next: page_url(follows.next_page), - prev: page_url(follows.prev_page) - ) - else - ActivityPub::CollectionPresenter.new( - id: account_followers_url(@account), - type: :ordered, - size: @account.followers_count, - first: page_url(1) - ) - end - end -end diff --git a/app/controllers/following_accounts_controller.rb b/app/controllers/following_accounts_controller.rb deleted file mode 100644 index 6dcf4eff..00000000 --- a/app/controllers/following_accounts_controller.rb +++ /dev/null @@ -1,65 +0,0 @@ -# frozen_string_literal: true - -class FollowingAccountsController < ApplicationController - include AccountControllerConcern - - before_action :set_cache_headers - - def index - respond_to do |format| - format.html do - mark_cacheable! unless user_signed_in? - - next if @account.user_hides_network? - - follows - @relationships = AccountRelationshipsPresenter.new(follows.map(&:target_account_id), current_user.account_id) if user_signed_in? - end - - format.json do - raise GabSocial::NotPermittedError if params[:page].present? && @account.user_hides_network? - - if params[:page].blank? - skip_session! - expires_in 3.minutes, public: true - end - - render json: collection_presenter, - serializer: ActivityPub::CollectionSerializer, - adapter: ActivityPub::Adapter, - content_type: 'application/activity+json' - end - end - end - - private - - def follows - @follows ||= Follow.where(account: @account).recent.page(params[:page]).per(FOLLOW_PER_PAGE).preload(:target_account) - end - - def page_url(page) - account_following_index_url(@account, page: page) unless page.nil? - end - - def collection_presenter - if params[:page].present? - ActivityPub::CollectionPresenter.new( - id: account_following_index_url(@account, page: params.fetch(:page, 1)), - type: :ordered, - size: @account.following_count, - items: follows.map { |f| ActivityPub::TagManager.instance.uri_for(f.target_account) }, - part_of: account_following_index_url(@account), - next: page_url(follows.next_page), - prev: page_url(follows.prev_page) - ) - else - ActivityPub::CollectionPresenter.new( - id: account_following_index_url(@account), - type: :ordered, - size: @account.following_count, - first: page_url(1) - ) - end - end -end diff --git a/app/controllers/intents_controller.rb b/app/controllers/intents_controller.rb deleted file mode 100644 index 9f41cf48..00000000 --- a/app/controllers/intents_controller.rb +++ /dev/null @@ -1,33 +0,0 @@ -# frozen_string_literal: true - -class IntentsController < ApplicationController - before_action :check_uri - rescue_from Addressable::URI::InvalidURIError, with: :handle_invalid_uri - - def show - if uri.scheme == 'web+mastodon' - case uri.host - when 'follow' - return redirect_to authorize_interaction_path(uri: uri.query_values['uri'].gsub(/\Aacct:/, '')) - when 'share' - return redirect_to share_path(text: uri.query_values['text']) - end - end - - not_found - end - - private - - def check_uri - not_found if uri.blank? - end - - def handle_invalid_uri - not_found - end - - def uri - @uri ||= Addressable::URI.parse(params[:uri]) - end -end diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb deleted file mode 100644 index fdb3a096..00000000 --- a/app/controllers/invites_controller.rb +++ /dev/null @@ -1,52 +0,0 @@ -# frozen_string_literal: true - -class InvitesController < ApplicationController - include Authorization - - layout 'admin' - - before_action :authenticate_user! - before_action :set_body_classes - - def index - authorize :invite, :create? - - @invites = invites - @invite = Invite.new - end - - def create - authorize :invite, :create? - - @invite = Invite.new(resource_params) - @invite.user = current_user - - if @invite.save - redirect_to invites_path - else - @invites = invites - render :index - end - end - - def destroy - @invite = invites.find(params[:id]) - authorize @invite, :destroy? - @invite.expire! - redirect_to invites_path - end - - private - - def invites - Invite.where(user: current_user).order(id: :desc) - end - - def resource_params - params.require(:invite).permit(:max_uses, :expires_in, :autofollow) - end - - def set_body_classes - @body_classes = 'admin' - end -end diff --git a/app/controllers/manifests_controller.rb b/app/controllers/manifests_controller.rb index 2b8ab280..09985129 100644 --- a/app/controllers/manifests_controller.rb +++ b/app/controllers/manifests_controller.rb @@ -5,4 +5,5 @@ class ManifestsController < EmptyController def show render json: InstancePresenter.new, serializer: ManifestSerializer end + end diff --git a/app/controllers/media_controller.rb b/app/controllers/media_controller.rb deleted file mode 100644 index 86a7d3e0..00000000 --- a/app/controllers/media_controller.rb +++ /dev/null @@ -1,37 +0,0 @@ -# frozen_string_literal: true - -class MediaController < ApplicationController - include Authorization - - skip_before_action :store_current_location - - before_action :set_media_attachment - before_action :verify_permitted_status! - - content_security_policy only: :player do |p| - p.frame_ancestors(false) - end - - def show - redirect_to @media_attachment.file.url(:original) - end - - def player - @body_classes = 'player' - response.headers['X-Frame-Options'] = 'ALLOWALL' - raise ActiveRecord::RecordNotFound unless @media_attachment.video? || @media_attachment.gifv? - end - - private - - def set_media_attachment - @media_attachment = MediaAttachment.attached.find_by!(shortcode: params[:id] || params[:medium_id]) - end - - def verify_permitted_status! - authorize @media_attachment.status, :show? - rescue GabSocial::NotPermittedError - # Reraise in order to get a 404 instead of a 403 error code - raise ActiveRecord::RecordNotFound - end -end diff --git a/app/controllers/public_timelines_controller.rb b/app/controllers/public_timelines_controller.rb deleted file mode 100644 index 53d4472d..00000000 --- a/app/controllers/public_timelines_controller.rb +++ /dev/null @@ -1,34 +0,0 @@ -# frozen_string_literal: true - -class PublicTimelinesController < ApplicationController - layout 'public' - - before_action :check_enabled - before_action :set_body_classes - before_action :set_instance_presenter - - def show - respond_to do |format| - format.html do - @initial_state_json = ActiveModelSerializers::SerializableResource.new( - InitialStatePresenter.new(settings: { known_fediverse: Setting.show_known_fediverse_at_about_page }, token: current_session&.token), - serializer: InitialStateSerializer - ).to_json - end - end - end - - private - - def check_enabled - raise ActiveRecord::RecordNotFound unless Setting.timeline_preview - end - - def set_body_classes - @body_classes = 'with-modals' - end - - def set_instance_presenter - @instance_presenter = InstancePresenter.new - end -end diff --git a/app/controllers/react_controller.rb b/app/controllers/react_controller.rb index 5295afcc..cb7d4822 100644 --- a/app/controllers/react_controller.rb +++ b/app/controllers/react_controller.rb @@ -52,7 +52,7 @@ class ReactController < ApplicationController end def find_route_matches - request.path.match(/\A\/(home|news|suggestions|links|messages|shortcuts|group|groups|list|lists|notifications|tags|compose|follow_requests|admin|account|settings|filters|timeline|blocks|domain_blocks|mutes)/) + request.path.match(/\A\/(home|news|suggestions|links|messages|shortcuts|group|groups|list|lists|notifications|tags|compose|follow_requests|admin|account|settings|filters|timeline|blocks|mutes)/) end def find_public_route_matches diff --git a/app/controllers/relationships_controller.rb b/app/controllers/relationships_controller.rb deleted file mode 100644 index e6705c32..00000000 --- a/app/controllers/relationships_controller.rb +++ /dev/null @@ -1,104 +0,0 @@ -# frozen_string_literal: true - -class RelationshipsController < ApplicationController - layout 'admin' - - before_action :authenticate_user! - before_action :set_accounts, only: :show - before_action :set_body_classes - - helper_method :following_relationship?, :followed_by_relationship?, :mutual_relationship? - - def show - @form = Form::AccountBatch.new - end - - def update - @form = Form::AccountBatch.new(form_account_batch_params.merge(current_account: current_account, action: action_from_button)) - @form.save - rescue ActionController::ParameterMissing - # Do nothing - ensure - redirect_to relationships_path(current_params) - end - - private - - def set_accounts - @accounts = relationships_scope.page(params[:page]).per(40) - end - - def relationships_scope - scope = begin - if following_relationship? - current_account.following.eager_load(:account_stat).reorder(nil) - else - current_account.followers.eager_load(:account_stat).reorder(nil) - end - end - - scope.merge!(Follow.recent) if params[:order].blank? || params[:order] == 'recent' - scope.merge!(Account.by_recent_status) if params[:order] == 'active' - scope.merge!(mutual_relationship_scope) if mutual_relationship? - scope.merge!(moved_account_scope) if params[:status] == 'moved' - scope.merge!(primary_account_scope) if params[:status] == 'primary' - scope.merge!(by_domain_scope) if params[:by_domain].present? - scope.merge!(dormant_account_scope) if params[:activity] == 'dormant' - - scope - end - - def mutual_relationship_scope - Account.where(id: current_account.following) - end - - def moved_account_scope - Account.where.not(moved_to_account_id: nil) - end - - def primary_account_scope - Account.where(moved_to_account_id: nil) - end - - def dormant_account_scope - AccountStat.where(last_status_at: nil).or(AccountStat.where(AccountStat.arel_table[:last_status_at].lt(1.month.ago))) - end - - def by_domain_scope - Account.where(domain: params[:by_domain]) - end - - def form_account_batch_params - params.require(:form_account_batch).permit(:action, account_ids: []) - end - - def following_relationship? - params[:relationship].blank? || params[:relationship] == 'following' - end - - def mutual_relationship? - params[:relationship] == 'mutual' - end - - def followed_by_relationship? - params[:relationship] == 'followed_by' - end - - def current_params - params.slice(:page, :status, :relationship, :by_domain, :activity, :order).permit(:page, :status, :relationship, :by_domain, :activity, :order) - end - - def action_from_button - if params[:unfollow] - 'unfollow' - elsif params[:remove_from_followers] - 'remove_from_followers' - elsif params[:block_domains] - 'block_domains' - end - end - - def set_body_classes - @body_classes = 'admin' - end -end diff --git a/app/controllers/remote_follow_controller.rb b/app/controllers/remote_follow_controller.rb deleted file mode 100644 index 8ba331cd..00000000 --- a/app/controllers/remote_follow_controller.rb +++ /dev/null @@ -1,47 +0,0 @@ -# frozen_string_literal: true - -class RemoteFollowController < ApplicationController - layout 'modal' - - before_action :set_account - before_action :gone, if: :suspended_account? - before_action :set_body_classes - - def new - @remote_follow = RemoteFollow.new(session_params) - end - - def create - @remote_follow = RemoteFollow.new(resource_params) - - if @remote_follow.valid? - session[:remote_follow] = @remote_follow.acct - redirect_to @remote_follow.subscribe_address_for(@account) - else - render :new - end - end - - private - - def resource_params - params.require(:remote_follow).permit(:acct) - end - - def session_params - { acct: session[:remote_follow] } - end - - def set_account - @account = Account.find_local!(params[:account_username]) - end - - def suspended_account? - @account.suspended? - end - - def set_body_classes - @body_classes = 'modal-layout' - @hide_header = true - end -end diff --git a/app/controllers/remote_interaction_controller.rb b/app/controllers/remote_interaction_controller.rb deleted file mode 100644 index 2cb19333..00000000 --- a/app/controllers/remote_interaction_controller.rb +++ /dev/null @@ -1,53 +0,0 @@ -# frozen_string_literal: true - -class RemoteInteractionController < ApplicationController - include Authorization - - layout 'modal' - - before_action :set_interaction_type - before_action :set_status - before_action :set_body_classes - - def new - @remote_follow = RemoteFollow.new(session_params) - end - - def create - @remote_follow = RemoteFollow.new(resource_params) - - if @remote_follow.valid? - session[:remote_follow] = @remote_follow.acct - redirect_to @remote_follow.interact_address_for(@status) - else - render :new - end - end - - private - - def resource_params - params.require(:remote_follow).permit(:acct) - end - - def session_params - { acct: session[:remote_follow] } - end - - def set_status - @status = Status.find(params[:id]) - authorize @status, :show? - rescue GabSocial::NotPermittedError - # Reraise in order to get a 404 - raise ActiveRecord::RecordNotFound - end - - def set_body_classes - @body_classes = 'modal-layout' - @hide_header = true - end - - def set_interaction_type - @interaction_type = %w(reply reblog favourite).include?(params[:type]) ? params[:type] : 'reply' - end -end diff --git a/app/controllers/remote_unfollows_controller.rb b/app/controllers/remote_unfollows_controller.rb deleted file mode 100644 index 494218da..00000000 --- a/app/controllers/remote_unfollows_controller.rb +++ /dev/null @@ -1,39 +0,0 @@ -# frozen_string_literal: true - -class RemoteUnfollowsController < ApplicationController - layout 'modal' - - before_action :authenticate_user! - before_action :set_body_classes - - def create - @account = unfollow_attempt.try(:target_account) - - if @account.nil? - render :error - else - render :success - end - rescue ActiveRecord::RecordNotFound, GabSocial::NotPermittedError - render :error - end - - private - - def unfollow_attempt - username, domain = acct_without_prefix.split('@') - UnfollowService.new.call(current_account, Account.find_remote!(username, domain)) - end - - def acct_without_prefix - acct_params.gsub(/\Aacct:/, '') - end - - def acct_params - params.fetch(:acct, '') - end - - def set_body_classes - @body_classes = 'modal-layout' - end -end diff --git a/app/controllers/settings/deletes_controller.rb b/app/controllers/settings/deletes_controller.rb index dd19aadf..709efaf1 100644 --- a/app/controllers/settings/deletes_controller.rb +++ b/app/controllers/settings/deletes_controller.rb @@ -3,7 +3,6 @@ class Settings::DeletesController < Settings::BaseController layout 'admin' - before_action :check_enabled_deletion before_action :authenticate_user! def show @@ -22,10 +21,6 @@ class Settings::DeletesController < Settings::BaseController private - def check_enabled_deletion - redirect_to root_path unless Setting.open_deletion - end - def delete_params params.require(:form_delete_confirmation).permit(:password) end diff --git a/app/controllers/settings/exports/blocked_domains_controller.rb b/app/controllers/settings/exports/blocked_domains_controller.rb deleted file mode 100644 index 6676ce34..00000000 --- a/app/controllers/settings/exports/blocked_domains_controller.rb +++ /dev/null @@ -1,19 +0,0 @@ -# frozen_string_literal: true - -module Settings - module Exports - class BlockedDomainsController < ApplicationController - include ExportControllerConcern - - def index - send_export_file - end - - private - - def export_data - @export.to_blocked_domains_csv - end - end - end -end diff --git a/app/controllers/settings/identity_proofs_controller.rb b/app/controllers/settings/identity_proofs_controller.rb deleted file mode 100644 index e22b4d9b..00000000 --- a/app/controllers/settings/identity_proofs_controller.rb +++ /dev/null @@ -1,63 +0,0 @@ -# frozen_string_literal: true - -class Settings::IdentityProofsController < Settings::BaseController - layout 'admin' - - before_action :authenticate_user! - before_action :check_required_params, only: :new - - def index - @proofs = AccountIdentityProof.where(account: current_account).order(provider: :asc, provider_username: :asc) - @proofs.each(&:refresh!) - end - - def new - @proof = current_account.identity_proofs.new( - token: params[:token], - provider: params[:provider], - provider_username: params[:provider_username] - ) - - if current_account.username.casecmp(params[:username]).zero? - render layout: 'auth' - else - flash[:alert] = I18n.t('identity_proofs.errors.wrong_user', proving: params[:username], current: current_account.username) - redirect_to settings_identity_proofs_path - end - end - - def create - @proof = current_account.identity_proofs.where(provider: resource_params[:provider], provider_username: resource_params[:provider_username]).first_or_initialize(resource_params) - @proof.token = resource_params[:token] - - if @proof.save - PostStatusService.new.call(current_user.account, text: post_params[:status_text]) if publish_proof? - redirect_to @proof.on_success_path(params[:user_agent]) - else - flash[:alert] = I18n.t('identity_proofs.errors.failed', provider: @proof.provider.capitalize) - redirect_to settings_identity_proofs_path - end - end - - private - - def check_required_params - redirect_to settings_identity_proofs_path unless [:provider, :provider_username, :username, :token].all? { |k| params[k].present? } - end - - def resource_params - params.require(:account_identity_proof).permit(:provider, :provider_username, :token) - end - - def publish_proof? - ActiveModel::Type::Boolean.new.cast(post_params[:post_status]) - end - - def post_params - params.require(:account_identity_proof).permit(:post_status, :status_text) - end - - def set_body_classes - @body_classes = '' - end -end diff --git a/app/controllers/settings/imports_controller.rb b/app/controllers/settings/imports_controller.rb deleted file mode 100644 index 38f2e39c..00000000 --- a/app/controllers/settings/imports_controller.rb +++ /dev/null @@ -1,34 +0,0 @@ -# frozen_string_literal: true - -class Settings::ImportsController < Settings::BaseController - layout 'admin' - - before_action :authenticate_user! - before_action :set_account - - def show - @import = Import.new - end - - def create - @import = Import.new(import_params) - @import.account = @account - - if @import.save - ImportWorker.perform_async(@import.id) - redirect_to settings_import_path, notice: I18n.t('imports.success') - else - render :show - end - end - - private - - def set_account - @account = current_user.account - end - - def import_params - params.require(:import).permit(:data, :type) - end -end diff --git a/app/controllers/settings/migrations_controller.rb b/app/controllers/settings/migrations_controller.rb deleted file mode 100644 index 59eb4877..00000000 --- a/app/controllers/settings/migrations_controller.rb +++ /dev/null @@ -1,34 +0,0 @@ -# frozen_string_literal: true - -class Settings::MigrationsController < Settings::BaseController - layout 'admin' - - before_action :authenticate_user! - - def show - @migration = Form::Migration.new(account: current_account.moved_to_account) - end - - def update - @migration = Form::Migration.new(resource_params) - - if @migration.valid? && migration_account_changed? - current_account.update!(moved_to_account: @migration.account) - ActivityPub::UpdateDistributionWorker.perform_async(current_account.id) - redirect_to settings_migration_path, notice: I18n.t('migrations.updated_msg') - else - render :show - end - end - - private - - def resource_params - params.require(:migration).permit(:acct) - end - - def migration_account_changed? - current_account.moved_to_account_id != @migration.account&.id && - current_account.id != @migration.account&.id - end -end diff --git a/app/controllers/settings/notifications_controller.rb b/app/controllers/settings/notifications_controller.rb index b1e527e4..6464c7eb 100644 --- a/app/controllers/settings/notifications_controller.rb +++ b/app/controllers/settings/notifications_controller.rb @@ -25,7 +25,7 @@ class Settings::NotificationsController < Settings::BaseController def user_settings_params params.require(:user).permit( - notification_emails: %i(follow follow_request reblog favourite mention digest report pending_account emails_from_gabcom), + notification_emails: %i(follow follow_request reblog favourite mention digest report emails_from_gabcom), interactions: %i(must_be_follower must_be_following must_be_following_dm) ) end diff --git a/app/controllers/settings/preferences_controller.rb b/app/controllers/settings/preferences_controller.rb index cb1de69d..4ce457e3 100644 --- a/app/controllers/settings/preferences_controller.rb +++ b/app/controllers/settings/preferences_controller.rb @@ -47,9 +47,8 @@ class Settings::PreferencesController < Settings::BaseController :setting_theme, :setting_hide_network, :setting_aggregate_reblogs, - :setting_show_application, :setting_group_in_home_feed, - notification_emails: %i(follow follow_request reblog favourite mention digest report pending_account emails_from_gabcom), + notification_emails: %i(follow follow_request reblog favourite mention digest report emails_from_gabcom), interactions: %i(must_be_follower must_be_following) ) end diff --git a/app/controllers/settings/profiles_controller.rb b/app/controllers/settings/profiles_controller.rb index 32714955..0312017b 100644 --- a/app/controllers/settings/profiles_controller.rb +++ b/app/controllers/settings/profiles_controller.rb @@ -22,7 +22,6 @@ class Settings::ProfilesController < Settings::BaseController redirect_to settings_profile_path else if UpdateAccountService.new.call(@account, account_params) - ActivityPub::UpdateDistributionWorker.perform_async(@account.id) redirect_to settings_profile_path, notice: I18n.t('generic.changes_saved_msg') else @account.build_fields diff --git a/app/controllers/shares_controller.rb b/app/controllers/shares_controller.rb deleted file mode 100644 index af605b98..00000000 --- a/app/controllers/shares_controller.rb +++ /dev/null @@ -1,32 +0,0 @@ -# frozen_string_literal: true - -class SharesController < ApplicationController - layout 'modal' - - before_action :authenticate_user! - before_action :set_body_classes - - def show - serializable_resource = ActiveModelSerializers::SerializableResource.new(InitialStatePresenter.new(initial_state_params), serializer: InitialStateSerializer) - @initial_state_json = serializable_resource.to_json - end - - private - - def initial_state_params - text = [params[:title], params[:text], params[:url]].compact.join(' ') - - { - settings: Web::Setting.find_by(user: current_user)&.data || {}, - push_subscription: current_account.user.web_push_subscription(current_session), - current_account: current_account, - token: current_session.token, - admin: Account.find_local(Setting.site_contact_username.strip.gsub(/\A@/, '')), - text: text, - } - end - - def set_body_classes - @body_classes = 'modal-layout compose-standalone' - end -end diff --git a/app/controllers/statuses_controller.rb b/app/controllers/statuses_controller.rb deleted file mode 100644 index dbb4bd08..00000000 --- a/app/controllers/statuses_controller.rb +++ /dev/null @@ -1,230 +0,0 @@ -# frozen_string_literal: true - -class StatusesController < ReactController - include SignatureAuthentication - include Authorization - - ANCESTORS_LIMIT = 40 - DESCENDANTS_LIMIT = 60 - DESCENDANTS_DEPTH_LIMIT = 20 - - before_action :set_account - before_action :set_status - before_action :set_instance_presenter - before_action :set_link_headers - before_action :check_account_suspension - before_action :redirect_to_original, only: [:show] - before_action :set_referrer_policy_header, only: [:show] - before_action :set_cache_headers - before_action :set_replies, only: [:replies] - - content_security_policy only: :embed do |p| - p.frame_ancestors(false) - end - - def show - respond_to do |format| - format.html do - unless user_signed_in? - skip_session! - expires_in 10.seconds, public: true - end - - return process(:react) - end - - format.json do - mark_cacheable! unless @stream_entry.hidden? - - render_cached_json(['activitypub', 'note', @status], content_type: 'application/activity+json', public: !@stream_entry.hidden?) do - ActiveModelSerializers::SerializableResource.new(@status, serializer: ActivityPub::NoteSerializer, adapter: ActivityPub::Adapter) - end - end - end - end - - def activity - skip_session! - - render_cached_json(['activitypub', 'activity', @status], content_type: 'application/activity+json', public: !@stream_entry.hidden?) do - ActiveModelSerializers::SerializableResource.new(@status, serializer: ActivityPub::ActivitySerializer, adapter: ActivityPub::Adapter) - end - end - - def embed - raise ActiveRecord::RecordNotFound if @status.hidden? - - skip_session! - expires_in 180, public: true - response.headers['X-Frame-Options'] = 'ALLOWALL' - @autoplay = ActiveModel::Type::Boolean.new.cast(params[:autoplay]) - - render 'stream_entries/embed', layout: 'embedded' - end - - def replies - skip_session! - - render json: replies_collection_presenter, - serializer: ActivityPub::CollectionSerializer, - adapter: ActivityPub::Adapter, - content_type: 'application/activity+json', - skip_activities: true - end - - private - - def replies_collection_presenter - page = ActivityPub::CollectionPresenter.new( - id: replies_account_status_url(@account, @status, page_params), - type: :unordered, - part_of: replies_account_status_url(@account, @status), - next: next_page, - items: @replies.map { |status| status.local ? status : status.id } - ) - if page_requested? - page - else - ActivityPub::CollectionPresenter.new( - id: replies_account_status_url(@account, @status), - type: :unordered, - first: page - ) - end - end - - def create_descendant_thread(starting_depth, statuses) - depth = starting_depth + statuses.size - if depth < DESCENDANTS_DEPTH_LIMIT - { statuses: statuses, starting_depth: starting_depth } - else - next_status = statuses.pop - { statuses: statuses, starting_depth: starting_depth, next_status: next_status } - end - end - - def set_account - @account = Account.find_acct!(params[:account_username]) - end - - def set_ancestors - @ancestors = @status.reply? ? cache_collection(@status.ancestors(ANCESTORS_LIMIT, current_account), Status) : [] - @next_ancestor = @ancestors.size < ANCESTORS_LIMIT ? nil : @ancestors.shift - end - - def set_descendants - @max_descendant_thread_id = params[:max_descendant_thread_id]&.to_i - @since_descendant_thread_id = params[:since_descendant_thread_id]&.to_i - - descendants = cache_collection( - @status.descendants( - DESCENDANTS_LIMIT, - current_account, - @max_descendant_thread_id, - @since_descendant_thread_id, - DESCENDANTS_DEPTH_LIMIT - ), - Status - ) - - @descendant_threads = [] - - if descendants.present? - statuses = [descendants.first] - starting_depth = 0 - - descendants.drop(1).each_with_index do |descendant, index| - if descendants[index].id == descendant.in_reply_to_id - statuses << descendant - else - @descendant_threads << create_descendant_thread(starting_depth, statuses) - - # The thread is broken, assume it's a reply to the root status - starting_depth = 0 - - # ... unless we can find its ancestor in one of the already-processed threads - @descendant_threads.reverse_each do |descendant_thread| - statuses = descendant_thread[:statuses] - - index = statuses.find_index do |thread_status| - thread_status.id == descendant.in_reply_to_id - end - - if index.present? - starting_depth = descendant_thread[:starting_depth] + index + 1 - break - end - end - - statuses = [descendant] - end - end - - @descendant_threads << create_descendant_thread(starting_depth, statuses) - end - - @max_descendant_thread_id = @descendant_threads.pop[:statuses].first.id if descendants.size >= DESCENDANTS_LIMIT - end - - def set_link_headers - return if !@account.local? # TODO: Handle remote accounts - - response.headers['Link'] = LinkHeader.new( - [ - [account_stream_entry_url(@account, @status.stream_entry, format: 'atom'), [%w(rel alternate), %w(type application/atom+xml)]], - [ActivityPub::TagManager.instance.uri_for(@status), [%w(rel alternate), %w(type application/activity+json)]], - ] - ) - end - - def set_status - @status = @account.statuses.find(params[:id]) - @stream_entry = @status.stream_entry - @type = @stream_entry&.activity_type&.downcase - - authorize @status, :show? - rescue GabSocial::NotPermittedError - # Reraise in order to get a 404 - raise ActiveRecord::RecordNotFound - end - - def set_instance_presenter - @instance_presenter = InstancePresenter.new - end - - def check_account_suspension - gone if @account.suspended? - end - - def redirect_to_original - redirect_to ::TagManager.instance.url_for(@status.reblog) if @status.reblog? - end - - def set_referrer_policy_header - return if @status.public_visibility? || @status.unlisted_visibility? - response.headers['Referrer-Policy'] = 'origin' - end - - def page_requested? - params[:page] == 'true' - end - - def set_replies - @replies = page_params[:other_accounts] ? Status.where.not(account_id: @account.id) : @account.statuses - @replies = @replies.where(in_reply_to_id: @status.id, visibility: [:public, :unlisted]) - @replies = @replies.paginate_by_min_id(DESCENDANTS_LIMIT, params[:min_id]) - end - - def next_page - last_reply = @replies.last - return if last_reply.nil? - same_account = last_reply.account_id == @account.id - return unless same_account || @replies.size == DESCENDANTS_LIMIT - same_account = false unless @replies.size == DESCENDANTS_LIMIT - replies_account_status_url(@account, @status, page: true, min_id: last_reply.id, other_accounts: !same_account) - end - - def page_params - { page: true, other_accounts: params[:other_accounts], min_id: params[:min_id] }.compact - end -end diff --git a/app/controllers/stream_entries_controller.rb b/app/controllers/stream_entries_controller.rb deleted file mode 100644 index e4003adc..00000000 --- a/app/controllers/stream_entries_controller.rb +++ /dev/null @@ -1,70 +0,0 @@ -# frozen_string_literal: true - -class StreamEntriesController < ApplicationController - include Authorization - include SignatureVerification - - layout 'public' - - before_action :set_account - before_action :set_stream_entry - before_action :set_link_headers - before_action :check_account_suspension - before_action :set_cache_headers - - def show - respond_to do |format| - format.html do - unless user_signed_in? - skip_session! - expires_in 5.minutes, public: true - end - - redirect_to short_account_status_url(params[:account_username], @stream_entry.activity) if @type == 'status' - end - - format.atom do - unless @stream_entry.hidden? - skip_session! - expires_in 3.minutes, public: true - end - - render xml: OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.entry(@stream_entry, true)) - end - end - end - - def embed - redirect_to embed_short_account_status_url(@account, @stream_entry.activity), status: 301 - end - - private - - def set_account - @account = Account.find_local!(params[:account_username]) - end - - def set_link_headers - response.headers['Link'] = LinkHeader.new( - [ - [account_stream_entry_url(@account, @stream_entry, format: 'atom'), [%w(rel alternate), %w(type application/atom+xml)]], - [ActivityPub::TagManager.instance.uri_for(@stream_entry.activity), [%w(rel alternate), %w(type application/activity+json)]], - ] - ) - end - - def set_stream_entry - @stream_entry = @account.stream_entries.where(activity_type: 'Status').find(params[:id]) - @type = @stream_entry.activity_type.downcase - - raise ActiveRecord::RecordNotFound if @stream_entry.activity.nil? - authorize @stream_entry.activity, :show? if @stream_entry.hidden? - rescue GabSocial::NotPermittedError - # Reraise in order to get a 404 - raise ActiveRecord::RecordNotFound - end - - def check_account_suspension - gone if @account.suspended? - end -end diff --git a/app/controllers/tags_controller.rb b/app/controllers/tags_controller.rb deleted file mode 100644 index 02df87c6..00000000 --- a/app/controllers/tags_controller.rb +++ /dev/null @@ -1,59 +0,0 @@ -# frozen_string_literal: true - -class TagsController < ApplicationController - PAGE_SIZE = 20 - - layout 'public' - - before_action :set_body_classes - before_action :set_instance_presenter - - def show - @tag = Tag.find_normalized!(params[:id]) - - respond_to do |format| - format.html do - @initial_state_json = ActiveModelSerializers::SerializableResource.new( - InitialStatePresenter.new(settings: {}, token: current_session&.token), - serializer: InitialStateSerializer - ).to_json - end - - format.rss do - @statuses = HashtagQueryService.new.call(@tag, params.slice(:any, :all, :none)).limit(PAGE_SIZE) - @statuses = cache_collection(@statuses, Status) - - render xml: RSS::TagSerializer.render(@tag, @statuses) - end - - format.json do - @statuses = HashtagQueryService.new.call(@tag, params.slice(:any, :all, :none), current_account).paginate_by_max_id(PAGE_SIZE, params[:max_id]) - @statuses = cache_collection(@statuses, Status) - - render json: collection_presenter, - serializer: ActivityPub::CollectionSerializer, - adapter: ActivityPub::Adapter, - content_type: 'application/activity+json' - end - end - end - - private - - def set_body_classes - @body_classes = 'with-modals' - end - - def set_instance_presenter - @instance_presenter = InstancePresenter.new - end - - def collection_presenter - ActivityPub::CollectionPresenter.new( - id: tag_url(@tag, params.slice(:any, :all, :none)), - type: :ordered, - size: @tag.statuses.count, - items: @statuses.map { |s| ActivityPub::TagManager.instance.uri_for(s) } - ) - end -end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 5a636508..86a5a0d4 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -19,28 +19,8 @@ module ApplicationHelper !user_signed_in? && !single_user_mode? end - def open_registrations? - Setting.registrations_mode == 'open' - end - - def approved_registrations? - Setting.registrations_mode == 'approved' - end - - def closed_registrations? - Setting.registrations_mode == 'none' - end - def available_sign_up_path - if closed_registrations? - 'https://gab.com/hosting#getting-started' - else - new_user_registration_path - end - end - - def open_deletion? - Setting.open_deletion + new_user_registration_path end def locale_direction diff --git a/app/helpers/home_helper.rb b/app/helpers/home_helper.rb index df60b7dd..8e17bda2 100644 --- a/app/helpers/home_helper.rb +++ b/app/helpers/home_helper.rb @@ -65,13 +65,4 @@ module HomeHelper end end - def sign_up_message - if closed_registrations? - t('auth.registration_closed', instance: site_hostname) - elsif open_registrations? - t('auth.register') - elsif approved_registrations? - t('auth.apply_for_account') - end - end end diff --git a/app/helpers/stream_entries_helper.rb b/app/helpers/statuses_helper.rb similarity index 91% rename from app/helpers/stream_entries_helper.rb rename to app/helpers/statuses_helper.rb index d1700151..948a9be0 100644 --- a/app/helpers/stream_entries_helper.rb +++ b/app/helpers/statuses_helper.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module StreamEntriesHelper +module StatusesHelper EMBEDDED_CONTROLLER = 'statuses' EMBEDDED_ACTION = 'embed' @@ -41,16 +41,6 @@ module StreamEntriesHelper def account_badge(account, all: false) if account.bot? content_tag(:div, content_tag(:div, t('accounts.roles.bot'), class: 'account-role bot'), class: 'roles') - elsif (Setting.show_staff_badge && account.user_staff?) || all - content_tag(:div, class: 'roles') do - if all && !account.user_staff? - content_tag(:div, t('admin.accounts.roles.user'), class: 'account-role') - elsif account.user_admin? - content_tag(:div, t('accounts.roles.admin'), class: 'account-role admin') - elsif account.user_moderator? - content_tag(:div, t('accounts.roles.moderator'), class: 'account-role moderator') - end - end end end diff --git a/app/javascript/gabsocial/actions/accounts.js b/app/javascript/gabsocial/actions/accounts.js index eb0ae3f5..38c1d563 100644 --- a/app/javascript/gabsocial/actions/accounts.js +++ b/app/javascript/gabsocial/actions/accounts.js @@ -36,14 +36,6 @@ export const ACCOUNT_UNMUTE_REQUEST = 'ACCOUNT_UNMUTE_REQUEST'; export const ACCOUNT_UNMUTE_SUCCESS = 'ACCOUNT_UNMUTE_SUCCESS'; export const ACCOUNT_UNMUTE_FAIL = 'ACCOUNT_UNMUTE_FAIL'; -export const ACCOUNT_PIN_REQUEST = 'ACCOUNT_PIN_REQUEST'; -export const ACCOUNT_PIN_SUCCESS = 'ACCOUNT_PIN_SUCCESS'; -export const ACCOUNT_PIN_FAIL = 'ACCOUNT_PIN_FAIL'; - -export const ACCOUNT_UNPIN_REQUEST = 'ACCOUNT_UNPIN_REQUEST'; -export const ACCOUNT_UNPIN_SUCCESS = 'ACCOUNT_UNPIN_SUCCESS'; -export const ACCOUNT_UNPIN_FAIL = 'ACCOUNT_UNPIN_FAIL'; - export const FOLLOWERS_FETCH_REQUEST = 'FOLLOWERS_FETCH_REQUEST'; export const FOLLOWERS_FETCH_SUCCESS = 'FOLLOWERS_FETCH_SUCCESS'; export const FOLLOWERS_FETCH_FAIL = 'FOLLOWERS_FETCH_FAIL'; @@ -772,72 +764,3 @@ export function rejectFollowRequestFail(id, error) { }; }; -export function pinAccount(id) { - return (dispatch, getState) => { - if (!me) return; - - dispatch(pinAccountRequest(id)); - - api(getState).post(`/api/v1/accounts/${id}/pin`).then(response => { - dispatch(pinAccountSuccess(response.data)); - }).catch(error => { - dispatch(pinAccountFail(error)); - }); - }; -}; - -export function unpinAccount(id) { - return (dispatch, getState) => { - if (!me) return; - - dispatch(unpinAccountRequest(id)); - - api(getState).post(`/api/v1/accounts/${id}/unpin`).then(response => { - dispatch(unpinAccountSuccess(response.data)); - }).catch(error => { - dispatch(unpinAccountFail(error)); - }); - }; -}; - -export function pinAccountRequest(id) { - return { - type: ACCOUNT_PIN_REQUEST, - id, - }; -}; - -export function pinAccountSuccess(relationship) { - return { - type: ACCOUNT_PIN_SUCCESS, - relationship, - }; -}; - -export function pinAccountFail(error) { - return { - type: ACCOUNT_PIN_FAIL, - error, - }; -}; - -export function unpinAccountRequest(id) { - return { - type: ACCOUNT_UNPIN_REQUEST, - id, - }; -}; - -export function unpinAccountSuccess(relationship) { - return { - type: ACCOUNT_UNPIN_SUCCESS, - relationship, - }; -}; - -export function unpinAccountFail(error) { - return { - type: ACCOUNT_UNPIN_FAIL, - error, - }; -}; diff --git a/app/javascript/gabsocial/actions/blocks.js b/app/javascript/gabsocial/actions/blocks.js index f241eef7..279f505f 100644 --- a/app/javascript/gabsocial/actions/blocks.js +++ b/app/javascript/gabsocial/actions/blocks.js @@ -11,79 +11,69 @@ export const BLOCKS_EXPAND_REQUEST = 'BLOCKS_EXPAND_REQUEST' export const BLOCKS_EXPAND_SUCCESS = 'BLOCKS_EXPAND_SUCCESS' export const BLOCKS_EXPAND_FAIL = 'BLOCKS_EXPAND_FAIL' -export function fetchBlocks() { - return (dispatch, getState) => { - if (!me) return +/** + * + */ +export const fetchBlocks = () => (dispatch, getState) => { + if (!me) return - dispatch(fetchBlocksRequest()) + dispatch(fetchBlocksRequest()) - api(getState).get('/api/v1/blocks').then(response => { - const next = getLinks(response).refs.find(link => link.rel === 'next') - dispatch(importFetchedAccounts(response.data)) - dispatch(fetchBlocksSuccess(response.data, next ? next.uri : null)) - dispatch(fetchRelationships(response.data.map(item => item.id))) - }).catch(error => dispatch(fetchBlocksFail(error))) - } + api(getState).get('/api/v1/blocks').then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next') + dispatch(importFetchedAccounts(response.data)) + dispatch(fetchBlocksSuccess(response.data, next ? next.uri : null)) + dispatch(fetchRelationships(response.data.map(item => item.id))) + }).catch(error => dispatch(fetchBlocksFail(error))) } -export function fetchBlocksRequest() { - return { - type: BLOCKS_FETCH_REQUEST, - } +export const fetchBlocksRequest = () => ({ + type: BLOCKS_FETCH_REQUEST, +}) + +export const fetchBlocksSuccess = (accounts, next) => ({ + type: BLOCKS_FETCH_SUCCESS, + accounts, + next, +}) + +export const fetchBlocksFail = (error) => ({ + type: BLOCKS_FETCH_FAIL, + error, +}) + +/** + * + */ +export const expandBlocks = () => (dispatch, getState) => { + if (!me) return + + const url = getState().getIn(['user_lists', 'blocks', me, 'next']) + const isLoading = getState().getIn(['user_lists', 'blocks', me, 'isLoading']) + + if (url === null || isLoading) return + + dispatch(expandBlocksRequest()) + + api(getState).get(url).then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next') + dispatch(importFetchedAccounts(response.data)) + dispatch(expandBlocksSuccess(response.data, next ? next.uri : null)) + dispatch(fetchRelationships(response.data.map(item => item.id))) + }).catch(error => dispatch(expandBlocksFail(error))) } -export function fetchBlocksSuccess(accounts, next) { - return { - type: BLOCKS_FETCH_SUCCESS, - accounts, - next, - } -} +export const expandBlocksRequest = () => ({ + type: BLOCKS_EXPAND_REQUEST, +}) -export function fetchBlocksFail(error) { - return { - type: BLOCKS_FETCH_FAIL, - error, - } -} +export const expandBlocksSuccess = (accounts, next) => ({ + type: BLOCKS_EXPAND_SUCCESS, + accounts, + next, +}) -export function expandBlocks() { - return (dispatch, getState) => { - if (!me) return - - const url = getState().getIn(['user_lists', 'blocks', me, 'next']) - const isLoading = getState().getIn(['user_lists', 'blocks', me, 'isLoading']) - - if (url === null || isLoading) return - - dispatch(expandBlocksRequest()) - - api(getState).get(url).then(response => { - const next = getLinks(response).refs.find(link => link.rel === 'next') - dispatch(importFetchedAccounts(response.data)) - dispatch(expandBlocksSuccess(response.data, next ? next.uri : null)) - dispatch(fetchRelationships(response.data.map(item => item.id))) - }).catch(error => dispatch(expandBlocksFail(error))) - } -} - -export function expandBlocksRequest() { - return { - type: BLOCKS_EXPAND_REQUEST, - } -} - -export function expandBlocksSuccess(accounts, next) { - return { - type: BLOCKS_EXPAND_SUCCESS, - accounts, - next, - } -} - -export function expandBlocksFail(error) { - return { - type: BLOCKS_EXPAND_FAIL, - error, - } -} +export const expandBlocksFail = (error) => ({ + type: BLOCKS_EXPAND_FAIL, + error, +}) diff --git a/app/javascript/gabsocial/actions/bookmarks.js b/app/javascript/gabsocial/actions/bookmarks.js index 6bbce6dd..3c41d2ff 100644 --- a/app/javascript/gabsocial/actions/bookmarks.js +++ b/app/javascript/gabsocial/actions/bookmarks.js @@ -10,89 +10,79 @@ export const BOOKMARKED_STATUSES_EXPAND_REQUEST = 'BOOKMARKED_STATUSES_EXPAND_RE export const BOOKMARKED_STATUSES_EXPAND_SUCCESS = 'BOOKMARKED_STATUSES_EXPAND_SUCCESS' export const BOOKMARKED_STATUSES_EXPAND_FAIL = 'BOOKMARKED_STATUSES_EXPAND_FAIL' -export function fetchBookmarkedStatuses() { - return (dispatch, getState) => { - if (!me) return +/** + * + */ +export const fetchBookmarkedStatuses = () => (dispatch, getState) => { + if (!me) return - if (getState().getIn(['status_lists', 'bookmarks', 'isLoading'])) { - return - } - - dispatch(fetchBookmarkedStatusesRequest()) - - api(getState).get('/api/v1/bookmarks').then(response => { - const next = getLinks(response).refs.find(link => link.rel === 'next') - dispatch(importFetchedStatuses(response.data)) - dispatch(fetchBookmarkedStatusesSuccess(response.data, next ? next.uri : null)) - }).catch(error => { - dispatch(fetchBookmarkedStatusesFail(error)) - }) + if (getState().getIn(['status_lists', 'bookmarks', 'isLoading'])) { + return } + + dispatch(fetchBookmarkedStatusesRequest()) + + api(getState).get('/api/v1/bookmarks').then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next') + dispatch(importFetchedStatuses(response.data)) + dispatch(fetchBookmarkedStatusesSuccess(response.data, next ? next.uri : null)) + }).catch(error => { + dispatch(fetchBookmarkedStatusesFail(error)) + }) } -export function fetchBookmarkedStatusesRequest() { - return { - type: BOOKMARKED_STATUSES_FETCH_REQUEST, - skipLoading: true, +const fetchBookmarkedStatusesRequest = () => ({ + type: BOOKMARKED_STATUSES_FETCH_REQUEST, + skipLoading: true, +}) + +const fetchBookmarkedStatusesSuccess = (statuses, next) => ({ + type: BOOKMARKED_STATUSES_FETCH_SUCCESS, + statuses, + next, + skipLoading: true, +}) + +const fetchBookmarkedStatusesFail = (error) => ({ + type: BOOKMARKED_STATUSES_FETCH_FAIL, + error, + skipLoading: true, +}) + +/** + * + */ +export const expandBookmarkedStatuses = () => (dispatch, getState) => { + if (!me) return + + const url = getState().getIn(['status_lists', 'bookmarks', 'next'], null) + + if (url === null || getState().getIn(['status_lists', 'bookmarks', 'isLoading'])) { + return } + + dispatch(expandBookmarkedStatusesRequest()) + + api(getState).get(url).then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next') + dispatch(importFetchedStatuses(response.data)) + dispatch(expandBookmarkedStatusesSuccess(response.data, next ? next.uri : null)) + }).catch(error => { + dispatch(expandBookmarkedStatusesFail(error)) + }) } -export function fetchBookmarkedStatusesSuccess(statuses, next) { - return { - type: BOOKMARKED_STATUSES_FETCH_SUCCESS, - statuses, - next, - skipLoading: true, - } -} +const expandBookmarkedStatusesRequest = () => ({ + type: BOOKMARKED_STATUSES_EXPAND_REQUEST, +}) -export function fetchBookmarkedStatusesFail(error) { - return { - type: BOOKMARKED_STATUSES_FETCH_FAIL, - error, - skipLoading: true, - } -} +const expandBookmarkedStatusesSuccess = (statuses, next) => ({ + type: BOOKMARKED_STATUSES_EXPAND_SUCCESS, + statuses, + next, +}) -export function expandBookmarkedStatuses() { - return (dispatch, getState) => { - if (!me) return - - const url = getState().getIn(['status_lists', 'bookmarks', 'next'], null) - - if (url === null || getState().getIn(['status_lists', 'bookmarks', 'isLoading'])) { - return - } - - dispatch(expandBookmarkedStatusesRequest()) - - api(getState).get(url).then(response => { - const next = getLinks(response).refs.find(link => link.rel === 'next') - dispatch(importFetchedStatuses(response.data)) - dispatch(expandBookmarkedStatusesSuccess(response.data, next ? next.uri : null)) - }).catch(error => { - dispatch(expandBookmarkedStatusesFail(error)) - }) - } -} - -export function expandBookmarkedStatusesRequest() { - return { - type: BOOKMARKED_STATUSES_EXPAND_REQUEST, - } -} - -export function expandBookmarkedStatusesSuccess(statuses, next) { - return { - type: BOOKMARKED_STATUSES_EXPAND_SUCCESS, - statuses, - next, - } -} - -export function expandBookmarkedStatusesFail(error) { - return { - type: BOOKMARKED_STATUSES_EXPAND_FAIL, - error, - } -} +const expandBookmarkedStatusesFail = (error) => ({ + type: BOOKMARKED_STATUSES_EXPAND_FAIL, + error, +}) diff --git a/app/javascript/gabsocial/actions/bundles.js b/app/javascript/gabsocial/actions/bundles.js index ecc9c8f7..97fc24de 100644 --- a/app/javascript/gabsocial/actions/bundles.js +++ b/app/javascript/gabsocial/actions/bundles.js @@ -1,25 +1,19 @@ -export const BUNDLE_FETCH_REQUEST = 'BUNDLE_FETCH_REQUEST'; -export const BUNDLE_FETCH_SUCCESS = 'BUNDLE_FETCH_SUCCESS'; -export const BUNDLE_FETCH_FAIL = 'BUNDLE_FETCH_FAIL'; +export const BUNDLE_FETCH_REQUEST = 'BUNDLE_FETCH_REQUEST' +export const BUNDLE_FETCH_SUCCESS = 'BUNDLE_FETCH_SUCCESS' +export const BUNDLE_FETCH_FAIL = 'BUNDLE_FETCH_FAIL' -export function fetchBundleRequest(skipLoading) { - return { - type: BUNDLE_FETCH_REQUEST, - skipLoading, - }; -} +export const fetchBundleRequest = (skipLoading) => ({ + type: BUNDLE_FETCH_REQUEST, + skipLoading, +}) -export function fetchBundleSuccess(skipLoading) { - return { - type: BUNDLE_FETCH_SUCCESS, - skipLoading, - }; -} +export const fetchBundleSuccess = (skipLoading) => ({ + type: BUNDLE_FETCH_SUCCESS, + skipLoading, +}) -export function fetchBundleFail(error, skipLoading) { - return { - type: BUNDLE_FETCH_FAIL, - error, - skipLoading, - }; -} +export const fetchBundleFail = (error, skipLoading) => ({ + type: BUNDLE_FETCH_FAIL, + error, + skipLoading, +}) diff --git a/app/javascript/gabsocial/actions/compose.js b/app/javascript/gabsocial/actions/compose.js index d1a81375..fe9e4d80 100644 --- a/app/javascript/gabsocial/actions/compose.js +++ b/app/javascript/gabsocial/actions/compose.js @@ -1,23 +1,23 @@ -import api from '../api'; +import api from '../api' import { FormattedMessage } from 'react-intl' -import { CancelToken, isCancel } from 'axios'; +import { CancelToken, isCancel } from 'axios' import throttle from 'lodash.throttle' import moment from 'moment-mini' import { isMobile } from '../utils/is_mobile' -import { search as emojiSearch } from '../components/emoji/emoji_mart_search_light'; +import { search as emojiSearch } from '../components/emoji/emoji_mart_search_light' import { urlRegex } from '../features/ui/util/url_regex' -import { tagHistory } from '../settings'; +import { tagHistory } from '../settings' import { joinGroup } from './groups' -import { useEmoji } from './emojis'; -import resizeImage from '../utils/resize_image'; -import { importFetchedAccounts } from './importer'; +import { useEmoji } from './emojis' +import resizeImage from '../utils/resize_image' +import { importFetchedAccounts } from './importer' import { updateTimelineQueue, updateTimeline, } from './timelines' -// import { showAlert, showAlertForError } from './alerts'; -import { defineMessages } from 'react-intl'; -import { openModal, closeModal } from './modal'; +// import { showAlert, showAlertForError } from './alerts' +import { defineMessages } from 'react-intl' +import { openModal, closeModal } from './modal' import { STATUS_EXPIRATION_OPTION_5_MINUTES, STATUS_EXPIRATION_OPTION_60_MINUTES, @@ -26,57 +26,58 @@ import { STATUS_EXPIRATION_OPTION_3_DAYS, STATUS_EXPIRATION_OPTION_7_DAYS, } from '../constants' -import { me } from '../initial_state'; +import { me } from '../initial_state' import { makeGetStatus } from '../selectors' -let cancelFetchComposeSuggestionsAccounts; +let cancelFetchComposeSuggestionsAccounts -export const COMPOSE_CHANGE = 'COMPOSE_CHANGE'; -export const COMPOSE_SUBMIT_REQUEST = 'COMPOSE_SUBMIT_REQUEST'; -export const COMPOSE_SUBMIT_SUCCESS = 'COMPOSE_SUBMIT_SUCCESS'; -export const COMPOSE_SUBMIT_FAIL = 'COMPOSE_SUBMIT_FAIL'; -export const COMPOSE_REPLY = 'COMPOSE_REPLY'; -export const COMPOSE_QUOTE = 'COMPOSE_QUOTE'; -export const COMPOSE_REPLY_CANCEL = 'COMPOSE_REPLY_CANCEL'; -export const COMPOSE_MENTION = 'COMPOSE_MENTION'; -export const COMPOSE_RESET = 'COMPOSE_RESET'; -export const COMPOSE_UPLOAD_REQUEST = 'COMPOSE_UPLOAD_REQUEST'; -export const COMPOSE_UPLOAD_SUCCESS = 'COMPOSE_UPLOAD_SUCCESS'; -export const COMPOSE_UPLOAD_FAIL = 'COMPOSE_UPLOAD_FAIL'; -export const COMPOSE_UPLOAD_PROGRESS = 'COMPOSE_UPLOAD_PROGRESS'; -export const COMPOSE_UPLOAD_UNDO = 'COMPOSE_UPLOAD_UNDO'; +export const COMPOSE_CHANGE = 'COMPOSE_CHANGE' +export const COMPOSE_SUBMIT_REQUEST = 'COMPOSE_SUBMIT_REQUEST' +export const COMPOSE_SUBMIT_SUCCESS = 'COMPOSE_SUBMIT_SUCCESS' +export const COMPOSE_SUBMIT_FAIL = 'COMPOSE_SUBMIT_FAIL' +export const COMPOSE_REPLY = 'COMPOSE_REPLY' +export const COMPOSE_QUOTE = 'COMPOSE_QUOTE' +export const COMPOSE_REPLY_CANCEL = 'COMPOSE_REPLY_CANCEL' +export const COMPOSE_MENTION = 'COMPOSE_MENTION' +export const COMPOSE_RESET = 'COMPOSE_RESET' -export const COMPOSE_SUGGESTIONS_CLEAR = 'COMPOSE_SUGGESTIONS_CLEAR'; -export const COMPOSE_SUGGESTIONS_READY = 'COMPOSE_SUGGESTIONS_READY'; -export const COMPOSE_SUGGESTION_SELECT = 'COMPOSE_SUGGESTION_SELECT'; -export const COMPOSE_SUGGESTION_TAGS_UPDATE = 'COMPOSE_SUGGESTION_TAGS_UPDATE'; +export const COMPOSE_UPLOAD_REQUEST = 'COMPOSE_UPLOAD_REQUEST' +export const COMPOSE_UPLOAD_SUCCESS = 'COMPOSE_UPLOAD_SUCCESS' +export const COMPOSE_UPLOAD_FAIL = 'COMPOSE_UPLOAD_FAIL' +export const COMPOSE_UPLOAD_PROGRESS = 'COMPOSE_UPLOAD_PROGRESS' +export const COMPOSE_UPLOAD_UNDO = 'COMPOSE_UPLOAD_UNDO' -export const COMPOSE_TAG_HISTORY_UPDATE = 'COMPOSE_TAG_HISTORY_UPDATE'; +export const COMPOSE_SUGGESTIONS_CLEAR = 'COMPOSE_SUGGESTIONS_CLEAR' +export const COMPOSE_SUGGESTIONS_READY = 'COMPOSE_SUGGESTIONS_READY' +export const COMPOSE_SUGGESTION_SELECT = 'COMPOSE_SUGGESTION_SELECT' +export const COMPOSE_SUGGESTION_TAGS_UPDATE = 'COMPOSE_SUGGESTION_TAGS_UPDATE' -export const COMPOSE_MOUNT = 'COMPOSE_MOUNT'; -export const COMPOSE_UNMOUNT = 'COMPOSE_UNMOUNT'; +export const COMPOSE_TAG_HISTORY_UPDATE = 'COMPOSE_TAG_HISTORY_UPDATE' -export const COMPOSE_SENSITIVITY_CHANGE = 'COMPOSE_SENSITIVITY_CHANGE'; -export const COMPOSE_SPOILERNESS_CHANGE = 'COMPOSE_SPOILERNESS_CHANGE'; -export const COMPOSE_SPOILER_TEXT_CHANGE = 'COMPOSE_SPOILER_TEXT_CHANGE'; -export const COMPOSE_VISIBILITY_CHANGE = 'COMPOSE_VISIBILITY_CHANGE'; -export const COMPOSE_LISTABILITY_CHANGE = 'COMPOSE_LISTABILITY_CHANGE'; -export const COMPOSE_COMPOSING_CHANGE = 'COMPOSE_COMPOSING_CHANGE'; +export const COMPOSE_MOUNT = 'COMPOSE_MOUNT' +export const COMPOSE_UNMOUNT = 'COMPOSE_UNMOUNT' -export const COMPOSE_EMOJI_INSERT = 'COMPOSE_EMOJI_INSERT'; +export const COMPOSE_SENSITIVITY_CHANGE = 'COMPOSE_SENSITIVITY_CHANGE' +export const COMPOSE_SPOILERNESS_CHANGE = 'COMPOSE_SPOILERNESS_CHANGE' +export const COMPOSE_SPOILER_TEXT_CHANGE = 'COMPOSE_SPOILER_TEXT_CHANGE' +export const COMPOSE_VISIBILITY_CHANGE = 'COMPOSE_VISIBILITY_CHANGE' +export const COMPOSE_LISTABILITY_CHANGE = 'COMPOSE_LISTABILITY_CHANGE' +export const COMPOSE_COMPOSING_CHANGE = 'COMPOSE_COMPOSING_CHANGE' -export const COMPOSE_UPLOAD_CHANGE_REQUEST = 'COMPOSE_UPLOAD_UPDATE_REQUEST'; -export const COMPOSE_UPLOAD_CHANGE_SUCCESS = 'COMPOSE_UPLOAD_UPDATE_SUCCESS'; -export const COMPOSE_UPLOAD_CHANGE_FAIL = 'COMPOSE_UPLOAD_UPDATE_FAIL'; +export const COMPOSE_EMOJI_INSERT = 'COMPOSE_EMOJI_INSERT' -export const COMPOSE_POLL_ADD = 'COMPOSE_POLL_ADD'; -export const COMPOSE_POLL_REMOVE = 'COMPOSE_POLL_REMOVE'; -export const COMPOSE_POLL_OPTION_ADD = 'COMPOSE_POLL_OPTION_ADD'; -export const COMPOSE_POLL_OPTION_CHANGE = 'COMPOSE_POLL_OPTION_CHANGE'; -export const COMPOSE_POLL_OPTION_REMOVE = 'COMPOSE_POLL_OPTION_REMOVE'; -export const COMPOSE_POLL_SETTINGS_CHANGE = 'COMPOSE_POLL_SETTINGS_CHANGE'; +export const COMPOSE_UPLOAD_CHANGE_REQUEST = 'COMPOSE_UPLOAD_UPDATE_REQUEST' +export const COMPOSE_UPLOAD_CHANGE_SUCCESS = 'COMPOSE_UPLOAD_UPDATE_SUCCESS' +export const COMPOSE_UPLOAD_CHANGE_FAIL = 'COMPOSE_UPLOAD_UPDATE_FAIL' -export const COMPOSE_SCHEDULED_AT_CHANGE = 'COMPOSE_SCHEDULED_AT_CHANGE'; +export const COMPOSE_POLL_ADD = 'COMPOSE_POLL_ADD' +export const COMPOSE_POLL_REMOVE = 'COMPOSE_POLL_REMOVE' +export const COMPOSE_POLL_OPTION_ADD = 'COMPOSE_POLL_OPTION_ADD' +export const COMPOSE_POLL_OPTION_CHANGE = 'COMPOSE_POLL_OPTION_CHANGE' +export const COMPOSE_POLL_OPTION_REMOVE = 'COMPOSE_POLL_OPTION_REMOVE' +export const COMPOSE_POLL_SETTINGS_CHANGE = 'COMPOSE_POLL_SETTINGS_CHANGE' + +export const COMPOSE_SCHEDULED_AT_CHANGE = 'COMPOSE_SCHEDULED_AT_CHANGE' export const COMPOSE_EXPIRES_AT_CHANGE = 'COMPOSE_EXPIRES_AT_CHANGE' @@ -87,15 +88,15 @@ export const COMPOSE_CLEAR = 'COMPOSE_CLEAR' const messages = defineMessages({ uploadErrorLimit: { id: 'upload_error.limit', defaultMessage: 'File upload limit exceeded.' }, uploadErrorPoll: { id: 'upload_error.poll', defaultMessage: 'File upload not allowed with polls.' }, -}); +}) -const COMPOSE_PANEL_BREAKPOINT = 600 + (285 * 1) + (10 * 1); +const COMPOSE_PANEL_BREAKPOINT = 600 + (285 * 1) + (10 * 1) export const ensureComposeIsVisible = (getState, routerHistory) => { if (!getState().getIn(['compose', 'mounted']) && window.innerWidth < COMPOSE_PANEL_BREAKPOINT) { - routerHistory.push('/posts/new'); + routerHistory.push('/posts/new') } -}; +} export function changeCompose(text, markdown, replyId, isStandalone, caretPosition) { return function (dispatch, getState) { @@ -566,13 +567,11 @@ export function readyComposeSuggestionsEmojis(token, emojis) { }; }; -export function readyComposeSuggestionsAccounts(token, accounts) { - return { - type: COMPOSE_SUGGESTIONS_READY, - token, - accounts, - }; -}; +export const readyComposeSuggestionsAccounts = (token, accounts) => ({ + type: COMPOSE_SUGGESTIONS_READY, + token, + accounts, +}) export function selectComposeSuggestion(position, token, suggestion, path) { return (dispatch, getState) => { @@ -730,31 +729,35 @@ export function removePollOption(index) { }; }; -export function changePollSettings(expiresIn, isMultiple) { - return { - type: COMPOSE_POLL_SETTINGS_CHANGE, - expiresIn, - isMultiple, - }; -}; +/** + * + */ +export const changePollSettings = (expiresIn, isMultiple) => ({ + type: COMPOSE_POLL_SETTINGS_CHANGE, + expiresIn, + isMultiple, +}) -export function changeScheduledAt(date) { - return { - type: COMPOSE_SCHEDULED_AT_CHANGE, - date, - }; -}; +/** + * + */ +export const changeScheduledAt = (date) => ({ + type: COMPOSE_SCHEDULED_AT_CHANGE, + date, +}) -export function changeExpiresAt(value) { - return { - type: COMPOSE_EXPIRES_AT_CHANGE, - value, - } -} +/** + * + */ +export const changeExpiresAt = (value) => ({ + type: COMPOSE_EXPIRES_AT_CHANGE, + value, +}) -export function changeRichTextEditorControlsVisibility(open) { - return { - type: COMPOSE_RICH_TEXT_EDITOR_CONTROLS_VISIBILITY, - open, - } -} \ No newline at end of file +/** + * + */ +export const changeRichTextEditorControlsVisibility = (open) => ({ + type: COMPOSE_RICH_TEXT_EDITOR_CONTROLS_VISIBILITY, + open, +}) \ No newline at end of file diff --git a/app/javascript/gabsocial/actions/conversations.js b/app/javascript/gabsocial/actions/conversations.js deleted file mode 100644 index b0c3af2f..00000000 --- a/app/javascript/gabsocial/actions/conversations.js +++ /dev/null @@ -1,89 +0,0 @@ -import api, { getLinks } from '../api'; -import { - importFetchedAccounts, - importFetchedStatuses, - importFetchedStatus, -} from './importer'; -import { me } from '../initial_state'; - -export const CONVERSATIONS_MOUNT = 'CONVERSATIONS_MOUNT'; -export const CONVERSATIONS_UNMOUNT = 'CONVERSATIONS_UNMOUNT'; - -export const CONVERSATIONS_FETCH_REQUEST = 'CONVERSATIONS_FETCH_REQUEST'; -export const CONVERSATIONS_FETCH_SUCCESS = 'CONVERSATIONS_FETCH_SUCCESS'; -export const CONVERSATIONS_FETCH_FAIL = 'CONVERSATIONS_FETCH_FAIL'; -export const CONVERSATIONS_UPDATE = 'CONVERSATIONS_UPDATE'; - -export const CONVERSATIONS_READ = 'CONVERSATIONS_READ'; - -export const mountConversations = () => ({ - type: CONVERSATIONS_MOUNT, -}); - -export const unmountConversations = () => ({ - type: CONVERSATIONS_UNMOUNT, -}); - -export const markConversationRead = conversationId => (dispatch, getState) => { - if (!me) return; - - dispatch({ - type: CONVERSATIONS_READ, - id: conversationId, - }); - - api(getState).post(`/api/v1/conversations/${conversationId}/read`); -}; - -export const expandConversations = ({ maxId } = {}) => (dispatch, getState) => { - if (!me) return; - - dispatch(expandConversationsRequest()); - - const params = { max_id: maxId }; - - if (!maxId) { - params.since_id = getState().getIn(['conversations', 'items', 0, 'last_status']); - } - - const isLoadingRecent = !!params.since_id; - - api(getState).get('/api/v1/conversations', { params }) - .then(response => { - const next = getLinks(response).refs.find(link => link.rel === 'next'); - - dispatch(importFetchedAccounts(response.data.reduce((aggr, item) => aggr.concat(item.accounts), []))); - dispatch(importFetchedStatuses(response.data.map(item => item.last_status).filter(x => !!x))); - dispatch(expandConversationsSuccess(response.data, next ? next.uri : null, isLoadingRecent)); - }) - .catch(err => dispatch(expandConversationsFail(err))); -}; - -export const expandConversationsRequest = () => ({ - type: CONVERSATIONS_FETCH_REQUEST, -}); - -export const expandConversationsSuccess = (conversations, next, isLoadingRecent) => ({ - type: CONVERSATIONS_FETCH_SUCCESS, - conversations, - next, - isLoadingRecent, -}); - -export const expandConversationsFail = error => ({ - type: CONVERSATIONS_FETCH_FAIL, - error, -}); - -export const updateConversations = conversation => dispatch => { - dispatch(importFetchedAccounts(conversation.accounts)); - - if (conversation.last_status) { - dispatch(importFetchedStatus(conversation.last_status)); - } - - dispatch({ - type: CONVERSATIONS_UPDATE, - conversation, - }); -}; diff --git a/app/javascript/gabsocial/actions/custom_emojis.js b/app/javascript/gabsocial/actions/custom_emojis.js index 7b7d0091..486e271e 100644 --- a/app/javascript/gabsocial/actions/custom_emojis.js +++ b/app/javascript/gabsocial/actions/custom_emojis.js @@ -1,40 +1,32 @@ -import api from '../api'; +import api from '../api' -export const CUSTOM_EMOJIS_FETCH_REQUEST = 'CUSTOM_EMOJIS_FETCH_REQUEST'; -export const CUSTOM_EMOJIS_FETCH_SUCCESS = 'CUSTOM_EMOJIS_FETCH_SUCCESS'; -export const CUSTOM_EMOJIS_FETCH_FAIL = 'CUSTOM_EMOJIS_FETCH_FAIL'; +export const CUSTOM_EMOJIS_FETCH_REQUEST = 'CUSTOM_EMOJIS_FETCH_REQUEST' +export const CUSTOM_EMOJIS_FETCH_SUCCESS = 'CUSTOM_EMOJIS_FETCH_SUCCESS' +export const CUSTOM_EMOJIS_FETCH_FAIL = 'CUSTOM_EMOJIS_FETCH_FAIL' -export function fetchCustomEmojis() { - return (dispatch, getState) => { - dispatch(fetchCustomEmojisRequest()); +export const fetchCustomEmojis = () => (dispatch, getState) => { + dispatch(fetchCustomEmojisRequest()) - api(getState).get('/api/v1/custom_emojis').then(response => { - dispatch(fetchCustomEmojisSuccess(response.data)); - }).catch(error => { - dispatch(fetchCustomEmojisFail(error)); - }); - }; -}; + api(getState).get('/api/v1/custom_emojis').then((response) => { + dispatch(fetchCustomEmojisSuccess(response.data)) + }).catch((error) => { + dispatch(fetchCustomEmojisFail(error)) + }) +} -export function fetchCustomEmojisRequest() { - return { - type: CUSTOM_EMOJIS_FETCH_REQUEST, - skipLoading: true, - }; -}; +const fetchCustomEmojisRequest = () => ({ + type: CUSTOM_EMOJIS_FETCH_REQUEST, + skipLoading: true, +}) -export function fetchCustomEmojisSuccess(custom_emojis) { - return { - type: CUSTOM_EMOJIS_FETCH_SUCCESS, - custom_emojis, - skipLoading: true, - }; -}; +const fetchCustomEmojisSuccess = (custom_emojis) => ({ + type: CUSTOM_EMOJIS_FETCH_SUCCESS, + custom_emojis, + skipLoading: true, +}) -export function fetchCustomEmojisFail(error) { - return { - type: CUSTOM_EMOJIS_FETCH_FAIL, - error, - skipLoading: true, - }; -}; +const fetchCustomEmojisFail = (error) => ({ + type: CUSTOM_EMOJIS_FETCH_FAIL, + error, + skipLoading: true, +}) diff --git a/app/javascript/gabsocial/actions/emojis.js b/app/javascript/gabsocial/actions/emojis.js index 7cd9d4b7..2a2e019b 100644 --- a/app/javascript/gabsocial/actions/emojis.js +++ b/app/javascript/gabsocial/actions/emojis.js @@ -1,14 +1,12 @@ -import { saveSettings } from './settings'; +import { saveSettings } from './settings' -export const EMOJI_USE = 'EMOJI_USE'; +export const EMOJI_USE = 'EMOJI_USE' -export function useEmoji(emoji) { - return dispatch => { - dispatch({ - type: EMOJI_USE, - emoji, - }); +export const useEmoji = (emoji) => (dispatch) => { + dispatch({ + type: EMOJI_USE, + emoji, + }); - dispatch(saveSettings()); - }; -}; + dispatch(saveSettings()) +} diff --git a/app/javascript/gabsocial/actions/favorites.js b/app/javascript/gabsocial/actions/favorites.js index f94830b7..a1648cbd 100644 --- a/app/javascript/gabsocial/actions/favorites.js +++ b/app/javascript/gabsocial/actions/favorites.js @@ -10,89 +10,79 @@ export const FAVORITED_STATUSES_EXPAND_REQUEST = 'FAVORITED_STATUSES_EXPAND_REQU export const FAVORITED_STATUSES_EXPAND_SUCCESS = 'FAVORITED_STATUSES_EXPAND_SUCCESS' export const FAVORITED_STATUSES_EXPAND_FAIL = 'FAVORITED_STATUSES_EXPAND_FAIL' -export function fetchFavoritedStatuses() { - return (dispatch, getState) => { - if (!me) return +/** + * + */ +export const fetchFavoritedStatuses = () => (dispatch, getState) => { + if (!me) return - if (getState().getIn(['status_lists', 'favorites', 'isLoading'])) { - return - } - - dispatch(fetchFavoritedStatusesRequest()) - - api(getState).get('/api/v1/favourites').then(response => { - const next = getLinks(response).refs.find(link => link.rel === 'next') - dispatch(importFetchedStatuses(response.data)) - dispatch(fetchFavoritedStatusesSuccess(response.data, next ? next.uri : null)) - }).catch(error => { - dispatch(fetchFavoritedStatusesFail(error)) - }) + if (getState().getIn(['status_lists', 'favorites', 'isLoading'])) { + return } + + dispatch(fetchFavoritedStatusesRequest()) + + api(getState).get('/api/v1/favourites').then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next') + dispatch(importFetchedStatuses(response.data)) + dispatch(fetchFavoritedStatusesSuccess(response.data, next ? next.uri : null)) + }).catch(error => { + dispatch(fetchFavoritedStatusesFail(error)) + }) } -export function fetchFavoritedStatusesRequest() { - return { - type: FAVORITED_STATUSES_FETCH_REQUEST, - skipLoading: true, +const fetchFavoritedStatusesRequest = () => ({ + type: FAVORITED_STATUSES_FETCH_REQUEST, + skipLoading: true, +}) + +const fetchFavoritedStatusesSuccess = (statuses, next) => ({ + type: FAVORITED_STATUSES_FETCH_SUCCESS, + statuses, + next, + skipLoading: true, +}) + +const fetchFavoritedStatusesFail = (error) => ({ + type: FAVORITED_STATUSES_FETCH_FAIL, + error, + skipLoading: true, +}) + +/** + * + */ +export const expandFavoritedStatuses = () => (dispatch, getState) => { + if (!me) return + + const url = getState().getIn(['status_lists', 'favorites', 'next'], null) + + if (url === null || getState().getIn(['status_lists', 'favorites', 'isLoading'])) { + return } + + dispatch(expandFavoritedStatusesRequest()) + + api(getState).get(url).then(response => { + const next = getLinks(response).refs.find(link => link.rel === 'next') + dispatch(importFetchedStatuses(response.data)) + dispatch(expandFavoritedStatusesSuccess(response.data, next ? next.uri : null)) + }).catch(error => { + dispatch(expandFavoritedStatusesFail(error)) + }) } -export function fetchFavoritedStatusesSuccess(statuses, next) { - return { - type: FAVORITED_STATUSES_FETCH_SUCCESS, - statuses, - next, - skipLoading: true, - } -} +const expandFavoritedStatusesRequest = () => ({ + type: FAVORITED_STATUSES_EXPAND_REQUEST, +}) -export function fetchFavoritedStatusesFail(error) { - return { - type: FAVORITED_STATUSES_FETCH_FAIL, - error, - skipLoading: true, - } -} +const expandFavoritedStatusesSuccess = (statuses, next) => ({ + type: FAVORITED_STATUSES_EXPAND_SUCCESS, + statuses, + next, +}) -export function expandFavoritedStatuses() { - return (dispatch, getState) => { - if (!me) return - - const url = getState().getIn(['status_lists', 'favorites', 'next'], null) - - if (url === null || getState().getIn(['status_lists', 'favorites', 'isLoading'])) { - return - } - - dispatch(expandFavoritedStatusesRequest()) - - api(getState).get(url).then(response => { - const next = getLinks(response).refs.find(link => link.rel === 'next') - dispatch(importFetchedStatuses(response.data)) - dispatch(expandFavoritedStatusesSuccess(response.data, next ? next.uri : null)) - }).catch(error => { - dispatch(expandFavoritedStatusesFail(error)) - }) - } -} - -export function expandFavoritedStatusesRequest() { - return { - type: FAVORITED_STATUSES_EXPAND_REQUEST, - } -} - -export function expandFavoritedStatusesSuccess(statuses, next) { - return { - type: FAVORITED_STATUSES_EXPAND_SUCCESS, - statuses, - next, - } -} - -export function expandFavoritedStatusesFail(error) { - return { - type: FAVORITED_STATUSES_EXPAND_FAIL, - error, - } -} +const expandFavoritedStatusesFail = (error) => ({ + type: FAVORITED_STATUSES_EXPAND_FAIL, + error, +}) diff --git a/app/javascript/gabsocial/actions/filters.js b/app/javascript/gabsocial/actions/filters.js index 20274141..01559de0 100644 --- a/app/javascript/gabsocial/actions/filters.js +++ b/app/javascript/gabsocial/actions/filters.js @@ -1,29 +1,40 @@ -import api from '../api'; -import { me } from '../initial_state'; +import api from '../api' +import { me } from '../initial_state' -export const FILTERS_FETCH_REQUEST = 'FILTERS_FETCH_REQUEST'; -export const FILTERS_FETCH_SUCCESS = 'FILTERS_FETCH_SUCCESS'; -export const FILTERS_FETCH_FAIL = 'FILTERS_FETCH_FAIL'; +export const FILTERS_FETCH_REQUEST = 'FILTERS_FETCH_REQUEST' +export const FILTERS_FETCH_SUCCESS = 'FILTERS_FETCH_SUCCESS' +export const FILTERS_FETCH_FAIL = 'FILTERS_FETCH_FAIL' +/** + * + */ export const fetchFilters = () => (dispatch, getState) => { - if (!me) return; + if (!me) return - dispatch({ - type: FILTERS_FETCH_REQUEST, - skipLoading: true, - }); + dispatch(fetchFiltersRequest()) - api(getState) - .get('/api/v1/filters') - .then(({ data }) => dispatch({ - type: FILTERS_FETCH_SUCCESS, - filters: data, - skipLoading: true, - })) - .catch(err => dispatch({ - type: FILTERS_FETCH_FAIL, - err, - skipLoading: true, - skipAlert: true, - })); -}; + api(getState).get('/api/v1/filters').then(({ data }) => { + dispatch(fetchFiltersSuccess(data)) + }).catch((err) => { + dispatch(fetchFiltersFail(err)) + }) +} + + +const fetchFiltersRequest = () => ({ + type: FILTERS_FETCH_REQUEST, + skipLoading: true, +}) + +const fetchFiltersSuccess = (filters) => ({ + type: FILTERS_FETCH_SUCCESS, + filters, + skipLoading: true, +}) + +const fetchFiltersFail = (err) => ({ + type: FILTERS_FETCH_FAIL, + err, + skipLoading: true, + skipAlert: true, +}) \ No newline at end of file diff --git a/app/javascript/gabsocial/actions/group_categories.js b/app/javascript/gabsocial/actions/group_categories.js index 242bc8fb..0861e4d7 100644 --- a/app/javascript/gabsocial/actions/group_categories.js +++ b/app/javascript/gabsocial/actions/group_categories.js @@ -4,6 +4,9 @@ export const GROUP_CATEGORIES_FETCH_REQUEST = 'GROUP_CATEGORIES_FETCH_REQUEST' export const GROUP_CATEGORIES_FETCH_SUCCESS = 'GROUP_CATEGORIES_FETCH_SUCCESS' export const GROUP_CATEGORIES_FETCH_FAIL = 'GROUP_CATEGORIES_FETCH_FAIL' +/** + * + */ export const fetchGroupCategories = () => (dispatch, getState) => { dispatch(fetchGroupCategoriesRequest()) @@ -12,16 +15,16 @@ export const fetchGroupCategories = () => (dispatch, getState) => { .catch(err => dispatch(fetchGroupCategoriesFail(err))) } -export const fetchGroupCategoriesRequest = () => ({ +const fetchGroupCategoriesRequest = () => ({ type: GROUP_CATEGORIES_FETCH_REQUEST, }) -export const fetchGroupCategoriesSuccess = (categories) => ({ +const fetchGroupCategoriesSuccess = (categories) => ({ type: GROUP_CATEGORIES_FETCH_SUCCESS, categories, }) -export const fetchGroupCategoriesFail = (error) => ({ +const fetchGroupCategoriesFail = (error) => ({ type: GROUP_CATEGORIES_FETCH_FAIL, error, }) \ No newline at end of file diff --git a/app/javascript/gabsocial/actions/group_editor.js b/app/javascript/gabsocial/actions/group_editor.js index d3a34459..cf4c80bd 100644 --- a/app/javascript/gabsocial/actions/group_editor.js +++ b/app/javascript/gabsocial/actions/group_editor.js @@ -22,6 +22,9 @@ export const GROUP_EDITOR_IS_VISIBLE_CHANGE = 'GROUP_EDITOR_IS_VISIBLE_CHANGE' export const GROUP_EDITOR_RESET = 'GROUP_EDITOR_RESET' export const GROUP_EDITOR_SETUP = 'GROUP_EDITOR_SETUP' +/** + * + */ export const submit = (routerHistory) => (dispatch, getState) => { if (!me) return @@ -50,16 +53,19 @@ export const submit = (routerHistory) => (dispatch, getState) => { } if (groupId === null) { - dispatch(create(options, routerHistory)) + dispatch(createGroup(options, routerHistory)) } else { - dispatch(update(groupId, options, routerHistory)) + dispatch(updateGroup(groupId, options, routerHistory)) } } -const create = (options, routerHistory) => (dispatch, getState) => { +/** + * + */ +const createGroup = (options, routerHistory) => (dispatch, getState) => { if (!me) return - dispatch(createRequest()) + dispatch(createGroupRequest()) const formData = new FormData() formData.append('title', options.title) @@ -81,28 +87,31 @@ const create = (options, routerHistory) => (dispatch, getState) => { 'Content-Type': 'multipart/form-data' } }).then(({ data }) => { - dispatch(createSuccess(data)) + dispatch(createGroupSuccess(data)) routerHistory.push(`/groups/${data.id}`) - }).catch(err => dispatch(createFail(err))) + }).catch((err) => dispatch(createGroupFail(err))) } -export const createRequest = (id) => ({ +const createGroupRequest = (id) => ({ type: GROUP_CREATE_REQUEST, id, }) -export const createSuccess = (group) => ({ +const createSuccess = (group) => ({ type: GROUP_CREATE_SUCCESS, group, }) -export const createFail = (error) => ({ +const createFail = (error) => ({ type: GROUP_CREATE_FAIL, error, }) -const update = (groupId, options, routerHistory) => (dispatch, getState) => { +/** + * + */ +const updateGroup = (groupId, options, routerHistory) => (dispatch, getState) => { if (!me) return dispatch(updateRequest()) @@ -130,26 +139,29 @@ const update = (groupId, options, routerHistory) => (dispatch, getState) => { 'Content-Type': 'multipart/form-data' } }).then(({ data }) => { - dispatch(updateSuccess(data)) + dispatch(updateGroupSuccess(data)) routerHistory.push(`/groups/${data.id}`) - }).catch(err => dispatch(updateFail(err))) + }).catch((err) => dispatch(updateGroupFail(err))) } -export const updateRequest = (id) => ({ +const updateGroupRequest = (id) => ({ type: GROUP_UPDATE_REQUEST, id, }) -export const updateSuccess = (group) => ({ +const updateGroupSuccess = (group) => ({ type: GROUP_UPDATE_SUCCESS, group, }) -export const updateFail = (error) => ({ +const updateGroupFail = (error) => ({ type: GROUP_UPDATE_FAIL, error, }) +/** + * + */ export const resetEditor = () => ({ type: GROUP_EDITOR_RESET }) diff --git a/app/javascript/gabsocial/actions/groups.js b/app/javascript/gabsocial/actions/groups.js index 9ddb5526..1f9d5590 100644 --- a/app/javascript/gabsocial/actions/groups.js +++ b/app/javascript/gabsocial/actions/groups.js @@ -107,6 +107,11 @@ export const importGroup = (group) => (dispatch) => { dispatch(fetchGroupSuccess(group)) } +export const importGroups = (groups) => (dispatch) => { + if (!Array.isArray(groups)) return + groups.map((group) => dispatch(fetchGroupSuccess(group))) +} + export const fetchGroup = (id) => (dispatch, getState) => { dispatch(fetchGroupRelationships([id])); diff --git a/app/javascript/gabsocial/actions/height_cache.js b/app/javascript/gabsocial/actions/height_cache.js index 4c752993..c8df2cc1 100644 --- a/app/javascript/gabsocial/actions/height_cache.js +++ b/app/javascript/gabsocial/actions/height_cache.js @@ -1,17 +1,13 @@ -export const HEIGHT_CACHE_SET = 'HEIGHT_CACHE_SET'; -export const HEIGHT_CACHE_CLEAR = 'HEIGHT_CACHE_CLEAR'; +export const HEIGHT_CACHE_SET = 'HEIGHT_CACHE_SET' +export const HEIGHT_CACHE_CLEAR = 'HEIGHT_CACHE_CLEAR' -export function setHeight (key, id, height) { - return { - type: HEIGHT_CACHE_SET, - key, - id, - height, - }; -}; +export const setHeight = (key, id, height) => ({ + type: HEIGHT_CACHE_SET, + key, + id, + height, +}) -export function clearHeight () { - return { - type: HEIGHT_CACHE_CLEAR, - }; -}; +export const clearHeight = () => ({ + type: HEIGHT_CACHE_CLEAR, +}) diff --git a/app/javascript/gabsocial/actions/importer/index.js b/app/javascript/gabsocial/actions/importer/index.js index 5dea143a..b9c1630f 100644 --- a/app/javascript/gabsocial/actions/importer/index.js +++ b/app/javascript/gabsocial/actions/importer/index.js @@ -1,12 +1,18 @@ -import { normalizeAccount, normalizeStatus, normalizePoll } from './normalizer'; +import isObject from 'lodash.isobject' +import { + normalizeAccount, + normalizeStatus, + normalizePoll, +} from './normalizer' import { fetchContext } from '../statuses' +import { importGroups } from '../groups' -export const ACCOUNT_IMPORT = 'ACCOUNT_IMPORT'; -export const ACCOUNTS_IMPORT = 'ACCOUNTS_IMPORT'; -export const STATUS_IMPORT = 'STATUS_IMPORT'; -export const STATUSES_IMPORT = 'STATUSES_IMPORT'; -export const POLLS_IMPORT = 'POLLS_IMPORT'; -export const ACCOUNT_FETCH_FAIL_FOR_USERNAME_LOOKUP = 'ACCOUNT_FETCH_FAIL_FOR_USERNAME_LOOKUP'; +export const ACCOUNT_IMPORT = 'ACCOUNT_IMPORT' +export const ACCOUNTS_IMPORT = 'ACCOUNTS_IMPORT' +export const STATUS_IMPORT = 'STATUS_IMPORT' +export const STATUSES_IMPORT = 'STATUSES_IMPORT' +export const POLLS_IMPORT = 'POLLS_IMPORT' +export const ACCOUNT_FETCH_FAIL_FOR_USERNAME_LOOKUP = 'ACCOUNT_FETCH_FAIL_FOR_USERNAME_LOOKUP' function pushUnique(array, object) { if (array.every(element => element.id !== object.id)) { @@ -14,34 +20,39 @@ function pushUnique(array, object) { } } -export function importAccount(account) { - return { type: ACCOUNT_IMPORT, account }; -} +export const importAccount = (account) => ({ + type: ACCOUNT_IMPORT, + account, +}) -export function importAccounts(accounts) { - return { type: ACCOUNTS_IMPORT, accounts }; -} +export const importAccounts = (accounts) => ({ + type: ACCOUNTS_IMPORT, + accounts, +}) -export function importStatus(status) { - return { type: STATUS_IMPORT, status }; -} +export const importStatus = (status) => ({ + type: STATUS_IMPORT, + status, +}) -export function importStatuses(statuses) { - return { type: STATUSES_IMPORT, statuses }; -} +export const importStatuses = (statuses) => ({ + type: STATUSES_IMPORT, + statuses, +}) -export function importPolls(polls) { - return { type: POLLS_IMPORT, polls }; -} +export const importPolls = (polls) => ({ + type: POLLS_IMPORT, + polls, +}) -export function importFetchedAccount(account) { +export const importFetchedAccount = (account) => { return importFetchedAccounts([account]); } -export function importFetchedAccounts(accounts) { +export const importFetchedAccounts = (accounts) => { const normalAccounts = []; - function processAccount(account) { + const processAccount = (account) => { pushUnique(normalAccounts, normalizeAccount(account)); if (account.moved) { @@ -54,47 +65,48 @@ export function importFetchedAccounts(accounts) { return importAccounts(normalAccounts); } -export function importFetchedStatus(status) { +export const importFetchedStatus = (status) => { return importFetchedStatuses([status]); } -export function importFetchedStatuses(statuses) { - return (dispatch, getState) => { - const accounts = []; - const normalStatuses = []; - const polls = []; +export const importFetchedStatuses = (statuses) => (dispatch, getState) => { + const accounts = [] + const normalStatuses = [] + const polls = [] + const groups = [] - function processStatus(status) { - pushUnique(normalStatuses, normalizeStatus(status, getState().getIn(['statuses', status.id]))); - pushUnique(accounts, status.account); + const processStatus = (status) => { + pushUnique(normalStatuses, normalizeStatus(status, getState().getIn(['statuses', status.id]))) - if (status.reblog && status.reblog.id) { - processStatus(status.reblog); - } - - if (status.quote && status.quote.id) { - processStatus(status.quote); - } - - if (status.poll && status.poll.id) { - pushUnique(polls, normalizePoll(status.poll)); - } + if (isObject(status.account)) pushUnique(accounts, status.account) + if (isObject(status.group)) pushUnique(groups, status.group) + + if (status.reblog && status.reblog.id) { + processStatus(status.reblog) } - statuses.forEach(processStatus); + if (status.quote && status.quote.id) { + processStatus(status.quote) + } - dispatch(importPolls(polls)); - dispatch(importFetchedAccounts(accounts)); - dispatch(importStatuses(normalStatuses)); - }; + if (status.poll && status.poll.id) { + pushUnique(polls, normalizePoll(status.poll)) + } + } + + statuses.forEach(processStatus) + + dispatch(importPolls(polls)) + dispatch(importFetchedAccounts(accounts)) + dispatch(importStatuses(normalStatuses)) + dispatch(importGroups(groups)) } -export function importFetchedPoll(poll) { - return dispatch => { - dispatch(importPolls([normalizePoll(poll)])); - }; +export const importFetchedPoll = (poll) => (dispatch) => { + dispatch(importPolls([normalizePoll(poll)])) } -export function importErrorWhileFetchingAccountByUsername(username) { - return { type: ACCOUNT_FETCH_FAIL_FOR_USERNAME_LOOKUP, username }; -}; +export const importErrorWhileFetchingAccountByUsername = (username) => ({ + type: ACCOUNT_FETCH_FAIL_FOR_USERNAME_LOOKUP, + username +}) diff --git a/app/javascript/gabsocial/actions/importer/normalizer.js b/app/javascript/gabsocial/actions/importer/normalizer.js index 46f487e7..69c3c26d 100644 --- a/app/javascript/gabsocial/actions/importer/normalizer.js +++ b/app/javascript/gabsocial/actions/importer/normalizer.js @@ -39,7 +39,7 @@ export function normalizeAccount(account) { export function normalizeStatus(status, normalOldStatus) { const normalStatus = { ...status }; - normalStatus.account = status.account.id; + normalStatus.account = status.account_id || status.account.id; if (status.reblog && status.reblog.id) { normalStatus.reblog = status.reblog.id; @@ -53,6 +53,10 @@ export function normalizeStatus(status, normalOldStatus) { normalStatus.poll = status.poll.id; } + if (!!status.group || !!status.group_id) { + normalStatus.group = status.group_id || status.group.id; + } + // Only calculate these values when status first encountered // Otherwise keep the ones already in the reducer if (normalOldStatus && normalOldStatus.get('content') === normalStatus.content && normalOldStatus.get('spoiler_text') === normalStatus.spoiler_text) { diff --git a/app/javascript/gabsocial/actions/interactions.js b/app/javascript/gabsocial/actions/interactions.js index 6d3d5f95..657ee262 100644 --- a/app/javascript/gabsocial/actions/interactions.js +++ b/app/javascript/gabsocial/actions/interactions.js @@ -1,34 +1,35 @@ -import api from '../api'; -import { importFetchedAccounts, importFetchedStatus } from './importer'; -import { me } from '../initial_state'; +import api from '../api' +import { importFetchedAccounts, importFetchedStatus } from './importer' +import { updateStatusStats } from './statuses' +import { me } from '../initial_state' -export const REPOST_REQUEST = 'REPOST_REQUEST'; -export const REPOST_SUCCESS = 'REPOST_SUCCESS'; -export const REPOST_FAIL = 'REPOST_FAIL'; +export const REPOST_REQUEST = 'REPOST_REQUEST' +export const REPOST_SUCCESS = 'REPOST_SUCCESS' +export const REPOST_FAIL = 'REPOST_FAIL' -export const FAVORITE_REQUEST = 'FAVORITE_REQUEST'; -export const FAVORITE_SUCCESS = 'FAVORITE_SUCCESS'; -export const FAVORITE_FAIL = 'FAVORITE_FAIL'; +export const FAVORITE_REQUEST = 'FAVORITE_REQUEST' +export const FAVORITE_SUCCESS = 'FAVORITE_SUCCESS' +export const FAVORITE_FAIL = 'FAVORITE_FAIL' -export const UNREPOST_REQUEST = 'UNREPOST_REQUEST'; -export const UNREPOST_SUCCESS = 'UNREPOST_SUCCESS'; -export const UNREPOST_FAIL = 'UNREPOST_FAIL'; +export const UNREPOST_REQUEST = 'UNREPOST_REQUEST' +export const UNREPOST_SUCCESS = 'UNREPOST_SUCCESS' +export const UNREPOST_FAIL = 'UNREPOST_FAIL' -export const UNFAVORITE_REQUEST = 'UNFAVORITE_REQUEST'; -export const UNFAVORITE_SUCCESS = 'UNFAVORITE_SUCCESS'; -export const UNFAVORITE_FAIL = 'UNFAVORITE_FAIL'; +export const UNFAVORITE_REQUEST = 'UNFAVORITE_REQUEST' +export const UNFAVORITE_SUCCESS = 'UNFAVORITE_SUCCESS' +export const UNFAVORITE_FAIL = 'UNFAVORITE_FAIL' -export const REPOSTS_FETCH_REQUEST = 'REPOSTS_FETCH_REQUEST'; -export const REPOSTS_FETCH_SUCCESS = 'REPOSTS_FETCH_SUCCESS'; -export const REPOSTS_FETCH_FAIL = 'REPOSTS_FETCH_FAIL'; +export const REPOSTS_FETCH_REQUEST = 'REPOSTS_FETCH_REQUEST' +export const REPOSTS_FETCH_SUCCESS = 'REPOSTS_FETCH_SUCCESS' +export const REPOSTS_FETCH_FAIL = 'REPOSTS_FETCH_FAIL' -export const PIN_REQUEST = 'PIN_REQUEST'; -export const PIN_SUCCESS = 'PIN_SUCCESS'; -export const PIN_FAIL = 'PIN_FAIL'; +export const PIN_REQUEST = 'PIN_REQUEST' +export const PIN_SUCCESS = 'PIN_SUCCESS' +export const PIN_FAIL = 'PIN_FAIL' -export const UNPIN_REQUEST = 'UNPIN_REQUEST'; -export const UNPIN_SUCCESS = 'UNPIN_SUCCESS'; -export const UNPIN_FAIL = 'UNPIN_FAIL'; +export const UNPIN_REQUEST = 'UNPIN_REQUEST' +export const UNPIN_SUCCESS = 'UNPIN_SUCCESS' +export const UNPIN_FAIL = 'UNPIN_FAIL' export const BOOKMARK_REQUEST = 'BOOKMARK_REQUEST' export const BOOKMARK_SUCCESS = 'BOOKMARK_SUCCESS' @@ -38,392 +39,342 @@ export const UNBOOKMARK_REQUEST = 'UNBOOKMARK_REQUEST' export const UNBOOKMARK_SUCCESS = 'UNBOOKMARK_SUCCESS' export const UNBOOKMARK_FAIL = 'UNBOOKMARK_FAIL' -export const LIKES_FETCH_REQUEST = 'LIKES_FETCH_REQUEST'; -export const LIKES_FETCH_SUCCESS = 'LIKES_FETCH_SUCCESS'; -export const LIKES_FETCH_FAIL = 'LIKES_FETCH_FAIL'; +export const LIKES_FETCH_REQUEST = 'LIKES_FETCH_REQUEST' +export const LIKES_FETCH_SUCCESS = 'LIKES_FETCH_SUCCESS' +export const LIKES_FETCH_FAIL = 'LIKES_FETCH_FAIL' -export function repost(status) { - return function (dispatch, getState) { - if (!me) return; +/** + * + */ +export const repost = (status) => (dispatch, getState) => { + if (!me) return - dispatch(repostRequest(status)); + dispatch(repostRequest(status)) - api(getState).post(`/api/v1/statuses/${status.get('id')}/reblog`).then(function (response) { - // The reblog API method returns a new status wrapped around the original. In this case we are only - // interested in how the original is modified, hence passing it skipping the wrapper - dispatch(importFetchedStatus(response.data.reblog)); - dispatch(repostSuccess(status)); - }).catch(function (error) { - dispatch(repostFail(status, error)); - }); - }; -}; - -export function unrepost(status) { - return (dispatch, getState) => { - if (!me) return; - - dispatch(unrepostRequest(status)); - - api(getState).post(`/api/v1/statuses/${status.get('id')}/unreblog`).then(response => { - dispatch(importFetchedStatus(response.data)); - dispatch(unrepostSuccess(status)); - }).catch(error => { - dispatch(unrepostFail(status, error)); - }); - }; -}; - -export function repostRequest(status) { - return { - type: REPOST_REQUEST, - status: status, - skipLoading: true, - }; -}; - -export function repostSuccess(status) { - return { - type: REPOST_SUCCESS, - status: status, - skipLoading: true, - }; -}; - -export function repostFail(status, error) { - return { - type: REPOST_FAIL, - status: status, - error: error, - skipLoading: true, - }; -}; - -export function unrepostRequest(status) { - return { - type: UNREPOST_REQUEST, - status: status, - skipLoading: true, - }; -}; - -export function unrepostSuccess(status) { - return { - type: UNREPOST_SUCCESS, - status: status, - skipLoading: true, - }; -}; - -export function unrepostFail(status, error) { - return { - type: UNREPOST_FAIL, - status: status, - error: error, - skipLoading: true, - }; -}; - -export function favorite(status) { - return function (dispatch, getState) { - if (!me) return; - - dispatch(favoriteRequest(status)); - - api(getState).post(`/api/v1/statuses/${status.get('id')}/favourite`).then(function (response) { - dispatch(importFetchedStatus(response.data)); - dispatch(favoriteSuccess(status)); - }).catch(function (error) { - dispatch(favoriteFail(status, error)); - }); - }; -}; - -export function unfavorite(status) { - return (dispatch, getState) => { - if (!me) return; - - dispatch(unfavoriteRequest(status)); - - api(getState).post(`/api/v1/statuses/${status.get('id')}/unfavourite`).then(response => { - dispatch(importFetchedStatus(response.data)); - dispatch(unfavoriteSuccess(status)); - }).catch(error => { - dispatch(unfavoriteFail(status, error)); - }); - }; -}; - -export function favoriteRequest(status) { - return { - type: FAVORITE_REQUEST, - status: status, - skipLoading: true, - }; -}; - -export function favoriteSuccess(status) { - return { - type: FAVORITE_SUCCESS, - status: status, - skipLoading: true, - }; -}; - -export function favoriteFail(status, error) { - return { - type: FAVORITE_FAIL, - status: status, - error: error, - skipLoading: true, - }; -}; - -export function unfavoriteRequest(status) { - return { - type: UNFAVORITE_REQUEST, - status: status, - skipLoading: true, - }; -}; - -export function unfavoriteSuccess(status) { - return { - type: UNFAVORITE_SUCCESS, - status: status, - skipLoading: true, - }; -}; - -export function unfavoriteFail(status, error) { - return { - type: UNFAVORITE_FAIL, - status: status, - error: error, - skipLoading: true, - }; -}; - -export function fetchReposts(id) { - return (dispatch, getState) => { - if (!me) return; - - dispatch(fetchRepostsRequest(id)); - - api(getState).get(`/api/v1/statuses/${id}/reblogged_by`).then(response => { - dispatch(importFetchedAccounts(response.data)); - dispatch(fetchRepostsSuccess(id, response.data)); - }).catch(error => { - dispatch(fetchRepostsFail(id, error)); - }); - }; -}; - -export function fetchRepostsRequest(id) { - return { - type: REPOSTS_FETCH_REQUEST, - id, - }; -}; - -export function fetchRepostsSuccess(id, accounts) { - return { - type: REPOSTS_FETCH_SUCCESS, - id, - accounts, - }; -}; - -export function fetchRepostsFail(id, error) { - return { - type: REPOSTS_FETCH_FAIL, - error, - }; -}; - -export function pin(status) { - return (dispatch, getState) => { - if (!me) return; - - dispatch(pinRequest(status)); - - api(getState).post(`/api/v1/statuses/${status.get('id')}/pin`).then(response => { - dispatch(importFetchedStatus(response.data)); - dispatch(pinSuccess(status)); - }).catch(error => { - dispatch(pinFail(status, error)); - }); - }; -}; - -export function pinRequest(status) { - return { - type: PIN_REQUEST, - status, - skipLoading: true, - }; -}; - -export function pinSuccess(status) { - return { - type: PIN_SUCCESS, - status, - skipLoading: true, - }; -}; - -export function pinFail(status, error) { - return { - type: PIN_FAIL, - status, - error, - skipLoading: true, - }; -}; - -export function unpin (status) { - return (dispatch, getState) => { - if (!me) return; - - dispatch(unpinRequest(status)); - - api(getState).post(`/api/v1/statuses/${status.get('id')}/unpin`).then(response => { - dispatch(importFetchedStatus(response.data)); - dispatch(unpinSuccess(status)); - }).catch(error => { - dispatch(unpinFail(status, error)); - }); - }; -}; - -export function unpinRequest(status) { - return { - type: UNPIN_REQUEST, - status, - skipLoading: true, - }; -}; - -export function unpinSuccess(status) { - return { - type: UNPIN_SUCCESS, - status, - skipLoading: true, - }; -}; - -export function unpinFail(status, error) { - return { - type: UNPIN_FAIL, - status, - error, - skipLoading: true, - }; -}; - -export function fetchLikes(id) { - return (dispatch, getState) => { - dispatch(fetchLikesRequest(id)); - - api(getState).get(`/api/v1/statuses/${id}/favourited_by`).then(response => { - dispatch(importFetchedAccounts(response.data)); - dispatch(fetchLikesSuccess(id, response.data)); - }).catch(error => { - dispatch(fetchLikesFail(id, error)); - }); - }; -}; - -export function fetchLikesRequest(id) { - return { - type: LIKES_FETCH_REQUEST, - id, - }; -}; - -export function fetchLikesSuccess(id, accounts) { - return { - type: LIKES_FETCH_SUCCESS, - id, - accounts, - }; -}; - -export function fetchLikesFail(id, error) { - return { - type: LIKES_FETCH_FAIL, - error, - }; -}; - -export function bookmark(status) { - return function (dispatch, getState) { - dispatch(bookmarkRequest(status)); - - api(getState).post(`/api/v1/statuses/${status.get('id')}/bookmark`).then(function (response) { - dispatch(importFetchedStatus(response.data)); - dispatch(bookmarkSuccess(status, response.data)); - }).catch(function (error) { - dispatch(bookmarkFail(status, error)) - }) - } + api(getState).post(`/api/v1/statuses/${status.get('id')}/reblog`).then((response) => { + // The reblog API method returns a new status wrapped around the original. In this case we are only + // interested in how the original is modified, hence passing it skipping the wrapper + dispatch(importFetchedStatus(response.data.reblog)) + dispatch(repostSuccess(status)) + }).catch((error) => { + dispatch(repostFail(status, error)) + }) } -export function unbookmark(status) { - return (dispatch, getState) => { - dispatch(unbookmarkRequest(status)) +export const repostRequest = (status) => ({ + type: REPOST_REQUEST, + status: status, + skipLoading: true, +}) - api(getState).post(`/api/v1/statuses/${status.get('id')}/unbookmark`).then(response => { - dispatch(importFetchedStatus(response.data)) - dispatch(unbookmarkSuccess(status, response.data)) - }).catch(error => { - dispatch(unbookmarkFail(status, error)) - }) - } +export const repostSuccess = (status) => ({ + type: REPOST_SUCCESS, + status: status, + skipLoading: true, +}) + +export const repostFail = (status, error) => ({ + type: REPOST_FAIL, + status: status, + error: error, + skipLoading: true, +}) + +/** + * + */ +export const unrepost = (status) => (dispatch, getState) => { + if (!me) return + + dispatch(unrepostRequest(status)) + + api(getState).post(`/api/v1/statuses/${status.get('id')}/unreblog`).then((response) => { + dispatch(importFetchedStatus(response.data)) + dispatch(unrepostSuccess(status)) + }).catch((error) => { + dispatch(unrepostFail(status, error)) + }) } -export function bookmarkRequest(status) { - return { - type: BOOKMARK_REQUEST, - status: status, - } +export const unrepostRequest = (status) => ({ + type: UNREPOST_REQUEST, + status: status, + skipLoading: true, +}) + +export const unrepostSuccess = (status) => ({ + type: UNREPOST_SUCCESS, + status: status, + skipLoading: true, +}) + +export const unrepostFail = (status, error) => ({ + type: UNREPOST_FAIL, + status: status, + error: error, + skipLoading: true, +}) + +/** + * + */ +export const favorite = (status) => (dispatch, getState) => { + if (!me) return + + dispatch(favoriteRequest(status)) + + api(getState).post(`/api/v1/statuses/${status.get('id')}/favourite`).then((response) => { + dispatch(updateStatusStats(response.data)) + dispatch(favoriteSuccess(status)) + }).catch((error) => { + dispatch(favoriteFail(status, error)) + }) } -export function bookmarkSuccess(status, response) { - return { - type: BOOKMARK_SUCCESS, - status: status, - response: response, - } +export const favoriteRequest = (status) => ({ + type: FAVORITE_REQUEST, + status: status, + skipLoading: true, +}) + +export const favoriteSuccess = (status) => ({ + type: FAVORITE_SUCCESS, + status: status, + skipLoading: true, +}) + +export const favoriteFail = (status, error) => ({ + type: FAVORITE_FAIL, + status: status, + error: error, + skipLoading: true, +}) + +/** + * + */ +export const unfavorite = (status) => (dispatch, getState) => { + if (!me) return + + dispatch(unfavoriteRequest(status)) + + api(getState).post(`/api/v1/statuses/${status.get('id')}/unfavourite`).then((response) => { + dispatch(importFetchedStatus(response.data)) + dispatch(unfavoriteSuccess(status)) + }).catch((error) => { + dispatch(unfavoriteFail(status, error)) + }) } -export function bookmarkFail(status, error) { - return { - type: BOOKMARK_FAIL, - status: status, - error: error, - } +export const unfavoriteRequest = (status) => ({ + type: UNFAVORITE_REQUEST, + status: status, + skipLoading: true, +}) + +export const unfavoriteSuccess = (status) => ({ + type: UNFAVORITE_SUCCESS, + status: status, + skipLoading: true, +}) + +export const unfavoriteFail = (status, error) => ({ + type: UNFAVORITE_FAIL, + status: status, + error: error, + skipLoading: true, +}) + +/** + * + */ +export const fetchReposts = (id) => (dispatch, getState) => { + if (!me) return + + dispatch(fetchRepostsRequest(id)) + + api(getState).get(`/api/v1/statuses/${id}/reblogged_by`).then((response) => { + dispatch(importFetchedAccounts(response.data)) + dispatch(fetchRepostsSuccess(id, response.data)) + }).catch((error) => { + dispatch(fetchRepostsFail(id, error)) + }) } -export function unbookmarkRequest(status) { - return { - type: UNBOOKMARK_REQUEST, - status: status, - } +export const fetchRepostsRequest = (id) => ({ + type: REPOSTS_FETCH_REQUEST, + id, +}) + +export const fetchRepostsSuccess = (id, accounts) => ({ + type: REPOSTS_FETCH_SUCCESS, + id, + accounts, +}) + +export const fetchRepostsFail = (id, error) => ({ + type: REPOSTS_FETCH_FAIL, + error, +}) + +/** + * + */ +export const pin = (status) => (dispatch, getState) => { + if (!me) return + + dispatch(pinRequest(status)) + + api(getState).post(`/api/v1/statuses/${status.get('id')}/pin`).then((response) => { + dispatch(importFetchedStatus(response.data)) + dispatch(pinSuccess(status)) + }).catch((error) => { + dispatch(pinFail(status, error)) + }) } -export function unbookmarkSuccess(status, response) { - return { - type: UNBOOKMARK_SUCCESS, - status: status, - response: response, - } +export const pinRequest = (status) => ({ + type: PIN_REQUEST, + status, + skipLoading: true, +}) + +export const pinSuccess = (status) => ({ + type: PIN_SUCCESS, + status, + skipLoading: true, +}) + +export const pinFail = (status, error) => ({ + type: PIN_FAIL, + status, + error, + skipLoading: true, +}) + +/** + * + */ +export const unpin = (status) => (dispatch, getState) => { + if (!me) return + + dispatch(unpinRequest(status)) + + api(getState).post(`/api/v1/statuses/${status.get('id')}/unpin`).then((response) => { + dispatch(importFetchedStatus(response.data)) + dispatch(unpinSuccess(status)) + }).catch((error) => { + dispatch(unpinFail(status, error)) + }) } -export function unbookmarkFail(status, error) { - return { - type: UNBOOKMARK_FAIL, - status: status, - error: error, - } -} \ No newline at end of file +export const unpinRequest = (status) => ({ + type: UNPIN_REQUEST, + status, + skipLoading: true, +}) + +export const unpinSuccess = (status) => ({ + type: UNPIN_SUCCESS, + status, + skipLoading: true, +}) + +export const unpinFail = (status, error) => ({ + type: UNPIN_FAIL, + status, + error, + skipLoading: true, +}) + +/** + * + */ +export const fetchLikes = (id) => (dispatch, getState) => { + dispatch(fetchLikesRequest(id)) + + api(getState).get(`/api/v1/statuses/${id}/favourited_by`).then((response) => { + dispatch(importFetchedAccounts(response.data)) + dispatch(fetchLikesSuccess(id, response.data)) + }).catch((error) => { + dispatch(fetchLikesFail(id, error)) + }) +} + +export const fetchLikesRequest = (id) => ({ + type: LIKES_FETCH_REQUEST, + id, +}) + +export const fetchLikesSuccess = (id, accounts) => ({ + type: LIKES_FETCH_SUCCESS, + id, + accounts, +}) + +export const fetchLikesFail = (id, error) => ({ + type: LIKES_FETCH_FAIL, + error, +}) + +/** + * + */ +export const bookmark = (status) => (dispatch, getState) => { + dispatch(bookmarkRequest(status)) + + api(getState).post(`/api/v1/statuses/${status.get('id')}/bookmark`).then((response) => { + dispatch(importFetchedStatus(response.data)) + dispatch(bookmarkSuccess(status, response.data)) + }).catch((error) => { + dispatch(bookmarkFail(status, error)) + }) +} + +export const bookmarkRequest = (status) => ({ + type: BOOKMARK_REQUEST, + status: status, +}) + +export const bookmarkSuccess = (status, response) => ({ + type: BOOKMARK_SUCCESS, + status: status, + response: response, +}) + +export const bookmarkFail = (status, error) => ({ + type: BOOKMARK_FAIL, + status: status, + error: error, +}) + +/** + * + */ +export const unbookmark = (status) => (dispatch, getState) => { + dispatch(unbookmarkRequest(status)) + + api(getState).post(`/api/v1/statuses/${status.get('id')}/unbookmark`).then((response) => { + dispatch(importFetchedStatus(response.data)) + dispatch(unbookmarkSuccess(status, response.data)) + }).catch((error) => { + dispatch(unbookmarkFail(status, error)) + }) +} + +export const unbookmarkRequest = (status) => ({ + type: UNBOOKMARK_REQUEST, + status: status, +}) + +export const unbookmarkSuccess = (status, response) => ({ + type: UNBOOKMARK_SUCCESS, + status: status, + response: response, +}) + +export const unbookmarkFail = (status, error) => ({ + type: UNBOOKMARK_FAIL, + status: status, + error: error, +}) \ No newline at end of file diff --git a/app/javascript/gabsocial/actions/links.js b/app/javascript/gabsocial/actions/links.js index f6d72447..fabc73a2 100644 --- a/app/javascript/gabsocial/actions/links.js +++ b/app/javascript/gabsocial/actions/links.js @@ -10,6 +10,17 @@ export const POPULAR_LINKS_FETCH_FAIL = 'POPULAR_LINKS_FETCH_FAIL' export const IMPORT_LINK_CARDS = 'IMPORT_LINK_CARDS' +/** + * + */ +export const importLinkCards = (cards) => ({ + type: IMPORT_LINK_CARDS, + cards, +}) + +/** + * + */ export const fetchLinkCard = (cardId) => (dispatch, getState) => { //If card exists, don't refetch const card = getState().getIn(['links', 'items', `${cardId}`]) @@ -39,11 +50,9 @@ export const fetchLinkCardFail = (error, cardId) => ({ cardId, }) -export const importLinkCards = (cards) => ({ - type: IMPORT_LINK_CARDS, - cards, -}) - +/** + * + */ export const fetchPopularLinks = () => (dispatch, getState) => { const isFetched = getState().getIn(['links', 'popular', 'isFetched'], false) if (isFetched) return @@ -56,16 +65,16 @@ export const fetchPopularLinks = () => (dispatch, getState) => { .catch((err) => dispatch(fetchPopularLinksFail(err))) } -export const fetchPopularLinksRequest = () => ({ +const fetchPopularLinksRequest = () => ({ type: POPULAR_LINKS_FETCH_REQUEST, }) -export const fetchPopularLinksSuccess = (cards) => ({ +const fetchPopularLinksSuccess = (cards) => ({ type: POPULAR_LINKS_FETCH_SUCCESS, cards, }) -export const fetchPopularLinksFail = (error) => ({ +const fetchPopularLinksFail = (error) => ({ type: POPULAR_LINKS_FETCH_FAIL, error, }) diff --git a/app/javascript/gabsocial/actions/lists.js b/app/javascript/gabsocial/actions/lists.js index e6c2af9c..27d77873 100644 --- a/app/javascript/gabsocial/actions/lists.js +++ b/app/javascript/gabsocial/actions/lists.js @@ -1,88 +1,92 @@ -import api from '../api'; -import { importFetchedAccounts } from './importer'; -// import { showAlertForError } from './alerts'; +import api from '../api' +import { importFetchedAccounts } from './importer' +// import { showAlertForError } from './alerts' import { me } from '../initial_state' -export const LIST_FETCH_REQUEST = 'LIST_FETCH_REQUEST'; -export const LIST_FETCH_SUCCESS = 'LIST_FETCH_SUCCESS'; -export const LIST_FETCH_FAIL = 'LIST_FETCH_FAIL'; +export const LIST_FETCH_REQUEST = 'LIST_FETCH_REQUEST' +export const LIST_FETCH_SUCCESS = 'LIST_FETCH_SUCCESS' +export const LIST_FETCH_FAIL = 'LIST_FETCH_FAIL' -export const LISTS_FETCH_REQUEST = 'LISTS_FETCH_REQUEST'; -export const LISTS_FETCH_SUCCESS = 'LISTS_FETCH_SUCCESS'; -export const LISTS_FETCH_FAIL = 'LISTS_FETCH_FAIL'; +export const LISTS_FETCH_REQUEST = 'LISTS_FETCH_REQUEST' +export const LISTS_FETCH_SUCCESS = 'LISTS_FETCH_SUCCESS' +export const LISTS_FETCH_FAIL = 'LISTS_FETCH_FAIL' -export const LIST_EDITOR_TITLE_CHANGE = 'LIST_EDITOR_TITLE_CHANGE'; -export const LIST_EDITOR_RESET = 'LIST_EDITOR_RESET'; -export const LIST_EDITOR_SETUP = 'LIST_EDITOR_SETUP'; +export const LIST_EDITOR_TITLE_CHANGE = 'LIST_EDITOR_TITLE_CHANGE' +export const LIST_EDITOR_RESET = 'LIST_EDITOR_RESET' +export const LIST_EDITOR_SETUP = 'LIST_EDITOR_SETUP' -export const LIST_CREATE_REQUEST = 'LIST_CREATE_REQUEST'; -export const LIST_CREATE_SUCCESS = 'LIST_CREATE_SUCCESS'; -export const LIST_CREATE_FAIL = 'LIST_CREATE_FAIL'; +export const LIST_CREATE_REQUEST = 'LIST_CREATE_REQUEST' +export const LIST_CREATE_SUCCESS = 'LIST_CREATE_SUCCESS' +export const LIST_CREATE_FAIL = 'LIST_CREATE_FAIL' -export const LIST_UPDATE_REQUEST = 'LIST_UPDATE_REQUEST'; -export const LIST_UPDATE_SUCCESS = 'LIST_UPDATE_SUCCESS'; -export const LIST_UPDATE_FAIL = 'LIST_UPDATE_FAIL'; +export const LIST_UPDATE_REQUEST = 'LIST_UPDATE_REQUEST' +export const LIST_UPDATE_SUCCESS = 'LIST_UPDATE_SUCCESS' +export const LIST_UPDATE_FAIL = 'LIST_UPDATE_FAIL' -export const LIST_DELETE_REQUEST = 'LIST_DELETE_REQUEST'; -export const LIST_DELETE_SUCCESS = 'LIST_DELETE_SUCCESS'; -export const LIST_DELETE_FAIL = 'LIST_DELETE_FAIL'; +export const LIST_DELETE_REQUEST = 'LIST_DELETE_REQUEST' +export const LIST_DELETE_SUCCESS = 'LIST_DELETE_SUCCESS' +export const LIST_DELETE_FAIL = 'LIST_DELETE_FAIL' -export const LIST_ACCOUNTS_FETCH_REQUEST = 'LIST_ACCOUNTS_FETCH_REQUEST'; -export const LIST_ACCOUNTS_FETCH_SUCCESS = 'LIST_ACCOUNTS_FETCH_SUCCESS'; -export const LIST_ACCOUNTS_FETCH_FAIL = 'LIST_ACCOUNTS_FETCH_FAIL'; +export const LIST_ACCOUNTS_FETCH_REQUEST = 'LIST_ACCOUNTS_FETCH_REQUEST' +export const LIST_ACCOUNTS_FETCH_SUCCESS = 'LIST_ACCOUNTS_FETCH_SUCCESS' +export const LIST_ACCOUNTS_FETCH_FAIL = 'LIST_ACCOUNTS_FETCH_FAIL' -export const LIST_EDITOR_SUGGESTIONS_CHANGE = 'LIST_EDITOR_SUGGESTIONS_CHANGE'; -export const LIST_EDITOR_SUGGESTIONS_READY = 'LIST_EDITOR_SUGGESTIONS_READY'; -export const LIST_EDITOR_SUGGESTIONS_CLEAR = 'LIST_EDITOR_SUGGESTIONS_CLEAR'; +export const LIST_EDITOR_SUGGESTIONS_CHANGE = 'LIST_EDITOR_SUGGESTIONS_CHANGE' +export const LIST_EDITOR_SUGGESTIONS_READY = 'LIST_EDITOR_SUGGESTIONS_READY' +export const LIST_EDITOR_SUGGESTIONS_CLEAR = 'LIST_EDITOR_SUGGESTIONS_CLEAR' -export const LIST_EDITOR_ADD_REQUEST = 'LIST_EDITOR_ADD_REQUEST'; -export const LIST_EDITOR_ADD_SUCCESS = 'LIST_EDITOR_ADD_SUCCESS'; -export const LIST_EDITOR_ADD_FAIL = 'LIST_EDITOR_ADD_FAIL'; +export const LIST_EDITOR_ADD_REQUEST = 'LIST_EDITOR_ADD_REQUEST' +export const LIST_EDITOR_ADD_SUCCESS = 'LIST_EDITOR_ADD_SUCCESS' +export const LIST_EDITOR_ADD_FAIL = 'LIST_EDITOR_ADD_FAIL' -export const LIST_EDITOR_REMOVE_REQUEST = 'LIST_EDITOR_REMOVE_REQUEST'; -export const LIST_EDITOR_REMOVE_SUCCESS = 'LIST_EDITOR_REMOVE_SUCCESS'; -export const LIST_EDITOR_REMOVE_FAIL = 'LIST_EDITOR_REMOVE_FAIL'; +export const LIST_EDITOR_REMOVE_REQUEST = 'LIST_EDITOR_REMOVE_REQUEST' +export const LIST_EDITOR_REMOVE_SUCCESS = 'LIST_EDITOR_REMOVE_SUCCESS' +export const LIST_EDITOR_REMOVE_FAIL = 'LIST_EDITOR_REMOVE_FAIL' -export const LIST_ADDER_RESET = 'LIST_ADDER_RESET'; -export const LIST_ADDER_SETUP = 'LIST_ADDER_SETUP'; +export const LIST_ADDER_RESET = 'LIST_ADDER_RESET' +export const LIST_ADDER_SETUP = 'LIST_ADDER_SETUP' -export const LIST_ADDER_LISTS_FETCH_REQUEST = 'LIST_ADDER_LISTS_FETCH_REQUEST'; -export const LIST_ADDER_LISTS_FETCH_SUCCESS = 'LIST_ADDER_LISTS_FETCH_SUCCESS'; -export const LIST_ADDER_LISTS_FETCH_FAIL = 'LIST_ADDER_LISTS_FETCH_FAIL'; +export const LIST_ADDER_LISTS_FETCH_REQUEST = 'LIST_ADDER_LISTS_FETCH_REQUEST' +export const LIST_ADDER_LISTS_FETCH_SUCCESS = 'LIST_ADDER_LISTS_FETCH_SUCCESS' +export const LIST_ADDER_LISTS_FETCH_FAIL = 'LIST_ADDER_LISTS_FETCH_FAIL' -export const fetchList = id => (dispatch, getState) => { - if (!me) return; +/** + * + */ +export const fetchList = (id) => (dispatch, getState) => { + if (!me) return - if (getState().getIn(['lists', id])) { - return; - } + if (getState().getIn(['lists', id])) return - dispatch(fetchListRequest(id)); + dispatch(fetchListRequest(id)) api(getState).get(`/api/v1/lists/${id}`) .then(({ data }) => dispatch(fetchListSuccess(data))) - .catch(err => dispatch(fetchListFail(id, err))); -}; + .catch((err) => dispatch(fetchListFail(id, err))) +} -export const fetchListRequest = id => ({ +const fetchListRequest = id => ({ type: LIST_FETCH_REQUEST, id, -}); +}) -export const fetchListSuccess = list => ({ +const fetchListSuccess = list => ({ type: LIST_FETCH_SUCCESS, list, -}); +}) -export const fetchListFail = (id, error) => ({ +const fetchListFail = (id, error) => ({ type: LIST_FETCH_FAIL, id, error, -}); +}) +/** + * + */ export const fetchLists = () => (dispatch, getState) => { return new Promise((resolve, reject) => { - dispatch(fetchListsRequest()); + dispatch(fetchListsRequest()) if (!me) return reject() api(getState).get('/api/v1/lists').then(({ data }) => { dispatch(fetchListsSuccess(data)) @@ -90,307 +94,367 @@ export const fetchLists = () => (dispatch, getState) => { }).catch((err) => { dispatch(fetchListsFail(err)) return reject() - }); + }) }) -}; +} -export const fetchListsRequest = () => ({ +const fetchListsRequest = () => ({ type: LISTS_FETCH_REQUEST, -}); +}) -export const fetchListsSuccess = (lists) => ({ +const fetchListsSuccess = (lists) => ({ type: LISTS_FETCH_SUCCESS, lists, -}); +}) -export const fetchListsFail = (error) => ({ +const fetchListsFail = (error) => ({ type: LISTS_FETCH_FAIL, error, -}); +}) +/** + * + */ export const submitListEditor = (shouldReset) => (dispatch, getState) => { - const listId = getState().getIn(['listEditor', 'listId']); - const title = getState().getIn(['listEditor', 'title']); + const listId = getState().getIn(['listEditor', 'listId']) + const title = getState().getIn(['listEditor', 'title']) if (listId === null) { - dispatch(createList(title, shouldReset)); + dispatch(createList(title, shouldReset)) } else { - dispatch(updateList(listId, title, shouldReset)); + dispatch(updateList(listId, title, shouldReset)) } -}; +} +/** + * + */ export const setupListEditor = (listId) => (dispatch, getState) => { dispatch({ type: LIST_EDITOR_SETUP, list: getState().getIn(['lists', listId]), - }); + }) - dispatch(fetchListAccounts(listId)); -}; + dispatch(fetchListAccounts(listId)) +} +/** + * + */ export const changeListEditorTitle = (value) => ({ type: LIST_EDITOR_TITLE_CHANGE, value, -}); +}) +/** + * + */ export const createList = (title, shouldReset) => (dispatch, getState) => { - if (!me) return; + if (!me) return - dispatch(createListRequest()); + dispatch(createListRequest()) api(getState).post('/api/v1/lists', { title }).then(({ data }) => { - dispatch(createListSuccess(data)); + dispatch(createListSuccess(data)) if (shouldReset) { - dispatch(resetListEditor()); + dispatch(resetListEditor()) } - }).catch(err => dispatch(createListFail(err))); -}; + }).catch((err) => dispatch(createListFail(err))) +} export const createListRequest = () => ({ type: LIST_CREATE_REQUEST, -}); +}) export const createListSuccess = (list) => ({ type: LIST_CREATE_SUCCESS, list, -}); +}) export const createListFail = (error) => ({ type: LIST_CREATE_FAIL, error, -}); +}) +/** + * + */ export const updateList = (id, title, shouldReset) => (dispatch, getState) => { - if (!me) return; + if (!me) return - dispatch(updateListRequest(id)); + dispatch(updateListRequest(id)) api(getState).put(`/api/v1/lists/${id}`, { title }).then(({ data }) => { - dispatch(updateListSuccess(data)); + dispatch(updateListSuccess(data)) if (shouldReset) { - dispatch(resetListEditor()); + dispatch(resetListEditor()) } - }).catch(err => dispatch(updateListFail(id, err))); -}; + }).catch((err) => dispatch(updateListFail(id, err))) +} export const updateListRequest = id => ({ type: LIST_UPDATE_REQUEST, id, -}); +}) export const updateListSuccess = list => ({ type: LIST_UPDATE_SUCCESS, list, -}); +}) export const updateListFail = (id, error) => ({ type: LIST_UPDATE_FAIL, id, error, -}); +}) export const resetListEditor = () => ({ type: LIST_EDITOR_RESET, -}); +}) +/** + * + */ export const deleteList = (id) => (dispatch, getState) => { - if (!me) return; + if (!me) return - dispatch(deleteListRequest(id)); + dispatch(deleteListRequest(id)) api(getState).delete(`/api/v1/lists/${id}`) .then(() => dispatch(deleteListSuccess(id))) - .catch(err => dispatch(deleteListFail(id, err))); -}; + .catch((err) => dispatch(deleteListFail(id, err))) +} export const deleteListRequest = (id) => ({ type: LIST_DELETE_REQUEST, id, -}); +}) export const deleteListSuccess = (id) => ({ type: LIST_DELETE_SUCCESS, id, -}); +}) export const deleteListFail = (id, error) => ({ type: LIST_DELETE_FAIL, id, error, -}); +}) +/** + * + */ export const fetchListAccounts = (listId) => (dispatch, getState) => { - if (!me) return; + if (!me) return - dispatch(fetchListAccountsRequest(listId)); + dispatch(fetchListAccountsRequest(listId)) api(getState).get(`/api/v1/lists/${listId}/accounts`, { params: { limit: 0 } }).then(({ data }) => { - dispatch(importFetchedAccounts(data)); - dispatch(fetchListAccountsSuccess(listId, data)); - }).catch(err => dispatch(fetchListAccountsFail(listId, err))); -}; + dispatch(importFetchedAccounts(data)) + dispatch(fetchListAccountsSuccess(listId, data)) + }).catch((err) => dispatch(fetchListAccountsFail(listId, err))) +} export const fetchListAccountsRequest = (id) => ({ type: LIST_ACCOUNTS_FETCH_REQUEST, id, -}); +}) export const fetchListAccountsSuccess = (id, accounts, next) => ({ type: LIST_ACCOUNTS_FETCH_SUCCESS, id, accounts, next, -}); +}) export const fetchListAccountsFail = (id, error) => ({ type: LIST_ACCOUNTS_FETCH_FAIL, id, error, -}); +}) +/** + * + */ export const fetchListSuggestions = (q) => (dispatch, getState) => { - if (!me) return; + if (!me) return const params = { q, resolve: false, limit: 25, - }; + } api(getState).get('/api/v1/accounts/search', { params }).then(({ data }) => { - dispatch(importFetchedAccounts(data)); - dispatch(fetchListSuggestionsReady(q, data)); + dispatch(importFetchedAccounts(data)) + dispatch(fetchListSuggestionsReady(q, data)) }) - // }).catch(error => dispatch(showAlertForError(error))); -}; + // }).catch(error => dispatch(showAlertForError(error))) +} +/** + * + */ export const fetchListSuggestionsReady = (query, accounts) => ({ type: LIST_EDITOR_SUGGESTIONS_READY, query, accounts, -}); +}) +/** + * + */ export const clearListSuggestions = () => ({ type: LIST_EDITOR_SUGGESTIONS_CLEAR, -}); +}) +/** + * + */ export const changeListSuggestions = (value) => ({ type: LIST_EDITOR_SUGGESTIONS_CHANGE, value, -}); +}) +/** + * + */ export const addToListEditor = accountId => (dispatch, getState) => { - dispatch(addToList(getState().getIn(['listEditor', 'listId']), accountId)); -}; + dispatch(addToList(getState().getIn(['listEditor', 'listId']), accountId)) +} +/** + * + */ export const addToList = (listId, accountId) => (dispatch, getState) => { - if (!me) return; + if (!me) return - dispatch(addToListRequest(listId, accountId)); + dispatch(addToListRequest(listId, accountId)) api(getState).post(`/api/v1/lists/${listId}/accounts`, { account_ids: [accountId] }) .then(() => dispatch(addToListSuccess(listId, accountId))) - .catch(err => dispatch(addToListFail(listId, accountId, err))); -}; + .catch((err) => dispatch(addToListFail(listId, accountId, err))) +} -export const addToListRequest = (listId, accountId) => ({ +const addToListRequest = (listId, accountId) => ({ type: LIST_EDITOR_ADD_REQUEST, listId, accountId, -}); +}) -export const addToListSuccess = (listId, accountId) => ({ +const addToListSuccess = (listId, accountId) => ({ type: LIST_EDITOR_ADD_SUCCESS, listId, accountId, -}); +}) -export const addToListFail = (listId, accountId, error) => ({ +const addToListFail = (listId, accountId, error) => ({ type: LIST_EDITOR_ADD_FAIL, listId, accountId, error, -}); +}) +/** + * + */ export const removeFromListEditor = accountId => (dispatch, getState) => { - dispatch(removeFromList(getState().getIn(['listEditor', 'listId']), accountId)); -}; + dispatch(removeFromList(getState().getIn(['listEditor', 'listId']), accountId)) +} +/** + * + */ export const removeFromList = (listId, accountId) => (dispatch, getState) => { - if (!me) return; + if (!me) return - dispatch(removeFromListRequest(listId, accountId)); + dispatch(removeFromListRequest(listId, accountId)) api(getState).delete(`/api/v1/lists/${listId}/accounts`, { params: { account_ids: [accountId] } }) .then(() => dispatch(removeFromListSuccess(listId, accountId))) - .catch(err => dispatch(removeFromListFail(listId, accountId, err))); -}; + .catch((err) => dispatch(removeFromListFail(listId, accountId, err))) +} -export const removeFromListRequest = (listId, accountId) => ({ +const removeFromListRequest = (listId, accountId) => ({ type: LIST_EDITOR_REMOVE_REQUEST, listId, accountId, -}); +}) -export const removeFromListSuccess = (listId, accountId) => ({ +const removeFromListSuccess = (listId, accountId) => ({ type: LIST_EDITOR_REMOVE_SUCCESS, listId, accountId, -}); +}) -export const removeFromListFail = (listId, accountId, error) => ({ +const removeFromListFail = (listId, accountId, error) => ({ type: LIST_EDITOR_REMOVE_FAIL, listId, accountId, error, -}); +}) +/** + * + */ export const resetListAdder = () => ({ type: LIST_ADDER_RESET, -}); +}) +/** + * + */ export const setupListAdder = accountId => (dispatch, getState) => { dispatch({ type: LIST_ADDER_SETUP, account: getState().getIn(['accounts', accountId]), - }); - dispatch(fetchLists()); - dispatch(fetchAccountLists(accountId)); -}; + }) + dispatch(fetchLists()) + dispatch(fetchAccountLists(accountId)) +} +/** + * + */ export const fetchAccountLists = (accountId) => (dispatch, getState) => { - if (!me) return; + if (!me) return - dispatch(fetchAccountListsRequest(accountId)); + dispatch(fetchAccountListsRequest(accountId)) api(getState).get(`/api/v1/accounts/${accountId}/lists`) .then(({ data }) => dispatch(fetchAccountListsSuccess(accountId, data))) - .catch(err => dispatch(fetchAccountListsFail(accountId, err))); -}; + .catch((err) => dispatch(fetchAccountListsFail(accountId, err))) +} -export const fetchAccountListsRequest = (id) => ({ +const fetchAccountListsRequest = (id) => ({ type:LIST_ADDER_LISTS_FETCH_REQUEST, id, -}); +}) -export const fetchAccountListsSuccess = (id, lists) => ({ +const fetchAccountListsSuccess = (id, lists) => ({ type: LIST_ADDER_LISTS_FETCH_SUCCESS, id, lists, -}); +}) -export const fetchAccountListsFail = (id, err) => ({ +const fetchAccountListsFail = (id, err) => ({ type: LIST_ADDER_LISTS_FETCH_FAIL, id, err, -}); +}) +/** + * + */ export const addToListAdder = (listId) => (dispatch, getState) => { - dispatch(addToList(listId, getState().getIn(['listAdder', 'accountId']))); -}; + dispatch(addToList(listId, getState().getIn(['listAdder', 'accountId']))) +} +/** + * + */ export const removeFromListAdder = (listId) => (dispatch, getState) => { - dispatch(removeFromList(listId, getState().getIn(['listAdder', 'accountId']))); -}; + dispatch(removeFromList(listId, getState().getIn(['listAdder', 'accountId']))) +} diff --git a/app/javascript/gabsocial/actions/modal.js b/app/javascript/gabsocial/actions/modal.js index e664baa7..836a43cb 100644 --- a/app/javascript/gabsocial/actions/modal.js +++ b/app/javascript/gabsocial/actions/modal.js @@ -1,16 +1,12 @@ export const MODAL_OPEN = 'MODAL_OPEN' export const MODAL_CLOSE = 'MODAL_CLOSE' -export function openModal(type, props) { - return { - type: MODAL_OPEN, - modalType: type, - modalProps: props, - } -} +export const openModal = (type, props) => ({ + type: MODAL_OPEN, + modalType: type, + modalProps: props, +}) -export function closeModal() { - return { - type: MODAL_CLOSE, - } -} +export const closeModal = () => ({ + type: MODAL_CLOSE, +}) diff --git a/app/javascript/gabsocial/actions/mutes.js b/app/javascript/gabsocial/actions/mutes.js index 31276a77..8e1d3c1f 100644 --- a/app/javascript/gabsocial/actions/mutes.js +++ b/app/javascript/gabsocial/actions/mutes.js @@ -1,103 +1,95 @@ -import api, { getLinks } from '../api'; -import { fetchRelationships } from './accounts'; -import { importFetchedAccounts } from './importer'; -import { openModal } from './modal'; -import { me } from '../initial_state'; +import api, { getLinks } from '../api' +import { fetchRelationships } from './accounts' +import { importFetchedAccounts } from './importer' +import { openModal } from './modal' +import { me } from '../initial_state' +import { MODAL_MUTE } from '../constants' -export const MUTES_FETCH_REQUEST = 'MUTES_FETCH_REQUEST'; -export const MUTES_FETCH_SUCCESS = 'MUTES_FETCH_SUCCESS'; -export const MUTES_FETCH_FAIL = 'MUTES_FETCH_FAIL'; +export const MUTES_FETCH_REQUEST = 'MUTES_FETCH_REQUEST' +export const MUTES_FETCH_SUCCESS = 'MUTES_FETCH_SUCCESS' +export const MUTES_FETCH_FAIL = 'MUTES_FETCH_FAIL' -export const MUTES_EXPAND_REQUEST = 'MUTES_EXPAND_REQUEST'; -export const MUTES_EXPAND_SUCCESS = 'MUTES_EXPAND_SUCCESS'; -export const MUTES_EXPAND_FAIL = 'MUTES_EXPAND_FAIL'; +export const MUTES_EXPAND_REQUEST = 'MUTES_EXPAND_REQUEST' +export const MUTES_EXPAND_SUCCESS = 'MUTES_EXPAND_SUCCESS' +export const MUTES_EXPAND_FAIL = 'MUTES_EXPAND_FAIL' -export const MUTES_INIT_MODAL = 'MUTES_INIT_MODAL'; +export const MUTES_INIT_MODAL = 'MUTES_INIT_MODAL' -export function fetchMutes() { - return (dispatch, getState) => { - if (!me) return; +/** + * + */ +export const fetchMutes = () => (dispatch, getState) => { + if (!me) return - dispatch(fetchMutesRequest()); + dispatch(fetchMutesRequest()) - api(getState).get('/api/v1/mutes').then(response => { - const next = getLinks(response).refs.find(link => link.rel === 'next'); - dispatch(importFetchedAccounts(response.data)); - dispatch(fetchMutesSuccess(response.data, next ? next.uri : null)); - dispatch(fetchRelationships(response.data.map(item => item.id))); - }).catch(error => dispatch(fetchMutesFail(error))); - }; -}; + api(getState).get('/api/v1/mutes').then((response) => { + const next = getLinks(response).refs.find(link => link.rel === 'next') + dispatch(importFetchedAccounts(response.data)) + dispatch(fetchMutesSuccess(response.data, next ? next.uri : null)) + dispatch(fetchRelationships(response.data.map(item => item.id))) + }).catch((error) => dispatch(fetchMutesFail(error))) +} -export function fetchMutesRequest() { - return { - type: MUTES_FETCH_REQUEST, - }; -}; +const fetchMutesRequest = () => ({ + type: MUTES_FETCH_REQUEST, +}) -export function fetchMutesSuccess(accounts, next) { - return { - type: MUTES_FETCH_SUCCESS, - accounts, - next, - }; -}; +const fetchMutesSuccess = (accounts, next) => ({ + type: MUTES_FETCH_SUCCESS, + accounts, + next, +}) -export function fetchMutesFail(error) { - return { - type: MUTES_FETCH_FAIL, - error, - }; -}; +const fetchMutesFail = (error) => ({ + type: MUTES_FETCH_FAIL, + error, +}) -export function expandMutes() { - return (dispatch, getState) => { - if (!me) return; - - const url = getState().getIn(['user_lists', 'mutes', me, 'next']); - const isLoading = getState().getIn(['user_lists', 'mutes', me, 'isLoading']); +/** + * + */ +export const expandMutes = () => (dispatch, getState) => { + if (!me) return + + const url = getState().getIn(['user_lists', 'mutes', me, 'next']) + const isLoading = getState().getIn(['user_lists', 'mutes', me, 'isLoading']) - if (url === null || isLoading) return + if (url === null || isLoading) return - dispatch(expandMutesRequest()); + dispatch(expandMutesRequest()) - api(getState).get(url).then(response => { - const next = getLinks(response).refs.find(link => link.rel === 'next'); - dispatch(importFetchedAccounts(response.data)); - dispatch(expandMutesSuccess(response.data, next ? next.uri : null)); - dispatch(fetchRelationships(response.data.map(item => item.id))); - }).catch(error => dispatch(expandMutesFail(error))); - }; -}; + api(getState).get(url).then((response) => { + const next = getLinks(response).refs.find(link => link.rel === 'next') + dispatch(importFetchedAccounts(response.data)) + dispatch(expandMutesSuccess(response.data, next ? next.uri : null)) + dispatch(fetchRelationships(response.data.map(item => item.id))) + }).catch((error) => dispatch(expandMutesFail(error))) +} -export function expandMutesRequest() { - return { - type: MUTES_EXPAND_REQUEST, - }; -}; +const expandMutesRequest = () => ({ + type: MUTES_EXPAND_REQUEST, +}) -export function expandMutesSuccess(accounts, next) { - return { - type: MUTES_EXPAND_SUCCESS, - accounts, - next, - }; -}; +const expandMutesSuccess = (accounts, next) => ({ + type: MUTES_EXPAND_SUCCESS, + accounts, + next, +}) -export function expandMutesFail(error) { - return { - type: MUTES_EXPAND_FAIL, - error, - }; -}; +export const expandMutesFail = (error) => ({ + type: MUTES_EXPAND_FAIL, + error, +}) -export function initMuteModal(account) { - return dispatch => { - dispatch({ - type: MUTES_INIT_MODAL, - account, - }); +/** + * + */ +export const initMuteModal = (account) => (dispatch) => { + dispatch({ + type: MUTES_INIT_MODAL, + account, + }) - dispatch(openModal('MUTE')); - }; + dispatch(openModal(MODAL_MUTE)) } \ No newline at end of file diff --git a/app/javascript/gabsocial/actions/news.js b/app/javascript/gabsocial/actions/news.js index 352a5093..dcdd860b 100644 --- a/app/javascript/gabsocial/actions/news.js +++ b/app/javascript/gabsocial/actions/news.js @@ -30,7 +30,6 @@ export const fetchGabTrends = () => (dispatch, getState) => { dispatch(fetchGabTrendsRequest()) const url = 'https://trends.gab.com/partner' - // api(getState).get(`/api/v1/gab_trends?type=partner`).then((response) => { axios.get(url).then((response) => { dispatch(fetchGabTrendsSuccess(response.data)) }).catch((error) => { @@ -65,7 +64,6 @@ export const expandGabTrendsFeed = (feedId) => (dispatch, getState) => { dispatch(expandGabTrendsFeedRequest(feedId)) const url = `https://trends.gab.com/feed/${feedId}?fmt=json&p=${page}` - // api(getState).get(`/api/v1/gab_trends?type=rss&page=${page}&feedId=${feedId}`).then((response) => { axios.get(url).then((response) => { dispatch(expandGabTrendsFeedSuccess(response.data.rssFeedItems, feedId, response.data.pagination.p)) }).catch((error) => { @@ -102,8 +100,7 @@ export const fetchGabNews = () => (dispatch, getState) => { dispatch(fetchGabNewsRequest()) const url = 'https://news.gab.com/feed/?feed=json' - // api(getState).get(`/api/v1/gab_trends?type=news`).then((response) => { - axios.get(url).then((response) => { + axios.get(url).then((response) => { dispatch(fetchGabNewsSuccess(response.data.items)) }).catch((error) => { dispatch(fetchGabNewsFail(error)) diff --git a/app/javascript/gabsocial/actions/notifications.js b/app/javascript/gabsocial/actions/notifications.js index 738a5d4b..99f584b3 100644 --- a/app/javascript/gabsocial/actions/notifications.js +++ b/app/javascript/gabsocial/actions/notifications.js @@ -1,278 +1,283 @@ -import api, { getLinks } from '../api'; -import IntlMessageFormat from 'intl-messageformat'; -import { fetchRelationships } from './accounts'; +import api, { getLinks } from '../api' +import IntlMessageFormat from 'intl-messageformat' +import { fetchRelationships } from './accounts' import { importFetchedAccount, importFetchedAccounts, importFetchedStatus, importFetchedStatuses, -} from './importer'; -import { defineMessages } from 'react-intl'; -import { List as ImmutableList } from 'immutable'; -import { unescapeHTML } from '../utils/html'; -import { getFilters, regexFromFilters } from '../selectors'; -import { me } from '../initial_state'; +} from './importer' +import { defineMessages } from 'react-intl' +import { List as ImmutableList } from 'immutable' +import { unescapeHTML } from '../utils/html' +import { getFilters, regexFromFilters } from '../selectors' +import { me } from '../initial_state' import { NOTIFICATION_FILTERS } from '../constants' -export const NOTIFICATIONS_INITIALIZE = 'NOTIFICATIONS_INITIALIZE'; -export const NOTIFICATIONS_UPDATE = 'NOTIFICATIONS_UPDATE'; -export const NOTIFICATIONS_UPDATE_QUEUE = 'NOTIFICATIONS_UPDATE_QUEUE'; -export const NOTIFICATIONS_DEQUEUE = 'NOTIFICATIONS_DEQUEUE'; +export const NOTIFICATIONS_INITIALIZE = 'NOTIFICATIONS_INITIALIZE' +export const NOTIFICATIONS_UPDATE = 'NOTIFICATIONS_UPDATE' +export const NOTIFICATIONS_UPDATE_QUEUE = 'NOTIFICATIONS_UPDATE_QUEUE' +export const NOTIFICATIONS_DEQUEUE = 'NOTIFICATIONS_DEQUEUE' -export const NOTIFICATIONS_EXPAND_REQUEST = 'NOTIFICATIONS_EXPAND_REQUEST'; -export const NOTIFICATIONS_EXPAND_SUCCESS = 'NOTIFICATIONS_EXPAND_SUCCESS'; -export const NOTIFICATIONS_EXPAND_FAIL = 'NOTIFICATIONS_EXPAND_FAIL'; +export const NOTIFICATIONS_EXPAND_REQUEST = 'NOTIFICATIONS_EXPAND_REQUEST' +export const NOTIFICATIONS_EXPAND_SUCCESS = 'NOTIFICATIONS_EXPAND_SUCCESS' +export const NOTIFICATIONS_EXPAND_FAIL = 'NOTIFICATIONS_EXPAND_FAIL' -export const NOTIFICATIONS_FILTER_SET = 'NOTIFICATIONS_FILTER_SET'; +export const NOTIFICATIONS_FILTER_SET = 'NOTIFICATIONS_FILTER_SET' -export const NOTIFICATIONS_CLEAR = 'NOTIFICATIONS_CLEAR'; -export const NOTIFICATIONS_SCROLL_TOP = 'NOTIFICATIONS_SCROLL_TOP'; -export const NOTIFICATIONS_MARK_READ = 'NOTIFICATIONS_MARK_READ'; +export const NOTIFICATIONS_CLEAR = 'NOTIFICATIONS_CLEAR' +export const NOTIFICATIONS_SCROLL_TOP = 'NOTIFICATIONS_SCROLL_TOP' +export const NOTIFICATIONS_MARK_READ = 'NOTIFICATIONS_MARK_READ' export const MAX_QUEUED_NOTIFICATIONS = 40 defineMessages({ mention: { id: 'notification.mention', defaultMessage: '{name} mentioned you' }, group: { id: 'notifications.group', defaultMessage: '{count} notifications' }, -}); +}) const fetchRelatedRelationships = (dispatch, notifications) => { - const accountIds = notifications.filter(item => item.type === 'follow').map(item => item.account.id); + const accountIds = notifications.filter(item => item.type === 'follow').map(item => item.account.id) if (accountIds.length > 0) { - dispatch(fetchRelationships(accountIds)); + dispatch(fetchRelationships(accountIds)) } } -export function initializeNotifications() { - return { - type: NOTIFICATIONS_INITIALIZE, - } -} - -export function updateNotifications(notification, intlMessages, intlLocale) { - return (dispatch, getState) => { - const showInColumn = getState().getIn(['notifications', 'filter', notification.type], true); - - if (showInColumn) { - dispatch(importFetchedAccount(notification.account)); - - if (notification.status) { - dispatch(importFetchedStatus(notification.status)); - } - - dispatch({ - type: NOTIFICATIONS_UPDATE, - notification, - }); - - fetchRelatedRelationships(dispatch, [notification]); - } - }; -}; - -export function updateNotificationsQueue(notification, intlMessages, intlLocale, curPath) { - return (dispatch, getState) => { - // : todo : - // const showAlert = getState().getIn(['settings', 'notifications', 'alerts', notification.type], true); - const filters = getFilters(getState(), { contextType: 'notifications' }); - - let filtered = false; - - const isOnNotificationsPage = curPath === '/notifications'; - - if (notification.type === 'mention') { - const regex = regexFromFilters(filters); - const searchIndex = notification.status.spoiler_text + '\n' + unescapeHTML(notification.status.content); - filtered = regex && regex.test(searchIndex); - } - - // Desktop notifications - // : todo : - // if (typeof window.Notification !== 'undefined' && showAlert && !filtered) { - // const title = new IntlMessageFormat(intlMessages[`notification.${notification.type}`], intlLocale).format({ name: notification.account.display_name.length > 0 ? notification.account.display_name : notification.account.username }); - // const body = (notification.status && notification.status.spoiler_text.length > 0) ? notification.status.spoiler_text : unescapeHTML(notification.status ? notification.status.content : ''); - - // const notify = new Notification(title, { body, icon: notification.account.avatar, tag: notification.id }); - - // notify.addEventListener('click', () => { - // window.focus(); - // notify.close(); - // }); - // } - - if (isOnNotificationsPage) { - dispatch({ - type: NOTIFICATIONS_UPDATE_QUEUE, - notification, - intlMessages, - intlLocale, - }); - } else { - dispatch(updateNotifications(notification, intlMessages, intlLocale)); - } - } -}; - -export function forceDequeueNotifications() { - return (dispatch,) => { - dispatch({ - type: NOTIFICATIONS_DEQUEUE, - }) - } -} - -export function dequeueNotifications() { - return (dispatch, getState) => { - const queuedNotifications = getState().getIn(['notifications', 'queuedNotifications'], ImmutableList()); - const totalQueuedNotificationsCount = getState().getIn(['notifications', 'totalQueuedNotificationsCount'], 0); - - if (totalQueuedNotificationsCount === 0) { - return; - } else if (totalQueuedNotificationsCount > 0 && totalQueuedNotificationsCount <= MAX_QUEUED_NOTIFICATIONS) { - queuedNotifications.forEach(block => { - dispatch(updateNotifications(block.notification, block.intlMessages, block.intlLocale)); - }); - } else { - dispatch(expandNotifications()); - } - - dispatch({ - type: NOTIFICATIONS_DEQUEUE, - }); - dispatch(markReadNotifications()); - } -}; - const excludeTypesFromFilter = filter => { - const allTypes = ImmutableList(['follow', 'favourite', 'reblog', 'mention', 'poll']); - return allTypes.filterNot(item => item === filter).toJS(); -}; + const allTypes = ImmutableList(['follow', 'favourite', 'reblog', 'mention', 'poll']) + return allTypes.filterNot(item => item === filter).toJS() +} const noOp = () => {} -export function expandNotifications({ maxId } = {}, done = noOp) { - return (dispatch, getState) => { - if (!me) return +/** + * + */ +export const initializeNotifications = () => ({ + type: NOTIFICATIONS_INITIALIZE, +}) - const onlyVerified = getState().getIn(['notifications', 'filter', 'onlyVerified']) - const onlyFollowing = getState().getIn(['notifications', 'filter', 'onlyFollowing']) - const activeFilter = getState().getIn(['notifications', 'filter', 'active']) - const notifications = getState().get('notifications') - const isLoadingMore = !!maxId +/** + * + */ +export const updateNotifications = (notification, intlMessages, intlLocale) => (dispatch, getState) => { + const showInColumn = getState().getIn(['notifications', 'filter', notification.type], true) - if (notifications.get('isLoading') || activeFilter === 'follow_requests') { - done(); - return; + if (showInColumn) { + dispatch(importFetchedAccount(notification.account)) + + if (notification.status) { + dispatch(importFetchedStatus(notification.status)) } - const params = { - max_id: maxId, - exclude_types: activeFilter === 'all' ? null : excludeTypesFromFilter(activeFilter), - } - - if (!!onlyVerified) params.only_verified = onlyVerified - if (!!onlyFollowing) params.only_following = onlyFollowing - - if (!maxId && notifications.get('items').size > 0) { - params.since_id = notifications.getIn(['items', 0, 'id']); - } - - dispatch(expandNotificationsRequest(isLoadingMore)); - - api(getState).get('/api/v1/notifications', { params }).then(response => { - const next = getLinks(response).refs.find(link => link.rel === 'next'); - - dispatch(importFetchedAccounts(response.data.map(item => item.account))); - dispatch(importFetchedStatuses(response.data.map(item => item.status).filter(status => !!status))); - - dispatch(expandNotificationsSuccess(response.data, next ? next.uri : null, isLoadingMore)); - - fetchRelatedRelationships(dispatch, response.data); - - done(); - }).catch(error => { - dispatch(expandNotificationsFail(error, isLoadingMore)); - done(); - }); - }; -}; - -export function expandNotificationsRequest(isLoadingMore) { - return { - type: NOTIFICATIONS_EXPAND_REQUEST, - skipLoading: !isLoadingMore, - }; -}; - -export function expandNotificationsSuccess(notifications, next, isLoadingMore) { - return { - type: NOTIFICATIONS_EXPAND_SUCCESS, - notifications, - next, - skipLoading: !isLoadingMore, - }; -}; - -export function expandNotificationsFail(error, isLoadingMore) { - return { - type: NOTIFICATIONS_EXPAND_FAIL, - error, - skipLoading: !isLoadingMore, - }; -}; - -export function clearNotifications() { - return (dispatch, getState) => { - if (!me) return; - dispatch({ - type: NOTIFICATIONS_CLEAR, - }); - - api(getState).post('/api/v1/notifications/clear'); - }; -}; - -export function scrollTopNotifications(top) { - return (dispatch, getState) => { - dispatch({ - type: NOTIFICATIONS_SCROLL_TOP, - top, - }); - dispatch(markReadNotifications()); - } -}; - -export function setFilter(path, value) { - return (dispatch) => { - if (path === 'active' && NOTIFICATION_FILTERS.indexOf(value) === -1) return - - dispatch({ - type: NOTIFICATIONS_FILTER_SET, - path: path, - value: value, + type: NOTIFICATIONS_UPDATE, + notification, }) - dispatch(expandNotifications()) + + fetchRelatedRelationships(dispatch, [notification]) } } -export function markReadNotifications() { - return (dispatch, getState) => { - if (!me) return - - const topNotification = parseInt(getState().getIn(['notifications', 'items', 0, 'id'])) - const lastReadId = getState().getIn(['notifications', 'lastReadId']) +/** + * + */ +export const updateNotificationsQueue = (notification, intlMessages, intlLocale, curPath) => (dispatch, getState) => { + // : todo : + // const showAlert = getState().getIn(['settings', 'notifications', 'alerts', notification.type], true) + const filters = getFilters(getState(), { contextType: 'notifications' }) - if (topNotification && topNotification > lastReadId && lastReadId !== -1) { - api(getState).post('/api/v1/notifications/mark_read', { - id: topNotification - }).then(() => { - dispatch({ - type: NOTIFICATIONS_MARK_READ, - notification: topNotification, - }) + let filtered = false + + const isOnNotificationsPage = curPath === '/notifications' + + if (notification.type === 'mention') { + const regex = regexFromFilters(filters) + const searchIndex = notification.status.spoiler_text + '\n' + unescapeHTML(notification.status.content) + filtered = regex && regex.test(searchIndex) + } + + // Desktop notifications + // : todo : + // if (typeof window.Notification !== 'undefined' && showAlert && !filtered) { + // const title = new IntlMessageFormat(intlMessages[`notification.${notification.type}`], intlLocale).format({ name: notification.account.display_name.length > 0 ? notification.account.display_name : notification.account.username }) + // const body = (notification.status && notification.status.spoiler_text.length > 0) ? notification.status.spoiler_text : unescapeHTML(notification.status ? notification.status.content : '') + + // const notify = new Notification(title, { body, icon: notification.account.avatar, tag: notification.id }) + + // notify.addEventListener('click', () => { + // window.focus() + // notify.close() + // }) + // } + + if (isOnNotificationsPage) { + dispatch({ + type: NOTIFICATIONS_UPDATE_QUEUE, + notification, + intlMessages, + intlLocale, + }) + } else { + dispatch(updateNotifications(notification, intlMessages, intlLocale)) + } +} + +/** + * + */ +export const forceDequeueNotifications = () => (dispatch) => { + dispatch({ + type: NOTIFICATIONS_DEQUEUE, + }) +} + +/** + * + */ +export const dequeueNotifications = () => (dispatch, getState) => { + const queuedNotifications = getState().getIn(['notifications', 'queuedNotifications'], ImmutableList()) + const totalQueuedNotificationsCount = getState().getIn(['notifications', 'totalQueuedNotificationsCount'], 0) + + if (totalQueuedNotificationsCount === 0) { + return + } else if (totalQueuedNotificationsCount > 0 && totalQueuedNotificationsCount <= MAX_QUEUED_NOTIFICATIONS) { + queuedNotifications.forEach((block) => { + dispatch(updateNotifications(block.notification, block.intlMessages, block.intlLocale)) + }) + } else { + dispatch(expandNotifications()) + } + + dispatch({ + type: NOTIFICATIONS_DEQUEUE, + }) + dispatch(markReadNotifications()) +} + +/** + * + */ +export const expandNotifications = ({ maxId } = {}, done = noOp) => (dispatch, getState) => { + if (!me) return + + const onlyVerified = getState().getIn(['notifications', 'filter', 'onlyVerified']) + const onlyFollowing = getState().getIn(['notifications', 'filter', 'onlyFollowing']) + const activeFilter = getState().getIn(['notifications', 'filter', 'active']) + const notifications = getState().get('notifications') + const isLoadingMore = !!maxId + + if (notifications.get('isLoading') || notifications.get('isError')|| activeFilter === 'follow_requests') { + done() + return + } + + const params = { + max_id: maxId, + exclude_types: activeFilter === 'all' ? null : excludeTypesFromFilter(activeFilter), + } + + if (!!onlyVerified) params.only_verified = onlyVerified + if (!!onlyFollowing) params.only_following = onlyFollowing + + if (!maxId && notifications.get('items').size > 0) { + params.since_id = notifications.getIn(['items', 0, 'id']) + } + + dispatch(expandNotificationsRequest(isLoadingMore)) + + api(getState).get('/api/v1/notifications', { params }).then((response) => { + const next = getLinks(response).refs.find(link => link.rel === 'next') + + dispatch(importFetchedAccounts(response.data.map(item => item.account))) + dispatch(importFetchedStatuses(response.data.map(item => item.status).filter(status => !!status))) + + dispatch(expandNotificationsSuccess(response.data, next ? next.uri : null, isLoadingMore)) + + fetchRelatedRelationships(dispatch, response.data) + + done() + }).catch((error) => { + dispatch(expandNotificationsFail(error, isLoadingMore)) + done() + }) +} + +export const expandNotificationsRequest = (isLoadingMore) => ({ + type: NOTIFICATIONS_EXPAND_REQUEST, + skipLoading: !isLoadingMore, +}) + +export const expandNotificationsSuccess = (notifications, next, isLoadingMore) => ({ + type: NOTIFICATIONS_EXPAND_SUCCESS, + notifications, + next, + skipLoading: !isLoadingMore, +}) + +export const expandNotificationsFail = (error, isLoadingMore) => ({ + type: NOTIFICATIONS_EXPAND_FAIL, + error, + skipLoading: !isLoadingMore, +}) + +/** + * + */ +// : todo : implement with alert/warning +export const clearNotifications = () => (dispatch, getState) => { + if (!me) return + + dispatch({ + type: NOTIFICATIONS_CLEAR, + }) + + api(getState).post('/api/v1/notifications/clear') +} + +/** + * + */ +export const scrollTopNotifications = (top) => (dispatch, getState) => { + dispatch({ + type: NOTIFICATIONS_SCROLL_TOP, + top, + }) + dispatch(markReadNotifications()) +} + +/** + * + */ +export const setFilter = (path, value) => (dispatch) => { + if (path === 'active' && NOTIFICATION_FILTERS.indexOf(value) === -1) return + + dispatch({ + type: NOTIFICATIONS_FILTER_SET, + path: path, + value: value, + }) + dispatch(expandNotifications()) +} + +/** + * + */ +export const markReadNotifications = () => (dispatch, getState) => { + if (!me) return + + const topNotification = parseInt(getState().getIn(['notifications', 'items', 0, 'id'])) + const lastReadId = getState().getIn(['notifications', 'lastReadId']) + + if (topNotification && topNotification > lastReadId && lastReadId !== -1) { + api(getState).post('/api/v1/notifications/mark_read', { + id: topNotification + }).then(() => { + dispatch({ + type: NOTIFICATIONS_MARK_READ, + notification: topNotification, }) - } + }) } } \ No newline at end of file diff --git a/app/javascript/gabsocial/actions/onboarding.js b/app/javascript/gabsocial/actions/onboarding.js deleted file mode 100644 index 52733a44..00000000 --- a/app/javascript/gabsocial/actions/onboarding.js +++ /dev/null @@ -1,6 +0,0 @@ -import { changeSetting, saveSettings } from './settings' - -export const saveShownOnboarding = () => (dispatch) => { - dispatch(changeSetting(['shownOnboarding'], true)) - dispatch(saveSettings()) -} \ No newline at end of file diff --git a/app/javascript/gabsocial/actions/polls.js b/app/javascript/gabsocial/actions/polls.js index 8e8b82df..29ba4f7d 100644 --- a/app/javascript/gabsocial/actions/polls.js +++ b/app/javascript/gabsocial/actions/polls.js @@ -1,60 +1,66 @@ -import api from '../api'; -import { importFetchedPoll } from './importer'; +import api from '../api' +import { importFetchedPoll } from './importer' -export const POLL_VOTE_REQUEST = 'POLL_VOTE_REQUEST'; -export const POLL_VOTE_SUCCESS = 'POLL_VOTE_SUCCESS'; -export const POLL_VOTE_FAIL = 'POLL_VOTE_FAIL'; +export const POLL_VOTE_REQUEST = 'POLL_VOTE_REQUEST' +export const POLL_VOTE_SUCCESS = 'POLL_VOTE_SUCCESS' +export const POLL_VOTE_FAIL = 'POLL_VOTE_FAIL' -export const POLL_FETCH_REQUEST = 'POLL_FETCH_REQUEST'; -export const POLL_FETCH_SUCCESS = 'POLL_FETCH_SUCCESS'; -export const POLL_FETCH_FAIL = 'POLL_FETCH_FAIL'; +export const POLL_FETCH_REQUEST = 'POLL_FETCH_REQUEST' +export const POLL_FETCH_SUCCESS = 'POLL_FETCH_SUCCESS' +export const POLL_FETCH_FAIL = 'POLL_FETCH_FAIL' +/** + * + */ export const vote = (pollId, choices) => (dispatch, getState) => { - dispatch(voteRequest()); + dispatch(voteRequest()) api(getState).post(`/api/v1/polls/${pollId}/votes`, { choices }) .then(({ data }) => { - dispatch(importFetchedPoll(data)); - dispatch(voteSuccess(data)); + dispatch(importFetchedPoll(data)) + dispatch(voteSuccess(data)) }) - .catch(err => dispatch(voteFail(err))); -}; + .catch(err => dispatch(voteFail(err))) +} +const voteRequest = () => ({ + type: POLL_VOTE_REQUEST, +}) + +const voteSuccess = (poll) => ({ + type: POLL_VOTE_SUCCESS, + poll, +}) + +const voteFail = (error) => ({ + type: POLL_VOTE_FAIL, + error, +}) + +/** + * + */ export const fetchPoll = pollId => (dispatch, getState) => { - dispatch(fetchPollRequest()); + dispatch(fetchPollRequest()) api(getState).get(`/api/v1/polls/${pollId}`) .then(({ data }) => { - dispatch(importFetchedPoll(data)); - dispatch(fetchPollSuccess(data)); + dispatch(importFetchedPoll(data)) + dispatch(fetchPollSuccess(data)) }) - .catch(err => dispatch(fetchPollFail(err))); -}; + .catch(err => dispatch(fetchPollFail(err))) +} -export const voteRequest = () => ({ - type: POLL_VOTE_REQUEST, -}); - -export const voteSuccess = poll => ({ - type: POLL_VOTE_SUCCESS, - poll, -}); - -export const voteFail = error => ({ - type: POLL_VOTE_FAIL, - error, -}); - -export const fetchPollRequest = () => ({ +const fetchPollRequest = () => ({ type: POLL_FETCH_REQUEST, -}); +}) -export const fetchPollSuccess = poll => ({ +const fetchPollSuccess = (poll) => ({ type: POLL_FETCH_SUCCESS, poll, -}); +}) -export const fetchPollFail = error => ({ +const fetchPollFail = (error) => ({ type: POLL_FETCH_FAIL, error, -}); +}) diff --git a/app/javascript/gabsocial/actions/popover.js b/app/javascript/gabsocial/actions/popover.js index f872fc03..25a4636b 100644 --- a/app/javascript/gabsocial/actions/popover.js +++ b/app/javascript/gabsocial/actions/popover.js @@ -1,29 +1,23 @@ export const POPOVER_OPEN = 'POPOVER_OPEN' export const POPOVER_CLOSE = 'POPOVER_CLOSE' -export function openPopover(type, props) { - return function (dispatch, getState) { - const currentlyOpenPopover = getState().getIn(['popover', 'popoverType']) +export const openPopover = (type, props) => (dispatch, getState) => { + const currentlyOpenPopover = getState().getIn(['popover', 'popoverType']) - if (currentlyOpenPopover === type) { - dispatch(closePopover(type)) - } else { - dispatch(handleOpenPopover(type, props)) - } + if (currentlyOpenPopover === type) { + dispatch(closePopover(type)) + } else { + dispatch(handleOpenPopover(type, props)) } } -export function closePopover(type) { - return { - type: POPOVER_CLOSE, - popoverType: type, - } -} +export const closePopover = (type) => ({ + type: POPOVER_CLOSE, + popoverType: type, +}) -const handleOpenPopover = (type, props) => { - return { - type: POPOVER_OPEN, - popoverType: type, - popoverProps: props, - } -} \ No newline at end of file +const handleOpenPopover = (type, props) => ({ + type: POPOVER_OPEN, + popoverType: type, + popoverProps: props, +}) \ No newline at end of file diff --git a/app/javascript/gabsocial/actions/promotions.js b/app/javascript/gabsocial/actions/promotions.js index c4cfeb80..bdca5e80 100644 --- a/app/javascript/gabsocial/actions/promotions.js +++ b/app/javascript/gabsocial/actions/promotions.js @@ -5,18 +5,19 @@ export const PROMOTIONS_FETCH_REQUEST = 'PROMOTIONS_FETCH_REQUEST' export const PROMOTIONS_FETCH_SUCCESS = 'PROMOTIONS_FETCH_SUCCESS' export const PROMOTIONS_FETCH_FAIL = 'PROMOTIONS_FETCH_FAIL' -export const fetchPromotions = () => { - return (dispatch, getState) => { - if (!me) return +/** + * + */ +export const fetchPromotions = () => (dispatch, getState) => { + if (!me) return - dispatch(fetchPromotionsRequest()) + dispatch(fetchPromotionsRequest()) - api(getState).get('/api/v1/promotions').then((response) => { - dispatch(fetchPromotionsSuccess(response.data)) - }).catch((error) => { - dispatch(fetchPromotionsFail(error)) - }) - } + api(getState).get('/api/v1/promotions').then((response) => { + dispatch(fetchPromotionsSuccess(response.data)) + }).catch((error) => { + dispatch(fetchPromotionsFail(error)) + }) } const fetchPromotionsRequest = () => ({ diff --git a/app/javascript/gabsocial/actions/push_notifications/index.js b/app/javascript/gabsocial/actions/push_notifications/index.js index 2ffec500..d7cc788e 100644 --- a/app/javascript/gabsocial/actions/push_notifications/index.js +++ b/app/javascript/gabsocial/actions/push_notifications/index.js @@ -4,8 +4,8 @@ import { CLEAR_SUBSCRIPTION, SET_ALERTS, setAlerts, -} from './setter'; -import { register, saveSettings } from './registerer'; +} from './setter' +import { register, saveSettings } from './registerer' export { SET_BROWSER_SUPPORT, @@ -13,11 +13,9 @@ export { CLEAR_SUBSCRIPTION, SET_ALERTS, register, -}; - -export function changeAlerts(path, value) { - return dispatch => { - dispatch(setAlerts(path, value)); - dispatch(saveSettings()); - }; +} + +export const changeAlerts = (path, value) => (dispatch) => { + dispatch(setAlerts(path, value)) + dispatch(saveSettings()) } diff --git a/app/javascript/gabsocial/actions/push_notifications/setter.js b/app/javascript/gabsocial/actions/push_notifications/setter.js index 5561766b..bcef5c6e 100644 --- a/app/javascript/gabsocial/actions/push_notifications/setter.js +++ b/app/javascript/gabsocial/actions/push_notifications/setter.js @@ -1,34 +1,26 @@ -export const SET_BROWSER_SUPPORT = 'PUSH_NOTIFICATIONS_SET_BROWSER_SUPPORT'; -export const SET_SUBSCRIPTION = 'PUSH_NOTIFICATIONS_SET_SUBSCRIPTION'; -export const CLEAR_SUBSCRIPTION = 'PUSH_NOTIFICATIONS_CLEAR_SUBSCRIPTION'; -export const SET_ALERTS = 'PUSH_NOTIFICATIONS_SET_ALERTS'; +export const SET_BROWSER_SUPPORT = 'PUSH_NOTIFICATIONS_SET_BROWSER_SUPPORT' +export const SET_SUBSCRIPTION = 'PUSH_NOTIFICATIONS_SET_SUBSCRIPTION' +export const CLEAR_SUBSCRIPTION = 'PUSH_NOTIFICATIONS_CLEAR_SUBSCRIPTION' +export const SET_ALERTS = 'PUSH_NOTIFICATIONS_SET_ALERTS' -export function setBrowserSupport (value) { - return { - type: SET_BROWSER_SUPPORT, +export const setBrowserSupport = (value) => ({ + type: SET_BROWSER_SUPPORT, + value, +}) + +export const setSubscription = (subscription) => ({ + type: SET_SUBSCRIPTION, + subscription, +}) + +export const clearSubscription = () => ({ + type: CLEAR_SUBSCRIPTION, +}) + +export const setAlerts = (path, value) => (dispatch) => { + dispatch({ + type: SET_ALERTS, + path, value, - }; -} - -export function setSubscription (subscription) { - return { - type: SET_SUBSCRIPTION, - subscription, - }; -} - -export function clearSubscription () { - return { - type: CLEAR_SUBSCRIPTION, - }; -} - -export function setAlerts (path, value) { - return dispatch => { - dispatch({ - type: SET_ALERTS, - path, - value, - }); - }; + }) } diff --git a/app/javascript/gabsocial/actions/reports.js b/app/javascript/gabsocial/actions/reports.js index afa0c341..094b3cf2 100644 --- a/app/javascript/gabsocial/actions/reports.js +++ b/app/javascript/gabsocial/actions/reports.js @@ -1,89 +1,82 @@ -import api from '../api'; -import { openModal, closeModal } from './modal'; +import api from '../api' +import { openModal, closeModal } from './modal' +import { MODAL_REPORT } from '../constants' -export const REPORT_INIT = 'REPORT_INIT'; -export const REPORT_CANCEL = 'REPORT_CANCEL'; +export const REPORT_INIT = 'REPORT_INIT' +export const REPORT_CANCEL = 'REPORT_CANCEL' -export const REPORT_SUBMIT_REQUEST = 'REPORT_SUBMIT_REQUEST'; -export const REPORT_SUBMIT_SUCCESS = 'REPORT_SUBMIT_SUCCESS'; -export const REPORT_SUBMIT_FAIL = 'REPORT_SUBMIT_FAIL'; +export const REPORT_SUBMIT_REQUEST = 'REPORT_SUBMIT_REQUEST' +export const REPORT_SUBMIT_SUCCESS = 'REPORT_SUBMIT_SUCCESS' +export const REPORT_SUBMIT_FAIL = 'REPORT_SUBMIT_FAIL' -export const REPORT_STATUS_TOGGLE = 'REPORT_STATUS_TOGGLE'; -export const REPORT_COMMENT_CHANGE = 'REPORT_COMMENT_CHANGE'; -export const REPORT_FORWARD_CHANGE = 'REPORT_FORWARD_CHANGE'; +export const REPORT_STATUS_TOGGLE = 'REPORT_STATUS_TOGGLE' +export const REPORT_COMMENT_CHANGE = 'REPORT_COMMENT_CHANGE' +export const REPORT_FORWARD_CHANGE = 'REPORT_FORWARD_CHANGE' -export function initReport(account, status) { - return dispatch => { - dispatch({ - type: REPORT_INIT, - account, - status, - }); +/** + * + */ +export const initReport = (account, status) => (dispatch) => { + dispatch({ + type: REPORT_INIT, + account, + status, + }) - dispatch(openModal('REPORT')); - }; -}; + dispatch(openModal(MODAL_REPORT)) +} -export function cancelReport() { - return { - type: REPORT_CANCEL, - }; -}; +/** + * + */ +export const cancelReport = () => ({ + type: REPORT_CANCEL, +}) -export function toggleStatusReport(statusId, checked) { - return { - type: REPORT_STATUS_TOGGLE, - statusId, - checked, - }; -}; +/** + * + */ +export const toggleStatusReport = (statusId, checked) => ({ + type: REPORT_STATUS_TOGGLE, + statusId, + checked, +}) -export function submitReport() { - return (dispatch, getState) => { - dispatch(submitReportRequest()); +/** + * + */ +export const submitReport = () => (dispatch, getState) => { + dispatch(submitReportRequest()) - api(getState).post('/api/v1/reports', { - account_id: getState().getIn(['reports', 'new', 'account_id']), - status_ids: getState().getIn(['reports', 'new', 'status_ids']), - comment: getState().getIn(['reports', 'new', 'comment']), - forward: getState().getIn(['reports', 'new', 'forward']), - }).then(response => { - dispatch(closeModal()); - dispatch(submitReportSuccess(response.data)); - }).catch(error => dispatch(submitReportFail(error))); - }; -}; + api(getState).post('/api/v1/reports', { + account_id: getState().getIn(['reports', 'new', 'account_id']), + status_ids: getState().getIn(['reports', 'new', 'status_ids']), + comment: getState().getIn(['reports', 'new', 'comment']), + forward: getState().getIn(['reports', 'new', 'forward']), + }).then((response) => { + dispatch(closeModal()); + dispatch(submitReportSuccess(response.data)) + }).catch((error) => dispatch(submitReportFail(error))) +} -export function submitReportRequest() { - return { - type: REPORT_SUBMIT_REQUEST, - }; -}; +const submitReportRequest = () => ({ + type: REPORT_SUBMIT_REQUEST, +}) -export function submitReportSuccess(report) { - return { - type: REPORT_SUBMIT_SUCCESS, - report, - }; -}; +const submitReportSuccess = (report) => ({ + type: REPORT_SUBMIT_SUCCESS, + report, +}) -export function submitReportFail(error) { - return { - type: REPORT_SUBMIT_FAIL, - error, - }; -}; +const submitReportFail = (error) => ({ + type: REPORT_SUBMIT_FAIL, + error, +}) -export function changeReportComment(comment) { - return { - type: REPORT_COMMENT_CHANGE, - comment, - }; -}; - -export function changeReportForward(forward) { - return { - type: REPORT_FORWARD_CHANGE, - forward, - }; -}; +/** + * + */ +export const changeReportComment = (comment) => ({ + type: REPORT_COMMENT_CHANGE, + comment, +}) diff --git a/app/javascript/gabsocial/actions/search.js b/app/javascript/gabsocial/actions/search.js index e98af32a..81d021cc 100644 --- a/app/javascript/gabsocial/actions/search.js +++ b/app/javascript/gabsocial/actions/search.js @@ -18,93 +18,92 @@ export const SEARCH_FETCH_FAIL = 'SEARCH_FETCH_FAIL'; export const SEARCH_FILTER_SET = 'SEARCH_FILTER_SET' -export function changeSearch(value) { - return { - type: SEARCH_CHANGE, - value, - }; -}; +/** + * + */ +export const changeSearch = (value) => ({ + type: SEARCH_CHANGE, + value, +}) -export function clearSearch() { - return { - type: SEARCH_CLEAR, - }; -}; +/** + * + */ +export const clearSearch = () => ({ + type: SEARCH_CLEAR, +}) -export function submitSearch() { - return (dispatch, getState) => { - const value = getState().getIn(['search', 'value']); - const onlyVerified = getState().getIn(['search', 'filter', 'onlyVerified']) +/** + * + */ +export const submitSearch = () => (dispatch, getState) => { + const value = getState().getIn(['search', 'value']) + const onlyVerified = getState().getIn(['search', 'filter', 'onlyVerified']) - if (value.length === 0) return + if (value.length === 0) return - dispatch(fetchSearchRequest()); + dispatch(fetchSearchRequest()) - api(getState).get('/api/v2/search', { - params: { - onlyVerified, - q: value, - resolve: true, - }, - }).then(response => { - if (response.data.accounts) { - dispatch(importFetchedAccounts(response.data.accounts)); - dispatch(fetchRelationships(response.data.accounts.map(item => item.id))); - } + api(getState).get('/api/v2/search', { + params: { + onlyVerified, + q: value, + resolve: true, + }, + }).then((response) => { + if (response.data.accounts) { + dispatch(importFetchedAccounts(response.data.accounts)) + dispatch(fetchRelationships(response.data.accounts.map(item => item.id))) + } - if (response.data.statuses) { - dispatch(importFetchedStatuses(response.data.statuses)); - } + if (response.data.statuses) { + dispatch(importFetchedStatuses(response.data.statuses)) + } - if (response.data.links) { - dispatch(importLinkCards(response.data.links)); - } + if (response.data.links) { + dispatch(importLinkCards(response.data.links)) + } - if (response.data.groups) { - dispatch(fetchGroupsSuccess(response.data.groups)) - dispatch(fetchGroupRelationships(response.data.groups.map(item => item.id))) - } + if (response.data.groups) { + dispatch(fetchGroupsSuccess(response.data.groups)) + dispatch(fetchGroupRelationships(response.data.groups.map(item => item.id))) + } - dispatch(fetchSearchSuccess(response.data)); - }).catch(error => { - dispatch(fetchSearchFail(error)); - }); - }; -}; + dispatch(fetchSearchSuccess(response.data)) + }).catch((error) => { + dispatch(fetchSearchFail(error)) + }) +} -export function fetchSearchRequest() { - return { - type: SEARCH_FETCH_REQUEST, - }; -}; +const fetchSearchRequest = () => ({ + type: SEARCH_FETCH_REQUEST, +}) -export function fetchSearchSuccess(results) { - return { - type: SEARCH_FETCH_SUCCESS, - results, - }; -}; +const fetchSearchSuccess = (results) => ({ + type: SEARCH_FETCH_SUCCESS, + results, +}) -export function fetchSearchFail(error) { - return { - type: SEARCH_FETCH_FAIL, - error, - }; -}; +const fetchSearchFail = (error) => ({ + type: SEARCH_FETCH_FAIL, + error, +}) -export function showSearch() { - return { - type: SEARCH_SHOW, - }; -}; +/** + * + */ +export const showSearch = () => ({ + type: SEARCH_SHOW, +}) -export function setFilter(path, value, shouldSubmit) { - return (dispatch) => { - dispatch({ - type: SEARCH_FILTER_SET, - path: path, - value: value, - }) - if (shouldSubmit) dispatch(submitSearch()) - } +/** + * + */ +export const setFilter = (path, value, shouldSubmit) => (dispatch) => { + dispatch({ + type: SEARCH_FILTER_SET, + path: path, + value: value, + }) + if (shouldSubmit) dispatch(submitSearch()) } \ No newline at end of file diff --git a/app/javascript/gabsocial/actions/settings.js b/app/javascript/gabsocial/actions/settings.js index 175c511a..2c18fb85 100644 --- a/app/javascript/gabsocial/actions/settings.js +++ b/app/javascript/gabsocial/actions/settings.js @@ -5,16 +5,26 @@ import { me } from '../initial_state' export const SETTING_CHANGE = 'SETTING_CHANGE' export const SETTING_SAVE = 'SETTING_SAVE' -export function changeSetting(path, value) { - return dispatch => { - dispatch({ - type: SETTING_CHANGE, - path, - value, - }) +export const saveShownOnboarding = () => (dispatch) => { + dispatch(changeSetting(['shownOnboarding'], true)) + dispatch(saveSettings()) +} - dispatch(saveSettings()) - } +export const changeSetting = (path, value) => (dispatch) => { + dispatch({ + type: SETTING_CHANGE, + path, + value, + }) + + dispatch(saveSettings()) +} + +/** + * + */ +export const saveSettings = () => (dispatch, getState) => { + debouncedSave(dispatch, getState) } const debouncedSave = debounce((dispatch, getState) => { @@ -28,7 +38,3 @@ const debouncedSave = debounce((dispatch, getState) => { .then(() => dispatch({ type: SETTING_SAVE })) .catch(() => { /* */ }) }, 350, { trailing: true }) - -export function saveSettings() { - return (dispatch, getState) => debouncedSave(dispatch, getState) -} diff --git a/app/javascript/gabsocial/actions/shop.js b/app/javascript/gabsocial/actions/shop.js index a437ec61..3d44c12a 100644 --- a/app/javascript/gabsocial/actions/shop.js +++ b/app/javascript/gabsocial/actions/shop.js @@ -1,47 +1,44 @@ + import axios from 'axios' +import api from '../api' import { me } from '../initial_state' export const SHOP_FEATURED_PRODUCTS_FETCH_REQUEST = 'SHOP_FEATURED_PRODUCTS_FETCH_REQUEST' export const SHOP_FEATURED_PRODUCTS_FETCH_SUCCESS = 'SHOP_FEATURED_PRODUCTS_FETCH_SUCCESS' export const SHOP_FEATURED_PRODUCTS_FETCH_FAIL = 'SHOP_FEATURED_PRODUCTS_FETCH_FAIL' -export const fetchFeaturedProducts = () => { - return function (dispatch, getState) { - if (!me) return +/** + * + */ +export const fetchFeaturedProducts = () => (dispatch, getState) => { + if (!me) return - dispatch(fetchFeaturedProductsRequest('featured')) + dispatch(fetchFeaturedProductsRequest('featured')) - axios.get('https://dissenter-shop.gab.com/product/group/json').then((response) => { - try { - dispatch(fetchFeaturedProductsSuccess(response.data.data, 'featured')) - } catch (error) { - // - } - }).catch(function (error) { - dispatch(fetchFeaturedProductsFail(error, 'featured')) - }) - } + axios.get('https://dissenter-shop.gab.com/product/group/json').then((response) => { + try { + dispatch(fetchFeaturedProductsSuccess(response.data.data, 'featured')) + } catch (error) { + // + } + }).catch((error) => { + dispatch(fetchFeaturedProductsFail(error, 'featured')) + }) } -function fetchFeaturedProductsRequest(listType) { - return { - type: SHOP_FEATURED_PRODUCTS_FETCH_REQUEST, - listType, - } -} +const fetchFeaturedProductsRequest = (listType) => ({ + type: SHOP_FEATURED_PRODUCTS_FETCH_REQUEST, + listType, +}) -function fetchFeaturedProductsSuccess(items, listType) { - return { - type: SHOP_FEATURED_PRODUCTS_FETCH_SUCCESS, - items, - listType, - } -} +const fetchFeaturedProductsSuccess = (items, listType) => ({ + type: SHOP_FEATURED_PRODUCTS_FETCH_SUCCESS, + items, + listType, +}) -function fetchFeaturedProductsFail(error, listType) { - return { - type: SHOP_FEATURED_PRODUCTS_FETCH_FAIL, - error, - listType, - } -} \ No newline at end of file +const fetchFeaturedProductsFail = (error, listType) => ({ + type: SHOP_FEATURED_PRODUCTS_FETCH_FAIL, + error, + listType, +}) \ No newline at end of file diff --git a/app/javascript/gabsocial/actions/shortcuts.js b/app/javascript/gabsocial/actions/shortcuts.js index 92d53ad2..6b1169d3 100644 --- a/app/javascript/gabsocial/actions/shortcuts.js +++ b/app/javascript/gabsocial/actions/shortcuts.js @@ -13,116 +13,104 @@ export const SHORTCUTS_REMOVE_REQUEST = 'SHORTCUTS_REMOVE_REQUEST' export const SHORTCUTS_REMOVE_SUCCESS = 'SHORTCUTS_REMOVE_SUCCESS' export const SHORTCUTS_REMOVE_FAIL = 'SHORTCUTS_REMOVE_FAIL' -export function fetchShortcuts() { - return (dispatch, getState) => { - if (!me) return +/** + * + */ +export const fetchShortcuts = () => (dispatch, getState) => { + if (!me) return + + const isFetched = getState().getIn(['shortcuts', 'isFetched'], false) + if (isFetched) return - dispatch(fetchShortcutsRequest()) + dispatch(fetchShortcutsRequest()) - api(getState).get('/api/v1/shortcuts').then(response => { - dispatch(fetchShortcutsSuccess(response.data)) - }).catch(error => dispatch(fetchShortcutsFail(error))) - } + api(getState).get('/api/v1/shortcuts').then(response => { + dispatch(fetchShortcutsSuccess(response.data)) + }).catch(error => dispatch(fetchShortcutsFail(error))) } -export function fetchShortcutsRequest() { - return { - type: SHORTCUTS_FETCH_REQUEST, - } +const fetchShortcutsRequest = () => ({ + type: SHORTCUTS_FETCH_REQUEST, +}) + +const fetchShortcutsSuccess = (shortcuts) => ({ + type: SHORTCUTS_FETCH_SUCCESS, + shortcuts, +}) + +const fetchShortcutsFail = (error) => ({ + type: SHORTCUTS_FETCH_FAIL, + error, +}) + +/** + * + */ +export const addShortcut = (shortcutType, shortcutId) => (dispatch, getState) => { + if (!me) return + + dispatch(addShortcutsRequest()) + + api(getState).post('/api/v1/shortcuts', { + shortcut_type: shortcutType, + shortcut_id: shortcutId, + }).then(response => { + dispatch(addShortcutsSuccess(response.data)) + }).catch(error => dispatch(addShortcutsFail(error))) } -export function fetchShortcutsSuccess(shortcuts) { - return { - shortcuts, - type: SHORTCUTS_FETCH_SUCCESS, - } -} +const addShortcutsRequest = () => ({ + type: SHORTCUTS_ADD_REQUEST, +}) -export function fetchShortcutsFail(error) { - return { - error, - type: SHORTCUTS_FETCH_FAIL, - } -} +const addShortcutsSuccess = (shortcut) => ({ + type: SHORTCUTS_ADD_SUCCESS, + shortcut, +}) -export function addShortcut(shortcutType, shortcutId) { - return (dispatch, getState) => { - if (!me) return +const addShortcutsFail = (error) => ({ + type: SHORTCUTS_ADD_FAIL, + error, +}) - dispatch(addShortcutsRequest()) - - api(getState).post('/api/v1/shortcuts', { - shortcut_type: shortcutType, - shortcut_id: shortcutId, - }).then(response => { - dispatch(addShortcutsSuccess(response.data)) - }).catch(error => dispatch(addShortcutsFail(error))) - } -} - -export function addShortcutsRequest() { - return { - type: SHORTCUTS_ADD_REQUEST, - } -} - -export function addShortcutsSuccess(shortcut) { - return { - shortcut, - type: SHORTCUTS_ADD_SUCCESS, - } -} - -export function addShortcutsFail(error) { - return { - error, - type: SHORTCUTS_ADD_FAIL, - } -} - -export function removeShortcut(shortcutObjectId, shortcutType, shortcutId) { - return (dispatch, getState) => { - if (!me) return - - let id - if (shortcutObjectId) { - id = shortcutObjectId - } else if (shortcutType && shortcutId) { - const shortcuts = getState().getIn(['shortcuts', 'items']) - const shortcut = shortcuts.find((s) => { - return s.get('shortcut_id') == shortcutId && s.get('shortcut_type') === shortcutType - }) - if (!!shortcut) { - id = shortcut.get('id') - } +/** + * + */ +export const removeShortcut = (shortcutObjectId, shortcutType, shortcutId) => (dispatch, getState) => { + if (!me) return + + let id + if (shortcutObjectId) { + id = shortcutObjectId + } else if (shortcutType && shortcutId) { + const shortcuts = getState().getIn(['shortcuts', 'items']) + const shortcut = shortcuts.find((s) => { + return s.get('shortcut_id') == shortcutId && s.get('shortcut_type') === shortcutType + }) + if (!!shortcut) { + id = shortcut.get('id') } - - if (!id) return - - dispatch(removeShortcutsRequest()) - - api(getState).delete(`/api/v1/shortcuts/${id}`).then(response => { - dispatch(removeShortcutsSuccess(response.data.id)) - }).catch(error => dispatch(removeShortcutsFail(error))) } + + if (!id) return + + dispatch(removeShortcutsRequest()) + + api(getState).delete(`/api/v1/shortcuts/${id}`).then(response => { + dispatch(removeShortcutsSuccess(response.data.id)) + }).catch(error => dispatch(removeShortcutsFail(error))) } -export function removeShortcutsRequest() { - return { - type: SHORTCUTS_REMOVE_REQUEST, - } -} +const removeShortcutsRequest = () => ({ + type: SHORTCUTS_REMOVE_REQUEST, +}) -export function removeShortcutsSuccess(shortcutId) { - return { - shortcutId, - type: SHORTCUTS_REMOVE_SUCCESS, - } -} +const removeShortcutsSuccess = (shortcutId) => ({ + type: SHORTCUTS_REMOVE_SUCCESS, + shortcutId, +}) -export function removeShortcutsFail(error) { - return { - error, - type: SHORTCUTS_REMOVE_FAIL, - } -} +const removeShortcutsFail = (error) => ({ + type: SHORTCUTS_REMOVE_FAIL, + error, +}) diff --git a/app/javascript/gabsocial/actions/sidebar.js b/app/javascript/gabsocial/actions/sidebar.js index 07c62911..d9268422 100644 --- a/app/javascript/gabsocial/actions/sidebar.js +++ b/app/javascript/gabsocial/actions/sidebar.js @@ -1,14 +1,10 @@ export const SIDEBAR_OPEN = 'SIDEBAR_OPEN' export const SIDEBAR_CLOSE = 'SIDEBAR_CLOSE' -export function openSidebar() { - return { - type: SIDEBAR_OPEN, - } -} +export const openSidebar = () => ({ + type: SIDEBAR_OPEN, +}) -export function closeSidebar() { - return { - type: SIDEBAR_CLOSE, - } -} +export const closeSidebar = () => ({ + type: SIDEBAR_CLOSE, +}) diff --git a/app/javascript/gabsocial/actions/status_revisions.js b/app/javascript/gabsocial/actions/status_revisions.js index ae879788..6425a381 100644 --- a/app/javascript/gabsocial/actions/status_revisions.js +++ b/app/javascript/gabsocial/actions/status_revisions.js @@ -4,6 +4,12 @@ export const STATUS_REVISIONS_LOAD = 'STATUS_REVISIONS_LOAD' export const STATUS_REVISIONS_LOAD_SUCCESS = 'STATUS_REVISIONS_SUCCESS' export const STATUS_REVISIONS_LOAD_FAIL = 'STATUS_REVISIONS_FAIL' +export const loadStatusRevisions = (statusId) => (dispatch, getState) => { + api(getState).get(`/api/v1/statuses/${statusId}/revisions`) + .then(res => dispatch(loadStatusRevisionsSuccess(res.data))) + .catch(() => dispatch(loadStatusRevisionsFail())) +} + const loadStatusRevisionsSuccess = (data) => ({ type: STATUS_REVISIONS_LOAD_SUCCESS, revisions: data, @@ -12,12 +18,4 @@ const loadStatusRevisionsSuccess = (data) => ({ const loadStatusRevisionsFail = () => ({ type: STATUS_REVISIONS_LOAD_FAIL, error: true, -}) - -export function loadStatusRevisions(statusId) { - return (dispatch, getState) => { - api(getState).get(`/api/v1/statuses/${statusId}/revisions`) - .then(res => dispatch(loadStatusRevisionsSuccess(res.data))) - .catch(() => dispatch(loadStatusRevisionsFail())) - } -} \ No newline at end of file +}) \ No newline at end of file diff --git a/app/javascript/gabsocial/actions/statuses.js b/app/javascript/gabsocial/actions/statuses.js index d22b6df1..3c9074ae 100644 --- a/app/javascript/gabsocial/actions/statuses.js +++ b/app/javascript/gabsocial/actions/statuses.js @@ -22,19 +22,13 @@ export const COMMENTS_FETCH_REQUEST = 'COMMENTS_FETCH_REQUEST'; export const COMMENTS_FETCH_SUCCESS = 'COMMENTS_FETCH_SUCCESS'; export const COMMENTS_FETCH_FAIL = 'COMMENTS_FETCH_FAIL'; -export const STATUS_MUTE_REQUEST = 'STATUS_MUTE_REQUEST'; -export const STATUS_MUTE_SUCCESS = 'STATUS_MUTE_SUCCESS'; -export const STATUS_MUTE_FAIL = 'STATUS_MUTE_FAIL'; - -export const STATUS_UNMUTE_REQUEST = 'STATUS_UNMUTE_REQUEST'; -export const STATUS_UNMUTE_SUCCESS = 'STATUS_UNMUTE_SUCCESS'; -export const STATUS_UNMUTE_FAIL = 'STATUS_UNMUTE_FAIL'; - export const STATUS_REVEAL = 'STATUS_REVEAL'; export const STATUS_HIDE = 'STATUS_HIDE'; export const STATUS_EDIT = 'STATUS_EDIT'; +export const UPDATE_STATUS_STATS = 'UPDATE_STATUS_STATS' + export function fetchStatusRequest(id, skipLoading) { return { type: STATUS_FETCH_REQUEST, @@ -280,78 +274,6 @@ export function fetchCommentsFail(id, error) { }; }; -export function muteStatus(id) { - return (dispatch, getState) => { - if (!me) return; - - dispatch(muteStatusRequest(id)); - - api(getState).post(`/api/v1/statuses/${id}/mute`).then(() => { - dispatch(muteStatusSuccess(id)); - }).catch(error => { - dispatch(muteStatusFail(id, error)); - }); - }; -}; - -export function muteStatusRequest(id) { - return { - type: STATUS_MUTE_REQUEST, - id, - }; -}; - -export function muteStatusSuccess(id) { - return { - type: STATUS_MUTE_SUCCESS, - id, - }; -}; - -export function muteStatusFail(id, error) { - return { - type: STATUS_MUTE_FAIL, - id, - error, - }; -}; - -export function unmuteStatus(id) { - return (dispatch, getState) => { - if (!me) return; - - dispatch(unmuteStatusRequest(id)); - - api(getState).post(`/api/v1/statuses/${id}/unmute`).then(() => { - dispatch(unmuteStatusSuccess(id)); - }).catch(error => { - dispatch(unmuteStatusFail(id, error)); - }); - }; -}; - -export function unmuteStatusRequest(id) { - return { - type: STATUS_UNMUTE_REQUEST, - id, - }; -}; - -export function unmuteStatusSuccess(id) { - return { - type: STATUS_UNMUTE_SUCCESS, - id, - }; -}; - -export function unmuteStatusFail(id, error) { - return { - type: STATUS_UNMUTE_FAIL, - id, - error, - }; -}; - export function hideStatus(ids) { if (!Array.isArray(ids)) { ids = [ids]; @@ -373,3 +295,10 @@ export function revealStatus(ids) { ids, }; }; + +export function updateStatusStats(data) { + return { + type: UPDATE_STATUS_STATS, + data, + }; +}; \ No newline at end of file diff --git a/app/javascript/gabsocial/actions/store.js b/app/javascript/gabsocial/actions/store.js index 0e60259f..9df1cdf7 100644 --- a/app/javascript/gabsocial/actions/store.js +++ b/app/javascript/gabsocial/actions/store.js @@ -1,24 +1,22 @@ -import { Iterable, fromJS } from 'immutable'; -import { hydrateCompose } from './compose'; -import { importFetchedAccounts } from './importer'; +import { Iterable, fromJS } from 'immutable' +import { hydrateCompose } from './compose' +import { importFetchedAccounts } from './importer' -export const STORE_HYDRATE = 'STORE_HYDRATE'; -export const STORE_HYDRATE_LAZY = 'STORE_HYDRATE_LAZY'; +export const STORE_HYDRATE = 'STORE_HYDRATE' +export const STORE_HYDRATE_LAZY = 'STORE_HYDRATE_LAZY' -const convertState = rawState => - fromJS(rawState, (k, v) => - Iterable.isIndexed(v) ? v.toList() : v.toMap()); +const convertState = (rawState) => { + return fromJS(rawState, (k, v) => Iterable.isIndexed(v) ? v.toList() : v.toMap()) +} -export function hydrateStore(rawState) { - return (dispatch) => { - const state = convertState(rawState); +export const hydrateStore = (rawState) => (dispatch) => { + const state = convertState(rawState) - dispatch({ - type: STORE_HYDRATE, - state, - }); + dispatch({ + type: STORE_HYDRATE, + state, + }) - dispatch(hydrateCompose()); - if (rawState.accounts) dispatch(importFetchedAccounts(Object.values(rawState.accounts))); - }; -}; + dispatch(hydrateCompose()) + if (rawState.accounts) dispatch(importFetchedAccounts(Object.values(rawState.accounts))) +} \ No newline at end of file diff --git a/app/javascript/gabsocial/actions/streaming.js b/app/javascript/gabsocial/actions/streaming.js index 8b6d247d..60c6ae42 100644 --- a/app/javascript/gabsocial/actions/streaming.js +++ b/app/javascript/gabsocial/actions/streaming.js @@ -1,70 +1,73 @@ -import { connectStream } from '../stream'; +import { connectStream } from '../stream' import { deleteFromTimelines, connectTimeline, disconnectTimeline, updateTimelineQueue, -} from './timelines'; -import { updateNotificationsQueue } from './notifications'; -import { updateConversations } from './conversations'; -import { fetchFilters } from './filters'; -import { getLocale } from '../locales'; -import { handleComposeSubmit } from './compose'; +} from './timelines' +import { updateNotificationsQueue } from './notifications' +import { fetchFilters } from './filters' +import { getLocale } from '../locales' +import { handleComposeSubmit } from './compose' -const { messages } = getLocale(); +const { messages } = getLocale() -export function connectTimelineStream (timelineId, path, pollingRefresh = null, accept = null) { +/** + * + */ +export const connectTimelineStream = (timelineId, path, pollingRefresh = null, accept = null) => { return connectStream (path, pollingRefresh, (dispatch, getState) => { - const locale = getState().getIn(['meta', 'locale']); + const locale = getState().getIn(['meta', 'locale']) return { onConnect() { - dispatch(connectTimeline(timelineId)); + dispatch(connectTimeline(timelineId)) }, - onDisconnect() { - dispatch(disconnectTimeline(timelineId)); + dispatch(disconnectTimeline(timelineId)) }, - onReceive (data) { switch(data.event) { case 'update': - dispatch(updateTimelineQueue(timelineId, JSON.parse(data.payload), accept)); - break; + dispatch(updateTimelineQueue(timelineId, JSON.parse(data.payload), accept)) + break case 'delete': - dispatch(deleteFromTimelines(data.payload)); - break; + dispatch(deleteFromTimelines(data.payload)) + break case 'notification': - dispatch(updateNotificationsQueue(JSON.parse(data.payload), messages, locale, window.location.pathname)); - break; - case 'conversation': - dispatch(updateConversations(JSON.parse(data.payload))); - break; + dispatch(updateNotificationsQueue(JSON.parse(data.payload), messages, locale, window.location.pathname)) + break case 'filters_changed': - dispatch(fetchFilters()); - break; + dispatch(fetchFilters()) + break } }, - }; - }); + } + }) } -export const connectUserStream = () => connectTimelineStream('home', 'user'); -export const connectProStream = () => connectTimelineStream('pro', 'pro'); -export const connectListStream = id => connectTimelineStream(`list:${id}`, `list&list=${id}`); - +/** + * + */ export const connectStatusUpdateStream = () => { + return connectStream('statuscard', null, (dispatch, getState) => { + return { onConnect() {}, onDisconnect() {}, onReceive (data) { - if (!data['event'] || !data['payload']) return; + if (!data['event'] || !data['payload']) return if (data.event === 'update') { handleComposeSubmit(dispatch, getState, {data: JSON.parse(data.payload)}, null) } }, - }; - }); -} \ No newline at end of file + } + }) +} + +/** + * + */ +export const connectUserStream = () => connectTimelineStream('home', 'user') diff --git a/app/javascript/gabsocial/actions/suggestions.js b/app/javascript/gabsocial/actions/suggestions.js index 77799ee5..efc6a21b 100644 --- a/app/javascript/gabsocial/actions/suggestions.js +++ b/app/javascript/gabsocial/actions/suggestions.js @@ -13,61 +13,59 @@ export const SUGGESTIONS_FETCH_FAIL = 'SUGGESTIONS_FETCH_FAIL' export const SUGGESTIONS_DISMISS = 'SUGGESTIONS_DISMISS' -export function fetchPopularSuggestions() { - return (dispatch, getState) => { - if (!me) return false - - dispatch(fetchSuggestionsRequest(SUGGESTION_TYPE_VERIFIED)) - - api(getState).get(`/api/v1/suggestions?type=${SUGGESTION_TYPE_VERIFIED}`).then(response => { - dispatch(importFetchedAccounts(response.data)) - dispatch(fetchSuggestionsSuccess(response.data, SUGGESTION_TYPE_VERIFIED)) - dispatch(fetchRelationships(response.data.map(item => item.id))) - }).catch(error => dispatch(fetchSuggestionsFail(error, SUGGESTION_TYPE_VERIFIED))) - } +/** + * + */ +export const fetchPopularSuggestions = () => (dispatch, getState) => { + if (!me) return false + fetchSuggestions(SUGGESTION_TYPE_VERIFIED, dispatch, getState) } -export function fetchRelatedSuggestions(unlimited = false) { - return (dispatch, getState) => { - if (!me) return false - - dispatch(fetchSuggestionsRequest(SUGGESTION_TYPE_RELATED)) - - api(getState).get(`/api/v1/suggestions?type=${SUGGESTION_TYPE_RELATED}&unlimited=${!!unlimited}`).then(response => { - dispatch(importFetchedAccounts(response.data)) - dispatch(fetchSuggestionsSuccess(response.data, SUGGESTION_TYPE_RELATED)) - dispatch(fetchRelationships(response.data.map(item => item.id))) - }).catch(error => dispatch(fetchSuggestionsFail(error, SUGGESTION_TYPE_RELATED))) - } +/** + * + */ +export const fetchRelatedSuggestions = (unlimited = false) => (dispatch, getState) => { + if (!me) return false + fetchSuggestions(SUGGESTION_TYPE_RELATED, dispatch, getState, unlimited) } -export function fetchSuggestionsRequest(suggestionType) { - return { - type: SUGGESTIONS_FETCH_REQUEST, - skipLoading: true, - suggestionType, - } +/** + * + */ +const fetchSuggestions = (suggestionType, dispatch, getState, unlimited = false) => { + dispatch(fetchSuggestionsRequest(suggestionType)) + + api(getState).get(`/api/v1/suggestions?type=${suggestionType}&unlimited=${!!unlimited}`).then((response) => { + dispatch(importFetchedAccounts(response.data)) + dispatch(fetchSuggestionsSuccess(response.data, suggestionType)) + dispatch(fetchRelationships(response.data.map(item => item.id))) + }).catch(error => dispatch(fetchSuggestionsFail(error, suggestionType))) } -export function fetchSuggestionsSuccess(accounts, suggestionType) { - return { - type: SUGGESTIONS_FETCH_SUCCESS, - skipLoading: true, - accounts, - suggestionType - } -} +const fetchSuggestionsRequest = (suggestionType) => ({ + type: SUGGESTIONS_FETCH_REQUEST, + skipLoading: true, + suggestionType, +}) -export function fetchSuggestionsFail(error, suggestionType) { - return { - type: SUGGESTIONS_FETCH_FAIL, - skipLoading: true, - skipAlert: true, - error, - suggestionType, - } -} +const fetchSuggestionsSuccess = (accounts, suggestionType) => ({ + type: SUGGESTIONS_FETCH_SUCCESS, + skipLoading: true, + accounts, + suggestionType +}) +const fetchSuggestionsFail = (error, suggestionType) => ({ + type: SUGGESTIONS_FETCH_FAIL, + skipLoading: true, + skipAlert: true, + error, + suggestionType, +}) + +/** + * + */ export const dismissRelatedSuggestion = (accountId) => (dispatch, getState) => { if (!me) return diff --git a/app/javascript/gabsocial/actions/timeline_injections.js b/app/javascript/gabsocial/actions/timeline_injections.js index 7d3ec55f..511f8cec 100644 --- a/app/javascript/gabsocial/actions/timeline_injections.js +++ b/app/javascript/gabsocial/actions/timeline_injections.js @@ -19,7 +19,7 @@ export const showTimelineInjection = (injectionId) => (dispatch) => { export const hideTimelineInjection = (injectionId) => (dispatch, getState) => { const existingInjectionWeight = getState().getIn(['settings', 'injections', injectionId], null) - if (!existingInjectionWeight) return false + if (!existingInjectionWeight) return const newInjectionWeight = Math.max(existingInjectionWeight - 0.005, 0.01) diff --git a/app/javascript/gabsocial/actions/timelines.js b/app/javascript/gabsocial/actions/timelines.js index 300bb1bf..560d4b92 100644 --- a/app/javascript/gabsocial/actions/timelines.js +++ b/app/javascript/gabsocial/actions/timelines.js @@ -19,13 +19,6 @@ export const TIMELINE_DISCONNECT = 'TIMELINE_DISCONNECT'; export const MAX_QUEUED_ITEMS = 40; -const fetchStatusesAccountsRelationships = (dispatch, statuses) => { - const accountIds = statuses.map(item => item.account.id) - if (accountIds.length > 0) { - dispatch(fetchRelationships(accountIds)); - } -} - export function updateTimeline(timeline, status, accept) { return dispatch => { if (typeof accept === 'function' && !accept(status)) { @@ -134,36 +127,34 @@ const parseTags = (tags = {}, mode) => { }); }; -export function expandTimeline(timelineId, path, params = {}, done = noOp) { - return (dispatch, getState) => { - const timeline = getState().getIn(['timelines', timelineId], ImmutableMap()); - const isLoadingMore = !!params.max_id; +export const expandTimeline = (timelineId, path, params = {}, done = noOp) => (dispatch, getState) => { + const timeline = getState().getIn(['timelines', timelineId], ImmutableMap()) + const isLoadingMore = !!params.max_id - if (timeline.get('isLoading')) { - done(); - return; - } + if (!!timeline && (timeline.get('isLoading') || timeline.get('isError'))) { + done() + return + } - if (!params.max_id && !params.pinned && timeline.get('items', ImmutableList()).size > 0) { - params.since_id = timeline.getIn(['items', 0]); - } + if (!params.max_id && !params.pinned && timeline.get('items', ImmutableList()).size > 0) { + params.since_id = timeline.getIn(['items', 0]) + } - const isLoadingRecent = !!params.since_id; + const isLoadingRecent = !!params.since_id - dispatch(expandTimelineRequest(timelineId, isLoadingMore)); + dispatch(expandTimelineRequest(timelineId, isLoadingMore)) - api(getState).get(path, { params }).then(response => { - const next = getLinks(response).refs.find(link => link.rel === 'next'); - dispatch(importFetchedStatuses(response.data)); - dispatch(expandTimelineSuccess(timelineId, response.data, next ? next.uri : null, response.code === 206, isLoadingRecent, isLoadingMore)); - fetchStatusesAccountsRelationships(dispatch, response.data) - done(); - }).catch(error => { - dispatch(expandTimelineFail(timelineId, error, isLoadingMore)); - done(); - }); - }; -}; + api(getState).get(path, { params }).then((response) => { + console.log("response:", response) + const next = getLinks(response).refs.find(link => link.rel === 'next') + dispatch(importFetchedStatuses(response.data)) + dispatch(expandTimelineSuccess(timelineId, response.data, next ? next.uri : null, response.code === 206, isLoadingRecent, isLoadingMore)) + done() + }).catch((error) => { + dispatch(expandTimelineFail(timelineId, error, isLoadingMore)) + done() + }) +} export const expandHomeTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('home', '/api/v1/timelines/home', { max_id: maxId }, done); export const expandExploreTimeline = ({ maxId, sortBy } = {}, done = noOp) => expandTimeline('explore', '/api/v1/timelines/explore', { max_id: maxId, sort_by: sortBy }, done); diff --git a/app/javascript/gabsocial/actions/toasts.js b/app/javascript/gabsocial/actions/toasts.js index 4616c610..3910f75d 100644 --- a/app/javascript/gabsocial/actions/toasts.js +++ b/app/javascript/gabsocial/actions/toasts.js @@ -7,26 +7,29 @@ export const TOAST_SHOW = 'TOAST_SHOW' export const TOAST_DISMISS = 'TOAST_DISMISS' export const TOAST_CLEAR = 'TOAST_CLEAR' -export function dismissToast(alert) { - return { - type: TOAST_DISMISS, - alert, - } -} +/** + * + */ +export const dismissToast = (alert) => ({ + type: TOAST_DISMISS, + alert, +}) -export function clearToast() { - return { - type: TOAST_CLEAR, - } -} +/** + * + */ +export const clearToast = () => ({ + type: TOAST_CLEAR, +}) -function showToast(type, message) { - return { - type: TOAST_SHOW, - toastType: type, - message, - } -} +/** + * + */ +export const showToast = (type, message) => ({ + type: TOAST_SHOW, + toastType: type, + message, +}) export const showToastError = (message) => { return showToast(TOAST_TYPE_ERROR, message) diff --git a/app/javascript/gabsocial/actions/user.js b/app/javascript/gabsocial/actions/user.js index 4e9f93a0..67c858b9 100644 --- a/app/javascript/gabsocial/actions/user.js +++ b/app/javascript/gabsocial/actions/user.js @@ -11,52 +11,50 @@ export const SAVE_USER_PROFILE_INFORMATION_FETCH_SUCCESS = 'SAVE_USER_PROFILE_IN export const SAVE_USER_PROFILE_INFORMATION_FETCH_FAIL = 'SAVE_USER_PROFILE_INFORMATION_FETCH_FAIL' export const RESEND_USER_CONFIRMATION_EMAIL_SUCCESS = 'RESEND_USER_CONFIRMATION_EMAIL_SUCCESS' -export const saveUserProfileInformation = (data) => { - return function (dispatch, getState) { - if (!isObject(data) || !me) return +/** + * + */ +export const saveUserProfileInformation = (data) => (dispatch, getState) => { + if (!isObject(data) || !me) return - dispatch(saveUserProfileInformationRequest()) + dispatch(saveUserProfileInformationRequest()) - const formData = new FormData() - if (!!data.displayName) formData.append('display_name', data.displayName) - if (data.note !== undefined) formData.append('note', data.note) - if (data.avatar !== undefined) formData.append('avatar', data.avatar) - if (data.header !== undefined) formData.append('header', data.header) - if (data.locked !== undefined) formData.append('locked', data.locked) + const formData = new FormData() + if (!!data.displayName) formData.append('display_name', data.displayName) + if (data.note !== undefined) formData.append('note', data.note) + if (data.avatar !== undefined) formData.append('avatar', data.avatar) + if (data.header !== undefined) formData.append('header', data.header) + if (data.locked !== undefined) formData.append('locked', data.locked) - api(getState).patch('/api/v1/accounts/update_credentials', formData, { - headers: { - 'Content-Type': 'multipart/form-data' - } - }).then((response) => { - dispatch(importFetchedAccount(response.data)) - dispatch(saveUserProfileInformationSuccess(response.data)) - }).catch(error => { - dispatch(saveUserProfileInformationFail(error)) - }) - } + api(getState).patch('/api/v1/accounts/update_credentials', formData, { + headers: { + 'Content-Type': 'multipart/form-data' + } + }).then((response) => { + dispatch(importFetchedAccount(response.data)) + dispatch(saveUserProfileInformationSuccess(response.data)) + }).catch((error) => { + dispatch(saveUserProfileInformationFail(error)) + }) } -function saveUserProfileInformationRequest() { - return { - type: SAVE_USER_PROFILE_INFORMATION_FETCH_REQUEST, - } -} +const saveUserProfileInformationRequest = () => ({ + type: SAVE_USER_PROFILE_INFORMATION_FETCH_REQUEST, +}) -function saveUserProfileInformationSuccess(userProfileData) { - return { - type: SAVE_USER_PROFILE_INFORMATION_FETCH_SUCCESS, - userProfileData, - } -} +const saveUserProfileInformationSuccess = (userProfileData) => ({ + type: SAVE_USER_PROFILE_INFORMATION_FETCH_SUCCESS, + userProfileData, +}) -function saveUserProfileInformationFail(error) { - return { - type: SAVE_USER_PROFILE_INFORMATION_FETCH_FAIL, - error, - } -} +const saveUserProfileInformationFail = (error) => ({ + type: SAVE_USER_PROFILE_INFORMATION_FETCH_FAIL, + error, +}) +/** + * + */ export const resendUserConfirmationEmail = () => (dispatch, getState) => { if (!me || emailConfirmed) return diff --git a/app/javascript/gabsocial/components/emoji/__tests__/emoji-test.js b/app/javascript/gabsocial/components/emoji/__tests__/emoji-test.js deleted file mode 100644 index c8425c4c..00000000 --- a/app/javascript/gabsocial/components/emoji/__tests__/emoji-test.js +++ /dev/null @@ -1,82 +0,0 @@ -import emojify from '../emoji'; - -describe('emoji', () => { - describe('.emojify', () => { - it('ignores unknown shortcodes', () => { - expect(emojify(':foobarbazfake:')).toEqual(':foobarbazfake:'); - }); - - it('ignores shortcodes inside of tags', () => { - expect(emojify('

')).toEqual('

'); - }); - - it('works with unclosed tags', () => { - expect(emojify('hello>')).toEqual('hello>'); - expect(emojify(' { - expect(emojify('smile:')).toEqual('smile:'); - expect(emojify(':smile')).toEqual(':smile'); - }); - - it('does unicode', () => { - expect(emojify('\uD83D\uDC69\u200D\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66')).toEqual( - '👩â€ðŸ‘©â€ðŸ‘¦â€ðŸ‘¦'); - expect(emojify('👨â€ðŸ‘©â€ðŸ‘§â€ðŸ‘§')).toEqual( - '👨â€ðŸ‘©â€ðŸ‘§â€ðŸ‘§'); - expect(emojify('👩â€ðŸ‘©â€ðŸ‘¦')).toEqual('👩â€ðŸ‘©â€ðŸ‘¦'); - expect(emojify('\u2757')).toEqual( - 'â—'); - }); - - it('does multiple unicode', () => { - expect(emojify('\u2757 #\uFE0F\u20E3')).toEqual( - 'â— #ï¸âƒ£'); - expect(emojify('\u2757#\uFE0F\u20E3')).toEqual( - 'â—#ï¸âƒ£'); - expect(emojify('\u2757 #\uFE0F\u20E3 \u2757')).toEqual( - 'â— #ï¸âƒ£ â—'); - expect(emojify('foo \u2757 #\uFE0F\u20E3 bar')).toEqual( - 'foo â— #ï¸âƒ£ bar'); - }); - - it('ignores unicode inside of tags', () => { - expect(emojify('

')).toEqual('

'); - }); - - it('does multiple emoji properly (issue 5188)', () => { - expect(emojify('👌🌈💕')).toEqual('👌🌈💕'); - expect(emojify('👌 🌈 💕')).toEqual('👌 🌈 💕'); - }); - - it('does an emoji that has no shortcode', () => { - expect(emojify('ðŸ‘â€ðŸ—¨')).toEqual('ðŸ‘â€ðŸ—¨'); - }); - - it('does an emoji whose filename is irregular', () => { - expect(emojify('↙ï¸')).toEqual('↙ï¸'); - }); - - it('avoid emojifying on invisible text', () => { - expect(emojify('example.com/te')) - .toEqual('example.com/te'); - expect(emojify('', { ':luigi:': { static_url: 'luigi.exe' } })) - .toEqual(''); - }); - - it('avoid emojifying on invisible text with nested tags', () => { - expect(emojify('😇')) - .toEqual('😇'); - expect(emojify('😇')) - .toEqual('😇'); - expect(emojify('😇')) - .toEqual('😇'); - }); - - it('skips the textual presentation VS15 character', () => { - expect(emojify('✴︎')) // This is U+2734 EIGHT POINTED BLACK STAR then U+FE0E VARIATION SELECTOR-15 - .toEqual('✴'); - }); - }); -}); diff --git a/app/javascript/gabsocial/components/emoji/__tests__/emoji_index-test.js b/app/javascript/gabsocial/components/emoji/__tests__/emoji_index-test.js deleted file mode 100644 index 849502d7..00000000 --- a/app/javascript/gabsocial/components/emoji/__tests__/emoji_index-test.js +++ /dev/null @@ -1,176 +0,0 @@ -import pick from 'lodash.pick' -import { emojiIndex } from 'emoji-mart'; -import { search } from '../emoji_mart_search_light'; - -const trimEmojis = emoji => pick(emoji, ['id', 'unified', 'native', 'custom']); - -describe('emoji_index', () => { - it('should give same result for emoji_index_light and emoji-mart', () => { - const expected = [ - { - id: 'pineapple', - unified: '1f34d', - native: 'ðŸ', - }, - ]; - expect(search('pineapple').map(trimEmojis)).toEqual(expected); - expect(emojiIndex.search('pineapple').map(trimEmojis)).toEqual(expected); - }); - - it('orders search results correctly', () => { - const expected = [ - { - id: 'apple', - unified: '1f34e', - native: 'ðŸŽ', - }, - { - id: 'pineapple', - unified: '1f34d', - native: 'ðŸ', - }, - { - id: 'green_apple', - unified: '1f34f', - native: 'ðŸ', - }, - { - id: 'iphone', - unified: '1f4f1', - native: '📱', - }, - ]; - expect(search('apple').map(trimEmojis)).toEqual(expected); - expect(emojiIndex.search('apple').map(trimEmojis)).toEqual(expected); - }); - - it('can include/exclude categories', () => { - expect(search('flag', { include: ['people'] })).toEqual([]); - expect(emojiIndex.search('flag', { include: ['people'] })).toEqual([]); - }); - - it('(different behavior from emoji-mart) do not erases custom emoji if not passed again', () => { - const custom = [ - { - id: 'gabsocial', - name: 'gabsocial', - short_names: ['gabsocial'], - text: '', - emoticons: [], - keywords: ['gabsocial'], - imageUrl: 'http://example.com', - custom: true, - }, - ]; - search('', { custom }); - emojiIndex.search('', { custom }); - const expected = []; - const lightExpected = [ - { - id: 'gabsocial', - custom: true, - }, - ]; - expect(search('masto').map(trimEmojis)).toEqual(lightExpected); - expect(emojiIndex.search('masto').map(trimEmojis)).toEqual(expected); - }); - - it('(different behavior from emoji-mart) erases custom emoji if another is passed', () => { - const custom = [ - { - id: 'gabsocial', - name: 'gabsocial', - short_names: ['gabsocial'], - text: '', - emoticons: [], - keywords: ['gabsocial'], - imageUrl: 'http://example.com', - custom: true, - }, - ]; - search('', { custom }); - emojiIndex.search('', { custom }); - const expected = []; - expect(search('masto', { custom: [] }).map(trimEmojis)).toEqual(expected); - expect(emojiIndex.search('masto').map(trimEmojis)).toEqual(expected); - }); - - it('handles custom emoji', () => { - const custom = [ - { - id: 'gabsocial', - name: 'gabsocial', - short_names: ['gabsocial'], - text: '', - emoticons: [], - keywords: ['gabsocial'], - imageUrl: 'http://example.com', - custom: true, - }, - ]; - search('', { custom }); - emojiIndex.search('', { custom }); - const expected = [ - { - id: 'gabsocial', - custom: true, - }, - ]; - expect(search('masto', { custom }).map(trimEmojis)).toEqual(expected); - expect(emojiIndex.search('masto', { custom }).map(trimEmojis)).toEqual(expected); - }); - - it('should filter only emojis we care about, exclude pineapple', () => { - const emojisToShowFilter = emoji => emoji.unified !== '1F34D'; - expect(search('apple', { emojisToShowFilter }).map((obj) => obj.id)) - .not.toContain('pineapple'); - expect(emojiIndex.search('apple', { emojisToShowFilter }).map((obj) => obj.id)) - .not.toContain('pineapple'); - }); - - it('does an emoji whose unified name is irregular', () => { - const expected = [ - { - 'id': 'water_polo', - 'unified': '1f93d', - 'native': '🤽', - }, - { - 'id': 'man-playing-water-polo', - 'unified': '1f93d-200d-2642-fe0f', - 'native': '🤽â€â™‚ï¸', - }, - { - 'id': 'woman-playing-water-polo', - 'unified': '1f93d-200d-2640-fe0f', - 'native': '🤽â€â™€ï¸', - }, - ]; - expect(search('polo').map(trimEmojis)).toEqual(expected); - expect(emojiIndex.search('polo').map(trimEmojis)).toEqual(expected); - }); - - it('can search for thinking_face', () => { - const expected = [ - { - id: 'thinking_face', - unified: '1f914', - native: '🤔', - }, - ]; - expect(search('thinking_fac').map(trimEmojis)).toEqual(expected); - expect(emojiIndex.search('thinking_fac').map(trimEmojis)).toEqual(expected); - }); - - it('can search for woman-facepalming', () => { - const expected = [ - { - id: 'woman-facepalming', - unified: '1f926-200d-2640-fe0f', - native: '🤦â€â™€ï¸', - }, - ]; - expect(search('woman-facep').map(trimEmojis)).toEqual(expected); - expect(emojiIndex.search('woman-facep').map(trimEmojis)).toEqual(expected); - }); -}); diff --git a/app/javascript/gabsocial/components/image.js b/app/javascript/gabsocial/components/image.js index 9d29e758..0906d15a 100644 --- a/app/javascript/gabsocial/components/image.js +++ b/app/javascript/gabsocial/components/image.js @@ -54,7 +54,7 @@ class Image extends React.PureComponent { {alt} { - this.setState({ loading: false, oembed: res.data }) - - const iframeDocument = this.iframe.contentWindow.document - - iframeDocument.open() - iframeDocument.write(res.data.html) - iframeDocument.close() - - iframeDocument.body.style.margin = 0 - this.iframe.width = iframeDocument.body.scrollWidth - this.iframe.height = iframeDocument.body.scrollHeight - }).catch(error => { - this.props.onError(error) - }) - } - - setIframeRef = c => { - this.iframe = c - } - - handleTextareaClick = (e) => { - e.target.select() - } - - render() { - const { intl, onClose } = this.props - const { oembed } = this.state - - return ( - -
- - {intl.formatMessage(messages.instructions)} - - -
- -
- - - - - {intl.formatMessage(messages.preview)} - - -
-