<commit_before>#
# Copyright (C) 2012 - 2015 Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#

require 'account_reports/report_helper'

module AccountReports
  class SisExporter
    include ReportHelper

    SIS_CSV_REPORTS = ["users", "accounts", "terms", "courses", "sections", "enrollments", "groups", "group_membership", "xlist"]

    def initialize(account_report, params = {})
      @account_report = account_report
      @reports = SIS_CSV_REPORTS & @account_report.parameters.keys
      @sis_format = params[:sis_format]
      extra_text_term(@account_report)

      if @account_report.has_parameter? "include_deleted"
        @include_deleted = @account_report.parameters["include_deleted"]
        add_extra_text(I18n.t('account_reports.grades.deleted',
                              'Include Deleted Objects: true;'))
      end
    end

    def csv
      files = ""
      @reports.each do |report_name|
        files << "#{report_name} "
      end
      @account_report.parameters["extra_text"] << I18n.t(
        'account_reports.sis_exporter.reports',
        'Reports: %{files}',
        :files => files
      )

      if @reports.length == 0
        send_report()
      elsif @reports.length == 1
        csv = self.send(@reports.first)
        send_report(csv)
      else
        csvs = {}

        @reports.each do |report_name|
          csvs[report_name] = self.send(report_name)
        end
        send_report(csvs)
        csvs
      end
    end

    def users
      filename = AccountReports.generate_file(@account_report)
      CSV.open(filename, "w") do |csv|
        if @sis_format
          # headers are not translated on sis_export to maintain import compatibility
          headers = ['user_id', 'login_id', 'password', 'first_name', 'last_name', 'email', 'status']
        else #provisioning_report
          headers = []
          headers << I18n.t('#account_reports.report_header_canvas_user_id', 'canvas_user_id')
          headers << I18n.t('#account_reports.report_header_user__id', 'user_id')
          headers << I18n.t('#account_reports.report_header_login_id', 'login_id')
          headers << I18n.t('#account_reports.report_header_first_name', 'first_name')
          headers << I18n.t('#account_reports.report_header_last_name', 'last_name')
          headers << I18n.t('#account_reports.report_header_email', 'email')
          headers << I18n.t('#account_reports.report_header_status', 'status')
        end
        csv << headers
        users = root_account.pseudonyms.except(:includes).joins(:user).select(
          "pseudonyms.id, pseudonyms.sis_user_id, pseudonyms.user_id,
           pseudonyms.unique_id, pseudonyms.workflow_state, users.sortable_name,
           users.updated_at AS user_updated_at").where(
          "NOT EXISTS (SELECT user_id
                       FROM enrollments e
                       WHERE e.type = 'StudentViewEnrollment'
                       AND e.user_id = pseudonyms.user_id)")

        if @sis_format
          users = users.where("sis_user_id IS NOT NULL")
        end

        if @include_deleted
          users = users.where("pseudonyms.workflow_state<>'deleted' OR pseudonyms.sis_user_id IS NOT NULL")
        else
          users = users.where("pseudonyms.workflow_state<>'deleted'")
        end

        users = add_user_sub_account_scope(users)

        Shackles.activate(:slave) do
          users.find_each do |u|
            row = []
            row << u.user_id unless @sis_format
            row << u.sis_user_id
            row << u.unique_id
            row << nil if @sis_format
            # build a user object to be able to call methods on it
            user = User.send(:instantiate, 'id' => u.user_id, 'sortable_name' => u.sortable_name, 'updated_at' => u.user_updated_at)
            row << user.first_name
            row << user.last_name
            row << user.email
            row << u.workflow_state
            csv << row
          end
        end
      end
      filename
    end

    def accounts
      filename = AccountReports.generate_file(@account_report)
      CSV.open(filename, "w") do |csv|
        if @sis_format
          # headers are not translated on sis_export to maintain import compatibility
          headers = ['account_id', 'parent_account_id', 'name', 'status']
        else
          headers = []
          headers << I18n.t('#account_reports.report_header_canvas_account_id', 'canvas_account_id')
          headers << I18n.t('#account_reports.report_header_account_id', 'account_id')
          headers << I18n.t('#account_reports.report_header_canvas_parent_id', 'canvas_parent_id')
          headers << I18n.t('#account_reports.report_header_parent_account_id', 'parent_account_id')
          headers << I18n.t('#account_reports.report_header_name', 'name')<commit_msg>don't call user.email on each pseudonym exported<commit_after>#
# Copyright (C) 2012 - 2015 Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#

require 'account_reports/report_helper'

module AccountReports
  class SisExporter
    include ReportHelper

    SIS_CSV_REPORTS = ["users", "accounts", "terms", "courses", "sections", "enrollments", "groups", "group_membership", "xlist"]

    def initialize(account_report, params = {})
      @account_report = account_report
      @reports = SIS_CSV_REPORTS & @account_report.parameters.keys
      @sis_format = params[:sis_format]
      extra_text_term(@account_report)

      if @account_report.has_parameter? "include_deleted"
        @include_deleted = @account_report.parameters["include_deleted"]
        add_extra_text(I18n.t('account_reports.grades.deleted',
                              'Include Deleted Objects: true;'))
      end
    end

    def csv
      files = ""
      @reports.each do |report_name|
        files << "#{report_name} "
      end
      @account_report.parameters["extra_text"] << I18n.t(
        'account_reports.sis_exporter.reports',
        'Reports: %{files}',
        :files => files
      )

      if @reports.length == 0
        send_report()
      elsif @reports.length == 1
        csv = self.send(@reports.first)
        send_report(csv)
      else
        csvs = {}

        @reports.each do |report_name|
          csvs[report_name] = self.send(report_name)
        end
        send_report(csvs)
        csvs
      end
    end

    def users
      filename = AccountReports.generate_file(@account_report)
      CSV.open(filename, "w") do |csv|
        if @sis_format
          # headers are not translated on sis_export to maintain import compatibility
          headers = ['user_id', 'login_id', 'password', 'first_name', 'last_name', 'email', 'status']
        else #provisioning_report
          headers = []
          headers << I18n.t('#account_reports.report_header_canvas_user_id', 'canvas_user_id')
          headers << I18n.t('#account_reports.report_header_user__id', 'user_id')
          headers << I18n.t('#account_reports.report_header_login_id', 'login_id')
          headers << I18n.t('#account_reports.report_header_first_name', 'first_name')
          headers << I18n.t('#account_reports.report_header_last_name', 'last_name')
          headers << I18n.t('#account_reports.report_header_email', 'email')
          headers << I18n.t('#account_reports.report_header_status', 'status')
        end
        csv << headers
        users = root_account.pseudonyms.except(:includes).joins(:user).select(
          "pseudonyms.id, pseudonyms.sis_user_id, pseudonyms.user_id,
           pseudonyms.unique_id, pseudonyms.workflow_state, users.sortable_name,
           users.updated_at AS user_updated_at").where(
          "NOT EXISTS (SELECT user_id
                       FROM enrollments e
                       WHERE e.type = 'StudentViewEnrollment'
                       AND e.user_id = pseudonyms.user_id)")

        if @sis_format
          users = users.where("sis_user_id IS NOT NULL")
        end

        if @include_deleted
          users = users.where("pseudonyms.workflow_state<>'deleted' OR pseudonyms.sis_user_id IS NOT NULL")
        else
          users = users.where("pseudonyms.workflow_state<>'deleted'")
        end

        users = add_user_sub_account_scope(users)

        Shackles.activate(:slave) do
          users.find_in_batches do |batch|
            emails = Shard.partition_by_shard(batch.map(&:user_id)) do |user_ids|
                CommunicationChannel.
                  email.
                  unretired.
                  select([:user_id, :path]).
                  where(user_id: user_ids).
                  order('user_id, position ASC').
                  distinct_on(:user_id)
            end.index_by(&:user_id)

            batch.each do |u|
              row = []
              row << u.user_id unless @sis_format
              row << u.sis_user_id
              row << u.unique_id
              row << nil if @sis_format
              name_parts = User.name_parts(u.sortable_name)
              row << name_parts[0] || '' # first name
              row << name_parts[1] || '' # last name
              row << emails[u.user_id].try(:path)
              row << u.workflow_state
              csv << row
            end
          end
        end
      end
      filename
    end

    def accounts
      filename = AccountReports.generate_file(@account_report)
      CSV.open(filename, "w") do |csv|
        if @sis_format
          # headers are not translated on sis_export to maintain import compatibility
          headers = ['account_id', 'parent_account_id', 'name', 'status']
        else
          headers = []
          headers << I18n.t('#account_reports.report_header_canvas_account_id', 'canvas_account_id')
          headers << I18n.t('#account_reports.report_header_account_id', 'account_id')
          headers << I18n.t('#account_reports.report_header_canvas_parent_id', 'canvas_parent_id')
          headers << I18n.t('#account_reports.report_header_parent_account_id', 'parent_account_id')
          headers << I18n.t('#account_reports.report_header_name', 'name')
{'fraction_non_alphanumeric': 0.10305241612530035, 'fraction_numerical': 0.007119337901575154, 'mean_word_length': 2.515170472317798, 'pattern_counts': {'":': 0, '<': 105, '<?xml version=': 0, '>': 14, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4043780', 'n_tokens_mistral': 3407, 'n_tokens_neox': 3254, 'n_words': 773}