fiedl/wingolfsplattform

View on GitHub
lib/importers/user_importer.rb

Summary

Maintainability
C
1 day
Test Coverage
require 'importers/importer'
require 'importers/models/user'
require 'importers/models/string'
require 'importers/models/profile_field'
require 'importers/models/netenv_user'

class UserImporter < Importer
  
  def initialize( args = {} )
    super(args)
    @object_class_name = "User"
    if @continue_with.in? [:last_user, :auto]
      if File.exists? @continue_with_file
        @continue_with = File.open(@continue_with_file, 'r') { |file| file.read }
      else
        @continue_with = nil
      end
    end
  end
  
  def import
    log.head "Wingolfsplattform User Import"
    
    log.section "Import Parameters"
    log.info "Import file:   #{@filename}"
    log.info "Results log:   #{@results_log_file}" if @results_log_file.present?
    log.info "Import filter: #{@filter || 'none'}"
    log.info "Continue import with #{@continue_with}." if @continue_with
    
    log.section "Progress"
    log.info ". = successfully created, u = successfully updated, I = ignored, W = warning, F = failure"
    
    import_file = ImportFile.new( filename: @filename, data_class_name: "NetenvUser" )
    import_file.each_row do |netenv_user|
      
      # Wenn bei einem bestimmten Benutzer fortgesetzt werden soll, vorige Datensätze
      # ohne jeden Hinweis übergehen.
      #
      next if before_point_of_continuation?(netenv_user, @continue_with)
      
      # Benutzer, die dem Import-Filter nicht entsprechen, werden übergangen.
      # Der Import-Filter wird beim Aufruf des Imports in lib/tasks/import_users.rake
      # gesetzt.
      #
      next unless netenv_user.match? @filter
      
      # Test-Benutzer des bisherigen Betreibers werden ignoriert.
      # 
      next if dummy_user? netenv_user
      
      # Duplikat-Benutzer werden ignoriert.
      # Siehe Trello-Karte: https://trello.com/c/Fv4eMohq/510-doppelte-user
      #
      next if duplicate_or_mistaken_user? netenv_user
      
      # Benutzer, die in der Datenbank des bisherigen Betreibers als gelöscht markiert
      # sind, wurden versehentlich angelegt. Ihre Daten werden nicht importiert.
      #
      next if deleted_user? netenv_user
      
      # Den Benutzer festhalten, bei dem der Import gerade ist, sodass man dem Import
      # mit der Option 'continue_with: :last_user' fortgesetzt werden kann.
      #
      save_point_of_continuation_for netenv_user
      
      # Falls die E-Mail-Adresse bereits im neuen System vergeben ist, und zwar einem
      # anderen Benutzer, liegt hier vermutlich ein Fehler vor. Deswegen wird eine Warnung
      # angezeigt. Der vorhandene Benutzer behält seine E-Mail-Adresse. Der zweite Benutzer
      # wird zwar angelegt, aber ohne E-Mail-Adresse. 
      # Ferner werden ungültige E-Mail-Adressen nicht mit ins System importiert.
      # 
      netenv_user.do_not_import_primary_email if email_issue? netenv_user
      
      # Existierenden Benutzer des neuen Systems heraussuchen oder einen neuen Benutzer
      # anlegen, falls noch keiner existiert.
      # 
      updating_user = find_existing_user_for(netenv_user) ? true : false
      user = find_or_build_user_for netenv_user
      
      # Grundlegende Attribute übernehmen.
      # Vor- und Zuname, E-Mail-Adresse, W-Nummer, Geburtsdatum.
      # 
      user.import_basic_attributes_from netenv_user
      user.save
      
      # Profilfelder importieren.
      # 
      user.import_general_profile_fields_from netenv_user
      user.import_contact_profile_fields_from netenv_user
      user.import_study_profile_fields_from netenv_user
      user.import_professional_profile_fields_from netenv_user
      user.import_profile_fields_about_me_from netenv_user
      user.import_bank_profile_fields_from netenv_user
      user.import_communication_profile_fields_from netenv_user
      user.create_template_profile_fields_where_non_existant
      
      # Mitgliedschaften in Korporationen importieren.
      # 
      check_corporation_memberships_consistency_for netenv_user
      user.import_corporation_memberships_from netenv_user
      perform_consistency_check_for_aktivitaetszahl_for user, netenv_user
      make_sure_all_corporation_memberships_have_been_imported_for user, netenv_user
      
      # BV-Zuordnung.
      #
      user.import_bv_membership_from netenv_user
      
      # Benutzer ggf. verstecken.
      #
      user.import_hidden_status_from netenv_user
      
      # Zeitstempel des Datensatzes importieren.
      # created_at, updated_at.
      #
      user.import_timestamps_from netenv_user
      
      # Fortschritt festhalten. In Abhängigkeit davon, ob ein neuer Benutzer angelegt oder
      # ein vorhandener aktualisiert wurde, wird ein entsprechendes Symbol angezeigt.
      #
      progress.log_success(updating_user)
    end

    log.info ""
    log.section "Results"    
    progress.print_status_report
  end
  
  def before_point_of_continuation?(netenv_user, continue_with)
    if continue_with.present? and (netenv_user.w_nummer < continue_with)
      progress.log_skip
      return true
    end
  end  
  
  def dummy_user?(netenv_user)
    if netenv_user.dummy_user?
      warning = { message: "Der Test-Benutzer #{netenv_user.w_nummer} wird nicht importiert. Kein Handlungsbedarf.",
        w_nummer: netenv_user.w_nummer, name: netenv_user.name,
        netenv_aktivitätszahl: netenv_user.netenv_aktivitätszahl
      }
      progress.log_ignore(warning)
      return true
    end
  end
  
  def duplicate_or_mistaken_user?(netenv_user)
    if netenv_user.duplicate_or_mistaken_user?
      warning = { message: "Der fälschlicherweise angelegte Duplikat-Benutzer #{netenv_user.w_nummer} wird nicht importiert. Kein Handlungsbedarf.",
        w_nummer: netenv_user.w_nummer, name: netenv_user.name,
        netenv_aktivitätszahl: netenv_user.netenv_aktivitätszahl
      }
      progress.log_ignore(warning)
      return true
    end
  end
  
  def deleted_user?(netenv_user)
    if netenv_user.deleted?
      warning = { message: "Der Benutzer #{netenv_user.w_nummer} wurde als gelöscht markiert und wird nicht importiert. Kein Handlungsbedarf.",
                  w_nummer: netenv_user.w_nummer, name: netenv_user.name }
      progress.log_ignore(warning)
      return true
    end
  end
  
  def email_issue?(netenv_user)
    return false if netenv_user.email.blank?
    email_duplicate?(netenv_user) or wrong_email_format?(netenv_user)
  end
  
  def email_duplicate?(netenv_user)
    existing_user_with_this_email = User.find_by_email(netenv_user.email)
    return false unless existing_user_with_this_email

    if existing_user_with_this_email.w_nummer != netenv_user.w_nummer
      warning = { message: "Doppelt vergebene E-Mail-Adresse #{netenv_user.email}. In diesem Import wird sie dem Benutzer #{existing_user_with_this_email.w_nummer} zugeschrieben. Der Benutzer #{netenv_user.w_nummer} wird ohne E-Mail-Adresse importiert. Telefonischer Rücksprache erforderlich.",
        w_nummer: netenv_user.w_nummer, name: netenv_user.name, email: netenv_user.email,
        existing_user: existing_user_with_this_email.w_nummer, existing_user_name: existing_user_with_this_email.name 
      }
      progress.log_warning(warning)
      return true
    end
  end
  
  def wrong_email_format?(netenv_user)
    if (not netenv_user.email.include?('@')) or (not netenv_user.email.include?('.'))
      warning = { message: "Die E-Mail-Adresse '#{netenv_user.email}' des Benutzers #{netenv_user.w_nummer} ist ungültig und wird nicht importiert.",
                  w_nummer: netenv_user.w_nummer, email: netenv_user.email }
      progress.log_warning(warning)
      return true
    end
  end
  
  def find_or_build_user_for(netenv_user)
    find_existing_user_for(netenv_user) || User.new
  end
  
  def find_existing_user_for(netenv_user)
    User.find_by_w_nummer(netenv_user.w_nummer)
  end
  
  def check_corporation_memberships_consistency_for(netenv_user)
    
    # Aktivmeldungsdatum?
    if not netenv_user.aktivmeldungsdatum
      warning = { message: 'Kein Aktivmeldungsdatum angegeben.',
                  name: netenv_user.name, w_nummer: netenv_user.w_nummer }
      progress.log_failure(warning)
    end
    
    # Aktivmeldungsdatum inkonsistent?
    if ( netenv_user.aktivmeldungsdatum_in_mutterverbindung and
         netenv_user.aktivmeldungsdatum_im_wingolfsbund and
         (netenv_user.aktivmeldungsdatum_im_wingolfsbund != netenv_user.aktivmeldungsdatum_in_mutterverbindung)
         )
      warning = { message: 'Inkonsistentes Aktivmeldungsdatum: Das Beitrittsdatum in den Wingolfsbund weicht vom Aktivmeldungsdatum in der Mutterverbindung ab.',
                  name: netenv_user.name, w_nummer: netenv_user.w_nummer,
                  aktivmeldungsdatum_im_wingolfsbund: netenv_user.aktivmeldungsdatum_im_wingolfsbund,
                  aktivmeldungsdatum_in_mutterverbindung: netenv_user.aktivmeldungsdatum_in_mutterverbindung,
                  mutterverbindung: netenv_user.primary_corporation.token }
      progress.log_warning(warning)
    end

    if netenv_user.aktivmeldungsdatum_aus_aktivitaetszahl.year != netenv_user.angegebenes_aktivmeldungsdatum.try(:year)
      if netenv_user.angegebenes_aktivmeldungsdatum
        warning = { message: 'Inkonsistentes Aktivmeldungsdatum: Das Aktivmeldungsdatum widerspricht der Aktivitätszahl.',
                    name: netenv_user.name, w_nummer: netenv_user.w_nummer,
                    angegebenes_aktivmeldungsdatum: netenv_user.angegebenes_aktivmeldungsdatum,
                    netenv_aktivitätszahl: netenv_user.netenv_aktivitätszahl,
                    ehemalige_netenv_aktivitätszahl: netenv_user.ehemalige_netenv_aktivitätszahl
                  }
        progress.log_warning(warning)
      end
    end
    
    # Receptionsdatum > Philistrationsdatum?
    if netenv_user.philistrationsdatum and netenv_user.receptionsdatum
      if netenv_user.receptionsdatum > netenv_user.philistrationsdatum
        warning = { message: 'Inkonsistenz: Das Philistrationsdatum liegt vor dem Receptionsdatum.',
                    name: netenv_user.name, w_nummer: netenv_user.w_nummer, 
                    philistrationsdatum: netenv_user.philistrationsdatum,
                    receptionsdatum: netenv_user.receptionsdatum }
        progress.log_warning(warning)
      end
    end
  end
  
  def perform_consistency_check_for_aktivitaetszahl_for( user, netenv_user )
    if netenv_user.aktivitätszahl.to_s != user.reload.aktivitätszahl.to_s
      warning = { 
        message: "Konsistenzprüfung fehlgeschlagen: Die rekonstruierte Aktivitätszahl '#{user.aktivitätszahl}' entspricht nicht der angegebenen Aktivitätszahl '#{netenv_user.aktivitätszahl}' des Benutzers #{netenv_user.w_nummer}. Dieser Benutzer muss nach Korrektur erneut importiert werden. Sonst hat ein Nicht-Wingolfit evtl. zu viele Rechte!",
        name: netenv_user.name, w_nummer: netenv_user.w_nummer,
        angegebene_aktivitätszahl: netenv_user.aktivitätszahl,
        rekonstruierte_aktivitätszahl: user.aktivitätszahl
      }
      progress.log_failure(warning)
    end
  end
  
  # Sicherstellen, dass für alle Korporationen, die in Netenv für diesen Benutzer eingetragen sind,
  # auch im neuen System einge Mitgliedschaft vorliegt.
  #
  def make_sure_all_corporation_memberships_have_been_imported_for( user, netenv_user )
    for corporation in netenv_user.corporations 
      if not user.reload.in? corporation.descendant_users
        warning = {
          message: "Konsistenzprüfung fehlgeschlagen: Für den Benutzer #{user.w_nummer} ist im alten System eine Mitgliedschaft in der Korporation '#{corporation.token}' vorgesehen. Es wurde jedoch keine solche Mitgliedschaft importiert. Prüfung und Korrektur des Import-Skripts sowie erneuter Import sind erforderlich.",
          name: netenv_user.name, w_nummer: user.w_nummer,
          corporation: corporation.token
        }
        progress.log_failure(warning)
      end
    end
  end
  
  # Den Benutzer abspeichern, bei dem wir gerade sind.
  #
  def save_point_of_continuation_for( netenv_user )
    File.open(@continue_with_file, 'w') { |file| file.write netenv_user.w_nummer } if @continue_with_file
  end
  
end