Organize directories

This commit is contained in:
Darren Clarke 2023-02-13 13:10:48 +00:00
parent 8a91c9b89b
commit 4898382f78
433 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,256 @@
class Index extends App.ControllerIntegrationBase
featureIntegration: 'pgp_integration'
featureName: 'PGP'
featureConfig: 'pgp_config'
description: [
['PGP (Pretty Good Privacy) is a widely accepted method (or more precisely, a protocol) for sending digitally signed and encrypted messages.']
]
events:
'change .js-switch input': 'switch'
render: =>
super
new Form(
el: @$('.js-form')
)
new App.HttpLog(
el: @$('.js-log')
facility: 'PGP'
)
class Form extends App.Controller
events:
'click .js-addPublicKey': 'addPublicKey'
'click .js-addPrivateKey': 'addPrivateKey'
'click .js-updateGroup': 'updateGroup'
constructor: ->
super
@render()
currentConfig: ->
App.Setting.get('pgp_config')
setConfig: (value) ->
App.Setting.set('pgp_config', value, {notify: true})
render: =>
@config = @currentConfig()
@html App.view('integration/pgp')(
config: @config
)
@keyList()
@groupList()
keyList: =>
new List(el: @$('.js-keyList'))
groupList: =>
new Group(
el: @$('.js-groupList')
config: @config
)
addPublicKey: =>
new PublicKey(
callback: @keyList
)
addPrivateKey: =>
new PrivateKey(
callback: @keyList
)
updateGroup: (e) =>
params = App.ControllerForm.params(e)
@setConfig(params)
class PublicKey extends App.ControllerModal
buttonClose: true
buttonCancel: true
buttonSubmit: 'Add'
autoFocusOnFirstInput: false
head: 'Add Public Key'
large: true
content: ->
# show start dialog
content = $(App.view('integration/pgp_public_key_add')(
head: 'Add Public Key'
))
content
onSubmit: (e) =>
params = new FormData($(e.currentTarget).closest('form').get(0))
params.set('try', true)
if _.isEmpty(params.get('data'))
params.delete('data')
@formDisable(e)
@ajax(
id: 'pgp-public_key-add'
type: 'POST'
url: "#{@apiPath}/integration/pgp/public_key"
processData: false
contentType: false
cache: false
data: params
success: (data, status, xhr) =>
@close()
@callback()
error: (data) =>
@close()
details = data.responseJSON || {}
@notify
type: 'error'
msg: App.i18n.translateContent(details.error_human || details.error || 'The import failed.')
timeout: 6000
)
class PrivateKey extends App.ControllerModal
buttonClose: true
buttonCancel: true
buttonSubmit: 'Add'
autoFocusOnFirstInput: false
head: 'Add Private Key'
large: true
content: ->
# show start dialog
content = $(App.view('integration/pgp_private_key_add')(
head: 'Add Private Key'
))
content
onSubmit: (e) =>
params = new FormData($(e.currentTarget).closest('form').get(0))
params.set('try', true)
if _.isEmpty(params.get('data'))
params.delete('data')
@formDisable(e)
@ajax(
id: 'pgp-private_key-add'
type: 'POST'
url: "#{@apiPath}/integration/pgp/private_key"
processData: false
contentType: false
cache: false
data: params
success: (data, status, xhr) =>
@close()
@callback()
error: (data) =>
@close()
details = data.responseJSON || {}
@notify
type: 'error'
msg: App.i18n.translateContent(details.error_human || details.error || 'The import failed.')
timeout: 6000
)
class List extends App.Controller
events:
'click .js-remove': 'remove'
constructor: ->
super
@load()
load: =>
@ajax(
id: 'pgp-list'
type: 'GET'
url: "#{@apiPath}/integration/pgp/public_key"
success: (data, status, xhr) =>
@render(data)
error: (data, status) =>
# do not close window if request is aborted
return if status is 'abort'
details = data.responseJSON || {}
@notify(
type: 'error'
msg: App.i18n.translateContent(details.error_human || details.error || 'Loading failed.')
)
# do something
)
render: (data) =>
@html App.view('integration/pgp_list')(
keyPairs: data
)
remove: (e) =>
e.preventDefault()
id = $(e.currentTarget).parents('tr').data('id')
return if !id
@ajax(
id: 'pgp-list'
type: 'DELETE'
url: "#{@apiPath}/integration/pgp/public_key"
data: JSON.stringify(id: id)
success: (data, status, xhr) =>
@load()
error: (data, status) =>
# do not close window if request is aborted
return if status is 'abort'
details = data.responseJSON || {}
@notify(
type: 'error'
msg: App.i18n.translateContent(details.error_human || details.error || 'Server operation failed.')
)
)
class Group extends App.Controller
constructor: ->
super
@render()
render: (data) =>
groups = App.Group.search(sortBy: 'name', filter: active: true)
@html App.view('integration/pgp_group')(
groups: groups
)
for group in groups
for type, selector of { default_sign: 'js-signDefault', default_encryption: 'js-encryptionDefault' }
selected = true
if @config?.group_id && @config.group_id[type]
selected = @config.group_id[type][group.id.toString()]
selection = App.UiElement.boolean.render(
name: "group_id::#{type}::#{group.id}"
multiple: false
null: false
nulloption: false
value: selected
class: 'form-control--small'
)
@$("[data-id=#{group.id}] .#{selector}").html(selection)
class State
@current: ->
App.Setting.get('pgp_integration')
App.Config.set(
'Integrationpgp'
{
name: 'PGP'
target: '#system/integration/pgp'
description: 'PGP enables you to send digitally signed and encrypted messages.'
controller: Index
state: State
}
'NavBarIntegrations'
)

View file

@ -0,0 +1,614 @@
# coffeelint: disable=camel_case_classes
class App.UiElement.ticket_perform_action
@defaults: (attribute) ->
defaults = ['ticket.state_id']
groups =
ticket:
name: 'Ticket'
model: 'Ticket'
article:
name: 'Article'
model: 'Article'
if attribute.notification
groups.notification =
name: 'Notification'
model: 'Notification'
# merge config
elements = {}
for groupKey, groupMeta of groups
if !groupMeta.model || !App[groupMeta.model]
if groupKey is 'notification'
elements["#{groupKey}.email"] = { name: 'email', display: 'Email' }
elements["#{groupKey}.sms"] = { name: 'sms', display: 'SMS' }
elements["#{groupKey}.webhook"] = { name: 'webhook', display: 'Webhook' }
else if groupKey is 'article'
elements["#{groupKey}.note"] = { name: 'note', display: 'Note' }
else
for row in App[groupMeta.model].configure_attributes
# ignore passwords and relations
if row.type isnt 'password' && row.name.substr(row.name.length-4,4) isnt '_ids'
# ignore readonly attributes
if !row.readonly
config = _.clone(row)
switch config.tag
when 'datetime'
config.operator = ['static', 'relative']
when 'tag'
config.operator = ['add', 'remove']
elements["#{groupKey}.#{config.name}"] = config
# add ticket deletion action
if attribute.ticket_delete
elements['ticket.action'] =
name: 'action'
display: 'Action'
tag: 'select'
null: false
translate: true
options:
delete: 'Delete'
[defaults, groups, elements]
@placeholder: (elementFull, attribute, params, groups, elements) ->
item = $( App.view('generic/ticket_perform_action/row')( attribute: attribute ) )
selector = @buildAttributeSelector(elementFull, groups, elements)
item.find('.js-attributeSelector').prepend(selector)
item
@render: (attribute, params = {}) ->
[defaults, groups, elements] = @defaults(attribute)
# return item
item = $( App.view('generic/ticket_perform_action/index')( attribute: attribute ) )
# add filter
item.on('click', '.js-rowActions .js-add', (e) =>
element = $(e.target).closest('.js-filterElement')
placeholder = @placeholder(item, attribute, params, groups, elements)
if element.get(0)
element.after(placeholder)
else
item.append(placeholder)
placeholder.find('.js-attributeSelector select').trigger('change')
@updateAttributeSelectors(item)
)
# remove filter
item.on('click', '.js-rowActions .js-remove', (e) =>
return if $(e.currentTarget).hasClass('is-disabled')
$(e.target).closest('.js-filterElement').remove()
@updateAttributeSelectors(item)
)
# change attribute selector
item.on('change', '.js-attributeSelector select', (e) =>
elementRow = $(e.target).closest('.js-filterElement')
groupAndAttribute = elementRow.find('.js-attributeSelector option:selected').attr('value')
@rebuildAttributeSelectors(item, elementRow, groupAndAttribute, elements, {}, attribute)
@updateAttributeSelectors(item)
)
# change operator selector
item.on('change', '.js-operator select', (e) =>
elementRow = $(e.target).closest('.js-filterElement')
groupAndAttribute = elementRow.find('.js-attributeSelector option:selected').attr('value')
@buildOperator(item, elementRow, groupAndAttribute, elements, {}, attribute)
)
# build initial params
if _.isEmpty(params[attribute.name])
for groupAndAttribute in defaults
# build and append
element = @placeholder(item, attribute, params, groups, elements)
item.append(element)
@rebuildAttributeSelectors(item, element, groupAndAttribute, elements, {}, attribute)
else
for groupAndAttribute, meta of params[attribute.name]
# build and append
element = @placeholder(item, attribute, params, groups, elements)
@rebuildAttributeSelectors(item, element, groupAndAttribute, elements, meta, attribute)
item.append(element)
@disableRemoveForOneAttribute(item)
item
@buildAttributeSelector: (elementFull, groups, elements) ->
# find first possible attribute
selectedValue = ''
elementFull.find('.js-attributeSelector select option').each(->
if !selectedValue && !$(@).prop('disabled')
selectedValue = $(@).val()
)
selection = $('<select class="form-control"></select>')
for groupKey, groupMeta of groups
displayName = App.i18n.translateInline(groupMeta.name)
selection.closest('select').append("<optgroup label=\"#{displayName}\" class=\"js-#{groupKey}\"></optgroup>")
optgroup = selection.find("optgroup.js-#{groupKey}")
for elementKey, elementGroup of elements
spacer = elementKey.split(/\./)
if spacer[0] is groupKey
attributeConfig = elements[elementKey]
displayName = App.i18n.translateInline(attributeConfig.display)
selected = ''
if elementKey is selectedValue
selected = 'selected="selected"'
optgroup.append("<option value=\"#{elementKey}\" #{selected}>#{displayName}</option>")
selection
# disable - if we only have one attribute
@disableRemoveForOneAttribute: (elementFull) ->
if elementFull.find('.js-attributeSelector select').length > 1
elementFull.find('.js-remove').removeClass('is-disabled')
else
elementFull.find('.js-remove').addClass('is-disabled')
@updateAttributeSelectors: (elementFull) ->
# enable all
elementFull.find('.js-attributeSelector select option').prop('disabled', false)
# disable all used attributes
elementFull.find('.js-attributeSelector select').each(->
keyLocal = $(@).val()
elementFull.find('.js-attributeSelector select option[value="' + keyLocal + '"]').attr('disabled', true)
)
# disable - if we only have one attribute
@disableRemoveForOneAttribute(elementFull)
@rebuildAttributeSelectors: (elementFull, elementRow, groupAndAttribute, elements, meta, attribute) ->
# set attribute
if groupAndAttribute
elementRow.find('.js-attributeSelector select').val(groupAndAttribute)
notificationTypeMatch = groupAndAttribute.match(/^notification.([\w]+)$/)
articleTypeMatch = groupAndAttribute.match(/^article.([\w]+)$/)
if _.isArray(notificationTypeMatch) && notificationType = notificationTypeMatch[1]
elementRow.find('.js-setAttribute').html('').addClass('hide')
elementRow.find('.js-setArticle').html('').addClass('hide')
@buildNotificationArea(notificationType, elementFull, elementRow, groupAndAttribute, elements, meta, attribute)
else if _.isArray(articleTypeMatch) && articleType = articleTypeMatch[1]
elementRow.find('.js-setAttribute').html('').addClass('hide')
elementRow.find('.js-setNotification').html('').addClass('hide')
@buildArticleArea(articleType, elementFull, elementRow, groupAndAttribute, elements, meta, attribute)
else
elementRow.find('.js-setNotification').html('').addClass('hide')
elementRow.find('.js-setArticle').html('').addClass('hide')
if !elementRow.find('.js-setAttribute div').get(0)
attributeSelectorElement = $( App.view('generic/ticket_perform_action/attribute_selector')(
attribute: attribute
name: name
meta: meta || {}
))
elementRow.find('.js-setAttribute').html(attributeSelectorElement).removeClass('hide')
@buildOperator(elementFull, elementRow, groupAndAttribute, elements, meta, attribute)
@buildOperator: (elementFull, elementRow, groupAndAttribute, elements, meta, attribute) ->
currentOperator = elementRow.find('.js-operator option:selected').attr('value')
if !meta.operator
meta.operator = currentOperator
name = "#{attribute.name}::#{groupAndAttribute}::operator"
selection = $("<select class=\"form-control\" name=\"#{name}\"></select>")
attributeConfig = elements[groupAndAttribute]
if !attributeConfig || !attributeConfig.operator
elementRow.find('.js-operator').parent().addClass('hide')
else
elementRow.find('.js-operator').parent().removeClass('hide')
if attributeConfig && attributeConfig.operator
for operator in attributeConfig.operator
operatorName = App.i18n.translateInline(operator)
selected = ''
if meta.operator is operator
selected = 'selected="selected"'
selection.append("<option value=\"#{operator}\" #{selected}>#{operatorName}</option>")
selection
elementRow.find('.js-operator select').replaceWith(selection)
@buildPreCondition(elementFull, elementRow, groupAndAttribute, elements, meta, attribute)
@buildPreCondition: (elementFull, elementRow, groupAndAttribute, elements, meta, attributeConfig) ->
currentOperator = elementRow.find('.js-operator option:selected').attr('value')
currentPreCondition = elementRow.find('.js-preCondition option:selected').attr('value')
if !meta.pre_condition
meta.pre_condition = currentPreCondition
toggleValue = =>
preCondition = elementRow.find('.js-preCondition option:selected').attr('value')
if preCondition isnt 'specific'
elementRow.find('.js-value select').html('')
elementRow.find('.js-value').addClass('hide')
else
elementRow.find('.js-value').removeClass('hide')
@buildValue(elementFull, elementRow, groupAndAttribute, elements, meta, attribute)
# force to use auto complition on user lookup
attribute = _.clone(attributeConfig)
name = "#{attribute.name}::#{groupAndAttribute}::value"
attributeSelected = elements[groupAndAttribute]
preCondition = false
if attributeSelected.relation is 'User'
preCondition = 'user'
attribute.tag = 'user_autocompletion'
if attributeSelected.relation is 'Organization'
preCondition = 'org'
attribute.tag = 'autocompletion_ajax'
if !preCondition
elementRow.find('.js-preCondition select').html('')
elementRow.find('.js-preCondition').closest('.controls').addClass('hide')
toggleValue()
@buildValue(elementFull, elementRow, groupAndAttribute, elements, meta, attribute)
return
elementRow.find('.js-preCondition').closest('.controls').removeClass('hide')
name = "#{attribute.name}::#{groupAndAttribute}::pre_condition"
selection = $("<select class=\"form-control\" name=\"#{name}\" ></select>")
options = {}
if preCondition is 'user'
options =
'current_user.id': App.i18n.translateInline('current user')
'specific': App.i18n.translateInline('specific user')
if attributeSelected.null is true
options['not_set'] = App.i18n.translateInline('unassign user')
else if preCondition is 'org'
options =
'current_user.organization_id': App.i18n.translateInline('current user organization')
'specific': App.i18n.translateInline('specific organization')
for key, value of options
selected = ''
if key is meta.pre_condition
selected = 'selected="selected"'
selection.append("<option value=\"#{key}\" #{selected}>#{App.i18n.translateInline(value)}</option>")
elementRow.find('.js-preCondition').closest('.controls').removeClass('hide')
elementRow.find('.js-preCondition select').replaceWith(selection)
elementRow.find('.js-preCondition select').on('change', (e) ->
toggleValue()
)
@buildValue(elementFull, elementRow, groupAndAttribute, elements, meta, attribute)
toggleValue()
@buildValue: (elementFull, elementRow, groupAndAttribute, elements, meta, attribute) ->
name = "#{attribute.name}::#{groupAndAttribute}::value"
# build new item
attributeConfig = elements[groupAndAttribute]
config = _.clone(attributeConfig)
if config.relation is 'User'
config.tag = 'user_autocompletion'
if config.relation is 'Organization'
config.tag = 'autocompletion_ajax'
# render ui element
item = ''
if config && App.UiElement[config.tag]
config['name'] = name
if attribute.value && attribute.value[groupAndAttribute]
config['value'] = _.clone(attribute.value[groupAndAttribute]['value'])
config.multiple = false
config.nulloption = config.null
if config.tag is 'checkbox'
config.tag = 'select'
tagSearch = "#{config.tag}_search"
if config.tag is 'datetime'
config.validationContainer = 'self'
if App.UiElement[tagSearch]
item = App.UiElement[tagSearch].render(config, {})
else
item = App.UiElement[config.tag].render(config, {})
relative_operators = [
'before (relative)',
'within next (relative)',
'within last (relative)',
'after (relative)',
'till (relative)',
'from (relative)',
'relative'
]
upcoming_operator = meta.operator
if !_.include(config.operator, upcoming_operator)
if Array.isArray(config.operator)
upcoming_operator = config.operator[0]
else
upcoming_operator = null
if _.include(relative_operators, upcoming_operator)
config['name'] = "#{attribute.name}::#{groupAndAttribute}"
if attribute.value && attribute.value[groupAndAttribute]
config['value'] = _.clone(attribute.value[groupAndAttribute])
item = App.UiElement['time_range'].render(config, {})
elementRow.find('.js-setAttribute > .flex > .js-value').removeClass('hide').html(item)
@buildNotificationArea: (notificationType, elementFull, elementRow, groupAndAttribute, elements, meta, attribute) ->
return if elementRow.find(".js-setNotification .js-body-#{notificationType}").get(0)
elementRow.find('.js-setNotification').empty()
options =
'article_last_sender': 'Sender of last article'
'ticket_owner': 'Owner'
'ticket_customer': 'Customer'
'ticket_agents': 'All agents'
name = "#{attribute.name}::notification.#{notificationType}"
messageLength = switch notificationType
when 'sms' then 160
else 200000
# meta.recipient was a string in the past (single-select) so we convert it to array if needed
if !_.isArray(meta.recipient)
meta.recipient = [meta.recipient]
columnSelectOptions = []
for key, value of options
selected = undefined
for recipient in meta.recipient
if key is recipient
selected = true
columnSelectOptions.push({ value: key, name: App.i18n.translatePlain(value), selected: selected })
columnSelectRecipientUserOptions = []
for user in App.User.all()
key = "userid_#{user.id}"
selected = undefined
for recipient in meta.recipient
if key is recipient
selected = true
columnSelectRecipientUserOptions.push({ value: key, name: "#{user.firstname} #{user.lastname}", selected: selected })
columnSelectRecipient = new App.ColumnSelect
attribute:
name: "#{name}::recipient"
options: [
{
label: 'Variables',
group: columnSelectOptions
},
{
label: 'User',
group: columnSelectRecipientUserOptions
},
]
selectionRecipient = columnSelectRecipient.element()
if notificationType is 'webhook'
notificationElement = $( App.view('generic/ticket_perform_action/webhook')(
attribute: attribute
name: name
notificationType: notificationType
meta: meta || {}
))
notificationElement.find('.js-recipient select').replaceWith(selectionRecipient)
if App.Webhook.search(filter: { active: true }).length isnt 0 || !_.isEmpty(meta.webhook_id)
webhookSelection = App.UiElement.select.render(
name: "#{name}::webhook_id"
multiple: false
null: false
relation: 'Webhook'
value: meta.webhook_id
translate: false
nulloption: true
)
else
webhookSelection = App.view('generic/ticket_perform_action/webhook_not_available')( attribute: attribute )
notificationElement.find('.js-webhooks').html(webhookSelection)
else
notificationElement = $( App.view('generic/ticket_perform_action/notification')(
attribute: attribute
name: name
notificationType: notificationType
meta: meta || {}
))
notificationElement.find('.js-recipient select').replaceWith(selectionRecipient)
visibilitySelection = App.UiElement.select.render(
name: "#{name}::internal"
multiple: false
null: false
options: { true: 'internal', false: 'public' }
value: meta.internal || 'false'
translate: true
)
includeAttachmentsCheckbox = App.UiElement.select.render(
name: "#{name}::include_attachments"
multiple: false
null: false
options: { true: 'Yes', false: 'No' }
value: meta.include_attachments || 'false'
translate: true
)
notificationElement.find('.js-internal').html(visibilitySelection)
notificationElement.find('.js-include_attachments').html(includeAttachmentsCheckbox)
notificationElement.find('.js-body div[contenteditable="true"]').ce(
mode: 'richtext'
placeholder: 'message'
maxlength: messageLength
)
new App.WidgetPlaceholder(
el: notificationElement.find('.js-body div[contenteditable="true"]').parent()
objects: [
{
prefix: 'ticket'
object: 'Ticket'
display: 'Ticket'
},
{
prefix: 'article'
object: 'TicketArticle'
display: 'Article'
},
{
prefix: 'user'
object: 'User'
display: 'Current User'
},
]
)
elementRow.find('.js-setNotification').html(notificationElement).removeClass('hide')
if App.Config.get('smime_integration') == true || App.Config.get('pgp_integration') == true
selection = App.UiElement.select.render(
name: "#{name}::sign"
multiple: false
options: {
'no': 'Do not sign email'
'discard': 'Sign email (if not possible, discard notification)'
'always': 'Sign email (if not possible, send notification anyway)'
}
value: meta.sign
translate: true
)
elementRow.find('.js-sign').html(selection)
selection = App.UiElement.select.render(
name: "#{name}::encryption"
multiple: false
options: {
'no': 'Do not encrypt email'
'discard': 'Encrypt email (if not possible, discard notification)'
'always': 'Encrypt email (if not possible, send notification anyway)'
}
value: meta.encryption
translate: true
)
elementRow.find('.js-encryption').html(selection)
@buildArticleArea: (articleType, elementFull, elementRow, groupAndAttribute, elements, meta, attribute) ->
return if elementRow.find(".js-setArticle .js-body-#{articleType}").get(0)
elementRow.find('.js-setArticle').empty()
name = "#{attribute.name}::article.#{articleType}"
selection = App.UiElement.select.render(
name: "#{name}::internal"
multiple: false
null: false
label: 'Visibility'
options: { true: 'internal', false: 'public' }
value: meta.internal
translate: true
)
articleElement = $( App.view('generic/ticket_perform_action/article')(
attribute: attribute
name: name
articleType: articleType
meta: meta || {}
))
articleElement.find('.js-internal').html(selection)
articleElement.find('.js-body div[contenteditable="true"]').ce(
mode: 'richtext'
placeholder: 'message'
maxlength: 200000
)
new App.WidgetPlaceholder(
el: articleElement.find('.js-body div[contenteditable="true"]').parent()
objects: [
{
prefix: 'ticket'
object: 'Ticket'
display: 'Ticket'
},
{
prefix: 'article'
object: 'TicketArticle'
display: 'Article'
},
{
prefix: 'user'
object: 'User'
display: 'Current User'
},
]
)
elementRow.find('.js-setArticle').html(articleElement).removeClass('hide')
@humanText: (condition) ->
none = App.i18n.translateContent('No filter.')
return [none] if _.isEmpty(condition)
[defaults, groups, operators, elements] = @defaults()
rules = []
for attribute, value of condition
objectAttribute = attribute.split(/\./)
# get stored params
if meta && objectAttribute[1]
model = toCamelCase(objectAttribute[0])
config = elements[attribute]
valueHuman = []
if _.isArray(value)
for data in value
r = @humanTextLookup(config, data)
valueHuman.push r
else
valueHuman.push @humanTextLookup(config, value)
if valueHuman.join
valueHuman = valueHuman.join(', ')
rules.push "#{App.i18n.translateContent('Set')} <b>#{App.i18n.translateContent(model)} -> #{App.i18n.translateContent(config.display)}</b> #{App.i18n.translateContent('to')} <b>#{valueHuman}</b>."
return [none] if _.isEmpty(rules)
rules
@humanTextLookup: (config, value) ->
return value if !App[config.relation]
return value if !App[config.relation].exists(value)
data = App[config.relation].fullLocal(value)
return value if !data
if data.displayName
return App.i18n.translateContent( data.displayName() )
valueHuman.push App.i18n.translateContent( data.name )

View file

@ -0,0 +1,99 @@
# Methods for displaying security ui elements and to get security params
App.SecurityOptions =
securityOptionsShow: ->
@$('.js-securityOptions').removeClass('hide')
securityOptionsHide: ->
@$('.js-securityOptions').addClass('hide')
securityOptionsShown: ->
!@$('.js-securityOptions').hasClass('hide')
securityEnabled: ->
App.Config.get('smime_integration') || App.Config.get('pgp_integration')
paramsSecurity: =>
if @$('.js-securityOptions').hasClass('hide')
return {}
security = {}
security.encryption ||= {}
security.sign ||= {}
if App.Config.get('pgp_integration')
security.type = 'PGP'
else
security.type = 'S/MIME'
if @$('.js-securityEncrypt').hasClass('btn--active')
security.encryption.success = true
if @$('.js-securitySign').hasClass('btn--active')
security.sign.success = true
security
updateSecurityOptionsRemote: (key, ticket, article, securityOptions) ->
if securityOptions.type == 'PGP'
id = "pgp-check-#{key}"
url = "#{@apiPath}/integration/pgp"
securityConfig = App.Config.get('pgp_config')
else
id = "smime-check-#{key}"
url = "#{@apiPath}/integration/smime"
securityConfig = App.Config.get('smime_config')
callback = =>
@ajax(
id: id
type: 'POST'
url: url
data: JSON.stringify(ticket: ticket, article: article)
processData: true
success: (data, status, xhr) =>
# get default selected security options
selected =
encryption: true
sign: true
for type, selector of { default_sign: 'sign', default_encryption: 'encryption' }
if securityConfig?.group_id?[type] && ticket.group_id
if securityConfig.group_id[type][ticket.group_id.toString()] == false
selected[selector] = false
@$('.js-securityEncryptComment').attr('title', data.encryption.comment)
# if encryption is possible
if data.encryption.success is true
@$('.js-securityEncrypt').attr('disabled', false)
# overrule current selection with Group configuration
if selected.encryption
@$('.js-securityEncrypt').addClass('btn--active')
else
@$('.js-securityEncrypt').removeClass('btn--active')
# if encryption is not possible
else
@$('.js-securityEncrypt').attr('disabled', true)
@$('.js-securityEncrypt').removeClass('btn--active')
@$('.js-securitySignComment').attr('title', data.sign.comment)
# if sign is possible
if data.sign.success is true
@$('.js-securitySign').attr('disabled', false)
# overrule current selection with Group configuration
if selected.sign
@$('.js-securitySign').addClass('btn--active')
else
@$('.js-securitySign').removeClass('btn--active')
# if sign is possible
else
@$('.js-securitySign').attr('disabled', true)
@$('.js-securitySign').removeClass('btn--active')
error: (data) ->
details = data.responseJSON || {}
console.log(details)
)
@delay(callback, 200, 'security-check')

View file

@ -0,0 +1,14 @@
<form>
<h2><%- @T('Public & Private Keys') %></h2>
<div class="settings-entry settings-entry--stretched js-keyList"></div>
<div class="btn btn--primary js-addPublicKey"><%- @T('Add Public Key') %></div>
<div class="btn js-addPrivateKey"><%- @T('Add Private Key') %></div>
<hr>
<h2><%- @T('Default Behavior') %></h2>
<p>Choose the default behavior of the PGP integration on per group basis. If signing or encrypting is not possible, the setting has no effect. Agents call always manually alter the behavior for each article.</p>
<div class="settings-entry settings-entry--stretched js-groupList"></div>
<div class="btn btn--primary js-updateGroup"><%- @T('Update') %></div>
</form>

View file

@ -0,0 +1,25 @@
<table class="settings-list">
<thead>
<tr>
<th width="55%"><%- @T('Group') %>
<th><%- @T('Sign') %>
<th><%- @T('Encryption') %>
</tr>
</thead>
<tbody>
<% if _.isEmpty(@groups): %>
<tr>
<td colspan="6">
<%- @T('No Entries') %>
</td>
</tr>
<% else: %>
<% for group in @groups: %>
<tr data-id="<%= group.id %>">
<td><%= group.name %>
<td class="js-signDefault">
<td class="js-encryptionDefault">
<% end %>
<% end %>
</tbody>
</table>

View file

@ -0,0 +1,44 @@
<table class="settings-list settings-list--stretch">
<thead>
<tr>
<th width="35%"><%- @T('Email') %>
<th width="60%"><%- @T('Fingerprint') %>
<th width="5%"><%- @T('Actions') %>
</thead>
<tbody>
<% if _.isEmpty(@keyPairs): %>
<tr>
<td colspan="6">
<%- @T('No Entries') %>
</td>
</tr>
<% else: %>
<% for keyPair in @keyPairs: %>
<tr data-id="<%= keyPair.id %>">
<td><% if !_.isEmpty(keyPair.email_addresses): %><%= keyPair.email_addresses.toString() %><% end %>
<% if keyPair.private_key: %><br><i><%- @T('Including private key.') %></i><% end %>
<td title="<%= keyPair.fingerprint %>"><%= keyPair.fingerprint %>
<td>
<div class="dropdown dropdown--actions">
<div class="btn btn--table btn--text btn--secondary js-action" data-toggle="dropdown">
<%- @Icon('overflow-button') %>
</div>
<ul class="dropdown-menu dropdown-menu-right js-table-action-menu" role="menu">
<% if keyPair.private_key: %>
<li role="presentation" data-table-action="download-private">
<a href="<%= @C('http_type') %>://<%= @C('fqdn')%>/api/v1/integration/pgp/private_key_download/<%= keyPair.id %>" download><%- @Icon('download') %> <%- @T('Download Private Key') %></a>
</li>
<% end %>
<li role="presentation" data-table-action="download-public">
<a href="<%= @C('http_type') %>://<%= @C('fqdn')%>/api/v1/integration/pgp/public_key_download/<%= keyPair.id %>"%download><%- @Icon('download') %> <%- @T('Download Public Key') %></a>
</li>
<li role="presentation" class="danger js-remove" data-table-action="remove">
<%- @Icon('trash') %> <%- @T('Delete') %>
</li>
</ul>
</div>
</td>
<% end %>
<% end %>
</tbody>
</table>

View file

@ -0,0 +1,38 @@
<div>
<p class="alert alert--danger js-error hide"></p>
<div class="form-field-group">
<div class="form-group">
<div class="formGroup-label">
<label for="private_key-upload"><%- @T('Upload Private Key') %></label>
</div>
<div class="controls">
<input name="file" type="file" id="private_key-upload">
</div>
</div>
<div class="or-divider">
<span><%- @T('or') %></span>
</div>
<div class="form-group">
<div class="formGroup-label">
<label for="private_key-paste"><%- @T('Paste Private Key') %></label>
</div>
<div class="controls">
<textarea cols="25" rows="20" name="data" style="height: 200px;"
id="private_key-paste"></textarea>
</div>
</div>
</div>
<div class="form-group">
<div class="formGroup-label">
<label for="private_key-secret"><%- @T('Enter Private Key Secret') %></label>
</div>
<div class="controls">
<input class="form-control" name="secret" type="password" id="private_key-secret">
</div>
</div>
</div>

View file

@ -0,0 +1,27 @@
<div>
<p class="alert alert--danger js-error hide"></p>
<div class="form-group">
<div class="formGroup-label">
<label for="public_key-upload"><%- @T('Upload Public Key') %></label>
</div>
<div class="controls">
<input name="file" type="file" id="public_key-upload">
</div>
</div>
<div class="or-divider">
<span><%- @T('or') %></span>
</div>
<div class="form-group">
<div class="formGroup-label">
<label for="public_key-paste"><%- @T('Paste Public Key') %></label>
</div>
<div class="controls">
<textarea cols="25" rows="20" name="data" style="height: 200px;"
id="public_key-paste"></textarea>
</div>
</div>
</div>

View file

@ -0,0 +1 @@
.icon-pgp { width:17px; height: 17px; }