~cytrogen/masto-fe

ref: 45a19ddfe48c8f9346bdb4c786726fc36e15a51e masto-fe/app/services/bulk_import_service.rb -rw-r--r-- 4.8 KiB
45a19ddf — Claire Merge pull request #2440 from ClearlyClaire/glitch-soc/merge-upstream 2 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# frozen_string_literal: true

class BulkImportService < BaseService
  def call(import)
    @import  = import
    @account = @import.account

    case @import.type.to_sym
    when :following
      import_follows!
    when :blocking
      import_blocks!
    when :muting
      import_mutes!
    when :domain_blocking
      import_domain_blocks!
    when :bookmarks
      import_bookmarks!
    when :lists
      import_lists!
    end

    @import.update!(state: :finished, finished_at: Time.now.utc) if @import.processed_items == @import.total_items
  rescue
    @import.update!(state: :finished, finished_at: Time.now.utc)

    raise
  end

  private

  def extract_rows_by_acct
    local_domain_suffix = "@#{Rails.configuration.x.local_domain}"
    @import.rows.to_a.index_by { |row| row.data['acct'].delete_suffix(local_domain_suffix) }
  end

  def import_follows!
    rows_by_acct = extract_rows_by_acct

    if @import.overwrite?
      @account.following.reorder(nil).find_each do |followee|
        row = rows_by_acct.delete(followee.acct)

        if row.nil?
          UnfollowService.new.call(@account, followee)
        else
          row.destroy
          @import.processed_items += 1
          @import.imported_items += 1

          # Since we're updating the settings of an existing relationship, we can safely call
          # FollowService directly
          FollowService.new.call(@account, followee, reblogs: row.data['show_reblogs'], notify: row.data['notify'], languages: row.data['languages'])
        end
      end

      # Save pending infos due to `overwrite?` handling
      @import.save!
    end

    Import::RowWorker.push_bulk(rows_by_acct.values) do |row|
      [row.id]
    end
  end

  def import_blocks!
    rows_by_acct = extract_rows_by_acct

    if @import.overwrite?
      @account.blocking.reorder(nil).find_each do |blocked_account|
        row = rows_by_acct.delete(blocked_account.acct)

        if row.nil?
          UnblockService.new.call(@account, blocked_account)
        else
          row.destroy
          @import.processed_items += 1
          @import.imported_items += 1
          BlockService.new.call(@account, blocked_account)
        end
      end

      # Save pending infos due to `overwrite?` handling
      @import.save!
    end

    Import::RowWorker.push_bulk(rows_by_acct.values) do |row|
      [row.id]
    end
  end

  def import_mutes!
    rows_by_acct = extract_rows_by_acct

    if @import.overwrite?
      @account.muting.reorder(nil).find_each do |muted_account|
        row = rows_by_acct.delete(muted_account.acct)

        if row.nil?
          UnmuteService.new.call(@account, muted_account)
        else
          row.destroy
          @import.processed_items += 1
          @import.imported_items += 1
          MuteService.new.call(@account, muted_account, notifications: row.data['hide_notifications'])
        end
      end

      # Save pending infos due to `overwrite?` handling
      @import.save!
    end

    Import::RowWorker.push_bulk(rows_by_acct.values) do |row|
      [row.id]
    end
  end

  def import_domain_blocks!
    domains = @import.rows.map { |row| row.data['domain'] }

    if @import.overwrite?
      @account.domain_blocks.find_each do |domain_block|
        domain = domains.delete(domain_block)

        @account.unblock_domain!(domain_block.domain) if domain.nil?
      end
    end

    @import.rows.delete_all
    domains.each { |domain| @account.block_domain!(domain) }
    @import.update!(processed_items: @import.total_items, imported_items: @import.total_items)

    AfterAccountDomainBlockWorker.push_bulk(domains) do |domain|
      [@account.id, domain]
    end
  end

  def import_bookmarks!
    rows_by_uri = @import.rows.index_by { |row| row.data['uri'] }

    if @import.overwrite?
      @account.bookmarks.includes(:status).find_each do |bookmark|
        row = rows_by_uri.delete(ActivityPub::TagManager.instance.uri_for(bookmark.status))

        if row.nil?
          bookmark.destroy!
        else
          row.destroy
          @import.processed_items += 1
          @import.imported_items += 1
        end
      end

      # Save pending infos due to `overwrite?` handling
      @import.save!
    end

    Import::RowWorker.push_bulk(rows_by_uri.values) do |row|
      [row.id]
    end
  end

  def import_lists!
    rows = @import.rows.to_a
    included_lists = rows.map { |row| row.data['list_name'] }.uniq

    if @import.overwrite?
      @account.owned_lists.where.not(title: included_lists).destroy_all

      # As list membership changes do not retroactively change timeline
      # contents, simplify things by just clearing everything
      @account.owned_lists.find_each do |list|
        list.list_accounts.destroy_all
      end
    end

    included_lists.each do |title|
      @account.owned_lists.find_or_create_by!(title: title)
    end

    Import::RowWorker.push_bulk(rows) do |row|
      [row.id]
    end
  end
end