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