mirror of https://github.com/mastodon/mastodon
This commit is contained in:
parent
03fb6c16ec
commit
e8875c6046
|
@ -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?
|
||||
|
|
|
@ -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
|
|
@ -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' }
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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"
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Fabricator(:import) do
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Import, type: :model do
|
||||
|
||||
end
|
Loading…
Reference in New Issue