Follow up - db3f553140 - Fixes #3215 - Renamed Office365 to Microsoft365.

This commit is contained in:
Thorsten Eckel 2020-10-27 15:05:10 +01:00
parent 5f3a8dc581
commit e972d0be89
20 changed files with 118 additions and 118 deletions

View file

@ -43,7 +43,7 @@ RSpec/ContextWording:
- 'spec/lib/auth_spec.rb' - 'spec/lib/auth_spec.rb'
- 'spec/lib/core_ext/string_spec.rb' - 'spec/lib/core_ext/string_spec.rb'
- 'spec/lib/external_credential/google_spec.rb' - 'spec/lib/external_credential/google_spec.rb'
- 'spec/lib/external_credential/office365_spec.rb' - 'spec/lib/external_credential/microsoft365_spec.rb'
- 'spec/lib/html_sanitizer_spec.rb' - 'spec/lib/html_sanitizer_spec.rb'
- 'spec/lib/import/exchange/folder_spec.rb' - 'spec/lib/import/exchange/folder_spec.rb'
- 'spec/lib/import/helper_spec.rb' - 'spec/lib/import/helper_spec.rb'
@ -145,7 +145,7 @@ RSpec/ContextWording:
- 'spec/requests/external_credentials_spec.rb' - 'spec/requests/external_credentials_spec.rb'
- 'spec/requests/integration/check_mk_spec.rb' - 'spec/requests/integration/check_mk_spec.rb'
- 'spec/requests/integration/gmail_spec.rb' - 'spec/requests/integration/gmail_spec.rb'
- 'spec/requests/integration/office365_spec.rb' - 'spec/requests/integration/microsoft365_spec.rb'
- 'spec/requests/integration/object_manager_attributes_spec.rb' - 'spec/requests/integration/object_manager_attributes_spec.rb'
- 'spec/requests/integration/smime_spec.rb' - 'spec/requests/integration/smime_spec.rb'
- 'spec/requests/knowledge_base/attachments_spec.rb' - 'spec/requests/knowledge_base/attachments_spec.rb'
@ -180,7 +180,7 @@ RSpec/ExampleLength:
- 'spec/lib/auto_wizard_spec.rb' - 'spec/lib/auto_wizard_spec.rb'
- 'spec/lib/core_ext/string_spec.rb' - 'spec/lib/core_ext/string_spec.rb'
- 'spec/lib/external_credential/google_spec.rb' - 'spec/lib/external_credential/google_spec.rb'
- 'spec/lib/external_credential/office365_spec.rb' - 'spec/lib/external_credential/microsoft365_spec.rb'
- 'spec/lib/external_sync_spec.rb' - 'spec/lib/external_sync_spec.rb'
- 'spec/lib/import/import_job_backend_examples.rb' - 'spec/lib/import/import_job_backend_examples.rb'
- 'spec/lib/import/ldap_spec.rb' - 'spec/lib/import/ldap_spec.rb'
@ -360,7 +360,7 @@ RSpec/LetSetup:
- 'spec/jobs/communicate_twitter_job_spec.rb' - 'spec/jobs/communicate_twitter_job_spec.rb'
- 'spec/jobs/ticket_online_notification_seen_job_spec.rb' - 'spec/jobs/ticket_online_notification_seen_job_spec.rb'
- 'spec/lib/external_credential/google_spec.rb' - 'spec/lib/external_credential/google_spec.rb'
- 'spec/lib/external_credential/office365_spec.rb' - 'spec/lib/external_credential/microsoft365_spec.rb'
- 'spec/lib/secure_mailing/smime_spec.rb' - 'spec/lib/secure_mailing/smime_spec.rb'
- 'spec/lib/sessions/backend/ticket_overview_list_spec.rb' - 'spec/lib/sessions/backend/ticket_overview_list_spec.rb'
- 'spec/models/channel/driver/twitter_spec.rb' - 'spec/models/channel/driver/twitter_spec.rb'
@ -619,7 +619,7 @@ RSpec/NestedGroups:
- 'spec/lib/core_ext/string_spec.rb' - 'spec/lib/core_ext/string_spec.rb'
- 'spec/lib/email_address_validation_spec.rb' - 'spec/lib/email_address_validation_spec.rb'
- 'spec/lib/external_credential/google_spec.rb' - 'spec/lib/external_credential/google_spec.rb'
- 'spec/lib/external_credential/office365_spec.rb' - 'spec/lib/external_credential/microsoft365_spec.rb'
- 'spec/lib/html_sanitizer_spec.rb' - 'spec/lib/html_sanitizer_spec.rb'
- 'spec/lib/import/exchange/folder_spec.rb' - 'spec/lib/import/exchange/folder_spec.rb'
- 'spec/lib/notification_factory/mailer_spec.rb' - 'spec/lib/notification_factory/mailer_spec.rb'

View file

@ -26,7 +26,7 @@ Metrics/AbcSize:
- 'app/controllers/attachments_controller.rb' - 'app/controllers/attachments_controller.rb'
- 'app/controllers/channels_email_controller.rb' - 'app/controllers/channels_email_controller.rb'
- 'app/controllers/channels_google_controller.rb' - 'app/controllers/channels_google_controller.rb'
- 'app/controllers/channels_office365_controller.rb' - 'app/controllers/channels_microsoft365_controller.rb'
- 'app/controllers/channels_sms_controller.rb' - 'app/controllers/channels_sms_controller.rb'
- 'app/controllers/channels_telegram_controller.rb' - 'app/controllers/channels_telegram_controller.rb'
- 'app/controllers/channels_twitter_controller.rb' - 'app/controllers/channels_twitter_controller.rb'
@ -275,7 +275,7 @@ Metrics/AbcSize:
- 'lib/excel_sheet/ticket.rb' - 'lib/excel_sheet/ticket.rb'
- 'lib/external_credential/facebook.rb' - 'lib/external_credential/facebook.rb'
- 'lib/external_credential/google.rb' - 'lib/external_credential/google.rb'
- 'lib/external_credential/office365.rb' - 'lib/external_credential/microsoft365.rb'
- 'lib/external_credential/twitter.rb' - 'lib/external_credential/twitter.rb'
- 'lib/facebook.rb' - 'lib/facebook.rb'
- 'lib/fill_db.rb' - 'lib/fill_db.rb'
@ -458,7 +458,7 @@ Metrics/CyclomaticComplexity:
- 'app/controllers/application_controller/renders_models.rb' - 'app/controllers/application_controller/renders_models.rb'
- 'app/controllers/channels_email_controller.rb' - 'app/controllers/channels_email_controller.rb'
- 'app/controllers/channels_google_controller.rb' - 'app/controllers/channels_google_controller.rb'
- 'app/controllers/channels_office365_controller.rb' - 'app/controllers/channels_microsoft365_controller.rb'
- 'app/controllers/channels_twitter_controller.rb' - 'app/controllers/channels_twitter_controller.rb'
- 'app/controllers/concerns/checks_user_attributes_by_current_user_permission.rb' - 'app/controllers/concerns/checks_user_attributes_by_current_user_permission.rb'
- 'app/controllers/concerns/creates_ticket_articles.rb' - 'app/controllers/concerns/creates_ticket_articles.rb'
@ -616,7 +616,7 @@ Metrics/CyclomaticComplexity:
- 'lib/excel_sheet.rb' - 'lib/excel_sheet.rb'
- 'lib/external_credential/facebook.rb' - 'lib/external_credential/facebook.rb'
- 'lib/external_credential/google.rb' - 'lib/external_credential/google.rb'
- 'lib/external_credential/office365.rb' - 'lib/external_credential/microsoft365.rb'
- 'lib/external_credential/twitter.rb' - 'lib/external_credential/twitter.rb'
- 'lib/facebook.rb' - 'lib/facebook.rb'
- 'lib/fill_db.rb' - 'lib/fill_db.rb'
@ -697,7 +697,7 @@ Metrics/PerceivedComplexity:
- 'app/controllers/application_controller/logs_http_access.rb' - 'app/controllers/application_controller/logs_http_access.rb'
- 'app/controllers/channels_email_controller.rb' - 'app/controllers/channels_email_controller.rb'
- 'app/controllers/channels_google_controller.rb' - 'app/controllers/channels_google_controller.rb'
- 'app/controllers/channels_office365_controller.rb' - 'app/controllers/channels_microsoft365_controller.rb'
- 'app/controllers/concerns/creates_ticket_articles.rb' - 'app/controllers/concerns/creates_ticket_articles.rb'
- 'app/controllers/first_steps_controller.rb' - 'app/controllers/first_steps_controller.rb'
- 'app/controllers/form_controller.rb' - 'app/controllers/form_controller.rb'
@ -842,7 +842,7 @@ Metrics/PerceivedComplexity:
- 'lib/excel_sheet.rb' - 'lib/excel_sheet.rb'
- 'lib/external_credential/facebook.rb' - 'lib/external_credential/facebook.rb'
- 'lib/external_credential/google.rb' - 'lib/external_credential/google.rb'
- 'lib/external_credential/office365.rb' - 'lib/external_credential/microsoft365.rb'
- 'lib/external_credential/twitter.rb' - 'lib/external_credential/twitter.rb'
- 'lib/facebook.rb' - 'lib/facebook.rb'
- 'lib/fill_db.rb' - 'lib/fill_db.rb'
@ -940,7 +940,7 @@ Style/OptionalBooleanParameter:
- 'lib/core_ext/string.rb' - 'lib/core_ext/string.rb'
- 'lib/external_credential/facebook.rb' - 'lib/external_credential/facebook.rb'
- 'lib/external_credential/google.rb' - 'lib/external_credential/google.rb'
- 'lib/external_credential/office365.rb' - 'lib/external_credential/microsoft365.rb'
- 'lib/external_credential/twitter.rb' - 'lib/external_credential/twitter.rb'
- 'lib/html_sanitizer.rb' - 'lib/html_sanitizer.rb'
- 'lib/models.rb' - 'lib/models.rb'

View file

@ -188,7 +188,7 @@ class App.ChannelEmailAccountOverview extends App.Controller
'click .js-emailAddressDelete': 'emailAddressDelete', 'click .js-emailAddressDelete': 'emailAddressDelete',
'click .js-editNotificationOutbound': 'editNotificationOutbound' 'click .js-editNotificationOutbound': 'editNotificationOutbound'
'click .js-migrateGoogleMail': 'migrateGoogleMail' 'click .js-migrateGoogleMail': 'migrateGoogleMail'
'click .js-migrateOffice365Mail': 'migrateOffice365Mail' 'click .js-migrateMicrosoft365Mail': 'migrateMicrosoft365Mail'
constructor: -> constructor: ->
super super
@ -386,10 +386,10 @@ class App.ChannelEmailAccountOverview extends App.Controller
id = $(e.target).closest('.action').data('id') id = $(e.target).closest('.action').data('id')
@navigate "#channels/google/#{id}" @navigate "#channels/google/#{id}"
migrateOffice365Mail: (e) => migrateMicrosoft365Mail: (e) =>
e.preventDefault() e.preventDefault()
id = $(e.target).closest('.action').data('id') id = $(e.target).closest('.action').data('id')
@navigate "#channels/office365/#{id}" @navigate "#channels/microsoft365/#{id}"
class App.ChannelEmailEdit extends App.ControllerModal class App.ChannelEmailEdit extends App.ControllerModal
buttonClose: true buttonClose: true

View file

@ -1,10 +1,10 @@
class App.ChannelOffice365 extends App.ControllerTabs class App.ChannelMicrosoft365 extends App.ControllerTabs
requiredPermission: 'admin.channel_office365' requiredPermission: 'admin.channel_microsoft365'
header: 'Office 365' header: 'Microsoft 365'
constructor: -> constructor: ->
super super
@title 'Office 365', true @title 'Microsoft 365', true
@tabs = [ @tabs = [
{ {
@ -33,7 +33,7 @@ class App.ChannelOffice365 extends App.ControllerTabs
@render() @render()
class ChannelAccountOverview extends App.ControllerSubContent class ChannelAccountOverview extends App.ControllerSubContent
requiredPermission: 'admin.channel_office365' requiredPermission: 'admin.channel_microsoft365'
events: events:
'click .js-new': 'new' 'click .js-new': 'new'
'click .js-delete': 'delete' 'click .js-delete': 'delete'
@ -56,13 +56,13 @@ class ChannelAccountOverview extends App.ControllerSubContent
load: (reset_channel_id = false) => load: (reset_channel_id = false) =>
if reset_channel_id if reset_channel_id
@channel_id = undefined @channel_id = undefined
@navigate '#channels/office365' @navigate '#channels/microsoft365'
@startLoading() @startLoading()
@ajax( @ajax(
id: 'office365_index' id: 'microsoft365_index'
type: 'GET' type: 'GET'
url: "#{@apiPath}/channels_office365" url: "#{@apiPath}/channels_microsoft365"
processData: true processData: true
success: (data, status, xhr) => success: (data, status, xhr) =>
@stopLoading() @stopLoading()
@ -73,10 +73,10 @@ class ChannelAccountOverview extends App.ControllerSubContent
render: (data) => render: (data) =>
# if no office365 app is registered, show intro # if no microsoft365 app is registered, show intro
external_credential = App.ExternalCredential.findByAttribute('name', 'office365') external_credential = App.ExternalCredential.findByAttribute('name', 'microsoft365')
if !external_credential if !external_credential
@html App.view('office365/index')() @html App.view('microsoft365/index')()
if @channel_id if @channel_id
@configApp() @configApp()
return return
@ -104,7 +104,7 @@ class ChannelAccountOverview extends App.ControllerSubContent
for email_address_id in data.not_used_email_address_ids for email_address_id in data.not_used_email_address_ids
not_used_email_addresses.push App.EmailAddress.find(email_address_id) not_used_email_addresses.push App.EmailAddress.find(email_address_id)
@html App.view('office365/list')( @html App.view('microsoft365/list')(
channels: channels channels: channels
external_credential: external_credential external_credential: external_credential
not_used_email_addresses: not_used_email_addresses not_used_email_addresses: not_used_email_addresses
@ -129,7 +129,7 @@ class ChannelAccountOverview extends App.ControllerSubContent
) )
new: (e) -> new: (e) ->
window.location.href = "#{@apiPath}/external_credentials/office365/link_account" window.location.href = "#{@apiPath}/external_credentials/microsoft365/link_account"
delete: (e) => delete: (e) =>
e.preventDefault() e.preventDefault()
@ -138,9 +138,9 @@ class ChannelAccountOverview extends App.ControllerSubContent
message: 'Sure?' message: 'Sure?'
callback: => callback: =>
@ajax( @ajax(
id: 'office365_delete' id: 'microsoft365_delete'
type: 'DELETE' type: 'DELETE'
url: "#{@apiPath}/channels_office365" url: "#{@apiPath}/channels_microsoft365"
data: JSON.stringify(id: id) data: JSON.stringify(id: id)
processData: true processData: true
success: => success: =>
@ -153,9 +153,9 @@ class ChannelAccountOverview extends App.ControllerSubContent
e.preventDefault() e.preventDefault()
id = $(e.target).closest('.action').data('id') id = $(e.target).closest('.action').data('id')
@ajax( @ajax(
id: 'office365_disable' id: 'microsoft365_disable'
type: 'POST' type: 'POST'
url: "#{@apiPath}/channels_office365_disable" url: "#{@apiPath}/channels_microsoft365_disable"
data: JSON.stringify(id: id) data: JSON.stringify(id: id)
processData: true processData: true
success: => success: =>
@ -166,9 +166,9 @@ class ChannelAccountOverview extends App.ControllerSubContent
e.preventDefault() e.preventDefault()
id = $(e.target).closest('.action').data('id') id = $(e.target).closest('.action').data('id')
@ajax( @ajax(
id: 'office365_enable' id: 'microsoft365_enable'
type: 'POST' type: 'POST'
url: "#{@apiPath}/channels_office365_enable" url: "#{@apiPath}/channels_microsoft365_enable"
data: JSON.stringify(id: id) data: JSON.stringify(id: id)
processData: true processData: true
success: => success: =>
@ -191,9 +191,9 @@ class ChannelAccountOverview extends App.ControllerSubContent
e.preventDefault() e.preventDefault()
id = $(e.target).closest('.action').data('id') id = $(e.target).closest('.action').data('id')
@ajax( @ajax(
id: 'office365_rollback_migration' id: 'microsoft365_rollback_migration'
type: 'POST' type: 'POST'
url: "#{@apiPath}/channels_office365_rollback_migration" url: "#{@apiPath}/channels_microsoft365_rollback_migration"
data: JSON.stringify(id: id) data: JSON.stringify(id: id)
processData: true processData: true
success: => success: =>
@ -296,7 +296,7 @@ class ChannelInboundEdit extends App.ControllerModal
@ajax( @ajax(
id: 'channel_email_inbound' id: 'channel_email_inbound'
type: 'POST' type: 'POST'
url: "#{@apiPath}/channels_office365_inbound/#{@item.id}" url: "#{@apiPath}/channels_microsoft365_inbound/#{@item.id}"
data: JSON.stringify(params) data: JSON.stringify(params)
processData: true processData: true
success: (data, status, xhr) => success: (data, status, xhr) =>
@ -351,7 +351,7 @@ class ChannelGroupEdit extends App.ControllerModal
@ajax( @ajax(
id: 'channel_email_group' id: 'channel_email_group'
type: 'POST' type: 'POST'
url: "#{@apiPath}/channels_office365_group/#{@item.id}" url: "#{@apiPath}/channels_microsoft365_group/#{@item.id}"
data: JSON.stringify(params) data: JSON.stringify(params)
processData: true processData: true
success: (data, status, xhr) => success: (data, status, xhr) =>
@ -364,15 +364,15 @@ class ChannelGroupEdit extends App.ControllerModal
) )
class AppConfig extends App.ControllerModal class AppConfig extends App.ControllerModal
head: 'Connect Office 365 App' head: 'Connect Microsoft 365 App'
shown: true shown: true
button: 'Connect' button: 'Connect'
buttonCancel: true buttonCancel: true
small: true small: true
content: -> content: ->
@external_credential = App.ExternalCredential.findByAttribute('name', 'office365') @external_credential = App.ExternalCredential.findByAttribute('name', 'microsoft365')
content = $(App.view('office365/app_config')( content = $(App.view('microsoft365/app_config')(
external_credential: @external_credential external_credential: @external_credential
callbackUrl: @callbackUrl callbackUrl: @callbackUrl
)) ))
@ -391,16 +391,16 @@ class AppConfig extends App.ControllerModal
# verify app credentials # verify app credentials
@ajax( @ajax(
id: 'office365_app_verify' id: 'microsoft365_app_verify'
type: 'POST' type: 'POST'
url: "#{@apiPath}/external_credentials/office365/app_verify" url: "#{@apiPath}/external_credentials/microsoft365/app_verify"
data: JSON.stringify(@formParams()) data: JSON.stringify(@formParams())
processData: true processData: true
success: (data, status, xhr) => success: (data, status, xhr) =>
if data.attributes if data.attributes
if !@external_credential if !@external_credential
@external_credential = new App.ExternalCredential @external_credential = new App.ExternalCredential
@external_credential.load(name: 'office365', credentials: data.attributes) @external_credential.load(name: 'microsoft365', credentials: data.attributes)
@external_credential.save( @external_credential.save(
done: => done: =>
@isChanged = true @isChanged = true
@ -413,4 +413,4 @@ class AppConfig extends App.ControllerModal
@el.find('.alert').removeClass('hidden').text(data.error || 'Unable to verify App.') @el.find('.alert').removeClass('hidden').text(data.error || 'Unable to verify App.')
) )
App.Config.set('office365', { prio: 5000, name: 'Office 365', parent: '#channels', target: '#channels/office365', controller: App.ChannelOffice365, permission: ['admin.channel_office365'] }, 'NavBarAdmin') App.Config.set('microsoft365', { prio: 5000, name: 'Microsoft 365', parent: '#channels', target: '#channels/microsoft365', controller: App.ChannelMicrosoft365, permission: ['admin.channel_microsoft365'] }, 'NavBarAdmin')

View file

@ -18,7 +18,7 @@ class App.EmailAddress extends App.Model
if localChannel if localChannel
return channel if channel.area is localChannel.area return channel if channel.area is localChannel.area
else else
return channel if channel.area is 'Google::Account' || channel.area is 'Office365::Account' || channel.area is 'Email::Account' return channel if channel.area is 'Google::Account' || channel.area is 'Microsoft365::Account' || channel.area is 'Email::Account'
) )
@configure_attributes = [ @configure_attributes = [

View file

@ -63,9 +63,9 @@
<% date_migration = new Date("#{date_migration_string}T00:00:00") %> <% date_migration = new Date("#{date_migration_string}T00:00:00") %>
<% date_now = new Date() %> <% date_now = new Date() %>
<% if date_now > date_migration: %> <% if date_now > date_migration: %>
<%- @T('%s will only allow access via OAuth. Password-based access is no longer supported since %s.', 'Office 365', date_migration_string_local) %> <div class="flex-spacer"></div><div class="double-spacer"></div><button class="btn js-migrateGoogleMail" type="button"><%- @T('Migrate now!') %></button> <%- @T('%s will only allow access via OAuth. Password-based access is no longer supported since %s.', 'Microsoft 365', date_migration_string_local) %> <div class="flex-spacer"></div><div class="double-spacer"></div><button class="btn js-migrateMicrosoft365Mail" type="button"><%- @T('Migrate now!') %></button>
<% else: %> <% else: %>
<%- @T('%s will only allow access via OAuth. Password-based access will no longer be supported on %s.', 'Office 365', date_migration_string_local) %> <div class="flex-spacer"></div><div class="double-spacer"></div><button class="btn js-migrateGoogleMail" type="button"><%- @T('Migrate now!') %></button> <%- @T('%s will only allow access via OAuth. Password-based access will no longer be supported on %s.', 'Microsoft 365', date_migration_string_local) %> <div class="flex-spacer"></div><div class="double-spacer"></div><button class="btn js-migrateMicrosoft365Mail" type="button"><%- @T('Migrate now!') %></button>
<% end %> <% end %>
</div> </div>
<% end %> <% end %>

View file

@ -1,9 +1,9 @@
<div class="alert alert--danger hidden" role="alert"></div> <div class="alert alert--danger hidden" role="alert"></div>
<p> <p>
<%- @T('The tutorial on how to manage a %s is hosted on our online documentation %l.', 'Office 365 App', 'https://admin-docs.zammad.org/en/latest/channels/office365.html') %> <%- @T('The tutorial on how to manage a %s is hosted on our online documentation %l.', 'Microsoft 365 App', 'https://admin-docs.zammad.org/en/latest/channels/microsoft365.html') %>
</p> </p>
<fieldset> <fieldset>
<h2><%- @T('Enter your %s App Keys', 'Office 365') %></h2> <h2><%- @T('Enter your %s App Keys', 'Microsoft 365') %></h2>
<div class="input form-group"> <div class="input form-group">
<div class="formGroup-label"> <div class="formGroup-label">
<label for="client_id">Client ID <span>*</span></label> <label for="client_id">Client ID <span>*</span></label>

View file

@ -0,0 +1,12 @@
<div class="page-header">
<div class="page-header-title">
<h1><%- @T('Microsoft 365') %> <small><%- @T('Accounts') %></small></h1>
</div>
</div>
<div class="page-content">
<div class="page-description">
<p><%- @T('You can connect %s with Zammad. You need to connect your Zammad with %s first.', 'Microsoft 365 Accounts', 'Microsoft 365') %></p>
<div class="btn btn--success js-configApp"><%- @T('Connect Microsoft 365 App') %></div>
</div>
</div>

View file

@ -1,6 +1,6 @@
<div class="page-header"> <div class="page-header">
<div class="page-header-title"> <div class="page-header-title">
<h1><%- @T('Office 365') %> <small><%- @T('Accounts') %></small></h1> <h1><%- @T('Microsoft 365') %> <small><%- @T('Accounts') %></small></h1>
</div> </div>
<div class="page-header-meta"> <div class="page-header-meta">

View file

@ -1,12 +0,0 @@
<div class="page-header">
<div class="page-header-title">
<h1><%- @T('Office 365') %> <small><%- @T('Accounts') %></small></h1>
</div>
</div>
<div class="page-content">
<div class="page-description">
<p><%- @T('You can connect %s with Zammad. You need to connect your Zammad with %s first.', 'Office 365 Accounts', 'Office 365') %></p>
<div class="btn btn--success js-configApp"><%- @T('Connect Office 365 App') %></div>
</div>
</div>

View file

@ -1,6 +1,6 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class ChannelsOffice365Controller < ApplicationController class ChannelsMicrosoft365Controller < ApplicationController
prepend_before_action -> { authentication_check && authorize! } prepend_before_action -> { authentication_check && authorize! }
def index def index
@ -8,13 +8,13 @@ class ChannelsOffice365Controller < ApplicationController
assets = {} assets = {}
external_credential_ids = [] external_credential_ids = []
ExternalCredential.where(name: 'office365').each do |external_credential| ExternalCredential.where(name: 'microsoft365').each do |external_credential|
assets = external_credential.assets(assets) assets = external_credential.assets(assets)
external_credential_ids.push external_credential.id external_credential_ids.push external_credential.id
end end
channel_ids = [] channel_ids = []
Channel.where(area: 'Office365::Account').order(:id).each do |channel| Channel.where(area: 'Microsoft365::Account').order(:id).each do |channel|
assets = channel.assets(assets) assets = channel.assets(assets)
channel_ids.push channel.id channel_ids.push channel.id
end end
@ -34,26 +34,26 @@ class ChannelsOffice365Controller < ApplicationController
not_used_email_address_ids: not_used_email_address_ids, not_used_email_address_ids: not_used_email_address_ids,
channel_ids: channel_ids, channel_ids: channel_ids,
external_credential_ids: external_credential_ids, external_credential_ids: external_credential_ids,
callback_url: ExternalCredential.callback_url('office365'), callback_url: ExternalCredential.callback_url('microsoft365'),
} }
end end
def enable def enable
channel = Channel.find_by(id: params[:id], area: 'Office365::Account') channel = Channel.find_by(id: params[:id], area: 'Microsoft365::Account')
channel.active = true channel.active = true
channel.save! channel.save!
render json: {} render json: {}
end end
def disable def disable
channel = Channel.find_by(id: params[:id], area: 'Office365::Account') channel = Channel.find_by(id: params[:id], area: 'Microsoft365::Account')
channel.active = false channel.active = false
channel.save! channel.save!
render json: {} render json: {}
end end
def destroy def destroy
channel = Channel.find_by(id: params[:id], area: 'Office365::Account') channel = Channel.find_by(id: params[:id], area: 'Microsoft365::Account')
email = EmailAddress.find_by(channel_id: channel.id) email = EmailAddress.find_by(channel_id: channel.id)
email.destroy! email.destroy!
channel.destroy! channel.destroy!
@ -61,14 +61,14 @@ class ChannelsOffice365Controller < ApplicationController
end end
def group def group
channel = Channel.find_by(id: params[:id], area: 'Office365::Account') channel = Channel.find_by(id: params[:id], area: 'Microsoft365::Account')
channel.group_id = params[:group_id] channel.group_id = params[:group_id]
channel.save! channel.save!
render json: {} render json: {}
end end
def inbound def inbound
channel = Channel.find_by(id: params[:id], area: 'Office365::Account') channel = Channel.find_by(id: params[:id], area: 'Microsoft365::Account')
%w[folder keep_on_server].each do |key| %w[folder keep_on_server].each do |key|
channel.options[:inbound][:options][key] = params[:options][key] channel.options[:inbound][:options][key] = params[:options][key]
end end
@ -90,7 +90,7 @@ class ChannelsOffice365Controller < ApplicationController
end end
def rollback_migration def rollback_migration
channel = Channel.find_by(id: params[:id], area: 'Office365::Account') channel = Channel.find_by(id: params[:id], area: 'Microsoft365::Account')
raise 'Failed to find backup on channel!' if !channel.options[:backup_imap_classic] raise 'Failed to find backup on channel!' if !channel.options[:backup_imap_classic]
channel.update!(channel.options[:backup_imap_classic][:attributes]) channel.update!(channel.options[:backup_imap_classic][:attributes])

View file

@ -2,7 +2,7 @@ class ImapAuthenticationMigrationCleanupJob < ApplicationJob
include HasActiveJobLock include HasActiveJobLock
def perform def perform
Channel.where(area: ['Google::Account', 'Office365::Account']).find_each do |channel| Channel.where(area: ['Google::Account', 'Microsoft365::Account']).find_each do |channel|
next if channel.options.blank? next if channel.options.blank?
next if channel.options[:backup_imap_classic].blank? next if channel.options[:backup_imap_classic].blank?
next if channel.options[:backup_imap_classic][:migrated_at] > 7.days.ago next if channel.options[:backup_imap_classic][:migrated_at] > 7.days.ago

View file

@ -361,7 +361,7 @@ returns
# @return [Hash<String=>String>] # @return [Hash<String=>String>]
def self.parse_rfc822_headers(string) def self.parse_rfc822_headers(string)
array = string array = string
.gsub("\r\n\t", ' ') # Some servers (e.g. office365) may put attribute value on a separate line and tab it .gsub("\r\n\t", ' ') # Some servers (e.g. microsoft365) may put attribute value on a separate line and tab it
.lines(chomp: true) .lines(chomp: true)
.map { |line| line.split(/:\s*/, 2).map(&:strip) } .map { |line| line.split(/:\s*/, 2).map(&:strip) }

View file

@ -0,0 +1,3 @@
class Controllers::ChannelsMicrosoft365ControllerPolicy < Controllers::ApplicationControllerPolicy
default_permit!('admin.channel_microsoft365')
end

View file

@ -1,3 +0,0 @@
class Controllers::ChannelsOffice365ControllerPolicy < Controllers::ApplicationControllerPolicy
default_permit!('admin.channel_office365')
end

View file

@ -0,0 +1,12 @@
Zammad::Application.routes.draw do
api_path = Rails.configuration.api_path
match api_path + '/channels_microsoft365', to: 'channels_microsoft365#index', via: :get
match api_path + '/channels_microsoft365_disable', to: 'channels_microsoft365#disable', via: :post
match api_path + '/channels_microsoft365_enable', to: 'channels_microsoft365#enable', via: :post
match api_path + '/channels_microsoft365', to: 'channels_microsoft365#destroy', via: :delete
match api_path + '/channels_microsoft365_group/:id', to: 'channels_microsoft365#group', via: :post
match api_path + '/channels_microsoft365_inbound/:id', to: 'channels_microsoft365#inbound', via: :post
match api_path + '/channels_microsoft365_rollback_migration', to: 'channels_microsoft365#rollback_migration', via: :post
end

View file

@ -1,12 +0,0 @@
Zammad::Application.routes.draw do
api_path = Rails.configuration.api_path
match api_path + '/channels_office365', to: 'channels_office365#index', via: :get
match api_path + '/channels_office365_disable', to: 'channels_office365#disable', via: :post
match api_path + '/channels_office365_enable', to: 'channels_office365#enable', via: :post
match api_path + '/channels_office365', to: 'channels_office365#destroy', via: :delete
match api_path + '/channels_office365_group/:id', to: 'channels_office365#group', via: :post
match api_path + '/channels_office365_inbound/:id', to: 'channels_office365#inbound', via: :post
match api_path + '/channels_office365_rollback_migration', to: 'channels_office365#rollback_migration', via: :post
end

View file

@ -1,4 +1,4 @@
class ExternalCredential::Office365 class ExternalCredential::Microsoft365
def self.app_verify(params) def self.app_verify(params)
request_account_to_link(params, false) request_account_to_link(params, false)
@ -6,8 +6,8 @@ class ExternalCredential::Office365
end end
def self.request_account_to_link(credentials = {}, app_required = true) def self.request_account_to_link(credentials = {}, app_required = true)
external_credential = ExternalCredential.find_by(name: 'office365') external_credential = ExternalCredential.find_by(name: 'microsoft365')
raise Exceptions::UnprocessableEntity, 'No Office365 app configured!' if !external_credential && app_required raise Exceptions::UnprocessableEntity, 'No Microsoft365 app configured!' if !external_credential && app_required
if external_credential if external_credential
if credentials[:client_id].blank? if credentials[:client_id].blank?
@ -29,8 +29,8 @@ class ExternalCredential::Office365
end end
def self.link_account(_request_token, params) def self.link_account(_request_token, params)
external_credential = ExternalCredential.find_by(name: 'office365') external_credential = ExternalCredential.find_by(name: 'microsoft365')
raise Exceptions::UnprocessableEntity, 'No office365 app configured!' if !external_credential raise Exceptions::UnprocessableEntity, 'No Microsoft365 app configured!' if !external_credential
raise Exceptions::UnprocessableEntity, 'No code for session found!' if !params[:code] raise Exceptions::UnprocessableEntity, 'No code for session found!' if !params[:code]
response = authorize_tokens(external_credential.credentials[:client_id], external_credential.credentials[:client_secret], params[:code]) response = authorize_tokens(external_credential.credentials[:client_id], external_credential.credentials[:client_secret], params[:code])
@ -74,7 +74,7 @@ class ExternalCredential::Office365
}, },
}, },
auth: response.merge( auth: response.merge(
provider: 'office365', provider: 'microsoft365',
type: 'XOAUTH2', type: 'XOAUTH2',
client_id: external_credential.credentials[:client_id], client_id: external_credential.credentials[:client_id],
client_secret: external_credential.credentials[:client_secret], client_secret: external_credential.credentials[:client_secret],
@ -98,7 +98,7 @@ class ExternalCredential::Office365
} }
migrate_channel.update( migrate_channel.update(
area: 'Office365::Account', area: 'Microsoft365::Account',
options: channel_options.merge(backup_imap_classic: backup), options: channel_options.merge(backup_imap_classic: backup),
last_log_in: nil, last_log_in: nil,
last_log_out: nil, last_log_out: nil,
@ -122,7 +122,7 @@ class ExternalCredential::Office365
# create channel # create channel
channel = Channel.create!( channel = Channel.create!(
area: 'Office365::Account', area: 'Microsoft365::Account',
group_id: Group.first.id, group_id: Group.first.id,
options: channel_options, options: channel_options,
active: false, active: false,
@ -148,7 +148,7 @@ class ExternalCredential::Office365
params = { params = {
'client_id' => client_id, 'client_id' => client_id,
'redirect_uri' => ExternalCredential.callback_url('office365'), 'redirect_uri' => ExternalCredential.callback_url('microsoft365'),
'scope' => scope, 'scope' => scope,
'response_type' => 'code', 'response_type' => 'code',
'access_type' => 'offline', 'access_type' => 'offline',
@ -170,7 +170,7 @@ class ExternalCredential::Office365
'code' => authorization_code, 'code' => authorization_code,
'grant_type' => 'authorization_code', 'grant_type' => 'authorization_code',
'client_id' => client_id, 'client_id' => client_id,
'redirect_uri' => ExternalCredential.callback_url('office365'), 'redirect_uri' => ExternalCredential.callback_url('microsoft365'),
} }
uri = URI::HTTPS.build( uri = URI::HTTPS.build(

View file

@ -1,9 +1,9 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe ExternalCredential::Office365 do RSpec.describe ExternalCredential::Microsoft365 do
let(:token_url) { 'https://login.microsoftonline.com/common/oauth2/v2.0/token' } let(:token_url) { 'https://login.microsoftonline.com/common/oauth2/v2.0/token' }
let(:authorize_url) { "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?access_type=offline&client_id=#{client_id}&prompt=consent&redirect_uri=http%3A%2F%2Fzammad.example.com%2Fapi%2Fv1%2Fexternal_credentials%2Foffice365%2Fcallback&response_type=code&scope=https%3A%2F%2Foutlook.office.com%2FIMAP.AccessAsUser.All+https%3A%2F%2Foutlook.office.com%2FSMTP.Send+offline_access+openid+profile+email" } let(:authorize_url) { "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?access_type=offline&client_id=#{client_id}&prompt=consent&redirect_uri=http%3A%2F%2Fzammad.example.com%2Fapi%2Fv1%2Fexternal_credentials%2Fmicrosoft365%2Fcallback&response_type=code&scope=https%3A%2F%2Foutlook.office.com%2FIMAP.AccessAsUser.All+https%3A%2F%2Foutlook.office.com%2FSMTP.Send+offline_access+openid+profile+email" }
let(:id_token) { 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtnMkxZczJUMENUaklmajRydDZKSXluZW4zOCJ9.eyJhdWQiOiIyMTk4NTFhYS0wMDAwLTRhNDctMTExMS0zMmQwNzAyZTAxMjM0IiwiaXNzIjoiaHR0cHM6Ly9sb2dpbi5taWNyb3NvZnRvbmxpbmUuY29tLzM2YTlhYjU1LWZpZmEtMjAyMC04YTc4LTkwcnM0NTRkYmNmZDJkL3YyLjAiLCJpYXQiOjEzMDE1NTE4MzUsIm5iZiI6MTMwMTU1MTgzNSwiZXhwIjoxNjAxNTU5NzQ0LCJuYW1lIjoiRXhhbXBsZSBVc2VyIiwib2lkIjoiMTExYWIyMTQtMTJzNy00M2NnLThiMTItM2ozM2UydDBjYXUyIiwicHJlZmVycmVkX3VzZXJuYW1lIjoidGVzdEBleGFtcGxlLmNvbSIsImVtYWlsIjoidGVzdEBleGFtcGxlLmNvbSIsInJoIjoiMC40MjM0LWZmZnNmZGdkaGRLZUpEU1hiejlMYXBSbUNHZGdmZ2RmZ0kwZHkwSEF1QlhaSEFNYy4iLCJzdWIiOiJYY0VlcmVyQkVnX0EzNWJlc2ZkczNMTElXNjU1NFQtUy0ycGRnZ2R1Z3c1NDNXT2xJIiwidGlkIjoiMzZhOWFiNTUtZmlmYS0yMDIwLThhNzgtOTByczQ1NGRiY2ZkMmQiLCJ1dGkiOiJEU0dGZ3Nhc2RkZmdqdGpyMzV3cWVlIiwidmVyIjoiMi4wIn0=.l0nglq4rIlkR29DFK3PQFQTjE-VeHdgLmcnXwGvT8Z-QBaQjeTAcoMrVpr0WdL6SRYiyn2YuqPnxey6N0IQdlmvTMBv0X_dng_y4CiQ8ABdZrQK0VSRWZViboJgW5iBvJYFcMmVoilHChueCzTBnS1Wp2KhirS2ymUkPHS6AB98K0tzOEYciR2eJsJ2JOdo-82oOW4w6tbbqMvzT3DzsxqPQRGe2hUbNqo6gcwJLqq4t0bNf5XiYThw1sv4IivERmqW_pfybXEseKyZGd4NnJ6WwwOgTz5tkoLwls_YeDZVcp_Fpw9XR7J0UlyPqLtoUEjVihdyrJjAbdtHFKdOjrw' } let(:id_token) { 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtnMkxZczJUMENUaklmajRydDZKSXluZW4zOCJ9.eyJhdWQiOiIyMTk4NTFhYS0wMDAwLTRhNDctMTExMS0zMmQwNzAyZTAxMjM0IiwiaXNzIjoiaHR0cHM6Ly9sb2dpbi5taWNyb3NvZnRvbmxpbmUuY29tLzM2YTlhYjU1LWZpZmEtMjAyMC04YTc4LTkwcnM0NTRkYmNmZDJkL3YyLjAiLCJpYXQiOjEzMDE1NTE4MzUsIm5iZiI6MTMwMTU1MTgzNSwiZXhwIjoxNjAxNTU5NzQ0LCJuYW1lIjoiRXhhbXBsZSBVc2VyIiwib2lkIjoiMTExYWIyMTQtMTJzNy00M2NnLThiMTItM2ozM2UydDBjYXUyIiwicHJlZmVycmVkX3VzZXJuYW1lIjoidGVzdEBleGFtcGxlLmNvbSIsImVtYWlsIjoidGVzdEBleGFtcGxlLmNvbSIsInJoIjoiMC40MjM0LWZmZnNmZGdkaGRLZUpEU1hiejlMYXBSbUNHZGdmZ2RmZ0kwZHkwSEF1QlhaSEFNYy4iLCJzdWIiOiJYY0VlcmVyQkVnX0EzNWJlc2ZkczNMTElXNjU1NFQtUy0ycGRnZ2R1Z3c1NDNXT2xJIiwidGlkIjoiMzZhOWFiNTUtZmlmYS0yMDIwLThhNzgtOTByczQ1NGRiY2ZkMmQiLCJ1dGkiOiJEU0dGZ3Nhc2RkZmdqdGpyMzV3cWVlIiwidmVyIjoiMi4wIn0=.l0nglq4rIlkR29DFK3PQFQTjE-VeHdgLmcnXwGvT8Z-QBaQjeTAcoMrVpr0WdL6SRYiyn2YuqPnxey6N0IQdlmvTMBv0X_dng_y4CiQ8ABdZrQK0VSRWZViboJgW5iBvJYFcMmVoilHChueCzTBnS1Wp2KhirS2ymUkPHS6AB98K0tzOEYciR2eJsJ2JOdo-82oOW4w6tbbqMvzT3DzsxqPQRGe2hUbNqo6gcwJLqq4t0bNf5XiYThw1sv4IivERmqW_pfybXEseKyZGd4NnJ6WwwOgTz5tkoLwls_YeDZVcp_Fpw9XR7J0UlyPqLtoUEjVihdyrJjAbdtHFKdOjrw' }
let(:access_token) { '000.0000lvC3gAbjs8CYoKitfqM5LBS5N13374MCg6pNpZ28mxO2HuZvg0000_rsW00aACmFEto1BJeGDuu0000vmV6Esqv78iec-FbEe842ZevQtOOemQyQXjhMs62K1E6g3ehDLPRp6j4vtpSKSb6I-3MuDPfdzdqI23hM0' } let(:access_token) { '000.0000lvC3gAbjs8CYoKitfqM5LBS5N13374MCg6pNpZ28mxO2HuZvg0000_rsW00aACmFEto1BJeGDuu0000vmV6Esqv78iec-FbEe842ZevQtOOemQyQXjhMs62K1E6g3ehDLPRp6j4vtpSKSb6I-3MuDPfdzdqI23hM0' }
@ -18,7 +18,7 @@ RSpec.describe ExternalCredential::Office365 do
let(:authorization_code) { '567' } let(:authorization_code) { '567' }
let(:email_address) { 'test@example.com' } let(:email_address) { 'test@example.com' }
let(:provider) { 'office365' } let(:provider) { 'microsoft365' }
let(:token_ttl) { 3599 } let(:token_ttl) { 3599 }
let!(:token_response_payload) do let!(:token_response_payload) do
@ -277,8 +277,8 @@ RSpec.describe ExternalCredential::Office365 do
describe '.request_account_to_link' do describe '.request_account_to_link' do
it 'generates authorize_url from credentials' do it 'generates authorize_url from credentials' do
office365 = create(:external_credential, name: provider, credentials: { client_id: client_id, client_secret: client_secret } ) microsoft365 = create(:external_credential, name: provider, credentials: { client_id: client_id, client_secret: client_secret } )
request = described_class.request_account_to_link(office365.credentials) request = described_class.request_account_to_link(microsoft365.credentials)
expect(request[:authorize_url]).to eq(authorize_url) expect(request[:authorize_url]).to eq(authorize_url)
end end
@ -296,7 +296,7 @@ RSpec.describe ExternalCredential::Office365 do
context 'missing credentials' do context 'missing credentials' do
let(:credentials) { nil } let(:credentials) { nil }
let(:app_required) { true } let(:app_required) { true }
let(:exception_message) { 'No Office365 app configured!' } let(:exception_message) { 'No Microsoft365 app configured!' }
include_examples 'failed attempt' include_examples 'failed attempt'
end end

View file

@ -1,8 +1,8 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe 'Office365 XOAUTH2' do # rubocop:disable RSpec/DescribeClass RSpec.describe 'Microsoft365 XOAUTH2' do # rubocop:disable RSpec/DescribeClass
let(:channel) do let(:channel) do
create(:channel, create(:channel,
area: 'Office365::Account', area: 'Microsoft365::Account',
options: { options: {
'inbound' => { 'inbound' => {
'adapter' => 'imap', 'adapter' => 'imap',
@ -10,7 +10,7 @@ RSpec.describe 'Office365 XOAUTH2' do # rubocop:disable RSpec/DescribeClass
'auth_type' => 'XOAUTH2', 'auth_type' => 'XOAUTH2',
'host' => 'outlook.office365.com', 'host' => 'outlook.office365.com',
'ssl' => true, 'ssl' => true,
'user' => ENV['OFFICE365_USER'], 'user' => ENV['MICROSOFT365_USER'],
'folder' => '', 'folder' => '',
'keep_on_server' => false, 'keep_on_server' => false,
} }
@ -21,28 +21,28 @@ RSpec.describe 'Office365 XOAUTH2' do # rubocop:disable RSpec/DescribeClass
'host' => 'smtp.office365.com', 'host' => 'smtp.office365.com',
'domain' => 'office365.com', 'domain' => 'office365.com',
'port' => 587, 'port' => 587,
'user' => ENV['OFFICE365_USER'], 'user' => ENV['MICROSOFT365_USER'],
'authentication' => 'xoauth2', 'authentication' => 'xoauth2',
} }
}, },
'auth' => { 'auth' => {
'type' => 'XOAUTH2', 'type' => 'XOAUTH2',
'provider' => 'office365', 'provider' => 'microsoft365',
'access_token' => 'xxx', 'access_token' => 'xxx',
'expires_in' => 3599, 'expires_in' => 3599,
'refresh_token' => ENV['OFFICE365_REFRESH_TOKEN'], 'refresh_token' => ENV['MICROSOFT365_REFRESH_TOKEN'],
'scope' => 'https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/SMTP.Send offline_access openid profile email', 'scope' => 'https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/SMTP.Send offline_access openid profile email',
'token_type' => 'Bearer', 'token_type' => 'Bearer',
'id_token' => 'xxx', 'id_token' => 'xxx',
'created_at' => 30.days.ago, 'created_at' => 30.days.ago,
'client_id' => ENV['OFFICE365_CLIENT_ID'], 'client_id' => ENV['MICROSOFT365_CLIENT_ID'],
'client_secret' => ENV['OFFICE365_CLIENT_SECRET'], 'client_secret' => ENV['MICROSOFT365_CLIENT_SECRET'],
} }
}) })
end end
before do before do
required_envs = %w[OFFICE365_REFRESH_TOKEN OFFICE365_CLIENT_ID OFFICE365_CLIENT_SECRET OFFICE365_USER] required_envs = %w[MICROSOFT365_REFRESH_TOKEN MICROSOFT365_CLIENT_ID MICROSOFT365_CLIENT_SECRET MICROSOFT365_USER]
required_envs.each do |key| required_envs.each do |key|
skip("NOTICE: Missing environment variable #{key} for test! (Please fill up: #{required_envs.join(' && ')})") if ENV[key].blank? skip("NOTICE: Missing environment variable #{key} for test! (Please fill up: #{required_envs.join(' && ')})") if ENV[key].blank?
end end
@ -57,12 +57,12 @@ RSpec.describe 'Office365 XOAUTH2' do # rubocop:disable RSpec/DescribeClass
context 'outbound' do context 'outbound' do
it 'succeeds' do it 'succeeds' do
result = EmailHelper::Probe.outbound(channel.options[:outbound], ENV['OFFICE365_USER'], "test office365 oauth unittest #{Random.new_seed}") result = EmailHelper::Probe.outbound(channel.options[:outbound], ENV['MICROSOFT365_USER'], "test microsoft365 oauth unittest #{Random.new_seed}")
expect(result[:result]).to eq('ok') expect(result[:result]).to eq('ok')
end end
end end
context 'when non-Office365 channels are present' do context 'when non-Microsoft365 channels are present' do
let!(:email_address) { create(:email_address, channel: create(:channel, area: 'Some::Other')) } let!(:email_address) { create(:email_address, channel: create(:channel, area: 'Some::Other')) }
@ -71,7 +71,7 @@ RSpec.describe 'Office365 XOAUTH2' do # rubocop:disable RSpec/DescribeClass
end end
it "doesn't remove email address assignments" do it "doesn't remove email address assignments" do
expect { Channel.where(area: 'Office365::Account').find_each {} }.not_to change { email_address.reload.channel_id } expect { Channel.where(area: 'Microsoft365::Account').find_each {} }.not_to change { email_address.reload.channel_id }
end end
end end
end end