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) |     @statuses = cache_collection(@statuses) | ||||||
| 
 | 
 | ||||||
|     set_maps(@statuses) |     set_maps(@statuses) | ||||||
|     set_counters_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_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? |     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? |     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) |     @statuses = cache_collection(@statuses) | ||||||
| 
 | 
 | ||||||
|     set_maps(@statuses) |     set_maps(@statuses) | ||||||
|     set_counters_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_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? |     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? |     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) |     @statuses = cache_collection(@statuses) | ||||||
| 
 | 
 | ||||||
|     set_maps(@statuses) |     set_maps(@statuses) | ||||||
|     set_counters_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_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? |     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? |     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-wrapper | ||||||
|       .content |       .content | ||||||
|         %h2= yield :page_title |         %h2= yield :page_title | ||||||
|  | 
 | ||||||
|  |         - if flash[:notice] | ||||||
|  |           .flash-message.notice | ||||||
|  |             %strong= flash[:notice] | ||||||
|  | 
 | ||||||
|  |         - if flash[:alert] | ||||||
|  |           .flash-message.alert | ||||||
|  |             %strong= flash[:alert] | ||||||
|  | 
 | ||||||
|         = yield |         = yield | ||||||
| 
 | 
 | ||||||
| = render template: "layouts/application", locals: { body_classes: 'admin' } | = 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: |     validation_errors: | ||||||
|       one: Something isn't quite right yet! Please review the error below |       one: Something isn't quite right yet! Please review the error below | ||||||
|       other: Something isn't quite right yet! Please review %{count} errors 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>. |   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: |   notification_mailer: | ||||||
|     digest: |     digest: | ||||||
|  | @ -124,6 +131,7 @@ en: | ||||||
|     back: Back to Mastodon |     back: Back to Mastodon | ||||||
|     edit_profile: Edit profile |     edit_profile: Edit profile | ||||||
|     export: Data export |     export: Data export | ||||||
|  |     import: Import | ||||||
|     preferences: Preferences |     preferences: Preferences | ||||||
|     settings: Settings |     settings: Settings | ||||||
|     two_factor_auth: Two-factor Authentication |     two_factor_auth: Two-factor Authentication | ||||||
|  |  | ||||||
|  | @ -8,12 +8,15 @@ en: | ||||||
|         header: PNG, GIF or JPG. At most 2MB. Will be downscaled to 700x335px |         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 |         locked: Requires you to manually approve followers and defaults post privacy to followers-only | ||||||
|         note: At most 160 characters |         note: At most 160 characters | ||||||
|  |       imports: | ||||||
|  |         data: CSV file exported from another Mastodon instance | ||||||
|     labels: |     labels: | ||||||
|       defaults: |       defaults: | ||||||
|         avatar: Avatar |         avatar: Avatar | ||||||
|         confirm_new_password: Confirm new password |         confirm_new_password: Confirm new password | ||||||
|         confirm_password: Confirm password |         confirm_password: Confirm password | ||||||
|         current_password: Current password |         current_password: Current password | ||||||
|  |         data: Data | ||||||
|         display_name: Display name |         display_name: Display name | ||||||
|         email: E-mail address |         email: E-mail address | ||||||
|         header: Header |         header: Header | ||||||
|  | @ -24,6 +27,7 @@ en: | ||||||
|         otp_attempt: Two-factor code |         otp_attempt: Two-factor code | ||||||
|         password: Password |         password: Password | ||||||
|         setting_default_privacy: Post privacy |         setting_default_privacy: Post privacy | ||||||
|  |         type: Import type | ||||||
|         username: Username |         username: Username | ||||||
|       interactions: |       interactions: | ||||||
|         must_be_follower: Block notifications from non-followers |         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 :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 :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 :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 :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 |       settings.item :authorized_apps, safe_join([fa_icon('list fw'), t('settings.authorized_apps')]), oauth_authorized_applications_url | ||||||
|     end |     end | ||||||
|  |  | ||||||
|  | @ -51,6 +51,7 @@ Rails.application.routes.draw do | ||||||
|   namespace :settings do |   namespace :settings do | ||||||
|     resource :profile, only: [:show, :update] |     resource :profile, only: [:show, :update] | ||||||
|     resource :preferences, only: [:show, :update] |     resource :preferences, only: [:show, :update] | ||||||
|  |     resource :import, only: [:show, :create] | ||||||
| 
 | 
 | ||||||
|     resource :export, only: [:show] do |     resource :export, only: [:show] do | ||||||
|       collection 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. | # 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 |   # These are extensions that must be enabled in order to support this database | ||||||
|   enable_extension "plpgsql" |   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 |     t.index ["account_id", "target_account_id"], name: "index_follows_on_account_id_and_target_account_id", unique: true, using: :btree | ||||||
|   end |   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| |   create_table "media_attachments", force: :cascade do |t| | ||||||
|     t.bigint   "status_id" |     t.bigint   "status_id" | ||||||
|     t.string   "file_file_name" |     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
		Add a link
		
	
		Reference in a new issue