fiedl/your_platform

View on GitHub
app/models/concerns/user_backup.rb

Summary

Maintainability
A
1 hr
Test Coverage
concern :UserBackup do

  def backup_profile
    FileUtils.mkdir_p backup_path
    File.open(backup_file, "w") do |f|
      f.write as_json_for_backup.to_json
    end
  end

  def as_json_for_backup
    as_json(include: {
      profile_fields: {
        only: [:type, :key, :value, :created_at, :updated_at, :parent_id, :children],
        methods: [:key],
        include: {
          children: {
            only: [:type, :key, :value, :created_at, :updated_at, :parent_id],
            methods: [:key]
          },
          flags: {
            only: [:key, :created_at, :updated_at]
          }
        }
      },
      account: {
        only: [:created_at, :updated_at, :encrypted_password, :auth_token]
      }
    })
  end

  def backup_and_remove_profile(confirmation = {})
    backup_profile
    anonymize_name_and_remove_profile_and_account!(confirmation)
  end

  def restore_profile
    raise "This user (#{id}) already has an existing profile. Not restoring from backup file." if profile_fields.any?
    hash = ActiveSupport::JSON.decode(File.read(latest_backup_file))

    if (address = hash['profile_fields'].select { |pf| pf['type'] == "ProfileFields::Address" }.first) && address['children'].present?
      raise "Achtung! Das Adress-Format hat sich geändert, weil Adressen jetzt Freitextfelder sind. TODO: Das muss das Restore-System noch lernen, bevor ein Import durchgeführt wird."
    end

    self.first_name = hash['first_name']
    self.last_name = hash['last_name']
    self.alias = hash['alias']
    self.save!
    hash['profile_fields'].each do |profile_field_hash|
      profile_field = self.profile_fields.create profile_field_hash.except('children', 'key', 'flags')
      profile_field.key = profile_field_hash['key']
      profile_field.save
      profile_field.children.destroy_all # there might be relic children lying around
      profile_field_hash['children'].each do |child_hash|
        profile_field.children.create child_hash.except('parent_id')
      end
      profile_field_hash['flags'].each do |flag_hash|
        profile_field.flags.create flag_hash
      end
    end
    self.delete_cache; self.reload  # to have `User#email` present
    if hash['account'] && self.email.present?
      account = self.build_account hash['account']
      account.password = Password.generate
      account.save!
      account.encrypted_password = hash['account']['encrypted_password']
      account.save!
    end
    self.delete_cache
  end

  def restore_minimal_profile
    raise "This user (#{id}) already has an existing profile. Not restoring from backup file." if profile_fields.any?
    hash = ActiveSupport::JSON.decode(File.read(latest_backup_file))
    self.first_name = hash['first_name']
    self.last_name = hash['last_name']
    self.save!
    hash['profile_fields']
      .select { |pf| pf['key'].to_s.in? ['date_of_birth', 'date_of_death', 'W-Nummer', 'w_nummer'] }
      .each do |profile_field_hash|
        profile_field = self.profile_fields.create profile_field_hash.except('children', 'key', 'flags')
        profile_field.key = profile_field_hash['key']
        profile_field.save
    end
    self.delete_cache; self.reload
  end

  def restore_w_nummer
    raise "Der Benutzer #{id} hat bereits eine W-Nummer #{w_nummer}" if w_nummer.present?
    hash = ActiveSupport::JSON.decode(File.read(latest_backup_file))
    self.w_nummer = hash['profile_fields'].detect { |pf| pf['key'].to_s.in? ['W-Nummer', 'w_nummer'] }['value']
    self.save
    self.delete_cache; self.reload
  end

  def anonymize_name_and_remove_profile_and_account!(confirmation = {})
    raise "Please confirm the destructive action by 'confirm: \"yes\"'." unless confirmation[:confirm] == "yes"
    self.profile_fields.destroy_all
    self.account.try(:destroy!)
    self.reload
    self.first_name = ""
    self.last_name = self.last_name.first
    self.email = nil
    self.alias = nil
    self.save!
  end

  def backup_path
    Rails.root.join('backups', self.class.storage_namespace, 'users')
  end

  def backup_file
    File.join backup_path, "#{id}-#{title.parameterize}-#{Time.zone.now.to_s.parameterize}.json"
  end

  def backup_files
    Dir.glob(File.join(backup_path, "#{id}-*")).sort
  end

  def latest_backup_file
    backup_files.last
  end

end