@ -1,9 +1,35 @@
|
||||
import emojione from 'emojione';
|
||||
|
||||
emojione.imageType = 'png';
|
||||
emojione.sprites = false;
|
||||
emojione.imagePathPNG = '/emoji/';
|
||||
const toImage = str => shortnameToImage(unicodeToImage(str));
|
||||
|
||||
const unicodeToImage = str => {
|
||||
const mappedUnicode = emojione.mapUnicodeToShort();
|
||||
|
||||
return str.replace(emojione.regUnicode, unicodeChar => {
|
||||
if (typeof unicodeChar === 'undefined' || unicodeChar === '' || !(unicodeChar in emojione.jsEscapeMap)) {
|
||||
return unicodeChar;
|
||||
}
|
||||
|
||||
const unicode = emojione.jsEscapeMap[unicodeChar];
|
||||
const short = mappedUnicode[unicode];
|
||||
const filename = emojione.emojioneList[short].fname;
|
||||
const alt = emojione.convert(unicode.toUpperCase());
|
||||
|
||||
return `<img draggable="false" class="emojione" alt="${alt}" src="/emoji/${filename}.svg" />`;
|
||||
});
|
||||
};
|
||||
|
||||
const shortnameToImage = str => str.replace(emojione.regShortNames, shortname => {
|
||||
if (typeof shortname === 'undefined' || shortname === '' || !(shortname in emojione.emojioneList)) {
|
||||
return shortname;
|
||||
}
|
||||
|
||||
const unicode = emojione.emojioneList[shortname].unicode[emojione.emojioneList[shortname].unicode.length - 1];
|
||||
const alt = emojione.convert(unicode.toUpperCase());
|
||||
|
||||
return `<img draggable="false" class="emojione" alt="${alt}" src="/emoji/${unicode}.svg" />`;
|
||||
});
|
||||
|
||||
export default function emojify(text) {
|
||||
return emojione.toImage(text);
|
||||
return toImage(text);
|
||||
};
|
||||
|
@ -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
|
@ -1,11 +1,11 @@
|
||||
object @account
|
||||
|
||||
attributes :id, :username, :acct, :display_name, :locked
|
||||
attributes :id, :username, :acct, :display_name, :locked, :created_at
|
||||
|
||||
node(:note) { |account| Formatter.instance.simplified_format(account) }
|
||||
node(:url) { |account| TagManager.instance.url_for(account) }
|
||||
node(:avatar) { |account| full_asset_url(account.avatar.url(:original)) }
|
||||
node(:header) { |account| full_asset_url(account.header.url(:original)) }
|
||||
node(:followers_count) { |account| defined?(@followers_counts_map) ? (@followers_counts_map[account.id] || 0) : (account.try(:followers_count) || account.followers.count) }
|
||||
node(:following_count) { |account| defined?(@following_counts_map) ? (@following_counts_map[account.id] || 0) : (account.try(:following_count) || account.following.count) }
|
||||
node(:statuses_count) { |account| defined?(@statuses_counts_map) ? (@statuses_counts_map[account.id] || 0) : (account.try(:statuses_count) || account.statuses.count) }
|
||||
node(:followers_count) { |account| defined?(@followers_counts_map) ? (@followers_counts_map[account.id] || 0) : account.followers_count }
|
||||
node(:following_count) { |account| defined?(@following_counts_map) ? (@following_counts_map[account.id] || 0) : account.following_count }
|
||||
node(:statuses_count) { |account| defined?(@statuses_counts_map) ? (@statuses_counts_map[account.id] || 0) : account.statuses_count }
|
||||
|
@ -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
|
@ -0,0 +1,13 @@
|
||||
class AddCounterCaches < ActiveRecord::Migration[5.0]
|
||||
def change
|
||||
add_column :statuses, :favourites_count, :integer, null: false, default: 0
|
||||
add_column :statuses, :reblogs_count, :integer, null: false, default: 0
|
||||
add_column :accounts, :statuses_count, :integer, null: false, default: 0
|
||||
add_column :accounts, :followers_count, :integer, null: false, default: 0
|
||||
add_column :accounts, :following_count, :integer, null: false, default: 0
|
||||
end
|
||||
end
|
||||
|
||||
# To make the new fields contain correct data:
|
||||
# update statuses set favourites_count = (select count(*) from favourites where favourites.status_id = statuses.id), reblogs_count = (select count(*) from statuses as reblogs where reblogs.reblog_of_id = statuses.id);
|
||||
# update accounts set statuses_count = (select count(*) from statuses where account_id = accounts.id), followers_count = (select count(*) from follows where target_account_id = accounts.id), following_count = (select count(*) from follows where account_id = accounts.id);
|
@ -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
|
After Width: | Height: | Size: 596 B |
After Width: | Height: | Size: 363 B |
After Width: | Height: | Size: 902 B |
After Width: | Height: | Size: 679 B |
After Width: | Height: | Size: 788 B |
After Width: | Height: | Size: 569 B |
After Width: | Height: | Size: 485 B |
After Width: | Height: | Size: 266 B |
After Width: | Height: | Size: 775 B |
After Width: | Height: | Size: 556 B |
After Width: | Height: | Size: 918 B |
After Width: | Height: | Size: 699 B |
After Width: | Height: | Size: 479 B |
After Width: | Height: | Size: 260 B |
After Width: | Height: | Size: 726 B |
After Width: | Height: | Size: 507 B |
After Width: | Height: | Size: 889 B |
After Width: | Height: | Size: 674 B |
After Width: | Height: | Size: 525 B |
After Width: | Height: | Size: 320 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 833 B |
After Width: | Height: | Size: 885 B |
After Width: | Height: | Size: 662 B |
After Width: | Height: | Size: 811 B |
After Width: | Height: | Size: 394 B |
After Width: | Height: | Size: 909 B |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 328 B |
After Width: | Height: | Size: 479 B |
After Width: | Height: | Size: 417 B |
After Width: | Height: | Size: 381 B |
After Width: | Height: | Size: 581 B |
After Width: | Height: | Size: 691 B |
After Width: | Height: | Size: 865 B |
After Width: | Height: | Size: 571 B |
After Width: | Height: | Size: 543 B |
After Width: | Height: | Size: 471 B |
After Width: | Height: | Size: 519 B |
After Width: | Height: | Size: 718 B |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 896 B |
After Width: | Height: | Size: 861 B |
After Width: | Height: | Size: 5.8 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 443 B |
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 620 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 387 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 714 B |
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 376 B |