Class: Jobs::ExportCsvFile

Inherits:
Base
  • Object
show all
Defined in:
app/jobs/regular/export_csv_file.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Base

acquire_cluster_concurrency_lock!, clear_cluster_concurrency_lock!, cluster_concurrency, cluster_concurrency_redis_key, delayed_perform, #error_context, get_cluster_concurrency, #last_db_duration, #log, #perform, #perform_immediately

Instance Attribute Details

#current_userObject

Returns the value of attribute current_user.



10
11
12
# File 'app/jobs/regular/export_csv_file.rb', line 10

def current_user
  @current_user
end

#entityObject

Returns the value of attribute entity.



11
12
13
# File 'app/jobs/regular/export_csv_file.rb', line 11

def entity
  @entity
end

#extraObject

Returns the value of attribute extra.



9
10
11
# File 'app/jobs/regular/export_csv_file.rb', line 9

def extra
  @extra
end

Instance Method Details

#execute(args) ⇒ Object



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
# File 'app/jobs/regular/export_csv_file.rb', line 61

def execute(args)
  @entity = args[:entity]
  @extra = HashWithIndifferentAccess.new(args[:args]) if args[:args]
  @current_user = User.find_by(id: args[:user_id])

  entity = { name: @entity }
  entity[:method] = :"#{entity[:name]}_export"
  raise Discourse::InvalidParameters.new(:entity) unless respond_to?(entity[:method])

  @timestamp ||= Time.now.strftime("%y%m%d-%H%M%S")
  entity[:filename] = if entity[:name] == "report" && @extra[:name].present?
    "#{@extra[:name].dasherize}-#{@timestamp}"
  else
    "#{entity[:name].dasherize}-#{@timestamp}"
  end

  export_title =
    if @entity == "report" && @extra[:name].present?
      I18n.t("reports.#{@extra[:name]}.title")
    else
      @entity.gsub("_", " ").titleize
    end

  filename = entity[:filename]
  user_export = UserExport.create(file_name: filename, user_id: @current_user.id)
  filename = "#{filename}-#{user_export.id}"

  zip_filename = write_to_csv_and_zip(filename, entity)

  # create upload
  upload = nil

  if File.exist?(zip_filename)
    File.open(zip_filename) do |file|
      upload =
        UploadCreator.new(
          file,
          File.basename(zip_filename),
          type: "csv_export",
          for_export: "true",
        ).create_for(@current_user.id)

      if upload.persisted?
        user_export.update_columns(upload_id: upload.id)
      else
        Rails.logger.warn("Failed to upload the file #{zip_filename}")
      end
    end

    File.delete(zip_filename)
  end
ensure
  post = notify_user(upload, export_title)

  if user_export.present? && post.present?
    topic = post.topic
    user_export.update_columns(topic_id: topic.id)
    topic.update_status("closed", true, Discourse.system_user)
  end
end

#get_header(entity) ⇒ Object



246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# File 'app/jobs/regular/export_csv_file.rb', line 246

def get_header(entity)
  if entity == "user_list"
    header_array =
      HEADER_ATTRS_FOR["user_list"] + HEADER_ATTRS_FOR["user_stats"] +
        HEADER_ATTRS_FOR["user_profile"]
    header_array.concat(HEADER_ATTRS_FOR["user_sso"]) if SiteSetting.enable_discourse_connect
    user_custom_fields = UserField.all
    if user_custom_fields.present?
      user_custom_fields.each do |custom_field|
        header_array.push("#{custom_field.name} (custom user field)")
      end
    end
    header_array.push("group_names")
  else
    header_array = HEADER_ATTRS_FOR[entity]
  end

  header_array
end

#report_export {|header.map { |k| titles[k] || k }| ... } ⇒ Object

Yields:

  • (header.map { |k| titles[k] || k })


183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'app/jobs/regular/export_csv_file.rb', line 183

def report_export
  # If dates are invalid consider then `nil`
  if @extra[:start_date].is_a?(String)
    @extra[:start_date] = begin
      @extra[:start_date].to_date.beginning_of_day
    rescue StandardError
      nil
    end
  end
  if @extra[:end_date].is_a?(String)
    @extra[:end_date] = begin
      @extra[:end_date].to_date.end_of_day
    rescue StandardError
      nil
    end
  end

  @extra[:filters] = {}
  @extra[:filters][:category] = @extra[:category].to_i if @extra[:category].present?
  @extra[:filters][:group] = @extra[:group].to_i if @extra[:group].present?
  @extra[:filters][:include_subcategories] = !!ActiveRecord::Type::Boolean.new.cast(
    @extra[:include_subcategories],
  ) if @extra[:include_subcategories].present?

  report = Report.find(@extra[:name], @extra)

  header = []
  titles = {}

  report.labels.each do |label|
    if label[:type] == :user
      titles[label[:properties][:username]] = label[:title]
      header << label[:properties][:username]
    elsif label[:type] == :topic
      titles[label[:properties][:id]] = label[:title]
      header << label[:properties][:id]
    else
      titles[label[:property]] = label[:title]
      header << label[:property]
    end
  end

  if report.modes == [:stacked_chart]
    header = [:x]
    data = {}

    report.data.map do |series|
      header << series[:label]
      series[:data].each do |datapoint|
        data[datapoint[:x]] ||= { x: datapoint[:x] }
        data[datapoint[:x]][series[:label]] = datapoint[:y]
      end
    end

    data = data.values
  else
    data = report.data
  end

  yield header.map { |k| titles[k] || k }
  data.each { |row| yield row.values_at(*header).map(&:to_s) }
end

#screened_email_exportObject



161
162
163
164
165
# File 'app/jobs/regular/export_csv_file.rb', line 161

def screened_email_export
  ScreenedEmail.find_each(order: :desc) do |screened_email|
    yield get_screened_email_fields(screened_email)
  end
end

#screened_ip_exportObject



167
168
169
170
171
# File 'app/jobs/regular/export_csv_file.rb', line 167

def screened_ip_export
  ScreenedIpAddress.find_each(order: :desc) do |screened_ip|
    yield get_screened_ip_fields(screened_ip)
  end
end

#screened_url_exportObject



173
174
175
176
177
178
179
180
181
# File 'app/jobs/regular/export_csv_file.rb', line 173

def screened_url_export
  ScreenedUrl
    .select(
      "domain, sum(match_count) as match_count, max(last_match_at) as last_match_at, min(created_at) as created_at",
    )
    .group(:domain)
    .order("last_match_at DESC")
    .each { |screened_url| yield get_screened_url_fields(screened_url) }
end

#staff_action_exportObject



148
149
150
151
152
153
154
155
156
157
158
159
# File 'app/jobs/regular/export_csv_file.rb', line 148

def staff_action_export
  staff_action_data =
    if @current_user.admin?
      UserHistory.only_staff_actions
    else
      UserHistory.where(admin_only: false).only_staff_actions
    end

  staff_action_data.find_each(order: :desc) do |staff_action|
    yield get_staff_action_fields(staff_action)
  end
end

#user_list_exportObject



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
# File 'app/jobs/regular/export_csv_file.rb', line 122

def user_list_export
  user_field_ids = UserField.pluck(:id)

  condition = {}
  if @extra && @extra[:trust_level] &&
       trust_level = TrustLevel.levels[@extra[:trust_level].to_sym]
    condition = { trust_level: trust_level }
  end

  includes = %i[user_profile user_stat groups user_emails]
  includes << [:single_sign_on_record] if SiteSetting.enable_discourse_connect

  User
    .where(condition)
    .includes(*includes)
    .find_each do |user|
       = get_base_user_array(user)
      if SiteSetting.enable_discourse_connect
         = add_single_sign_on(user, )
      end
       = add_custom_fields(user, , user_field_ids)
       = add_group_names(user, )
      yield 
    end
end