Merge branch 'develop' of github.com:martini/zammad into develop

This commit is contained in:
Felix Niklas 2015-08-06 18:19:35 +02:00
commit 506e2f1e04
19 changed files with 377 additions and 211 deletions

View file

@ -287,6 +287,11 @@ class Base extends App.ControllerContent
@navigate '#import/' + data.import_backend
return
# import config options
if data.config
for key, value of data.config
App.Config.set(key, value)
# render page
@render()
)

View file

@ -375,7 +375,7 @@ class LayoutRefCommunicationReply extends App.ControllerContent
for i in [0..100]
setTimeout @updateUploadProgress, i*duration/100 , i
setTimeout (=>
setTimeout (=>
callback()
@renderAttachment(fileName, fileSize)
), duration
@ -584,7 +584,7 @@ class ImportWizard extends App.ControllerWizard
@render()
# wait 500 ms after the last user input before we check the link
@otrsLink.on 'input', _.debounce(@checkOtrsLink, 600)
@otrsLink.on 'input', _.debounce(@checkOtrsLink, 600)
checkOtrsLink: (e) =>
if @otrsLink.val() is ""
@ -852,14 +852,14 @@ class highlightRef extends App.ControllerContent
# containing the offsets and the highlight classes
#
# we have to check how it works with having open several tickets it might break
#
#
# if classes can be changed in the admin interface
# we have to watch out to not end up with empty highlight classes
storeHighlights: ->
localStorage['highlights'] = @highlighter.serialize()
# the colors is set via css classes (can't do it inline with rangy)
# thus we have to create a stylesheet if the colors
# thus we have to create a stylesheet if the colors
# can be changed in the admin interface
addClassApplier: (entry) ->
@highlighter.addClassApplier rangy.createCssClassApplier(@highlightClassPrefix + entry.name)
@ -884,7 +884,7 @@ class highlightRef extends App.ControllerContent
activate: ->
selection = rangy.getSelection()
# if there's already something selected,
# if there's already something selected,
# don't go into highlight mode
# just toggle the selected
if !selection.isCollapsed
@ -914,10 +914,10 @@ class highlightRef extends App.ControllerContent
onMouseUp: (e) =>
@toggleHighlightAtSelection $(e.currentTarget).closest @articles.selector
#
#
# toggle Highlight
# ================
#
#
# - only works when the selection starts and ends inside an article
# - clears highlights in selection
# - or highlights the selection
@ -931,7 +931,7 @@ class highlightRef extends App.ControllerContent
else
@highlighter.highlightSelection @highlightClass,
selection: selection
containerElementId: article.get(0).id
containerElementId: article.get(0).id
# remove selection
selection.removeAllRanges()
@ -1096,7 +1096,7 @@ class cluesRef extends App.ControllerContent
showWindow: =>
@modalWindow.velocity
properties:
properties:
scale: [1, 0.2]
opacity: [1, 0]
options:
@ -1105,7 +1105,7 @@ class cluesRef extends App.ControllerContent
hideWindow: (callback) =>
@modalWindow.velocity
properties:
properties:
scale: [0.2, 1]
opacity: 0
options:
@ -1131,7 +1131,7 @@ class cluesRef extends App.ControllerContent
if target.right + modal.width <= maxWidth
left = target.right
position = 'right'
else
else
# place left
left = target.left - modal.width
position = 'left'
@ -1208,7 +1208,7 @@ class cluesRef extends App.ControllerContent
getVisibleBoundingBox: (el) ->
###
getBoundingClientRect doesn't take
getBoundingClientRect doesn't take
absolute-positioned child nodes into account
###
@ -1412,7 +1412,7 @@ class schedulersRef extends App.ControllerContent
switch items.length
when 1 then return items[0]
when 2 then return "#{ items[0] } and #{ items[1] }"
else
else
return "#{ items.slice(0, -1).join(', ') } and #{ items[items.length-1] }"
App.Config.set( 'layout_ref/schedulers', schedulersRef, 'Routes' )
@ -1431,11 +1431,22 @@ class InputsRef extends App.ControllerContent
# selectable search
searchableSelectObject = new App.SearchableSelect
attribute:
name: 'project-name'
id: 'project-name-123'
name: 'project-name'
id: 'project-name-123'
placeholder: 'Enter Project Name'
options: [{"value":0,"name":"Apple"},{"value":1,"name":"Microsoft","selected":true},{"value":2,"name":"Google"},{"value":3,"name":"Deutsche Bahn"},{"value":4,"name":"Sparkasse"},{"value":5,"name":"Deutsche Post"},{"value":6,"name":"Mitfahrzentrale"},{"value":7,"name":"Starbucks"},{"value":8,"name":"Mac Donalds"},{"value":9,"name":"Flixbus"},{"value":10,"name":"Betahaus"},{"value":11,"name":"Bruno Banani"},{"value":12,"name":"Alpina"},{"value":13,"name":"Samsung"},{"value":14,"name":"ChariTea"},{"value":15,"name":"fritz-kola"},{"value":16,"name":"Vitamin Water"},{"value":17,"name":"Znuny"},{"value":18,"name":"Max & Moritz"}]
@$('.searchableSelectPlaceholder').replaceWith( searchableSelectObject.el )
options: [{"value":0,"name":"Apple"},{"value":1,"name":"Microsoft","selected":true},{"value":2,"name":"Google"},{"value":3,"name":"Deutsche Bahn"},{"value":4,"name":"Sparkasse"},{"value":5,"name":"Deutsche Post"},{"value":6,"name":"Mitfahrzentrale"},{"value":7,"name":"Starbucks"},{"value":8,"name":"Mac Donalds"},{"value":9,"name":"Flixbus"},{"value":10,"name":"Betahaus"},{"value":11,"name":"Bruno Banani"},{"value":12,"name":"Alpina"},{"value":13,"name":"Samsung"},{"value":14,"name":"ChariTea"},{"value":15,"name":"fritz-kola"},{"value":16,"name":"Vitamin Water"},{"value":17,"name":"Znuny"},{"value":18,"name":"Max & Moritz"}]
@$('.searchableSelectPlaceholder').replaceWith( searchableSelectObject.element() )
# selectable search
searchableAjaxSelectObject = new App.SearchableAjaxSelect
attribute:
name: 'user'
id: 'user-123'
placeholder: 'Enter User'
limt: 10
object: 'User'
@$('.searchableAjaxSelectPlaceholder').replaceWith( searchableAjaxSelectObject.element() )
# time and timeframe
@$('.time').timepicker()
@ -1515,7 +1526,7 @@ class calendarSubscriptionsRef extends App.ControllerContent
switch items.length
when 1 then return items[0]
when 2 then return "#{ items[0] } and #{ items[1] }"
else
else
return "#{ items.slice(0, -1).join(', ') } and #{ items[items.length-1] }"

View file

@ -166,35 +166,17 @@ class App.Navigation extends App.ControllerWidgetPermanent
area.result = []
for id in area.ids
ticket = App.Ticket.find( id )
data =
display: "##{ticket.number} - #{ticket.title}"
id: ticket.id
class: "level-#{ticket.level()} ticket-popover"
url: ticket.uiUrl()
iconClass: "priority"
area.result.push data
area.result.push ticket.searchResultAttributes()
else if area.name is 'User'
area.result = []
for id in area.ids
user = App.User.find( id )
data =
display: "#{user.displayName()}"
id: user.id
class: "user user-popover"
url: user.uiUrl()
iconClass: "user"
area.result.push data
area.result.push user.searchResultAttributes()
else if area.name is 'Organization'
area.result = []
for id in area.ids
organization = App.Organization.find( id )
data =
display: "#{organization.displayName()}"
id: organization.id
class: "organization organization-popover"
url: organization.uiUrl()
iconClass: "organization"
area.result.push data
area.result.push organization.searchResultAttributes()
@renderResult(result)

View file

@ -26,7 +26,6 @@ class App.SearchableSelect extends Spine.Controller
@render()
render: ->
console.log "options", @options
firstSelected = _.find @options.attribute.options, (option) -> option.selected
if firstSelected

View file

@ -14,7 +14,7 @@ class App.UserOrganizationAutocompletion extends App.Controller
@key = Math.floor( Math.random() * 999999 ).toString()
if !@attribute.source
@attribute.source = @apiPath + '/search_user_org'
@attribute.source = @apiPath + '/search/user-organization'
@build()
element: =>
@ -114,6 +114,10 @@ class App.UserOrganizationAutocompletion extends App.Controller
item = ''
@close()
# if tab / close recipientList
if e.keyCode is 9
@close()
# ignore arrow keys
if e.keyCode is 37
return

View file

@ -100,47 +100,62 @@ class App.Utils
# textWithoutTags = App.Utils.htmlRemoveTags( html )
@htmlRemoveTags: (html) ->
htmlTmp = $( '<div>' + html.html() + '</div>' )
# remove comments
@_removeComments( htmlTmp )
# remove work markup
htmlTmp = @_removeWordMarkup( htmlTmp )
# remove tags, keep content
html.find('div, span, p, li, ul, ol, a, b, u, i, label, small, strong, strike, pre, code, center, blockquote, form, textarea, font, address, table, thead, tbody, tr, td, h1, h2, h3, h4, h5, h6').replaceWith( ->
htmlTmp.find('div, span, p, li, ul, ol, a, b, u, i, label, small, strong, strike, pre, code, center, blockquote, form, textarea, font, address, table, thead, tbody, tr, td, h1, h2, h3, h4, h5, h6').replaceWith( ->
$(@).contents()
)
# remove tags & content
html.find('div, span, p, li, ul, ol, a, b, u, i, label, small, strong, strike, pre, code, center, blockquote, form, textarea, font, table, thead, tbody, tr, td, h1, h2, h3, h4, h5, h6, br, hr, img, input, select, button, style, applet, canvas, script, frame, iframe').remove()
htmlTmp.find('div, span, p, li, ul, ol, a, b, u, i, label, small, strong, strike, pre, code, center, blockquote, form, textarea, font, table, thead, tbody, tr, td, h1, h2, h3, h4, h5, h6, br, hr, img, input, select, button, style, applet, embed, noframes, canvas, script, frame, iframe').remove()
html
html.html(htmlTmp)
# htmlOnlyWithRichtext = App.Utils.htmlRemoveRichtext( html )
@htmlRemoveRichtext: (html) ->
htmlTmp = $( '<div>' + html.html() + '</div>' )
# remove comments
@_removeComments( html )
@_removeComments( htmlTmp )
# remove style and class
@_removeAttributes( html )
@_removeAttributes( htmlTmp )
# remove work markup
htmlTmp = @_removeWordMarkup( htmlTmp )
# remove tags, keep content
html.find('li, ul, ol, a, b, u, i, label, small, strong, strike, pre, code, center, blockquote, form, textarea, font, address, table, thead, tbody, tr, td, h1, h2, h3, h4, h5, h6').replaceWith( ->
htmlTmp.find('li, ul, ol, a, b, u, i, label, small, strong, strike, pre, code, center, blockquote, form, textarea, font, address, table, thead, tbody, tr, td, h1, h2, h3, h4, h5, h6').replaceWith( ->
$(@).contents()
)
# remove tags & content
html.find('li, ul, ol, a, b, u, i, label, small, strong, strike, pre, code, center, blockquote, form, textarea, font, address, table, thead, tbody, tr, td, h1, h2, h3, h4, h5, h6, hr, img, input, select, button, style, applet, canvas, script, frame, iframe').remove()
htmlTmp.find('li, ul, ol, a, b, u, i, label, small, strong, strike, pre, code, center, blockquote, form, textarea, font, address, table, thead, tbody, tr, td, h1, h2, h3, h4, h5, h6, hr, img, input, select, button, style, applet, embed, noframes, canvas, script, frame, iframe').remove()
html
html.html(htmlTmp)
# cleanHtmlWithRichText = App.Utils.htmlCleanup( html )
@htmlCleanup: (html) ->
htmlTmp = $( '<div>' + html.html() + '</div>' )
# remove comments
@_removeComments( html )
@_removeComments( htmlTmp )
# remove style and class
@_removeAttributes( html )
@_removeAttributes( htmlTmp )
# remove work markup
htmlTmp = @_removeWordMarkup( htmlTmp )
# remove tags, keep content
html.find('a, font, small, time').replaceWith( ->
htmlTmp.find('a, font, small, time').replaceWith( ->
$(@).contents()
)
@ -148,31 +163,32 @@ class App.Utils
# New type of the tag
replacementTag = 'div';
# Replace all a tags with the type of replacementTag
html.find('h1, h2, h3, h4, h5, h6, textarea').each( ->
# Replace all x tags with the type of replacementTag
htmlTmp.find('h1, h2, h3, h4, h5, h6, textarea').each( ->
outer = this.outerHTML;
# Replace opening tag
regex = new RegExp('<' + this.tagName, 'i');
newTag = outer.replace(regex, '<' + replacementTag);
regex = new RegExp('<' + this.tagName, 'i')
newTag = outer.replace(regex, '<' + replacementTag)
# Replace closing tag
regex = new RegExp('</' + this.tagName, 'i');
newTag = newTag.replace(regex, '</' + replacementTag);
regex = new RegExp('</' + this.tagName, 'i')
newTag = newTag.replace(regex, '</' + replacementTag)
$(@).replaceWith(newTag);
$(@).replaceWith(newTag)
)
# remove tags & content
html.find('form, font, hr, img, input, select, button, style, applet, canvas, script, frame, iframe').remove()
htmlTmp.find('form, font, hr, img, input, select, button, style, applet, embed, noframes, canvas, script, frame, iframe').remove()
html
html.html(htmlTmp)
@_removeAttributes: (html) ->
html.find('div, span, p, li, ul, ol, a, b, u, i, label, small, strong, strike, pre, code, center, blockquote, h1, h2, h3, h4, h5, h6')
html.find('*')
.removeAttr( 'style' )
.removeAttr( 'class' )
.removeAttr( 'title' )
.removeAttr( 'lang' )
html
@_removeComments: (html) ->
@ -182,6 +198,14 @@ class App.Utils
)
html
@_removeWordMarkup: (html) ->
htmlTmp = html.get(0).outerHTML
regex = new RegExp('<(/w|w)\:[A-Za-z]{3}>')
htmlTmp = htmlTmp.replace(regex, '')
regex = new RegExp('<(/o|o)\:[A-Za-z]{1}>')
htmlTmp = htmlTmp.replace(regex, '')
$(htmlTmp)
# signatureNeeded = App.Utils.signatureCheck( message, signature )
@signatureCheck: (message, signature) ->
messageText = $( '<div>' + message + '</div>' ).text().trim()

View file

@ -3,12 +3,81 @@ class App.SearchableAjaxSelect extends App.SearchableSelect
onInput: (event) =>
super
# send ajax request @query
# convert requested object
# e.g. Ticket to ticket or AnotherObject to another_object
objectString = underscored( @options.attribute.object )
onAjaxResponse: (data) =>
# create common accessors
@apiPath = App.Config.get('api_path')
# create cache and cache key
@searchResultCache = @searchResultCache || {}
@cacheKey = "#{objectString}+#{@query}"
# use cache for search result
if @searchResultCache[@cacheKey]
return @onAjaxResponse( @searchResultCache[@cacheKey] )
# add timout for loader icon
clearTimeout @loaderTimeoutId
@loaderTimeoutId = setTimeout @showLoader, 1000
# start search request and update options
App.Ajax.request(
id: @options.attribute.id
type: 'GET'
url: "#{@apiPath}/search/#{objectString}"
data:
query: @query
limit: @options.attribute.limit
processData: true
success: @onAjaxResponse
)
onAjaxResponse: (data, status, xhr) =>
# clear timout and remove loader icon
clearTimeout @loaderTimeoutId
@el.removeClass('is-loading')
# cache search result
@searchResultCache[@cacheKey] = data
# load assets
App.Collection.loadAssets( data.assets )
# get options from search result
options = []
for object in data.result
if object.type is 'Ticket'
ticket = App.Ticket.find( object.id )
data =
name: "##{ticket.number} - #{ticket.title}"
value: ticket.id
options.push data
else if object.type is 'User'
user = App.User.find( object.id )
data =
name: "#{user.displayName()}"
value: user.id
options.push data
else if object.type is 'Organization'
organization = App.Organization.find( object.id )
data =
name: "#{organization.displayName()}"
value: organization.id
options.push data
# fill template with gathered options
@optionsList.html App.view('generic/searchable_select_options')
options: data
options: options
# refresh elements
@refreshElements()
@filterByQuery @query
# execute filter
@filterByQuery @query
showLoader: =>
@el.addClass('is-loading')

View file

@ -30,3 +30,10 @@ class App.Organization extends App.Model
user = App.User.find( user_id )
data['members'].push user
data
searchResultAttributes: ->
display: "#{@displayName()}"
id: @id
class: "organization organization-popover"
url: @uiUrl()
iconClass: "organization"

View file

@ -50,4 +50,10 @@ class App.Ticket extends App.Model
iconActivity: (user) ->
if @owner_id == user.id
return 'important'
''
''
searchResultAttributes: ->
display: "##{@number} - #{@title}"
id: @id
class: "level-#{@level()} ticket-popover"
url: @uiUrl()
iconClass: "priority"

View file

@ -119,3 +119,10 @@ class App.User extends App.Model
data['groups'].push group
data
searchResultAttributes: ->
display: "#{@displayName()}"
id: @id
class: "user user-popover"
url: @uiUrl()
iconClass: "user"

View file

@ -1,3 +1,5 @@
<% for option in @options: %>
<li role="presentation" class="js-option" data-value="<%= option.value %>"><%= option.name %>
<% if @options: %>
<% for option in @options: %>
<li role="presentation" class="js-option" data-value="<%= option.value %>"><%= option.name %>
<% end %>
<% end %>

View file

@ -66,6 +66,10 @@
<div class="searchableSelectPlaceholder"></div>
</div>
<div class="select form-group">
<label for="b">Users (searchable ajax)</label>
<div class="searchableAjaxSelectPlaceholder"></div>
</div>
<h2>Checkbox</h2>
<div class="checkbox form-group">

View file

@ -155,7 +155,7 @@ function clone(item, full) {
function clone2(item) {
if (!item) { return item; } // null, undefined values check
var types = [ Number, String, Boolean ],
var types = [ Number, String, Boolean ],
result;
// normalizing primitives if someone did new String('aaa'), or new Number('444');
@ -168,13 +168,13 @@ function clone2(item) {
if (typeof result == "undefined") {
if (Object.prototype.toString.call( item ) === "[object Array]") {
result = [];
item.forEach(function(child, index, array) {
item.forEach(function(child, index, array) {
result[index] = clone( child );
});
} else if (typeof item == "object") {
// testing that this is DOM
if (item.nodeType && typeof item.cloneNode == "function") {
var result = item.cloneNode( true );
var result = item.cloneNode( true );
} else if (!item.prototype) { // check that this is a literal
if (item instanceof Date) {
result = new Date(item);
@ -203,6 +203,11 @@ function clone2(item) {
return result;
}
// taken from https://github.com/epeli/underscore.string/blob/master/underscored.js
function underscored (str) {
return str.trim().replace(/([a-z\d])([A-Z]+)/g, '$1_$2').replace(/[-\s]+/g, '_').toLowerCase();
}
jQuery.event.special.remove = {
remove: function(e) {
if (e.handler) e.handler();

View file

@ -977,8 +977,15 @@ curl http://localhost/api/v1/getting_started -v -u #{login}:#{password}
system_online_service: Setting.get('system_online_service'),
addresses: addresses,
groups: groups,
config: config_to_update,
}
true
end
def config_to_update
{
product_logo: Setting.get('product_logo')
}
end
end

View file

@ -3,8 +3,9 @@
class SearchController < ApplicationController
before_action :authentication_check
# GET /api/v1/search_user_org
def search_user_org
# GET|POST /api/v1/search/:objects
def search_generic
# enable search only for agents and admins
if !current_user.role?(Z_ROLENAME_AGENT) && !current_user.role?(Z_ROLENAME_ADMIN)
@ -16,47 +17,59 @@ class SearchController < ApplicationController
query = params[:query]
limit = params[:limit] || 10
# convert objects string into array of class names
# e.g. user-ticket-another_object = %w( User Ticket AnotherObject )
objects = params[:objects].split('-').map(&:camelize)
search_tickets = objects.delete('Ticket')
# try search index backend
assets = {}
result = []
if SearchIndexBackend.enabled?
items = SearchIndexBackend.search( query, limit, %w(User Organization) )
items = SearchIndexBackend.search( query, limit, objects )
items.each { |item|
require item[:type].to_filename
record = Kernel.const_get( item[:type] ).find( item[:id] )
assets = record.assets(assets)
result.push item
}
# do ticket query by Ticket class to handle ticket permissions
if search_tickets
tickets = Ticket.search(
query: query,
limit: limit,
current_user: current_user,
)
tickets.each do |ticket|
assets = ticket.assets(assets)
item = {
id: ticket.id,
type: 'Ticket',
}
result.push item
end
end
else
# do query
users = User.search(
query: query,
limit: limit,
current_user: current_user,
)
users.each do |user|
item = {
id: user.id,
type: user.class.to_s
}
result.push item
assets = user.assets(assets)
end
objects.each { |object|
organizations = Organization.search(
query: query,
limit: limit,
current_user: current_user,
)
found_objects = object.constantize.search(
query: query,
limit: limit,
current_user: current_user,
)
organizations.each do |organization|
item = {
id: organization.id,
type: organization.class.to_s
}
result.push item
assets = organization.assets(assets)
end
found_objects.each do |found_object|
item = {
id: found_object.id,
type: found_object.class.to_s
}
result.push item
assets = found_object.assets(assets)
end
}
end
render json: {
@ -68,64 +81,74 @@ class SearchController < ApplicationController
# GET /api/v1/search
def search
# build result list
tickets = Ticket.search(
limit: params[:limit],
query: params[:term],
current_user: current_user,
)
assets = {}
ticket_result = []
tickets.each do |ticket|
assets = ticket.assets(assets)
ticket_result.push ticket.id
end
# get params
query = params[:term]
limit = params[:limit] || 10
# do query
users = User.search(
query: params[:term],
limit: params[:limit],
current_user: current_user,
)
user_result = []
users.each do |user|
user_result.push user.id
assets = user.assets(assets)
end
assets = {}
result = []
objects = %w( Ticket User Organization )
if SearchIndexBackend.enabled?
organizations = Organization.search(
query: params[:term],
limit: params[:limit],
current_user: current_user,
)
# to ticket search in serparate call
objects.delete('Ticket')
organization_result = []
organizations.each do |organization|
organization_result.push organization.id
assets = organization.assets(assets)
end
# to query search index backend (excluse tickets here, see below)
found_objects = {}
items = SearchIndexBackend.search( query, limit, objects )
items.each { |item|
require item[:type].to_filename
record = Kernel.const_get( item[:type] ).find( item[:id] )
assets = record.assets(assets)
result = []
if ticket_result[0]
data = {
name: 'Ticket',
ids: ticket_result,
found_objects[ item[:type] ] ||= []
found_objects[ item[:type] ].push item[:id]
}
result.push data
end
if user_result[0]
data = {
name: 'User',
ids: user_result,
# do ticket query by Ticket class to handle ticket permissions
tickets = Ticket.search(
query: query,
limit: limit,
current_user: current_user,
)
tickets.each do |ticket|
found_objects[ 'Ticket' ] ||= []
found_objects[ 'Ticket' ].push ticket.id
end
# generate whole result
found_objects.each { |object, object_ids|
data = {
name: object,
ids: object_ids,
}
result.push data
}
result.push data
end
if organization_result[0]
data = {
name: 'Organization',
ids: organization_result,
else
objects.each { |object|
found_objects = object.constantize.search(
query: query,
limit: limit,
current_user: current_user,
)
object_ids = []
found_objects.each do |found_object|
object_ids.push found_object.id
assets = found_object.assets(assets)
end
next if object_ids.empty?
data = {
name: object,
ids: object_ids,
}
result.push data
}
result.push data
end
# return result

View file

@ -2,9 +2,8 @@ Zammad::Application.routes.draw do
api_path = Rails.configuration.api_path
# search
match api_path + '/search', to: 'search#search', via: [:get, :post]
# search_user_org
match api_path + '/search_user_org', to: 'search#search_user_org', via: [:get, :post]
match api_path + '/search', to: 'search#search', via: [:get, :post]
# search_generic
match api_path + '/search/:objects', to: 'search#search_generic', via: [:get, :post]
end

View file

@ -1116,7 +1116,7 @@ module Import::OTRS
}
# check if customer already exists
user_old = User.where( login: user_new[:login] ).first
user_old = User.where( login: user_new[:login].downcase ).first
# create / update agent
if user_old
@ -1304,9 +1304,9 @@ module Import::OTRS
end
end
user = User.where( email: email ).first
user = User.where( email: email.downcase ).first
if !user
user = User.where( login: email ).first
user = User.where( login: email.downcase ).first
end
if !user
begin
@ -1334,7 +1334,7 @@ module Import::OTRS
)
rescue ActiveRecord::RecordNotUnique
log "User #{email} was handled by another thread, taking this."
user = User.find_by( login: email )
user = User.find_by( login: email.downcase )
if !user
log "User #{email} wasn't created sleep and retry."
sleep rand 3

View file

@ -45,6 +45,7 @@ returns
preferences: {
'Content-Type' => content_type
},
created_by_id: 1,
)
filename(file)
end
@ -91,6 +92,7 @@ returns
preferences: {
'Content-Type' => content_type
},
created_by_id: 1,
)
StaticAssets.sync
filename(file)
@ -142,6 +144,10 @@ generate filename based on Store model
extention = '.jpg'
elsif file.preferences['Content-Type'] =~ /png/i
extention = '.png'
elsif file.preferences['Content-Type'] =~ /gif/i
extention = '.gif'
elsif file.preferences['Content-Type'] =~ /svg/i
extention = '.svg'
end
"#{hash}#{extention}"
end

View file

@ -212,43 +212,47 @@ test( "htmlEscape", function() {
test( "htmlRemoveTags", function() {
var source = "<div>test</div>"
var should = "test"
var should = "<div>test</div>"
var result = App.Utils.htmlRemoveTags( $(source) )
equal( result.html(), should, source )
source = "<div>test<!-- some comment --></div>"
should = "<div>test</div>"
result = App.Utils.htmlRemoveTags( $(source) )
equal( result.html(), should, source )
source = "<a href=\"some_link\">some link to somewhere</a>"
should = "some link to somewhere"
should = "<div>some link to somewhere</div>"
result = App.Utils.htmlRemoveTags( $(source) )
equal( result.html(), should, source )
source = "<div><a href=\"some_link\">some link to somewhere</a></div>"
should = "some link to somewhere"
should = "<div>some link to somewhere</div>"
result = App.Utils.htmlRemoveTags( $(source) )
equal( result.html(), should, source )
source = "<div><a href=\"some_link\">some link to somewhere</a><input value=\"should not be shown\"></div>"
should = "some link to somewhere"
should = "<div>some link to somewhere</div>"
result = App.Utils.htmlRemoveTags( $(source) )
equal( result.html(), should, source )
source = "<div><a href=\"some_link\">some link to somewhere</a> <div><hr></div> <span>123</span> <img src=\"some_image\"/></div>"
should = "some link to somewhere 123 "
should = "<div>some link to somewhere 123 </div>"
result = App.Utils.htmlRemoveTags( $(source) )
equal( result.html(), should, source )
source = "<div><form class=\"xxx\">test 123</form></div>"
should = "test 123"
should = "<div>test 123</div>"
result = App.Utils.htmlRemoveRichtext( $(source) )
equal( result.html(), should, source )
source = "<div><textarea class=\"xxx\">test 123</textarea></div>"
should = "test 123"
should = "<div>test 123</div>"
result = App.Utils.htmlRemoveRichtext( $(source) )
equal( result.html(), should, source )
source = "<div><font size=\"3\" color=\"red\">This is some text!</font></div>"
//should = "<div>This is some text!</div>"
should = "This is some text!"
should = "<div>This is some text!</div>"
result = App.Utils.htmlRemoveRichtext( $(source) )
equal( result.html(), should, source )
});
@ -257,145 +261,147 @@ test( "htmlRemoveTags", function() {
test( "htmlRemoveRichtext", function() {
var source = "<div><!--test comment--><a href=\"test\">test</a></div>"
var should = "test"
var should = "<div>test</div>"
var result = App.Utils.htmlRemoveRichtext( $(source) )
equal( result.html(), should, source )
source = "<div><!--[if !supportLists]--><span lang=\"DE\">1.1.1<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span><!--[endif]--><span lang=\"DE\">Description</span></div>"
should = "<div><span>1.1.1<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span><span>Description</span></div>"
result = App.Utils.htmlRemoveRichtext( $(source) )
equal( result.html(), should, source )
source = "<a href=\"some_link\">some link to somewhere</a>"
should = "some link to somewhere"
should = "<div>some link to somewhere</div>"
result = App.Utils.htmlRemoveRichtext( $(source) )
equal( result.html(), should, source )
source = "<div><a href=\"some_link\"></a> test </div>"
should = " test "
should = "<div> test </div>"
result = App.Utils.htmlRemoveRichtext( $(source) )
equal( result.html(), should, source )
source = "<div><b></b> test </div>"
should = " test "
should = "<div> test </div>"
result = App.Utils.htmlRemoveRichtext( $(source) )
equal( result.html(), should, source )
source = "<div><div><b></b> test </div></div>"
should = "<div> test </div>"
should = "<div><div> test </div></div>"
result = App.Utils.htmlRemoveRichtext( $(source) )
equal( result.html(), should, source )
source = "<div><div><b></b> test <input value=\"should not be shown\"></div></div>"
should = "<div> test </div>"
should = "<div><div> test </div></div>"
result = App.Utils.htmlRemoveRichtext( $(source) )
equal( result.html(), should, source )
source = "<div><div><b></b> test </div><span>123</span></div>"
should = "<div> test </div><span>123</span>"
should = "<div><div> test </div><span>123</span></div>"
result = App.Utils.htmlRemoveRichtext( $(source) )
equal( result.html(), should, source )
source = "<div><div class=\"xxx\"><b></b> test </div></div>"
should = "<div> test </div>"
source = "<div><div class=\"xxx\" title=\"some title\" lang=\"en\"><b></b> test </div></div>"
should = "<div><div> test </div></div>"
result = App.Utils.htmlRemoveRichtext( $(source) )
equal( result.html(), should, source )
source = "<div><textarea class=\"xxx\"> test </textarea></div>"
//should = "<div> test </div>"
should = " test "
should = "<div> test </div>"
result = App.Utils.htmlRemoveRichtext( $(source) )
equal( result.html(), should, source )
source = "<div><br></div>"
should = "<br>"
result = App.Utils.htmlRemoveRichtext( $(source) )
equal( result.html(), should, source )
source = "<div><div class=\"xxx\"><br></div></div>"
should = "<div><br></div>"
result = App.Utils.htmlRemoveRichtext( $(source) )
equal( result.html(), should, source )
source = "<div><div class=\"xxx\"><br></div></div>"
should = "<div><div><br></div></div>"
result = App.Utils.htmlRemoveRichtext( $(source) )
equal( result.html(), should, source )
source = "<div><form class=\"xxx\">test 123</form></div>"
//should = "<div>test 123</div>"
should = "test 123"
should = "<div>test 123</div>"
result = App.Utils.htmlRemoveRichtext( $(source) )
equal( result.html(), should, source )
source = "<div><font size=\"3\" color=\"red\">This is some text!</font></div>"
//should = "<div>This is some text!</div>"
should = "This is some text!"
should = "<div>This is some text!</div>"
result = App.Utils.htmlRemoveRichtext( $(source) )
equal( result.html(), should, source )
});
// htmlCleanup
test( "htmlCleanup", function() {
var source = "<div><!--test comment--><a href=\"test\">test</a></div>"
var should = "test"
var should = "<div>test</div>"
var result = App.Utils.htmlCleanup( $(source) )
equal( result.html(), should, source )
source = "<a href=\"some_link\">some link to somewhere</a>"
should = "some link to somewhere"
result = App.Utils.htmlCleanup( $(source) )
equal( result.html(), should, source )
source = "<div><h1>some link to somewhere</h1></a>"
//should = "some link to somewhere"
should = "<div>some link to somewhere</div>"
result = App.Utils.htmlCleanup( $(source) )
equal( result.html(), should, source )
source = "<div><h1>some link to somewhere</h1></div>"
should = "<div><div>some link to somewhere</div></div>"
result = App.Utils.htmlCleanup( $(source) )
equal( result.html(), should, source )
source = "<div><small>some link to somewhere</small></a>"
//should = "<div>some link to somewhere</div>"
should = "some link to somewhere"
should = "<div>some link to somewhere</div>"
result = App.Utils.htmlCleanup( $(source) )
equal( result.html(), should, source )
source = "<div><time>some link to somewhere</time></a>"
//should = "<div>some link to somewhere</div>"
should = "some link to somewhere"
should = "<div>some link to somewhere</div>"
result = App.Utils.htmlCleanup( $(source) )
equal( result.html(), should, source )
source = "<div><h1>some link to somewhere</h1><p><hr></p></div>"
should = "<div>some link to somewhere</div><p></p><p></p>"
source = "<div><h1>some h1 for somewhere</h1><p><hr></p></div>"
should = "<div><div>some h1 for somewhere</div><p></p><p></p></div>"
result = App.Utils.htmlCleanup( $(source) )
equal( result.html(), should, source )
source = "<div><br></div>"
should = "<br>"
should = "<div><br></div>"
result = App.Utils.htmlCleanup( $(source) )
equal( result.html(), should, source )
source = "<div><div class=\"xxx\"><br></div></div>"
should = "<div><br></div>"
should = "<div><div><br></div></div>"
result = App.Utils.htmlRemoveRichtext( $(source) )
equal( result.html(), should, source )
source = "<div><form class=\"xxx\">test 123</form></div>"
//should = "<div>test 123<br></div>"
should = "test 123"
should = "<div>test 123</div>"
result = App.Utils.htmlRemoveRichtext( $(source) )
equal( result.html(), should, source )
source = "<div><form class=\"xxx\">test 123</form> some other value</div>"
//should = "<div>ttest 123 some other value</div>"
should = "test 123 some other value"
should = "<div>test 123 some other value</div>"
result = App.Utils.htmlRemoveRichtext( $(source) )
equal( result.html(), should, source )
source = "<div><form class=\"xxx\">test 123</form> some other value<input value=\"should not be shown\"></div>"
//should = "<div>test 123 some other value</div>"
should = "test 123 some other value"
should = "<div>test 123 some other value</div>"
result = App.Utils.htmlRemoveRichtext( $(source) )
equal( result.html(), should, source )
source = "<div><font size=\"3\" color=\"red\">This is some text!</font></div>"
//should = "<div>This is some text!</div>"
should = "This is some text!"
should = "<div>This is some text!</div>"
result = App.Utils.htmlRemoveRichtext( $(source) )
equal( result.html(), should, source )
source = "<div><p>some link to somewhere from word<w:sdt>abc</w:sdt></p><o:p></o:p></a>"
should = "<div><p>some link to somewhere from wordabc</p></div>"
result = App.Utils.htmlCleanup( $(source) )
equal( result.html(), should, source )
});
// wrap