diff --git a/app/controllers/settings/exports/account_notes_controller.rb b/app/controllers/settings/exports/account_notes_controller.rb
new file mode 100644
index 0000000000..93c4cec8a6
--- /dev/null
+++ b/app/controllers/settings/exports/account_notes_controller.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Settings
+ module Exports
+ class AccountNotesController < BaseController
+ include Settings::ExportControllerConcern
+
+ def index
+ send_export_file
+ end
+
+ private
+
+ def export_data
+ @export.to_account_notes_csv
+ end
+ end
+ end
+end
diff --git a/app/models/bulk_import.rb b/app/models/bulk_import.rb
index 9b3f4c8a3a..21647dcd51 100644
--- a/app/models/bulk_import.rb
+++ b/app/models/bulk_import.rb
@@ -31,6 +31,7 @@ class BulkImport < ApplicationRecord
domain_blocking: 3,
bookmarks: 4,
lists: 5,
+ account_notes: 6,
}
enum :state, {
diff --git a/app/models/export.rb b/app/models/export.rb
index 6ed9f60c7c..5521c40cd5 100644
--- a/app/models/export.rb
+++ b/app/models/export.rb
@@ -55,6 +55,14 @@ class Export
end
end
+ def to_account_notes_csv
+ CSV.generate(headers: ['Account address', 'Account note'], write_headers: true, encoding: Encoding::UTF_8) do |csv|
+ account.account_notes.includes(:target_account).reorder(id: :desc).each do |account_note|
+ csv << [acct(account_note.target_account), account_note.comment]
+ end
+ end
+ end
+
private
def to_csv(accounts)
diff --git a/app/models/form/import.rb b/app/models/form/import.rb
index 3cc4af064f..e6cd5712d3 100644
--- a/app/models/form/import.rb
+++ b/app/models/form/import.rb
@@ -19,6 +19,7 @@ class Form::Import
domain_blocking: ['#domain'],
bookmarks: ['#uri'],
lists: ['List name', 'Account address'],
+ account_notes: ['Account address', 'Account note'],
}.freeze
KNOWN_FIRST_HEADERS = EXPECTED_HEADERS_BY_TYPE.values.map(&:first).uniq.freeze
@@ -32,6 +33,7 @@ class Form::Import
'#domain' => 'domain',
'#uri' => 'uri',
'List name' => 'list_name',
+ 'Account note' => 'comment',
}.freeze
class EmptyFileError < StandardError; end
@@ -55,6 +57,8 @@ class Form::Import
:bookmarks
elsif file_name_matches?('lists')
:lists
+ elsif csv_headers_match?('Account note') || file_name_matches?('account_notes')
+ :account_notes
end
end
@@ -102,6 +106,8 @@ class Form::Import
['#uri']
when :lists
['List name', 'Account address']
+ when :account_notes
+ ['Account address', 'Account note']
end
end
@@ -118,7 +124,7 @@ class Form::Import
field.strip.gsub(/\A@/, '')
when '#domain'
field&.strip&.downcase
- when '#uri', 'List name'
+ when '#uri', 'List name', 'Account note'
field.strip
else
field
diff --git a/app/presenters/export_summary.rb b/app/presenters/export_summary.rb
index 8e45aadf67..1c8c04c1d0 100644
--- a/app/presenters/export_summary.rb
+++ b/app/presenters/export_summary.rb
@@ -14,6 +14,11 @@ class ExportSummary
prefix: true
)
+ delegate(
+ :account_notes,
+ to: :account
+ )
+
def initialize(account)
@account = account
@counts = populate_counts
@@ -47,6 +52,10 @@ class ExportSummary
counts[:muting].value
end
+ def total_account_notes
+ counts[:account_notes].value
+ end
+
def total_statuses
account.statuses_count
end
@@ -64,6 +73,7 @@ class ExportSummary
domain_blocks: account_domain_blocks.async_count,
owned_lists: account_owned_lists.async_count,
muting: account_muting.async_count,
+ account_notes: account_notes.async_count,
storage: account_media_attachments.async_sum(:file_file_size),
}
end
diff --git a/app/services/bulk_import_row_service.rb b/app/services/bulk_import_row_service.rb
index 26909dfe04..6a8d7ab62d 100644
--- a/app/services/bulk_import_row_service.rb
+++ b/app/services/bulk_import_row_service.rb
@@ -7,7 +7,7 @@ class BulkImportRowService
@type = row.bulk_import.type.to_sym
case @type
- when :following, :blocking, :muting, :lists
+ when :following, :blocking, :muting, :lists, :account_notes
target_acct = @data['acct']
target_domain = domain(target_acct)
@target_account = stoplight_wrapper(target_domain).run { ResolveAccountService.new.call(target_acct, { check_delivery_availability: true }) }
@@ -39,6 +39,10 @@ class BulkImportRowService
FollowService.new.call(@account, @target_account) unless @account.id == @target_account.id
list.accounts << @target_account
+ when :account_notes
+ @note = AccountNote.find_or_initialize_by(account: @account, target_account: @target_account)
+ @note.comment = @data['comment']
+ @note.save! if @note.changed?
end
true
diff --git a/app/services/bulk_import_service.rb b/app/services/bulk_import_service.rb
index a361c7a3da..5562977355 100644
--- a/app/services/bulk_import_service.rb
+++ b/app/services/bulk_import_service.rb
@@ -18,6 +18,8 @@ class BulkImportService < BaseService
import_bookmarks!
when :lists
import_lists!
+ when :account_notes
+ import_account_notes!
end
@import.update!(state: :finished, finished_at: Time.now.utc) if @import.processed_items == @import.total_items
@@ -182,4 +184,32 @@ class BulkImportService < BaseService
[row.id]
end
end
+
+ def import_account_notes!
+ rows_by_acct = extract_rows_by_acct
+
+ if @import.overwrite?
+ @account.account_notes.reorder(nil).find_each do |account_note|
+ row = rows_by_acct.delete(account_note.target_account.acct)
+
+ if row.nil?
+ account_note.destroy!
+ else
+ row.destroy
+ @import.processed_items += 1
+ @import.imported_items += 1
+ @note = AccountNote.find_or_initialize_by(account: @account, target_account: row.data['acct'])
+ @note.comment = row.data['comment']
+ @note.save! if @note.changed?
+ end
+ end
+
+ # Save pending infos due to `overwrite?` handling
+ @import.save!
+ end
+
+ Import::RowWorker.push_bulk(rows) do |row|
+ [row.id]
+ end
+ end
end
diff --git a/app/views/settings/exports/show.html.haml b/app/views/settings/exports/show.html.haml
index 5a151be73b..171ec19c63 100644
--- a/app/views/settings/exports/show.html.haml
+++ b/app/views/settings/exports/show.html.haml
@@ -12,6 +12,10 @@
%th= t('accounts.posts_tab_heading')
%td= number_with_delimiter @export_summary.total_statuses
%td
+ %tr
+ %th= t('exports.account_notes')
+ %td= number_with_delimiter @export_summary.total_account_notes
+ %td= table_link_to 'download', t('exports.csv'), settings_exports_account_notes_path(format: :csv)
%tr
%th= t('admin.accounts.follows')
%td= number_with_delimiter @export_summary.total_follows
diff --git a/app/views/settings/imports/index.html.haml b/app/views/settings/imports/index.html.haml
index 55421991e1..363f5c1383 100644
--- a/app/views/settings/imports/index.html.haml
+++ b/app/views/settings/imports/index.html.haml
@@ -5,7 +5,7 @@
.field-group
= f.input :type,
as: :grouped_select,
- collection: { constructive: %i(following bookmarks lists), destructive: %i(muting blocking domain_blocking) },
+ collection: { constructive: %i(following bookmarks lists), destructive: %i(muting blocking domain_blocking), other: %i(account_notes) },
group_label_method: ->(group) { I18n.t("imports.type_groups.#{group.first}") },
group_method: :last,
hint: t('imports.preface'),
diff --git a/config/locales/en.yml b/config/locales/en.yml
index c88ef3fa20..6d7104a68e 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -1367,6 +1367,9 @@ en:
overwrite: Overwrite
overwrite_long: Replace current records with the new ones
overwrite_preambles:
+ account_notes_html:
+ one: You are about to import %{count} account note from %{filename}. Any existing account note on this account will be overwritten.
+ other: You are about to import %{count} account notes from %{filename}. Any existing account notes on these accounts will be overwritten.
blocking_html:
one: You are about to replace your block list with up to %{count} account from %{filename}.
other: You are about to replace your block list with up to %{count} accounts from %{filename}.
@@ -1386,6 +1389,9 @@ en:
one: You are about to replace your list of muted account with up to %{count} account from %{filename}.
other: You are about to replace your list of muted accounts with up to %{count} accounts from %{filename}.
preambles:
+ account_notes_html:
+ one: You are about to import %{count} account note from %{filename}.
+ other: You are about to import %{count} account notes from %{filename}.
blocking_html:
one: You are about to block up to %{count} account from %{filename}.
other: You are about to block up to %{count} accounts from %{filename}.
@@ -1415,6 +1421,7 @@ en:
success: Your data was successfully uploaded and will be processed in due time
time_started: Started at
titles:
+ account_notes: Importing account notes
blocking: Importing blocked accounts
bookmarks: Importing bookmarks
domain_blocking: Importing blocked domains
@@ -1425,6 +1432,7 @@ en:
type_groups:
constructive: Follows & Bookmarks
destructive: Blocks & mutes
+ other: Other
types:
blocking: Blocking list
bookmarks: Bookmarks
@@ -1432,6 +1440,7 @@ en:
following: Following list
lists: Lists
muting: Muting list
+ account_notes: Account notes
upload: Upload
invites:
delete: Deactivate
diff --git a/config/routes/settings.rb b/config/routes/settings.rb
index cefa24316d..21f5a66a87 100644
--- a/config/routes/settings.rb
+++ b/config/routes/settings.rb
@@ -26,6 +26,7 @@ namespace :settings do
resources :follows, only: :index, controller: :following_accounts
resources :blocks, only: :index, controller: :blocked_accounts
resources :mutes, only: :index, controller: :muted_accounts
+ resources :account_notes, only: :index, controller: :account_notes
resources :lists, only: :index
resources :domain_blocks, only: :index, controller: :blocked_domains
resources :bookmarks, only: :index