-
Notifications
You must be signed in to change notification settings - Fork 731
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixes #5010 - WhatsApp Business Channel (first iteration)
Co-authored-by: Benjamin Scharf <bs@zammad.com> Co-authored-by: Dominik Klein <dk@zammad.com> Co-authored-by: Dusan Vuckovic <dv@zammad.com> Co-authored-by: Mantas Masalskis <mm@zammad.com> Co-authored-by: Martin Gruner <mg@zammad.com> Co-authored-by: Tobias Schäfer <ts@zammad.com>
- Loading branch information
1 parent
40cc955
commit 1ef8c23
Showing
67 changed files
with
2,773 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
270 changes: 270 additions & 0 deletions
270
app/assets/javascripts/app/controllers/_channel/whatsapp.coffee
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,270 @@ | ||
class ChannelWhatsapp extends App.ControllerSubContent | ||
@requiredPermission: 'admin.channel_whatsapp' | ||
events: | ||
'click .js-new': 'new' | ||
'click .js-edit': 'edit' | ||
'click .js-delete': 'delete' | ||
'click .js-disable': 'disable' | ||
'click .js-enable': 'enable' | ||
|
||
constructor: -> | ||
super | ||
|
||
@load() | ||
|
||
load: => | ||
@startLoading() | ||
@ajax( | ||
id: 'whatsapp_index' | ||
type: 'GET' | ||
url: "#{@apiPath}/channels/admin/whatsapp" | ||
processData: true | ||
success: (data) => | ||
@stopLoading() | ||
App.Collection.loadAssets(data.assets) | ||
@render(data) | ||
) | ||
|
||
render: (data) => | ||
channels = data.channel_ids.map (elem) -> App.Channel.find(elem) | ||
|
||
@html App.view('whatsapp/index')( | ||
channels: channels | ||
) | ||
|
||
new: (e) => | ||
e.preventDefault() | ||
|
||
new WhatsappAccountCloudAPIModal( | ||
container: @el.parents('.content') | ||
load: @load | ||
headPrefix: __('New') | ||
) | ||
|
||
edit: (e) => | ||
e.preventDefault() | ||
|
||
id = $(e.target).closest('.action').data('id') | ||
channel = App.Channel.find(id) | ||
|
||
new WhatsappAccountCloudAPIModal( | ||
container: @el.parents('.content') | ||
channel: channel | ||
load: @load | ||
headPrefix: __('Edit') | ||
) | ||
|
||
delete: (e) => | ||
e.preventDefault() | ||
id = $(e.target).closest('.action').data('id') | ||
|
||
new App.ControllerConfirm( | ||
message: __('Are you sure?') | ||
buttonClass: 'btn--danger' | ||
callback: => | ||
@ajax( | ||
id: 'whatsapp_delete' | ||
type: 'DELETE' | ||
url: "#{@apiPath}/channels/admin/whatsapp/#{id}" | ||
processData: true | ||
success: => | ||
@load() | ||
) | ||
container: @el.closest('.content') | ||
) | ||
|
||
disable: (e) => | ||
e.preventDefault() | ||
|
||
id = $(e.target).closest('.action').data('id') | ||
|
||
@ajax( | ||
id: 'whatsapp_disable' | ||
type: 'POST' | ||
url: "#{@apiPath}/channels/admin/whatsapp/#{id}/disable" | ||
data: JSON.stringify(id: id) | ||
processData: true | ||
success: => | ||
@load() | ||
) | ||
|
||
enable: (e) => | ||
e.preventDefault() | ||
|
||
id = $(e.target).closest('.action').data('id') | ||
|
||
@ajax( | ||
id: 'whatsapp_enable' | ||
type: 'POST' | ||
url: "#{@apiPath}/channels/admin/whatsapp/#{id}/enable" | ||
processData: true | ||
success: => | ||
@load() | ||
) | ||
|
||
class WhatsappAccountCloudAPIModal extends App.ControllerModal | ||
head: __('WhatsApp Account') | ||
shown: true | ||
buttonSubmit: __('Next') | ||
buttonClass: 'btn--primary' | ||
buttonCancel: true | ||
small: true | ||
|
||
content: => | ||
$(App.view('whatsapp/account_cloud_api')( | ||
channel: @channel | ||
params: @params | ||
)) | ||
|
||
onSubmit: (e) => | ||
element = $(e.target).closest('form').get(0) | ||
if element && element.reportValidity && !element.reportValidity() | ||
return false | ||
|
||
@clearAlerts() | ||
@formDisable(e) | ||
|
||
params = if @params then _.extend(@params, @formParams()) else @formParams() | ||
|
||
@ajax( | ||
id: 'whatsapp_initial' | ||
type: 'POST' | ||
url: "#{@apiPath}/channels/admin/whatsapp/preload" | ||
data: JSON.stringify(params) | ||
processData: true | ||
success: (data) => | ||
@el.removeClass('fade') | ||
@close() | ||
|
||
params.available_phone_numbers = data.data.phone_numbers | ||
|
||
new WhatsappAccountPhoneNumberModal( | ||
params: params | ||
channel: @channel | ||
container: @container | ||
load: @load | ||
headPrefix: @headPrefix | ||
) | ||
error: (xhr) => | ||
data = JSON.parse(xhr.responseText) | ||
@formEnable(e) | ||
error_message = App.i18n.translateContent(data.error || __('The WhatsApp connection could not be saved.')) | ||
@showAlert(error_message) | ||
) | ||
|
||
class WhatsappAccountPhoneNumberModal extends App.ControllerModal | ||
head: __('WhatsApp Account') | ||
shown: true | ||
buttonCancel: true | ||
small: true | ||
|
||
content: => | ||
content = $(App.view('whatsapp/account_phone_number')( | ||
channel: @channel | ||
params: @params | ||
)) | ||
|
||
preselected_group_id = if @channel then @channel.group_id else 1 | ||
|
||
content.find('.js-messagesGroup').replaceWith App.UiElement.tree_select.render( | ||
name: 'group_id' | ||
multiple: false | ||
limit: 100 | ||
null: false | ||
relation: 'Group' | ||
nulloption: true | ||
value: preselected_group_id | ||
) | ||
|
||
content.find('.js-phoneNumbers').replaceWith App.UiElement.select.render( | ||
name: 'phone_number_id' | ||
multiple: false | ||
value: @channel?.options?.phone_number_id || @params.available_phone_numbers?[0]?.value | ||
options: @params.available_phone_numbers?.map (elem) -> { name: elem.label, value: elem.value } | ||
) | ||
|
||
content | ||
|
||
onClosed: => | ||
return if !@isChanged | ||
@isChanged = false | ||
@load() | ||
|
||
onSubmit: (e) => | ||
element = $(e.target).closest('form').get(0) | ||
if element && element.reportValidity && !element.reportValidity() | ||
return false | ||
|
||
@clearAlerts() | ||
|
||
if @channel | ||
url = "#{@apiPath}/channels/admin/whatsapp/#{@channel.id}" | ||
method = 'PUT' | ||
else | ||
url = "#{@apiPath}/channels/admin/whatsapp" | ||
method = 'POST' | ||
|
||
@formDisable(e) | ||
|
||
params = @formParams() | ||
|
||
@ajax( | ||
id: 'whatsapp_save' | ||
type: method | ||
url: url | ||
data: JSON.stringify(params) | ||
processData: true | ||
success: (data) => | ||
@isChanged = true | ||
@el.removeClass('fade') | ||
@close() | ||
|
||
new WhatsappAccountWebhookModal( | ||
channel: data | ||
container: @container | ||
headPrefix: @headPrefix | ||
) | ||
error: (xhr) => | ||
data = JSON.parse(xhr.responseText) | ||
@formEnable(e) | ||
error_message = App.i18n.translateContent(data.error || __('The WhatsApp connection could not be saved.')) | ||
@showAlert(error_message) | ||
) | ||
|
||
class WhatsappAccountWebhookModal extends App.ControllerModal | ||
head: __('WhatsApp Account') | ||
shown: true | ||
buttonSubmit: __('Finish') | ||
buttonClass: 'btn--primary' | ||
small: true | ||
events: | ||
'click .js-copy': 'copyToClipboard' | ||
|
||
content: => | ||
content = $(App.view('whatsapp/account_webhook')( | ||
channel: @channel | ||
callback_url: "#{@Config.get('http_type')}://#{@Config.get('fqdn')}/#{@apiPath}/channels_whatsapp_webhook/#{@channel.options?.callback_url_uuid}" | ||
)) | ||
|
||
content | ||
|
||
onSubmit: (e) => | ||
@close() | ||
|
||
copyToClipboard: (e) => | ||
e.preventDefault() | ||
|
||
button = $(e.target).parents('[role="button"]') | ||
field_name = button.data('targetField') | ||
value = $(@container).find("input[name='#{jQuery.escapeSelector(field_name)}']").val() | ||
|
||
@copyToClipboardWithTooltip(value, e.target,'.modal-body', true) | ||
|
||
App.Config.set('Whatsapp', { | ||
prio: 5100, | ||
name: __('WhatsApp'), | ||
parent: '#channels', | ||
target: '#channels/whatsapp', | ||
controller: ChannelWhatsapp, | ||
permission: ['admin.channel_whatsapp'] | ||
}, 'NavBarAdmin') |
34 changes: 34 additions & 0 deletions
34
app/assets/javascripts/app/views/whatsapp/account_cloud_api.jst.eco
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
<div class="alert alert--danger hidden" role="alert"></div> | ||
<p> | ||
<%- @T('You can find a tutorial on how to manage a %s in our online documentation %l.', 'WhatsApp Business Account', 'https://admin-docs.zammad.org/en/latest/channels/whatsapp.html') %> | ||
</p> | ||
<fieldset> | ||
<h2><%- @T('Step 1 of 3: WhatsApp Business Cloud API') %></h2> | ||
|
||
<div class="input form-group"> | ||
<div class="formGroup-label"> | ||
<label for="business_id"><%- @T('WhatsApp Business Account ID') %><% if !@channel: %> <span>*</span><% end %></label> | ||
</div> | ||
<div class="controls"> | ||
<input id="business_id" type="text" name="business_id" value="<%= @params?.business_id || @channel?.options?.business_id %>" class="form-control" <% if @channel: %>disabled<% else: %>required autocomplete="off"<% end %>> | ||
</div> | ||
</div> | ||
|
||
<div class="input form-group"> | ||
<div class="formGroup-label"> | ||
<label for="access_token"><%- @T('Access token') %> <span>*</span></label> | ||
</div> | ||
<div class="controls"> | ||
<input id="access_token" type="text" name="access_token" value="<%= @params?.access_token || @channel?.options?.access_token %>" class="form-control" required autocomplete="off"> | ||
</div> | ||
</div> | ||
|
||
<div class="input form-group"> | ||
<div class="formGroup-label"> | ||
<label for="app_secret"><%- @T('App secret') %> <span>*</span></label> | ||
</div> | ||
<div class="controls"> | ||
<input id="app_secret" type="text" name="app_secret" value="<%= @params?.app_secret || @channel?.options?.app_secret %>" class="form-control" required autocomplete="off"> | ||
</div> | ||
</div> | ||
</fieldset> |
Oops, something went wrong.