This commit is contained in:
		
							parent
							
								
									03fb6c16ec
								
							
						
					
					
						commit
						e8875c6046
					
				
					 15 changed files with 184 additions and 7 deletions
				
			
		| 
						 | 
				
			
			@ -11,8 +11,8 @@ class Api::V1::TimelinesController < ApiController
 | 
			
		|||
    @statuses = cache_collection(@statuses)
 | 
			
		||||
 | 
			
		||||
    set_maps(@statuses)
 | 
			
		||||
    set_counters_maps(@statuses)
 | 
			
		||||
    set_account_counters_maps(@statuses.flat_map { |s| [s.account, s.reblog? ? s.reblog.account : nil] }.compact.uniq)
 | 
			
		||||
    # set_counters_maps(@statuses)
 | 
			
		||||
    # set_account_counters_maps(@statuses.flat_map { |s| [s.account, s.reblog? ? s.reblog.account : nil] }.compact.uniq)
 | 
			
		||||
 | 
			
		||||
    next_path = api_v1_home_timeline_url(max_id: @statuses.last.id)    unless @statuses.empty?
 | 
			
		||||
    prev_path = api_v1_home_timeline_url(since_id: @statuses.first.id) unless @statuses.empty?
 | 
			
		||||
| 
						 | 
				
			
			@ -27,8 +27,8 @@ class Api::V1::TimelinesController < ApiController
 | 
			
		|||
    @statuses = cache_collection(@statuses)
 | 
			
		||||
 | 
			
		||||
    set_maps(@statuses)
 | 
			
		||||
    set_counters_maps(@statuses)
 | 
			
		||||
    set_account_counters_maps(@statuses.flat_map { |s| [s.account, s.reblog? ? s.reblog.account : nil] }.compact.uniq)
 | 
			
		||||
    # set_counters_maps(@statuses)
 | 
			
		||||
    # set_account_counters_maps(@statuses.flat_map { |s| [s.account, s.reblog? ? s.reblog.account : nil] }.compact.uniq)
 | 
			
		||||
 | 
			
		||||
    next_path = api_v1_public_timeline_url(max_id: @statuses.last.id)    unless @statuses.empty?
 | 
			
		||||
    prev_path = api_v1_public_timeline_url(since_id: @statuses.first.id) unless @statuses.empty?
 | 
			
		||||
| 
						 | 
				
			
			@ -44,8 +44,8 @@ class Api::V1::TimelinesController < ApiController
 | 
			
		|||
    @statuses = cache_collection(@statuses)
 | 
			
		||||
 | 
			
		||||
    set_maps(@statuses)
 | 
			
		||||
    set_counters_maps(@statuses)
 | 
			
		||||
    set_account_counters_maps(@statuses.flat_map { |s| [s.account, s.reblog? ? s.reblog.account : nil] }.compact.uniq)
 | 
			
		||||
    # set_counters_maps(@statuses)
 | 
			
		||||
    # set_account_counters_maps(@statuses.flat_map { |s| [s.account, s.reblog? ? s.reblog.account : nil] }.compact.uniq)
 | 
			
		||||
 | 
			
		||||
    next_path = api_v1_hashtag_timeline_url(params[:id], max_id: @statuses.last.id)    unless @statuses.empty?
 | 
			
		||||
    prev_path = api_v1_hashtag_timeline_url(params[:id], since_id: @statuses.first.id) unless @statuses.empty?
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										34
									
								
								app/controllers/settings/imports_controller.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								app/controllers/settings/imports_controller.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,34 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Settings::ImportsController < ApplicationController
 | 
			
		||||
  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 action: :show
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def set_account
 | 
			
		||||
    @account = current_user.account
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def import_params
 | 
			
		||||
    params.require(:import).permit(:data, :type)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										14
									
								
								app/models/import.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								app/models/import.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Import < ApplicationRecord
 | 
			
		||||
  self.inheritance_column = false
 | 
			
		||||
 | 
			
		||||
  enum type: [:following, :blocking]
 | 
			
		||||
 | 
			
		||||
  belongs_to :account
 | 
			
		||||
 | 
			
		||||
  FILE_TYPES = ['text/plain', 'text/csv'].freeze
 | 
			
		||||
 | 
			
		||||
  has_attached_file :data, url: '/system/:hash.:extension', hash_secret: ENV.fetch('PAPERCLIP_SECRET')
 | 
			
		||||
  validates_attachment_content_type :data, content_type: FILE_TYPES
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -12,6 +12,15 @@
 | 
			
		|||
    .content-wrapper
 | 
			
		||||
      .content
 | 
			
		||||
        %h2= yield :page_title
 | 
			
		||||
 | 
			
		||||
        - if flash[:notice]
 | 
			
		||||
          .flash-message.notice
 | 
			
		||||
            %strong= flash[:notice]
 | 
			
		||||
 | 
			
		||||
        - if flash[:alert]
 | 
			
		||||
          .flash-message.alert
 | 
			
		||||
            %strong= flash[:alert]
 | 
			
		||||
 | 
			
		||||
        = yield
 | 
			
		||||
 | 
			
		||||
= render template: "layouts/application", locals: { body_classes: 'admin' }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										11
									
								
								app/views/settings/imports/show.html.haml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								app/views/settings/imports/show.html.haml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
- content_for :page_title do
 | 
			
		||||
  = t('settings.import')
 | 
			
		||||
 | 
			
		||||
%p.hint= t('imports.preface')
 | 
			
		||||
 | 
			
		||||
= simple_form_for @import, url: settings_import_path do |f|
 | 
			
		||||
  = f.input :type, collection: Import.types.keys, wrapper: :with_label, include_blank: false, label_method: lambda { |type| I18n.t("imports.types.#{type}") }
 | 
			
		||||
  = f.input :data, wrapper: :with_label, hint: t('simple_form.hints.imports.data')
 | 
			
		||||
 | 
			
		||||
  .actions
 | 
			
		||||
    = f.button :button, t('imports.upload'), type: :submit
 | 
			
		||||
							
								
								
									
										54
									
								
								app/workers/import_worker.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								app/workers/import_worker.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,54 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
require 'csv'
 | 
			
		||||
 | 
			
		||||
class ImportWorker
 | 
			
		||||
  include Sidekiq::Worker
 | 
			
		||||
 | 
			
		||||
  sidekiq_options retry: false
 | 
			
		||||
 | 
			
		||||
  def perform(import_id)
 | 
			
		||||
    import = Import.find(import_id)
 | 
			
		||||
 | 
			
		||||
    case import.type
 | 
			
		||||
    when 'blocking'
 | 
			
		||||
      process_blocks(import)
 | 
			
		||||
    when 'following'
 | 
			
		||||
      process_follows(import)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    import.destroy
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def process_blocks(import)
 | 
			
		||||
    from_account = import.account
 | 
			
		||||
 | 
			
		||||
    CSV.foreach(import.data.path) do |row|
 | 
			
		||||
      next if row.size != 1
 | 
			
		||||
 | 
			
		||||
      begin
 | 
			
		||||
        target_account = FollowRemoteAccountService.new.call(row[0])
 | 
			
		||||
        next if target_account.nil?
 | 
			
		||||
        BlockService.new.call(from_account, target_account)
 | 
			
		||||
      rescue Goldfinger::Error, HTTP::Error, OpenSSL::SSL::SSLError
 | 
			
		||||
        next
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def process_follows(import)
 | 
			
		||||
    from_account = import.account
 | 
			
		||||
 | 
			
		||||
    CSV.foreach(import.data.path) do |row|
 | 
			
		||||
      next if row.size != 1
 | 
			
		||||
 | 
			
		||||
      begin
 | 
			
		||||
        FollowService.new.call(from_account, row[0])
 | 
			
		||||
      rescue Goldfinger::Error, HTTP::Error, OpenSSL::SSL::SSLError
 | 
			
		||||
        next
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -85,6 +85,13 @@ en:
 | 
			
		|||
    validation_errors:
 | 
			
		||||
      one: Something isn't quite right yet! Please review the error below
 | 
			
		||||
      other: Something isn't quite right yet! Please review %{count} errors below
 | 
			
		||||
  imports:
 | 
			
		||||
    preface: You can import certain data like all the people you are following or blocking into your account on this instance, from files created by an export on another instance.
 | 
			
		||||
    success: Your data was successfully uploaded and will now be processed in due time
 | 
			
		||||
    types:
 | 
			
		||||
      blocking: Blocking list
 | 
			
		||||
      following: Following list
 | 
			
		||||
    upload: Upload
 | 
			
		||||
  landing_strip_html: <strong>%{name}</strong> is a user on <strong>%{domain}</strong>. You can follow them or interact with them if you have an account anywhere in the fediverse. If you don't, you can <a href="%{sign_up_path}">sign up here</a>.
 | 
			
		||||
  notification_mailer:
 | 
			
		||||
    digest:
 | 
			
		||||
| 
						 | 
				
			
			@ -124,6 +131,7 @@ en:
 | 
			
		|||
    back: Back to Mastodon
 | 
			
		||||
    edit_profile: Edit profile
 | 
			
		||||
    export: Data export
 | 
			
		||||
    import: Import
 | 
			
		||||
    preferences: Preferences
 | 
			
		||||
    settings: Settings
 | 
			
		||||
    two_factor_auth: Two-factor Authentication
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,12 +8,15 @@ en:
 | 
			
		|||
        header: PNG, GIF or JPG. At most 2MB. Will be downscaled to 700x335px
 | 
			
		||||
        locked: Requires you to manually approve followers and defaults post privacy to followers-only
 | 
			
		||||
        note: At most 160 characters
 | 
			
		||||
      imports:
 | 
			
		||||
        data: CSV file exported from another Mastodon instance
 | 
			
		||||
    labels:
 | 
			
		||||
      defaults:
 | 
			
		||||
        avatar: Avatar
 | 
			
		||||
        confirm_new_password: Confirm new password
 | 
			
		||||
        confirm_password: Confirm password
 | 
			
		||||
        current_password: Current password
 | 
			
		||||
        data: Data
 | 
			
		||||
        display_name: Display name
 | 
			
		||||
        email: E-mail address
 | 
			
		||||
        header: Header
 | 
			
		||||
| 
						 | 
				
			
			@ -24,6 +27,7 @@ en:
 | 
			
		|||
        otp_attempt: Two-factor code
 | 
			
		||||
        password: Password
 | 
			
		||||
        setting_default_privacy: Post privacy
 | 
			
		||||
        type: Import type
 | 
			
		||||
        username: Username
 | 
			
		||||
      interactions:
 | 
			
		||||
        must_be_follower: Block notifications from non-followers
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,7 @@ SimpleNavigation::Configuration.run do |navigation|
 | 
			
		|||
      settings.item :preferences, safe_join([fa_icon('sliders fw'), t('settings.preferences')]), settings_preferences_url
 | 
			
		||||
      settings.item :password, safe_join([fa_icon('cog fw'), t('auth.change_password')]), edit_user_registration_url
 | 
			
		||||
      settings.item :two_factor_auth, safe_join([fa_icon('mobile fw'), t('settings.two_factor_auth')]), settings_two_factor_auth_url
 | 
			
		||||
      settings.item :import, safe_join([fa_icon('cloud-upload fw'), t('settings.import')]), settings_import_url
 | 
			
		||||
      settings.item :export, safe_join([fa_icon('cloud-download fw'), t('settings.export')]), settings_export_url
 | 
			
		||||
      settings.item :authorized_apps, safe_join([fa_icon('list fw'), t('settings.authorized_apps')]), oauth_authorized_applications_url
 | 
			
		||||
    end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,6 +51,7 @@ Rails.application.routes.draw do
 | 
			
		|||
  namespace :settings do
 | 
			
		||||
    resource :profile, only: [:show, :update]
 | 
			
		||||
    resource :preferences, only: [:show, :update]
 | 
			
		||||
    resource :import, only: [:show, :create]
 | 
			
		||||
 | 
			
		||||
    resource :export, only: [:show] do
 | 
			
		||||
      collection do
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										11
									
								
								db/migrate/20170330163835_create_imports.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								db/migrate/20170330163835_create_imports.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
class CreateImports < ActiveRecord::Migration[5.0]
 | 
			
		||||
  def change
 | 
			
		||||
    create_table :imports do |t|
 | 
			
		||||
      t.integer :account_id, null: false
 | 
			
		||||
      t.integer :type, null: false
 | 
			
		||||
      t.boolean :approved
 | 
			
		||||
 | 
			
		||||
      t.timestamps
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										11
									
								
								db/migrate/20170330164118_add_attachment_data_to_imports.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								db/migrate/20170330164118_add_attachment_data_to_imports.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
class AddAttachmentDataToImports < ActiveRecord::Migration
 | 
			
		||||
  def self.up
 | 
			
		||||
    change_table :imports do |t|
 | 
			
		||||
      t.attachment :data
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def self.down
 | 
			
		||||
    remove_attachment :imports, :data
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										14
									
								
								db/schema.rb
									
										
									
									
									
								
							
							
						
						
									
										14
									
								
								db/schema.rb
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -10,7 +10,7 @@
 | 
			
		|||
#
 | 
			
		||||
# It's strongly recommended that you check this file into your version control system.
 | 
			
		||||
 | 
			
		||||
ActiveRecord::Schema.define(version: 20170330021336) do
 | 
			
		||||
ActiveRecord::Schema.define(version: 20170330164118) do
 | 
			
		||||
 | 
			
		||||
  # These are extensions that must be enabled in order to support this database
 | 
			
		||||
  enable_extension "plpgsql"
 | 
			
		||||
| 
						 | 
				
			
			@ -93,6 +93,18 @@ ActiveRecord::Schema.define(version: 20170330021336) do
 | 
			
		|||
    t.index ["account_id", "target_account_id"], name: "index_follows_on_account_id_and_target_account_id", unique: true, using: :btree
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  create_table "imports", force: :cascade do |t|
 | 
			
		||||
    t.integer  "account_id",        null: false
 | 
			
		||||
    t.integer  "type",              null: false
 | 
			
		||||
    t.boolean  "approved"
 | 
			
		||||
    t.datetime "created_at",        null: false
 | 
			
		||||
    t.datetime "updated_at",        null: false
 | 
			
		||||
    t.string   "data_file_name"
 | 
			
		||||
    t.string   "data_content_type"
 | 
			
		||||
    t.integer  "data_file_size"
 | 
			
		||||
    t.datetime "data_updated_at"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  create_table "media_attachments", force: :cascade do |t|
 | 
			
		||||
    t.bigint   "status_id"
 | 
			
		||||
    t.string   "file_file_name"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								spec/fabricators/import_fabricator.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								spec/fabricators/import_fabricator.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
Fabricator(:import) do
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										5
									
								
								spec/models/import_spec.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								spec/models/import_spec.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
require 'rails_helper'
 | 
			
		||||
 | 
			
		||||
RSpec.describe Import, type: :model do
 | 
			
		||||
 | 
			
		||||
end
 | 
			
		||||
		Loading…
	
	Add table
		
		Reference in a new issue