<commit_before>class App.ChannelMicrosoft365 extends App.ControllerTabs
  requiredPermission: 'admin.channel_microsoft365'
  header: __('Microsoft 365')
  constructor: ->
    super

    @title __('Microsoft 365'), true

    @tabs = [
      {
        name:       __('Accounts'),
        target:     'c-account',
        controller: ChannelAccountOverview,
      },
      {
        name:       __('Filter'),
        target:     'c-filter',
        controller: App.ChannelEmailFilter,
      },
      {
        name:       __('Signatures'),
        target:     'c-signature',
        controller: App.ChannelEmailSignature,
      },
      {
        name:       __('Settings'),
        target:     'c-setting',
        controller: App.SettingsArea,
        params:     { area: 'Email::Base' },
      },
    ]

    @render()

class ChannelAccountOverview extends App.ControllerSubContent
  requiredPermission: 'admin.channel_microsoft365'
  events:
    'click .js-new':                'new'
    'click .js-delete':             'delete'
    'click .js-reauthenticate':     'reauthenticate'
    'click .js-configApp':          'configApp'
    'click .js-disable':            'disable'
    'click .js-enable':             'enable'
    'click .js-channelGroupChange': 'groupChange'
    'click .js-editInbound':        'editInbound'
    'click .js-rollbackMigration':  'rollbackMigration'
    'click .js-emailAddressNew':    'emailAddressNew'
    'click .js-emailAddressEdit':   'emailAddressEdit'
    'click .js-emailAddressDelete': 'emailAddressDelete',

  constructor: ->
    super

    @interval(@load, 30000)
    @load()

  load: (reset_channel_id = false) =>
    if reset_channel_id
      @channel_id = undefined
      @navigate '#channels/microsoft365'

    @startLoading()
    @ajax(
      id:   'microsoft365_index'
      type: 'GET'
      url:  "#{@apiPath}/channels_microsoft365"
      processData: true
      success: (data, status, xhr) =>
        @stopLoading()
        App.Collection.loadAssets(data.assets)
        @callbackUrl = data.callback_url
        @render(data)
    )

  render: (data) =>

    # if no microsoft365 app is registered, show intro
    external_credential = App.ExternalCredential.findByAttribute('name', 'microsoft365')
    if !external_credential
      @html App.view('microsoft365/index')()
      if @channel_id
        @configApp()
      return

    channels = []
    for channel_id in data.channel_ids
      channel = App.Channel.find(channel_id)
      if channel.group_id
        channel.group = App.Group.find(channel.group_id)
      else
        channel.group = '-'

      email_addresses = App.EmailAddress.search(filter: { channel_id: channel.id })
      channel.email_addresses = email_addresses

      channels.push channel

    # auto redirect to gmail account linking if we have no account
    if @channel_id && channels.length < 1
      @new()
      return

    # get all unlinked email addresses
    not_used_email_addresses = []
    for email_address_id in data.not_used_email_address_ids
      not_used_email_addresses.push App.EmailAddress.find(email_address_id)

    @html App.view('microsoft365/list')(
      channels: channels
      external_credential: external_credential
      not_used_email_addresses: not_used_email_addresses
    )

    if @channel_id
      item = App.Channel.find(@channel_id)
      if item && item.options && item.options.backup_imap_classic is undefined
        @editInbound(undefined, @channel_id, true)
        @channel_id = undefined

  show: (params) =>
    for key, value of params
      if key isnt 'el' && key isnt 'shown' && key isnt 'match'
        @[key] = value

  configApp: =>
    new AppConfig(
      container: @el.parents('.content')
      callbackUrl: @callbackUrl
      load: @load<commit_msg>Fixes #4060 - Error on second migration of an microsoft365 channel undefined method `options' for nil:NilClass.<commit_after>class App.ChannelMicrosoft365 extends App.ControllerTabs
  requiredPermission: 'admin.channel_microsoft365'
  header: __('Microsoft 365')
  constructor: ->
    super

    @title __('Microsoft 365'), true

    @tabs = [
      {
        name:       __('Accounts'),
        target:     'c-account',
        controller: ChannelAccountOverview,
      },
      {
        name:       __('Filter'),
        target:     'c-filter',
        controller: App.ChannelEmailFilter,
      },
      {
        name:       __('Signatures'),
        target:     'c-signature',
        controller: App.ChannelEmailSignature,
      },
      {
        name:       __('Settings'),
        target:     'c-setting',
        controller: App.SettingsArea,
        params:     { area: 'Email::Base' },
      },
    ]

    @render()

class ChannelAccountOverview extends App.ControllerSubContent
  requiredPermission: 'admin.channel_microsoft365'
  events:
    'click .js-new':                'new'
    'click .js-delete':             'delete'
    'click .js-reauthenticate':     'reauthenticate'
    'click .js-configApp':          'configApp'
    'click .js-disable':            'disable'
    'click .js-enable':             'enable'
    'click .js-channelGroupChange': 'groupChange'
    'click .js-editInbound':        'editInbound'
    'click .js-rollbackMigration':  'rollbackMigration'
    'click .js-emailAddressNew':    'emailAddressNew'
    'click .js-emailAddressEdit':   'emailAddressEdit'
    'click .js-emailAddressDelete': 'emailAddressDelete',

  constructor: ->
    super

    @interval(@load, 30000)
    @load()

  load: (reset_channel_id = false) =>
    if reset_channel_id
      @channel_id = undefined
      @navigate '#channels/microsoft365'

    @startLoading()
    @ajax(
      id:   'microsoft365_index'
      type: 'GET'
      url:  "#{@apiPath}/channels_microsoft365"
      processData: true
      success: (data, status, xhr) =>
        @stopLoading()
        App.Collection.loadAssets(data.assets)
        @callbackUrl = data.callback_url
        @render(data)
    )

  render: (data) =>

    # if no microsoft365 app is registered, show intro
    external_credential = App.ExternalCredential.findByAttribute('name', 'microsoft365')
    if !external_credential
      @html App.view('microsoft365/index')()
      if @channel_id
        @configApp()
      return

    channels = []
    for channel_id in data.channel_ids
      channel = App.Channel.find(channel_id)
      if channel.group_id
        channel.group = App.Group.find(channel.group_id)
      else
        channel.group = '-'

      email_addresses = App.EmailAddress.search(filter: { channel_id: channel.id })
      channel.email_addresses = email_addresses

      channels.push channel

    # on a channel migration we need to auto redirect
    # the user to the "Add Account" functionality after
    # the filled up the external credentials
    if @channel_id
      item = App.Channel.find(@channel_id)
      if item && item.area != 'Microsoft365::Account'
        @new()
        return

    # get all unlinked email addresses
    not_used_email_addresses = []
    for email_address_id in data.not_used_email_address_ids
      not_used_email_addresses.push App.EmailAddress.find(email_address_id)

    @html App.view('microsoft365/list')(
      channels: channels
      external_credential: external_credential
      not_used_email_addresses: not_used_email_addresses
    )

    # on a channel creation we will auto open the edit
    # dialog after the redirect back to zammad to optional
    # change the inbound configuration, but not for
    # migrated channel because we guess that the inbound configuration
    # is already correct for them.
    if @channel_id
      item = App.Channel.find(@channel_id)
      if item && item.area == 'Microsoft365::Account' && item.options && item.options.backup_imap_classic is undefined
        @editInbound(undefined, @channel_id, true)
        @channel_id = undefined

  show: (params) =>
    for key, value of params
      if key isnt 'el' && key isnt 'shown' && key isnt 'match'
        @[key] = value

  configApp: =>
    new AppConfig(
      container: @el.parents('.content')
      callbackUrl: @callbackUrl
      load: @load
{'fraction_non_alphanumeric': 0.10722181282240235, 'fraction_numerical': 0.011790714812085483, 'mean_word_length': 2.5312228967909802, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '5044574', 'n_tokens_mistral': 2491, 'n_tokens_neox': 2362, 'n_words': 555}