Merge branch 'develop' of git.znuny.com:zammad/zammad into develop

This commit is contained in:
Martin Edenhofer 2017-12-04 01:25:50 +01:00
commit 0d1d86511f
456 changed files with 3929 additions and 2621 deletions

View file

@ -45,29 +45,29 @@ Style/TrailingCommaInArguments:
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-trailing-array-commas' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-trailing-array-commas'
Enabled: false Enabled: false
Style/SpaceInsideParens: Layout/SpaceInsideParens:
Description: 'No spaces after ( or before ).' Description: 'No spaces after ( or before ).'
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-spaces-braces' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-spaces-braces'
Enabled: false Enabled: false
Style/SpaceAfterMethodName: Layout/SpaceAfterMethodName:
Description: >- Description: >-
Do not put a space between a method name and the opening Do not put a space between a method name and the opening
parenthesis in a method definition. parenthesis in a method definition.
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#parens-no-spaces' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#parens-no-spaces'
Enabled: false Enabled: false
Style/LeadingCommentSpace: Layout/LeadingCommentSpace:
Description: 'Comments should start with a space.' Description: 'Comments should start with a space.'
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#hash-space' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#hash-space'
Enabled: false Enabled: false
Style/MethodCallParentheses: Style/MethodCallWithoutArgsParentheses:
Description: 'Do not use parentheses for method calls with no arguments.' Description: 'Do not use parentheses for method calls with no arguments.'
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-args-no-parens' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-args-no-parens'
Enabled: false Enabled: false
Style/SpaceInsideBrackets: Layout/SpaceInsideBrackets:
Description: 'No spaces after [ or before ].' Description: 'No spaces after [ or before ].'
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-spaces-braces' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-spaces-braces'
Enabled: false Enabled: false
@ -83,19 +83,19 @@ Style/MethodDefParentheses:
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#method-parens' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#method-parens'
Enabled: false Enabled: false
Style/EmptyLinesAroundClassBody: Layout/EmptyLinesAroundClassBody:
Description: "Keeps track of empty lines around class bodies." Description: "Keeps track of empty lines around class bodies."
Enabled: false Enabled: false
Style/EmptyLinesAroundMethodBody: Layout/EmptyLinesAroundMethodBody:
Description: "Keeps track of empty lines around method bodies." Description: "Keeps track of empty lines around method bodies."
Enabled: false Enabled: false
Style/EmptyLinesAroundBlockBody: Layout/EmptyLinesAroundBlockBody:
Description: "Keeps track of empty lines around block bodies." Description: "Keeps track of empty lines around block bodies."
Enabled: false Enabled: false
Style/EmptyLinesAroundModuleBody: Layout/EmptyLinesAroundModuleBody:
Description: "Keeps track of empty lines around module bodies." Description: "Keeps track of empty lines around module bodies."
Enabled: false Enabled: false
@ -143,17 +143,29 @@ Rails/HasAndBelongsToMany:
# StyleGuide: 'https://github.com/bbatsov/rails-style-guide#has-many-through' # StyleGuide: 'https://github.com/bbatsov/rails-style-guide#has-many-through'
Enabled: false Enabled: false
Rails/SkipsModelValidations:
Description: >-
Use methods that skips model validations with caution.
See reference for more information.
Reference: 'http://guides.rubyonrails.org/active_record_validations.html#skipping-validations'
Enabled: true
Exclude:
- test/**/*
Style/ClassAndModuleChildren: Style/ClassAndModuleChildren:
Description: 'Checks style of children classes and modules.' Description: 'Checks style of children classes and modules.'
Enabled: false Enabled: false
Style/FileName: Naming/FileName:
Description: 'Use snake_case for source file names.' Description: 'Use snake_case for source file names.'
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#snake-case-files' StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#snake-case-files'
Enabled: true Enabled: true
Exclude: Exclude:
- 'script/websocket-server.rb' - 'script/websocket-server.rb'
Naming/VariableNumber:
Description: 'Use the configured style when numbering variables.'
Enabled: false
# 2.0 # 2.0
@ -184,8 +196,23 @@ Metrics/ModuleLength:
Description: 'Avoid modules longer than 100 lines of code.' Description: 'Avoid modules longer than 100 lines of code.'
Enabled: false Enabled: false
Metrics/BlockLength:
Enabled: false
Lint/RescueWithoutErrorClass:
Enabled: false
Rails/ApplicationRecord:
Enabled: false
# TODO # TODO
Rails/HasManyOrHasOneDependent:
Enabled: false
Style/DateTime:
Enabled: false
Style/Documentation: Style/Documentation:
Description: 'Document classes and non-namespace modules.' Description: 'Document classes and non-namespace modules.'
Enabled: false Enabled: false
@ -193,7 +220,7 @@ Style/Documentation:
Lint/UselessAssignment: Lint/UselessAssignment:
Enabled: false Enabled: false
Style/ExtraSpacing: Layout/ExtraSpacing:
Description: 'Do not use unnecessary spacing.' Description: 'Do not use unnecessary spacing.'
Enabled: false Enabled: false
@ -216,3 +243,13 @@ Style/NumericPredicate:
Enabled: true Enabled: true
Exclude: Exclude:
- "**/*_spec.rb" - "**/*_spec.rb"
Lint/AmbiguousBlockAssociation:
Description: >-
Checks for ambiguous block association with method when param passed without
parentheses.
StyleGuide: '#syntax'
Enabled: true
Exclude:
- "**/*_spec.rb"
- "**/*_examples.rb"

128
Gemfile
View file

@ -1,112 +1,131 @@
source 'https://rubygems.org' source 'https://rubygems.org'
# core - base
ruby '2.4.1' ruby '2.4.1'
gem 'rails', '5.1.4' gem 'rails', '5.1.4'
gem 'rails-observers'
# core - rails additions
gem 'activerecord-session_store' gem 'activerecord-session_store'
gem 'composite_primary_keys'
# Bundle edge Rails instead:
#gem 'rails', :git => 'git://github.com/rails/rails.git'
gem 'json' gem 'json'
gem 'rails-observers'
# Supported DBs # core - application servers
gem 'puma', group: :puma
gem 'unicorn', group: :unicorn
# core - supported ORMs
gem 'activerecord-nulldb-adapter', group: :nulldb gem 'activerecord-nulldb-adapter', group: :nulldb
gem 'mysql2', group: :mysql gem 'mysql2', group: :mysql
gem 'pg', group: :postgres gem 'pg', group: :postgres
# core - asynchrous task execution
gem 'daemons'
gem 'delayed_job_active_record'
# core - websocket
gem 'em-websocket'
gem 'eventmachine'
# core - password security
gem 'argon2'
# performance - Memcached
gem 'dalli'
# asset handling
group :assets do group :assets do
gem 'sass-rails' #, github: 'rails/sass-rails' # asset handling - coffee-script
gem 'coffee-rails' gem 'coffee-rails'
gem 'coffee-script-source' gem 'coffee-script-source'
gem 'sprockets' # asset handling - frontend templating
gem 'uglifier'
gem 'eco' gem 'eco'
# asset handling - SASS
gem 'sass-rails'
# asset handling - pipeline
gem 'sprockets'
gem 'uglifier'
end end
gem 'autoprefixer-rails' gem 'autoprefixer-rails'
# asset handling - javascript execution for e.g. linux
gem 'execjs'
gem 'libv8'
gem 'therubyracer'
# authentication - provider
gem 'doorkeeper' gem 'doorkeeper'
gem 'oauth2' gem 'oauth2'
# authentication - third party
gem 'omniauth' gem 'omniauth'
gem 'omniauth-oauth2'
gem 'omniauth-facebook' gem 'omniauth-facebook'
gem 'omniauth-github' gem 'omniauth-github'
gem 'omniauth-gitlab' gem 'omniauth-gitlab'
gem 'omniauth-google-oauth2' gem 'omniauth-google-oauth2'
gem 'omniauth-linkedin-oauth2' gem 'omniauth-linkedin-oauth2'
gem 'omniauth-twitter'
gem 'omniauth-microsoft-office365' gem 'omniauth-microsoft-office365'
gem 'omniauth-oauth2'
gem 'omniauth-twitter'
gem 'omniauth-weibo-oauth2' gem 'omniauth-weibo-oauth2'
gem 'twitter' # channels
gem 'telegramAPI'
gem 'koala' gem 'koala'
gem 'mail' gem 'telegramAPI'
gem 'valid_email2' gem 'twitter'
# channels - email additions
gem 'htmlentities' gem 'htmlentities'
gem 'mail', '2.6.6'
gem 'mime-types' gem 'mime-types'
gem 'valid_email2'
# feature - business hours
gem 'biz' gem 'biz'
gem 'composite_primary_keys' # feature - signature diffing
gem 'delayed_job_active_record' gem 'diffy'
gem 'daemons'
gem 'simple-rss'
# e. g. on linux we need a javascript execution
gem 'libv8'
gem 'execjs'
gem 'therubyracer'
require 'erb'
require 'yaml'
gem 'net-ldap'
# password security
gem 'argon2'
# feature - excel output
gem 'writeexcel' gem 'writeexcel'
gem 'icalendar'
gem 'icalendar-recurrence' # feature - device logging
gem 'browser' gem 'browser'
# feature - iCal export
gem 'icalendar'
gem 'icalendar-recurrence'
# integrations # integrations
gem 'slack-notifier'
gem 'clearbit' gem 'clearbit'
gem 'net-ldap'
gem 'slack-notifier'
gem 'zendesk_api' gem 'zendesk_api'
gem 'viewpoint'
gem 'rubyntlm', git: 'https://github.com/wimm/rubyntlm.git' # integrations - exchange
gem 'autodiscover', git: 'https://github.com/thorsteneckel/autodiscover.git' gem 'autodiscover', git: 'https://github.com/thorsteneckel/autodiscover.git'
gem 'rubyntlm', git: 'https://github.com/wimm/rubyntlm.git'
# event machine gem 'viewpoint'
gem 'eventmachine'
gem 'em-websocket'
gem 'diffy'
gem 'dalli'
# Gems used only for develop/test and not required # Gems used only for develop/test and not required
# in production environments by default. # in production environments by default.
group :development, :test do group :development, :test do
# test frameworks
gem 'rspec-rails' gem 'rspec-rails'
gem 'test-unit' gem 'test-unit'
gem 'spring'
gem 'spring-commands-rspec' # test DB
gem 'sqlite3' gem 'sqlite3'
# code coverage # code coverage
gem 'coveralls', require: false
gem 'simplecov' gem 'simplecov'
gem 'simplecov-rcov' gem 'simplecov-rcov'
gem 'coveralls', require: false
# UI tests w/ Selenium # UI tests w/ Selenium
gem 'selenium-webdriver', '2.53.4' gem 'selenium-webdriver', '2.53.4'
@ -121,9 +140,9 @@ group :development, :test do
gem 'guard-symlink', require: false gem 'guard-symlink', require: false
# code QA # code QA
gem 'coffeelint'
gem 'pre-commit' gem 'pre-commit'
gem 'rubocop' gem 'rubocop'
gem 'coffeelint'
# changelog generation # changelog generation
gem 'github_changelog_generator' gem 'github_changelog_generator'
@ -138,10 +157,7 @@ group :development, :test do
gem 'webmock' gem 'webmock'
end end
gem 'puma', group: :puma # load onw gems for development and testing purposes
gem 'unicorn', group: :unicorn
# load onw gem's
local_gemfile = File.join(File.dirname(__FILE__), 'Gemfile.local') local_gemfile = File.join(File.dirname(__FILE__), 'Gemfile.local')
if File.exist?(local_gemfile) if File.exist?(local_gemfile)
eval_gemfile local_gemfile eval_gemfile local_gemfile

View file

@ -217,13 +217,12 @@ GEM
crass (~> 1.0.2) crass (~> 1.0.2)
nokogiri (>= 1.5.9) nokogiri (>= 1.5.9)
lumberjack (1.0.12) lumberjack (1.0.12)
mail (2.7.0) mail (2.6.6)
mini_mime (>= 0.1.1) mime-types (>= 1.16, < 4)
memoizable (0.4.2) memoizable (0.4.2)
thread_safe (~> 0.3, >= 0.3.1) thread_safe (~> 0.3, >= 0.3.1)
method_source (0.9.0) method_source (0.9.0)
mime-types (2.99.3) mime-types (2.99.3)
mini_mime (1.0.0)
mini_portile2 (2.3.0) mini_portile2 (2.3.0)
minitest (5.10.3) minitest (5.10.3)
multi_json (1.12.2) multi_json (1.12.2)
@ -389,7 +388,6 @@ GEM
rubyzip (~> 1.0) rubyzip (~> 1.0)
websocket (~> 1.0) websocket (~> 1.0)
shellany (0.0.1) shellany (0.0.1)
simple-rss (1.3.1)
simple_oauth (0.3.1) simple_oauth (0.3.1)
simplecov (0.15.1) simplecov (0.15.1)
docile (~> 1.1.0) docile (~> 1.1.0)
@ -399,10 +397,6 @@ GEM
simplecov-rcov (0.2.3) simplecov-rcov (0.2.3)
simplecov (>= 0.4.1) simplecov (>= 0.4.1)
slack-notifier (2.3.1) slack-notifier (2.3.1)
spring (2.0.2)
activesupport (>= 4.2)
spring-commands-rspec (1.0.4)
spring (>= 0.9.1)
sprockets (3.7.1) sprockets (3.7.1)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
rack (> 1, < 3) rack (> 1, < 3)
@ -508,7 +502,7 @@ DEPENDENCIES
json json
koala koala
libv8 libv8
mail mail (= 2.6.6)
mime-types mime-types
mysql2 mysql2
net-ldap net-ldap
@ -535,12 +529,9 @@ DEPENDENCIES
rubyntlm! rubyntlm!
sass-rails sass-rails
selenium-webdriver (= 2.53.4) selenium-webdriver (= 2.53.4)
simple-rss
simplecov simplecov
simplecov-rcov simplecov-rcov
slack-notifier slack-notifier
spring
spring-commands-rspec
sprockets sprockets
sqlite3 sqlite3
telegramAPI telegramAPI

0
Rakefile Normal file → Executable file
View file

View file

@ -148,24 +148,26 @@ class App.ControllerGenericIndex extends App.Controller
return item return item
) )
# show description button, only if content exists if !@table
showDescription = false
if App[ @genericObject ].description && !_.isEmpty(objects)
showDescription = true
@html App.view('generic/admin/index')( # show description button, only if content exists
head: @pageData.objects showDescription = false
notes: @pageData.notes if App[ @genericObject ].description && !_.isEmpty(objects)
buttons: @pageData.buttons showDescription = true
menus: @pageData.menus
showDescription: showDescription
)
# show description in content if no no content exists @html App.view('generic/admin/index')(
if _.isEmpty(objects) && App[ @genericObject ].description head: @pageData.objects
description = marked(App[ @genericObject ].description) notes: @pageData.notes
@$('.table-overview').html(description) buttons: @pageData.buttons
return menus: @pageData.menus
showDescription: showDescription
)
# show description in content if no no content exists
if _.isEmpty(objects) && App[ @genericObject ].description
description = marked(App[ @genericObject ].description)
@$('.table-overview').html(description)
return
# append content table # append content table
params = _.extend( params = _.extend(
@ -184,7 +186,10 @@ class App.ControllerGenericIndex extends App.Controller
}, },
@pageData.tableExtend @pageData.tableExtend
) )
new App.ControllerTable(params) if !@table
@table = new App.ControllerTable(params)
else
@table.update(objects: objects)
edit: (id, e) => edit: (id, e) =>
e.preventDefault() e.preventDefault()
@ -1170,7 +1175,6 @@ class App.ObserverController extends App.Controller
if @globalRerender if @globalRerender
@bind('ui:rerender', => @bind('ui:rerender', =>
@lastAttributres = undefined @lastAttributres = undefined
console.log('aaaa', @model, @template)
@maybeRender(App[@model].fullLocal(@object_id)) @maybeRender(App[@model].fullLocal(@object_id))
) )

View file

@ -1,7 +1,7 @@
class SidebarCustomer extends App.Controller class SidebarCustomer extends App.Controller
sidebarItem: => sidebarItem: =>
return if !@permissionCheck('ticket.agent') return if !@permissionCheck('ticket.agent')
return if !@params.customer_id return if _.isEmpty(@params.customer_id)
{ {
head: 'Customer' head: 'Customer'
name: 'customer' name: 'customer'
@ -18,6 +18,7 @@ class SidebarCustomer extends App.Controller
showCustomer: (el) => showCustomer: (el) =>
@el = el @el = el
return if _.isEmpty(@params.customer_id)
new App.WidgetUser( new App.WidgetUser(
el: @el el: @el
user_id: @params.customer_id user_id: @params.customer_id

View file

@ -44,6 +44,8 @@ class App.IdoitObjectSelector extends App.ControllerModal
'' ''
search: (filter) => search: (filter) =>
if _.isEmpty(filter.type)
delete filter.type
if _.isEmpty(filter.title) if _.isEmpty(filter.title)
delete filter.title delete filter.title
else else

View file

@ -23,17 +23,22 @@ class Index extends App.ControllerSubContent
] ]
container: @el.closest('.content') container: @el.closest('.content')
large: true large: true
dndCallback: => dndCallback: (e, item) =>
items = @el.find('table > tbody > tr') items = @el.find('table > tbody > tr')
order = [] prios = []
prio = 0 prio = 0
for item in items for item in items
prio += 1 prio += 1
id = $(item).data('id') id = $(item).data('id')
overview = App.Overview.find(id) prios.push [id, prio]
if overview.prio isnt prio
overview.prio = prio @ajax(
overview.save() id: 'overview_prio'
type: 'POST'
url: "#{@apiPath}/overviews_prio"
processData: true
data: JSON.stringify(prios: prios)
)
) )
App.Config.set('Overview', { prio: 2300, name: 'Overviews', parent: '#manage', target: '#manage/overviews', controller: Index, permission: ['admin.overview'] }, 'NavBarAdmin') App.Config.set('Overview', { prio: 2300, name: 'Overviews', parent: '#manage', target: '#manage/overviews', controller: Index, permission: ['admin.overview'] }, 'NavBarAdmin')

View file

@ -18,8 +18,19 @@ class App.TicketCustomer extends App.ControllerModal
onSubmit: (e) => onSubmit: (e) =>
params = @formParam(e.target) params = @formParam(e.target)
@customer_id = params['customer_id'] ticket = App.Ticket.find(@ticket_id)
ticket.customer_id = params['customer_id']
errors = ticket.validate()
if !_.isEmpty(errors)
@log 'error', errors
@formValidate(
form: e.target
errors: errors
)
return
@customer_id = params['customer_id']
callback = => callback = =>
# close modal # close modal

View file

@ -71,7 +71,7 @@ class App.ObjectOrganizationAutocompletion extends App.Controller
@open() @open()
focusInput: => focusInput: =>
@objectSelect.focus() if not @formControl.hasClass 'focus' @objectSelect.focus() if not @formControl.hasClass('focus')
onBlur: => onBlur: =>
selectObject = @objectSelect.val() selectObject = @objectSelect.val()
@ -85,6 +85,9 @@ class App.ObjectOrganizationAutocompletion extends App.Controller
@objectId.val("guess:#{selectObject}") @objectId.val("guess:#{selectObject}")
@formControl.removeClass 'focus' @formControl.removeClass 'focus'
resetObjectSelection: =>
@objectId.val('').trigger('change')
onObjectClick: (e) => onObjectClick: (e) =>
objectId = $(e.currentTarget).data('object-id') objectId = $(e.currentTarget).data('object-id')
@selectObject(objectId) @selectObject(objectId)
@ -103,23 +106,23 @@ class App.ObjectOrganizationAutocompletion extends App.Controller
# Only work with the last one since its the newest one # Only work with the last one since its the newest one
objectId = @objectId.val().split(',').pop() objectId = @objectId.val().split(',').pop()
return if !objectId if objectId && App[@objectSingle].exists(objectId)
return if !App[@objectSingle].exists(objectId) object = App[@objectSingle].find(objectId)
object = App[@objectSingle].find(objectId) name = object.displayName()
name = object.displayName()
if @attribute.multiple if @attribute.multiple
# create token
@createToken name, objectId
else
if object.email
# quote name for special character # create token
if name.match(/\@|,|;|\^|\+|#|§|\$|%|&|\/|\(|\)|=|\?|!|\*|\[|\]/) @createToken(name, objectId)
name = "\"#{name}\"" else
name += " <#{object.email}>" if object.email
@objectSelect.val(name) # quote name for special character
if name.match(/\@|,|;|\^|\+|#|§|\$|%|&|\/|\(|\)|=|\?|!|\*|\[|\]/)
name = "\"#{name}\""
name += " <#{object.email}>"
@objectSelect.val(name)
if @callback if @callback
@callback(objectId) @callback(objectId)
@ -321,12 +324,16 @@ class App.ObjectOrganizationAutocompletion extends App.Controller
@hideOrganizationMembers() @hideOrganizationMembers()
# hide dropdown # hide dropdown
if !query if _.isEmpty(query)
@emptyResultList() @emptyResultList()
if !@attribute.disableCreateObject if !@attribute.disableCreateObject
@recipientList.append(@buildObjectNew()) @recipientList.append(@buildObjectNew())
# reset object selection
@resetObjectSelection()
return
# show dropdown # show dropdown
if query && ( !@attribute.minLengt || @attribute.minLengt <= query.length ) if query && ( !@attribute.minLengt || @attribute.minLengt <= query.length )
@lazySearch(query) @lazySearch(query)

View file

@ -387,15 +387,17 @@ set new attributes of model (remove already available attributes)
=> =>
return if _.isEmpty(@SUBSCRIPTION_COLLECTION) return if _.isEmpty(@SUBSCRIPTION_COLLECTION)
App.Log.debug('Model', "server notify collection change #{@className}") App.Log.debug('Model', "server notify collection change #{@className}")
@fetchFull( callback = =>
-> @fetchFull(
clear: true ->
) clear: true
)
App.Delay.set(callback, 200, "full-#{@className}")
"Collection::Subscribe::#{@className}" "Collection::Subscribe::#{@className}"
) )
key = @className + '-' + Math.floor( Math.random() * 99999 ) key = "#{@className}-#{Math.floor(Math.random() * 99999)}"
@SUBSCRIPTION_COLLECTION[key] = callback @SUBSCRIPTION_COLLECTION[key] = callback
# fetch init collection # fetch init collection

View file

@ -1,5 +1,5 @@
class App.Overview extends App.Model class App.Overview extends App.Model
@configure 'Overview', 'name', 'prio', 'condition', 'order', 'group_by', 'view', 'user_ids', 'organization_shared', 'role_ids', 'order', 'group_by', 'active', 'updated_at' @configure 'Overview', 'name', 'prio', 'condition', 'order', 'group_by', 'view', 'user_ids', 'organization_shared', 'role_ids', 'active'
@extend Spine.Model.Ajax @extend Spine.Model.Ajax
@url: @apiPath + '/overviews' @url: @apiPath + '/overviews'
@configure_attributes = [ @configure_attributes = [

View file

@ -200,6 +200,26 @@ class App.Ticket extends App.Model
result = true if objectValue.toString().match(contains_regex) result = true if objectValue.toString().match(contains_regex)
else if condition.operator == 'contains not' else if condition.operator == 'contains not'
result = true if !objectValue.toString().match(contains_regex) result = true if !objectValue.toString().match(contains_regex)
else if condition.operator == 'contains all'
result = true
for loopConditionValue in conditionValue
if !_.contains(objectValue, loopConditionValue)
result = false
else if condition.operator == 'contains one'
result = false
for loopConditionValue in conditionValue
if _.contains(objectValue, loopConditionValue)
result = true
else if condition.operator == 'contains all not'
result = true
for loopObjectValue in objectValue
if _.contains(conditionValue, loopObjectValue)
result = false
else if condition.operator == 'contains one not'
result = false
for loopObjectValue in objectValue
if !_.contains(conditionValue, loopObjectValue)
result = true
else if condition.operator == 'is' else if condition.operator == 'is'
result = true if objectValue.toString().trim().toLowerCase() is loopConditionValue.toString().trim().toLowerCase() result = true if objectValue.toString().trim().toLowerCase() is loopConditionValue.toString().trim().toLowerCase()
else if condition.operator == 'is not' else if condition.operator == 'is not'

View file

@ -18,7 +18,7 @@ module ApplicationController::Authenticates
raise Exceptions::NotAuthorized, 'Not authorized (token)!' raise Exceptions::NotAuthorized, 'Not authorized (token)!'
end end
return false if current_user && current_user.permissions?(key) return false if current_user&.permissions?(key)
raise Exceptions::NotAuthorized, 'Not authorized (user)!' raise Exceptions::NotAuthorized, 'Not authorized (user)!'
end end

View file

@ -26,8 +26,7 @@ module ApplicationController::HandlesDevices
if user_device_updated_at if user_device_updated_at
# check if entry exists / only if write action # check if entry exists / only if write action
diff = Time.zone.now - 10.minutes diff = Time.zone.now - 10.minutes
method = request.method if %w[GET OPTIONS HEAD].include?(request.method)
if method == 'GET' || method == 'OPTIONS' || method == 'HEAD'
diff = Time.zone.now - 30.minutes diff = Time.zone.now - 30.minutes
end end

View file

@ -72,7 +72,7 @@ module ApplicationController::HandlesErrors
data[:error_human] = data[:error] data[:error_human] = data[:error]
end end
if Rails.env.production? && !data[:error_human].empty? if Rails.env.production? && data[:error_human].present?
data[:error] = data.delete(:error_human) data[:error] = data.delete(:error_human)
end end
data data

View file

@ -146,7 +146,7 @@ module ApplicationController::RendersModels
def model_references_check(object, params) def model_references_check(object, params)
generic_object = object.find(params[:id]) generic_object = object.find(params[:id])
result = Models.references(object, generic_object.id) result = Models.references(object, generic_object.id)
return false if result.empty? return false if result.blank?
raise Exceptions::UnprocessableEntity, 'Can\'t delete, object has references.' raise Exceptions::UnprocessableEntity, 'Can\'t delete, object has references.'
rescue => e rescue => e
raise Exceptions::UnprocessableEntity, e raise Exceptions::UnprocessableEntity, e

View file

@ -226,7 +226,7 @@ class ChannelsEmailController < ApplicationController
Channel.where(area: 'Email::Notification').each do |channel| Channel.where(area: 'Email::Notification').each do |channel|
active = false active = false
if adapter =~ /^#{channel.options[:outbound][:adapter]}$/i if adapter.match?(/^#{channel.options[:outbound][:adapter]}$/i)
active = true active = true
channel.options = { channel.options = {
outbound: { outbound: {

View file

@ -44,7 +44,7 @@ class FormController < ApplicationController
errors['email'] = 'required' errors['email'] = 'required'
elsif params[:email] !~ /@/ elsif params[:email] !~ /@/
errors['email'] = 'invalid' errors['email'] = 'invalid'
elsif params[:email] =~ /(>|<|\||\!|"|§|'|\$|%|&|\(|\)|\?|\s|\.\.)/ elsif params[:email].match?(/(>|<|\||\!|"|§|'|\$|%|&|\(|\)|\?|\s|\.\.)/)
errors['email'] = 'invalid' errors['email'] = 'invalid'
end end
if params[:title].blank? if params[:title].blank?
@ -126,19 +126,16 @@ class FormController < ApplicationController
internal: false, internal: false,
) )
if params[:file] params[:file]&.each do |file|
Store.add(
params[:file].each do |file| object: 'Ticket::Article',
Store.add( o_id: article.id,
object: 'Ticket::Article', data: file.read,
o_id: article.id, filename: file.original_filename,
data: file.read, preferences: {
filename: file.original_filename, 'Mime-Type' => file.content_type,
preferences: { }
'Mime-Type' => file.content_type, )
}
)
end
end end
UserInfo.current_user_id = 1 UserInfo.current_user_id = 1

View file

@ -66,7 +66,7 @@ curl http://localhost/api/v1/getting_started -v -u #{login}:#{password}
# verify auto wizard file # verify auto wizard file
auto_wizard_data = AutoWizard.data auto_wizard_data = AutoWizard.data
if !auto_wizard_data || auto_wizard_data.empty? if auto_wizard_data.blank?
render json: { render json: {
auto_wizard: true, auto_wizard: true,
auto_wizard_success: false, auto_wizard_success: false,
@ -132,7 +132,7 @@ curl http://localhost/api/v1/getting_started -v -u #{login}:#{password}
end end
# validate organization # validate organization
if !params[:organization] || params[:organization].empty? if params[:organization].blank?
messages[:organization] = 'Invalid!' messages[:organization] = 'Invalid!'
else else
settings[:organization] = params[:organization] settings[:organization] = params[:organization]
@ -146,7 +146,7 @@ curl http://localhost/api/v1/getting_started -v -u #{login}:#{password}
end end
end end
if !messages.empty? if messages.present?
render json: { render json: {
result: 'invalid', result: 'invalid',
messages: messages, messages: messages,

View file

@ -26,7 +26,7 @@ class ImportOtrsController < ApplicationController
if !response.success? && response.code.to_s !~ /^40.$/ if !response.success? && response.code.to_s !~ /^40.$/
message_human = '' message_human = ''
translation_map.each do |key, message| translation_map.each do |key, message|
if response.error.to_s =~ /#{Regexp.escape(key)}/i if response.error.to_s.match?(/#{Regexp.escape(key)}/i)
message_human = message message_human = message
end end
end end
@ -39,7 +39,7 @@ class ImportOtrsController < ApplicationController
end end
result = {} result = {}
if response.body =~ /zammad migrator/ if response.body.match?(/zammad migrator/)
migrator_response = JSON.parse(response.body) migrator_response = JSON.parse(response.body)
@ -86,7 +86,7 @@ class ImportOtrsController < ApplicationController
message_human: migrator_response['Error'] message_human: migrator_response['Error']
} }
end end
elsif response.body =~ /(otrs\sag|otrs\.com|otrs\.org)/i elsif response.body.match?(/(otrs\sag|otrs\.com|otrs\.org)/i)
result = { result = {
result: 'invalid', result: 'invalid',
message_human: 'Host found, but no OTRS migrator is installed!' message_human: 'Host found, but no OTRS migrator is installed!'
@ -144,7 +144,7 @@ class ImportOtrsController < ApplicationController
end end
result = 'ok' result = 'ok'
if !issues.empty? if issues.present?
result = 'failed' result = 'failed'
end end
render json: { render json: {

View file

@ -28,7 +28,7 @@ class ImportZendeskController < ApplicationController
if !response.success? if !response.success?
message_human = '' message_human = ''
translation_map.each do |key, message| translation_map.each do |key, message|
if response.error.to_s =~ /#{Regexp.escape(key)}/i if response.error.to_s.match?(/#{Regexp.escape(key)}/i)
message_human = message message_human = message
end end
end end

View file

@ -133,6 +133,8 @@ UserAgent: #{request.env['HTTP_USER_AGENT']}
if Setting.get('check_mk_token') != params[:token] if Setting.get('check_mk_token') != params[:token]
raise Exceptions::UnprocessableEntity, 'Invalid token!' raise Exceptions::UnprocessableEntity, 'Invalid token!'
end end
true
end end
end end

View file

@ -1,9 +1,9 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class Integration::IdoitController < ApplicationController class Integration::IdoitController < ApplicationController
prepend_before_action -> { authentication_check(permission: ['agent.integration.idoit', 'admin.integration.idoit']) }, except: [:verify, :query, :update] prepend_before_action -> { authentication_check(permission: ['agent.integration.idoit', 'admin.integration.idoit']) }, except: %i[verify query update]
prepend_before_action -> { authentication_check(permission: ['admin.integration.idoit']) }, only: [:verify] prepend_before_action -> { authentication_check(permission: ['admin.integration.idoit']) }, only: [:verify]
prepend_before_action -> { authentication_check(permission: ['ticket.agent']) }, only: [:query, :update] prepend_before_action -> { authentication_check(permission: ['ticket.agent']) }, only: %i[query update]
def verify def verify
response = ::Idoit.verify(params[:api_token], params[:endpoint], params[:client_id]) response = ::Idoit.verify(params[:api_token], params[:endpoint], params[:client_id])

View file

@ -93,6 +93,8 @@ class Integration::SipgateController < ApplicationController
xml_error('Feature not configured, please contact your admin!') xml_error('Feature not configured, please contact your admin!')
return return
end end
true
end end
def config_integration def config_integration

View file

@ -18,7 +18,7 @@ class LongPollingController < ApplicationController
params['data'] = {} params['data'] = {}
end end
session_data = {} session_data = {}
if current_user && current_user.id if current_user&.id
session_data = { 'id' => current_user.id } session_data = { 'id' => current_user.id }
end end
@ -61,13 +61,12 @@ class LongPollingController < ApplicationController
# check queue to send # check queue to send
begin begin
# update last ping # update last ping
4.times do 4.times do
sleep 0.25 sleep 0.25
end end
#sleep 1 #sleep 1
Sessions.touch(client_id) Sessions.touch(client_id) # rubocop:disable Rails/SkipsModelValidations
# set max loop time to 24 sec. because of 30 sec. timeout of mod_proxy # set max loop time to 24 sec. because of 30 sec. timeout of mod_proxy
count = 3 count = 3

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class MonitoringController < ApplicationController class MonitoringController < ApplicationController
prepend_before_action -> { authentication_check(permission: 'admin.monitoring') }, except: [:health_check, :status] prepend_before_action -> { authentication_check(permission: 'admin.monitoring') }, except: %i[health_check status]
skip_before_action :verify_csrf_token skip_before_action :verify_csrf_token
=begin =begin
@ -39,7 +39,7 @@ curl http://localhost/api/v1/monitoring/health_check?token=XXX
# inbound channel # inbound channel
if channel.status_in == 'error' if channel.status_in == 'error'
message = "Channel: #{channel.area} in " message = "Channel: #{channel.area} in "
%w(host user uid).each do |key| %w[host user uid].each do |key|
next if channel.options[key].blank? next if channel.options[key].blank?
message += "key:#{channel.options[key]};" message += "key:#{channel.options[key]};"
end end
@ -52,7 +52,7 @@ curl http://localhost/api/v1/monitoring/health_check?token=XXX
# outbound channel # outbound channel
next if channel.status_out != 'error' next if channel.status_out != 'error'
message = "Channel: #{channel.area} out " message = "Channel: #{channel.area} out "
%w(host user uid).each do |key| %w[host user uid].each do |key|
next if channel.options[key].blank? next if channel.options[key].blank?
message += "key:#{channel.options[key]};" message += "key:#{channel.options[key]};"
end end
@ -60,7 +60,7 @@ curl http://localhost/api/v1/monitoring/health_check?token=XXX
end end
# unprocessable mail check # unprocessable mail check
directory = "#{Rails.root}/tmp/unprocessable_mail" directory = Rails.root.join('tmp', 'unprocessable_mail').to_s
if File.exist?(directory) if File.exist?(directory)
count = 0 count = 0
Dir.glob("#{directory}/*.eml") do |_entry| Dir.glob("#{directory}/*.eml") do |_entry|
@ -161,9 +161,7 @@ curl http://localhost/api/v1/monitoring/status?token=XXX
map.each do |key, class_name| map.each do |key, class_name|
status[:counts][key] = class_name.count status[:counts][key] = class_name.count
last = class_name.last last = class_name.last
status[:last_created_at][key] = if last status[:last_created_at][key] = last&.created_at
last.created_at
end
end end
render json: status render json: status

View file

@ -98,20 +98,20 @@ class ObjectManagerAttributesController < ApplicationController
private private
def check_params def check_params
if params[:data_type] =~ /^(boolean)$/ if params[:data_type].match?(/^(boolean)$/)
if params[:data_option][:options] if params[:data_option][:options]
# rubocop:disable Lint/BooleanSymbol
if params[:data_option][:options][:false] if params[:data_option][:options][:false]
params[:data_option][:options][false] = params[:data_option][:options][:false] params[:data_option][:options][false] = params[:data_option][:options].delete(:false)
params[:data_option][:options].delete(:false)
end end
if params[:data_option][:options][:true] if params[:data_option][:options][:true]
params[:data_option][:options][true] = params[:data_option][:options][:true] params[:data_option][:options][true] = params[:data_option][:options].delete(:true)
params[:data_option][:options].delete(:true)
end end
# rubocop:enable Lint/BooleanSymbol
end end
end end
if params[:data_option] && !params[:data_option].key?(:default) if params[:data_option] && !params[:data_option].key?(:default)
params[:data_option][:default] = if params[:data_type] =~ /^(input|select|tree_select)$/ params[:data_option][:default] = if params[:data_type].match?(/^(input|select|tree_select)$/)
'' ''
end end
end end

View file

@ -237,12 +237,16 @@ curl http://localhost/api/v1/organization/{id} -v -u #{login}:#{password} -H "Co
params[:limit].to_i = 500 params[:limit].to_i = 500
end end
query = params[:query]
if query.respond_to?(:permit!)
query = query.permit!.to_h
end
query_params = { query_params = {
query: params[:query], query: query,
limit: params[:limit], limit: params[:limit],
current_user: current_user, current_user: current_user,
} }
if params[:role_ids] && !params[:role_ids].empty? if params[:role_ids].present?
query_params[:role_ids] = params[:role_ids] query_params[:role_ids] = params[:role_ids]
end end

View file

@ -30,7 +30,7 @@ Example:
=begin =begin
Resource: Resource:
GET /api/v1/overviews.json GET /api/v1/overviews
Response: Response:
[ [
@ -47,7 +47,7 @@ Response:
] ]
Test: Test:
curl http://localhost/api/v1/overviews.json -v -u #{login}:#{password} curl http://localhost/api/v1/overviews -v -u #{login}:#{password}
=end =end
@ -58,7 +58,7 @@ curl http://localhost/api/v1/overviews.json -v -u #{login}:#{password}
=begin =begin
Resource: Resource:
GET /api/v1/overviews/#{id}.json GET /api/v1/overviews/#{id}
Response: Response:
{ {
@ -68,7 +68,7 @@ Response:
} }
Test: Test:
curl http://localhost/api/v1/overviews/#{id}.json -v -u #{login}:#{password} curl http://localhost/api/v1/overviews/#{id} -v -u #{login}:#{password}
=end =end
@ -79,7 +79,7 @@ curl http://localhost/api/v1/overviews/#{id}.json -v -u #{login}:#{password}
=begin =begin
Resource: Resource:
POST /api/v1/overviews.json POST /api/v1/overviews
Payload: Payload:
{ {
@ -101,7 +101,7 @@ Response:
} }
Test: Test:
curl http://localhost/api/v1/overviews.json -v -u #{login}:#{password} -H "Content-Type: application/json" -X POST -d '{"name": "some_name","active": true, "note": "some note"}' curl http://localhost/api/v1/overviews -v -u #{login}:#{password} -H "Content-Type: application/json" -X POST -d '{"name": "some_name","active": true, "note": "some note"}'
=end =end
@ -112,7 +112,7 @@ curl http://localhost/api/v1/overviews.json -v -u #{login}:#{password} -H "Conte
=begin =begin
Resource: Resource:
PUT /api/v1/overviews/{id}.json PUT /api/v1/overviews/{id}
Payload: Payload:
{ {
@ -134,7 +134,7 @@ Response:
} }
Test: Test:
curl http://localhost/api/v1/overviews.json -v -u #{login}:#{password} -H "Content-Type: application/json" -X PUT -d '{"name": "some_name","active": true, "note": "some note"}' curl http://localhost/api/v1/overviews -v -u #{login}:#{password} -H "Content-Type: application/json" -X PUT -d '{"name": "some_name","active": true, "note": "some note"}'
=end =end
@ -145,17 +145,55 @@ curl http://localhost/api/v1/overviews.json -v -u #{login}:#{password} -H "Conte
=begin =begin
Resource: Resource:
DELETE /api/v1/overviews/{id}.json DELETE /api/v1/overviews/{id}
Response: Response:
{} {}
Test: Test:
curl http://localhost/api/v1/overviews/#{id}.json -v -u #{login}:#{password} -H "Content-Type: application/json" -X DELETE curl http://localhost/api/v1/overviews/#{id} -v -u #{login}:#{password} -H "Content-Type: application/json" -X DELETE
=end =end
def destroy def destroy
model_destroy_render(Overview, params) model_destroy_render(Overview, params)
end end
=begin
Resource:
POST /api/v1/overviews_prio
Payload:
{
"prios": [
[overview_id, prio],
[overview_id, prio],
[overview_id, prio],
[overview_id, prio],
[overview_id, prio]
]
}
Response:
{
"success": true,
}
Test:
curl http://localhost/api/v1/overviews_prio -v -u #{login}:#{password} -H "Content-Type: application/json" -X POST -d '{"prios": [ [1,1], [44,2] ]}'
=end
def prio
Overview.without_callback(:update, :before, :rearrangement) do
params[:prios].each do |overview_prio|
overview = Overview.find(overview_prio[0])
next if overview.prio == overview_prio[1]
overview.prio = overview_prio[1]
overview.save!
end
end
render json: { success: true }, status: :ok
end
end end

View file

@ -16,6 +16,9 @@ class SearchController < ApplicationController
# get params # get params
query = params[:query] query = params[:query]
if query.respond_to?(:permit!)
query = query.permit!.to_h
end
limit = params[:limit] || 10 limit = params[:limit] || 10
# convert objects string into array of class names # convert objects string into array of class names

View file

@ -1,8 +1,8 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class SessionsController < ApplicationController class SessionsController < ApplicationController
prepend_before_action :authentication_check, only: [:switch_to_user, :list, :delete] prepend_before_action :authentication_check, only: %i[switch_to_user list delete]
skip_before_action :verify_csrf_token, only: [:create, :show, :destroy, :create_omniauth, :create_sso] skip_before_action :verify_csrf_token, only: %i[create show destroy create_omniauth create_sso]
# "Create" a login, aka "log the user in" # "Create" a login, aka "log the user in"
def create def create

View file

@ -93,11 +93,11 @@ class SettingsController < ApplicationController
def keep_certain_attributes def keep_certain_attributes
setting = Setting.find(params[:id]) setting = Setting.find(params[:id])
[:name, :area, :state_initial, :frontend, :options].each do |key| %i[name area state_initial frontend options].each do |key|
params.delete(key) params.delete(key)
end end
if !params[:preferences].empty? if params[:preferences].present?
[:online_service_disable, :permission, :render].each do |key| %i[online_service_disable permission render].each do |key|
params[:preferences].delete(key) params[:preferences].delete(key)
end end
params[:preferences].merge!(setting.preferences) params[:preferences].merge!(setting.preferences)

View file

@ -266,7 +266,7 @@ class TicketArticlesController < ApplicationController
def sanitized_disposition def sanitized_disposition
disposition = params.fetch(:disposition, 'inline') disposition = params.fetch(:disposition, 'inline')
valid_disposition = %w(inline attachment) valid_disposition = %w[inline attachment]
return disposition if valid_disposition.include?(disposition) return disposition if valid_disposition.include?(disposition)
raise Exceptions::NotAuthorized, "Invalid disposition #{disposition} requested. Only #{valid_disposition.join(', ')} are valid." raise Exceptions::NotAuthorized, "Invalid disposition #{disposition} requested. Only #{valid_disposition.join(', ')} are valid."
end end

View file

@ -80,7 +80,7 @@ class TicketsController < ApplicationController
# overwrite params # overwrite params
if !current_user.permissions?('ticket.agent') if !current_user.permissions?('ticket.agent')
[:owner, :owner_id, :customer, :customer_id, :organization, :organization_id, :preferences].each do |key| %i[owner owner_id customer customer_id organization organization_id preferences].each do |key|
clean_params.delete(key) clean_params.delete(key)
end end
clean_params[:customer_id] = current_user.id clean_params[:customer_id] = current_user.id
@ -186,7 +186,7 @@ class TicketsController < ApplicationController
# overwrite params # overwrite params
if !current_user.permissions?('ticket.agent') if !current_user.permissions?('ticket.agent')
[:owner, :owner_id, :customer, :customer_id, :organization, :organization_id, :preferences].each do |key| %i[owner owner_id customer customer_id organization organization_id preferences].each do |key|
clean_params.delete(key) clean_params.delete(key)
end end
end end
@ -270,7 +270,7 @@ class TicketsController < ApplicationController
.limit(6) .limit(6)
# if we do not have open related tickets, search for any tickets # if we do not have open related tickets, search for any tickets
if ticket_lists.empty? if ticket_lists.blank?
ticket_lists = Ticket ticket_lists = Ticket
.where( .where(
customer_id: ticket.customer_id, customer_id: ticket.customer_id,
@ -389,11 +389,16 @@ class TicketsController < ApplicationController
params[:limit].to_i = 100 params[:limit].to_i = 100
end end
query = params[:query]
if query.respond_to?(:permit!)
query = query.permit!.to_h
end
# build result list # build result list
tickets = Ticket.search( tickets = Ticket.search(
query: query,
condition: params[:condition].to_h,
limit: params[:limit], limit: params[:limit],
query: params[:query],
condition: params[:condition],
current_user: current_user, current_user: current_user,
) )
@ -435,11 +440,9 @@ class TicketsController < ApplicationController
assets = {} assets = {}
ticket_ids = [] ticket_ids = []
if tickets tickets&.each do |ticket|
tickets.each do |ticket| ticket_ids.push ticket.id
ticket_ids.push ticket.id assets = ticket.assets(assets)
assets = ticket.assets(assets)
end
end end
# return result # return result
@ -504,7 +507,7 @@ class TicketsController < ApplicationController
# lookup open org tickets # lookup open org tickets
org_tickets = {} org_tickets = {}
if params[:organization_id] && !params[:organization_id].empty? if params[:organization_id].present?
organization = Organization.lookup(id: params[:organization_id]) organization = Organization.lookup(id: params[:organization_id])
if !organization if !organization
raise "No such organization with id #{params[:organization_id]}" raise "No such organization with id #{params[:organization_id]}"

View file

@ -164,7 +164,7 @@ class TimeAccountingsController < ApplicationController
] ]
result = [] result = []
results.each do |row| results.each do |row|
row[:ticket].keys.each do |field| row[:ticket].each_key do |field|
next if row[:ticket][field].blank? next if row[:ticket][field].blank?
next if !row[:ticket][field].is_a?(ActiveSupport::TimeWithZone) next if !row[:ticket][field].is_a?(ActiveSupport::TimeWithZone)
@ -250,7 +250,7 @@ class TimeAccountingsController < ApplicationController
customers[ticket.customer_id][:time_unit] += local_time_unit[:time_unit] customers[ticket.customer_id][:time_unit] += local_time_unit[:time_unit]
end end
results = [] results = []
customers.each do |_customer_id, content| customers.each_value do |content|
results.push content results.push content
end end
@ -326,7 +326,7 @@ class TimeAccountingsController < ApplicationController
organizations[ticket.organization_id][:time_unit] += local_time_unit[:time_unit] organizations[ticket.organization_id][:time_unit] += local_time_unit[:time_unit]
end end
results = [] results = []
organizations.each do |_customer_id, content| organizations.each_value do |content|
results.push content results.push content
end end

View file

@ -14,7 +14,7 @@ class UserAccessTokenController < ApplicationController
end end
local_permissions = current_user.permissions local_permissions = current_user.permissions
local_permissions_new = {} local_permissions_new = {}
local_permissions.each do |key, _value| local_permissions.each_key do |key|
keys = Object.const_get('Permission').with_parents(key) keys = Object.const_get('Permission').with_parents(key)
keys.each do |local_key| keys.each do |local_key|
next if local_permissions_new.key?([local_key]) next if local_permissions_new.key?([local_key])

View file

@ -8,7 +8,7 @@ class UserDevicesController < ApplicationController
devices_full = [] devices_full = []
devices.each do |device| devices.each do |device|
attributes = device.attributes attributes = device.attributes
if device.location_details['city_name'] && !device.location_details['city_name'].empty? if device.location_details['city_name'].present?
attributes['location'] += ", #{device.location_details['city_name']}" attributes['location'] += ", #{device.location_details['city_name']}"
end end
attributes.delete('created_at') attributes.delete('created_at')

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class UsersController < ApplicationController class UsersController < ApplicationController
prepend_before_action :authentication_check, except: [:create, :password_reset_send, :password_reset_verify, :image] prepend_before_action :authentication_check, except: %i[create password_reset_send password_reset_verify image]
prepend_before_action :authentication_check_only, only: [:create] prepend_before_action :authentication_check_only, only: [:create]
# @path [GET] /users # @path [GET] /users
@ -145,7 +145,7 @@ class UsersController < ApplicationController
group_ids = [] group_ids = []
role_ids = [] role_ids = []
if count <= 2 if count <= 2
Role.where(name: %w(Admin Agent)).each do |role| Role.where(name: %w[Admin Agent]).each do |role|
role_ids.push role.id role_ids.push role.id
end end
Group.all().each do |group| Group.all().each do |group|
@ -363,12 +363,17 @@ class UsersController < ApplicationController
params[:limit].to_i = 500 params[:limit].to_i = 500
end end
query = params[:query]
if query.respond_to?(:permit!)
query = query.permit!.to_h
end
query_params = { query_params = {
query: params[:query], query: query,
limit: params[:limit], limit: params[:limit],
current_user: current_user, current_user: current_user,
} }
[:role_ids, :permissions].each do |key| %i[role_ids permissions].each do |key|
next if params[key].blank? next if params[key].blank?
query_params[key] = params[key] query_params[key] = params[key]
end end
@ -1046,7 +1051,7 @@ curl http://localhost/api/v1/users/avatar -v -u #{login}:#{password} -H "Content
def permission_check_by_permission(params) def permission_check_by_permission(params)
return true if current_user.permissions?('admin.user') return true if current_user.permissions?('admin.user')
%i(role_ids roles).each do |key| %i[role_ids roles].each do |key|
next if !params[key] next if !params[key]
if current_user.permissions?('ticket.agent') if current_user.permissions?('ticket.agent')
params.delete(key) params.delete(key)
@ -1059,7 +1064,7 @@ curl http://localhost/api/v1/users/avatar -v -u #{login}:#{password} -H "Content
params[:role_ids] = Role.signup_role_ids params[:role_ids] = Role.signup_role_ids
end end
%i(group_ids groups).each do |key| %i[group_ids groups].each do |key|
next if !params[key] next if !params[key]
if current_user.permissions?('ticket.agent') if current_user.permissions?('ticket.agent')
params.delete(key) params.delete(key)

View file

@ -99,7 +99,7 @@ return all activity entries of an user
permission_ids = user.permissions_with_child_ids permission_ids = user.permissions_with_child_ids
group_ids = user.group_ids_access('read') group_ids = user.group_ids_access('read')
stream = if group_ids.empty? stream = if group_ids.blank?
ActivityStream.where('(permission_id IN (?) AND group_id is NULL)', permission_ids) ActivityStream.where('(permission_id IN (?) AND group_id is NULL)', permission_ids)
.order('created_at DESC, id DESC') .order('created_at DESC, id DESC')
.limit(limit) .limit(limit)

View file

@ -33,7 +33,7 @@ returns
return data if !self['created_by_id'] && !self['updated_by_id'] return data if !self['created_by_id'] && !self['updated_by_id']
app_model_user = User.to_app_model app_model_user = User.to_app_model
%w(created_by_id updated_by_id).each do |local_user_id| %w[created_by_id updated_by_id].each do |local_user_id|
next if !self[ local_user_id ] next if !self[ local_user_id ]
next if data[ app_model_user ] && data[ app_model_user ][ self[ local_user_id ] ] next if data[ app_model_user ] && data[ app_model_user ][ self[ local_user_id ] ]
user = User.lookup(id: self[ local_user_id ]) user = User.lookup(id: self[ local_user_id ])
@ -75,12 +75,12 @@ get assets and record_ids of selector
attribute_ref_class = models[attribute_class][:reflections][reflection].klass attribute_ref_class = models[attribute_class][:reflections][reflection].klass
if content['value'].instance_of?(Array) if content['value'].instance_of?(Array)
content['value'].each do |item_id| content['value'].each do |item_id|
attribute_object = attribute_ref_class.find_by(id: item_id) next if item_id.blank?
if attribute_object attribute_object = attribute_ref_class.lookup(id: item_id)
assets = attribute_object.assets(assets) next if !attribute_object
end assets = attribute_object.assets(assets)
end end
else elsif content['value'].present?
attribute_object = attribute_ref_class.find_by(id: content['value']) attribute_object = attribute_ref_class.find_by(id: content['value'])
if attribute_object if attribute_object
assets = attribute_object.assets(assets) assets = attribute_object.assets(assets)
@ -138,11 +138,11 @@ get assets of object list
require item['object'].to_filename require item['object'].to_filename
record = Kernel.const_get(item['object']).find(item['o_id']) record = Kernel.const_get(item['object']).find(item['o_id'])
assets = record.assets(assets) assets = record.assets(assets)
if item['created_by_id'] if item['created_by_id'].present?
user = User.find(item['created_by_id']) user = User.find(item['created_by_id'])
assets = user.assets(assets) assets = user.assets(assets)
end end
if item['updated_by_id'] if item['updated_by_id'].present?
user = User.find(item['updated_by_id']) user = User.find(item['updated_by_id'])
assets = user.assets(assets) assets = user.assets(assets)
end end

View file

@ -109,7 +109,7 @@ returns
return cache if cache return cache if cache
attributes = self.attributes attributes = self.attributes
relevant = %i(has_and_belongs_to_many has_many) relevant = %i[has_and_belongs_to_many has_many]
eager_load = [] eager_load = []
pluck = [] pluck = []
keys = [] keys = []
@ -180,7 +180,7 @@ returns
next if !item[:name] next if !item[:name]
attributes[assoc.name.to_s].push item[:name] attributes[assoc.name.to_s].push item[:name]
end end
if ref.count.positive? && attributes[assoc.name.to_s].empty? if ref.count.positive? && attributes[assoc.name.to_s].blank?
attributes.delete(assoc.name.to_s) attributes.delete(assoc.name.to_s)
end end
next next
@ -216,7 +216,7 @@ returns
def filter_attributes(attributes) def filter_attributes(attributes)
# remove forbitten attributes # remove forbitten attributes
%w(password token tokens token_ids).each do |item| %w[password token tokens token_ids].each do |item|
attributes.delete(item) attributes.delete(item)
end end
end end
@ -237,7 +237,7 @@ returns
def association_id_validation(attribute_id, value) def association_id_validation(attribute_id, value)
return true if value.nil? return true if value.nil?
attributes.each do |key, _value| attributes.each_key do |key|
next if key != attribute_id next if key != attribute_id
# check if id is assigned # check if id is assigned
@ -339,16 +339,15 @@ returns
class_object = assoc.klass class_object = assoc.klass
lookup = nil lookup = nil
if class_object == User if class_object == User
if value.instance_of?(String) if !value.instance_of?(String)
if !lookup
lookup = class_object.lookup(login: value)
end
if !lookup
lookup = class_object.lookup(email: value)
end
else
raise ArgumentError, "String is needed as ref value #{value.inspect} for '#{assoc_name}'" raise ArgumentError, "String is needed as ref value #{value.inspect} for '#{assoc_name}'"
end end
if !lookup
lookup = class_object.lookup(login: value)
end
if !lookup
lookup = class_object.lookup(email: value)
end
else else
lookup = class_object.lookup(name: value) lookup = class_object.lookup(name: value)
end end
@ -367,7 +366,7 @@ returns
end end
next if !value.instance_of?(Array) next if !value.instance_of?(Array)
next if value.empty? next if value.blank?
next if !value[0].instance_of?(String) next if !value[0].instance_of?(String)
# handle _ids values # handle _ids values
@ -383,16 +382,15 @@ returns
value.each do |item| value.each do |item|
lookup = nil lookup = nil
if class_object == User if class_object == User
if item.instance_of?(String) if !item.instance_of?(String)
if !lookup
lookup = class_object.lookup(login: item)
end
if !lookup
lookup = class_object.lookup(email: item)
end
else
raise ArgumentError, "String is needed in array ref as ref value #{value.inspect} for '#{assoc_name}'" raise ArgumentError, "String is needed in array ref as ref value #{value.inspect} for '#{assoc_name}'"
end end
if !lookup
lookup = class_object.lookup(login: item)
end
if !lookup
lookup = class_object.lookup(email: item)
end
else else
lookup = class_object.lookup(name: item) lookup = class_object.lookup(name: item)
end end

View file

@ -43,7 +43,7 @@ returns
# only use object attributes # only use object attributes
clean_params = {} clean_params = {}
new.attributes.each do |attribute, _value| new.attributes.each_key do |attribute|
next if !data.key?(attribute.to_sym) next if !data.key?(attribute.to_sym)
# check reference records, referenced by _id attributes # check reference records, referenced by _id attributes
@ -80,7 +80,7 @@ returns
def filter_unused_params(data) def filter_unused_params(data)
# we do want to set this via database # we do want to set this via database
[:action, :controller, :updated_at, :created_at, :updated_by_id, :created_by_id, :updated_by, :created_by].each do |key| %i[action controller updated_at created_at updated_by_id created_by_id updated_by created_by].each do |key|
data.delete(key) data.delete(key)
end end

View file

@ -123,8 +123,8 @@ returns
return record return record
end end
record = new(data) record = new(data)
record.save record.save!
return record record
elsif data[:name] elsif data[:name]
# do lookup with == to handle case insensitive databases # do lookup with == to handle case insensitive databases
@ -140,8 +140,8 @@ returns
end end
end end
record = new(data) record = new(data)
record.save record.save!
return record record
elsif data[:login] elsif data[:login]
# do lookup with == to handle case insensitive databases # do lookup with == to handle case insensitive databases
@ -157,8 +157,8 @@ returns
end end
end end
record = new(data) record = new(data)
record.save record.save!
return record record
elsif data[:email] elsif data[:email]
# do lookup with == to handle case insensitive databases # do lookup with == to handle case insensitive databases
@ -174,8 +174,8 @@ returns
end end
end end
record = new(data) record = new(data)
record.save record.save!
return record record
elsif data[:locale] elsif data[:locale]
# do lookup with == to handle case insensitive databases # do lookup with == to handle case insensitive databases
@ -191,8 +191,8 @@ returns
end end
end end
record = new(data) record = new(data)
record.save record.save!
return record record
else else
raise ArgumentError, 'Need name, login, email or locale for create_or_update()' raise ArgumentError, 'Need name, login, email or locale for create_or_update()'
end end

View file

@ -21,7 +21,7 @@ touch references by params
object_class = Kernel.const_get(data[:object]) object_class = Kernel.const_get(data[:object])
object = object_class.lookup(id: data[:o_id]) object = object_class.lookup(id: data[:o_id])
return if !object return if !object
object.touch object.touch # rubocop:disable Rails/SkipsModelValidations
rescue => e rescue => e
logger.error e logger.error e
end end

View file

@ -37,7 +37,7 @@ store attachments for this object
self.attachments_buffer = attachments self.attachments_buffer = attachments
# update if object already exists # update if object already exists
return if !(id && id.nonzero?) return if !(id&.nonzero?)
attachments_buffer_check attachments_buffer_check
end end

View file

@ -90,7 +90,7 @@ class Authorization < ApplicationModel
def delete_user_cache def delete_user_cache
return if !user return if !user
user.touch user.touch # rubocop:disable Rails/SkipsModelValidations
end end
end end

View file

@ -105,16 +105,16 @@ add avatar by url
# fetch image based on http url # fetch image based on http url
if data[:url].present? if data[:url].present?
if data[:url] =~ /^http/ if data[:url].match?(/^http/)
# check if source ist already updated within last 2 minutes # check if source ist already updated within last 2 minutes
if avatar_already_exists && avatar_already_exists.source_url == data[:url] if avatar_already_exists&.source_url == data[:url]
return if avatar_already_exists.updated_at > 2.minutes.ago return if avatar_already_exists.updated_at > 2.minutes.ago
end end
# twitter workaround to get bigger avatar images # twitter workaround to get bigger avatar images
# see also https://dev.twitter.com/overview/general/user-profile-images-and-banners # see also https://dev.twitter.com/overview/general/user-profile-images-and-banners
if data[:url] =~ %r{//pbs.twimg.com/}i if data[:url].match?(%r{//pbs.twimg.com/}i)
data[:url].sub!(/normal\.(png|jpg|gif)$/, 'bigger.\1') data[:url].sub!(/normal\.(png|jpg|gif)$/, 'bigger.\1')
end end
@ -134,10 +134,10 @@ add avatar by url
end end
logger.info "Fetchd image '#{data[:url]}', http code: #{response.code}" logger.info "Fetchd image '#{data[:url]}', http code: #{response.code}"
mime_type = 'image' mime_type = 'image'
if data[:url] =~ /\.png/i if data[:url].match?(/\.png/i)
mime_type = 'image/png' mime_type = 'image/png'
end end
if data[:url] =~ /\.(jpg|jpeg)/i if data[:url].match?(/\.(jpg|jpeg)/i)
mime_type = 'image/jpeg' mime_type = 'image/jpeg'
end end
if !data[:resize] if !data[:resize]
@ -150,10 +150,10 @@ add avatar by url
data[:full][:mime_type] = mime_type data[:full][:mime_type] = mime_type
# try zammad backend to find image based on email # try zammad backend to find image based on email
elsif data[:url] =~ /@/ elsif data[:url].match?(/@/)
# check if source ist already updated within last 3 minutes # check if source ist already updated within last 3 minutes
if avatar_already_exists && avatar_already_exists.source_url == data[:url] if avatar_already_exists&.source_url == data[:url]
return if avatar_already_exists.updated_at > 2.minutes.ago return if avatar_already_exists.updated_at > 2.minutes.ago
end end
@ -170,8 +170,8 @@ add avatar by url
# check if avatar need to be updated # check if avatar need to be updated
if data[:resize].present? && data[:resize][:content].present? if data[:resize].present? && data[:resize][:content].present?
record[:store_hash] = Digest::MD5.hexdigest(data[:resize][:content]) record[:store_hash] = Digest::MD5.hexdigest(data[:resize][:content])
if avatar_already_exists && avatar_already_exists.store_hash == record[:store_hash] if avatar_already_exists&.store_hash == record[:store_hash]
avatar_already_exists.touch avatar_already_exists.touch # rubocop:disable Rails/SkipsModelValidations
return avatar_already_exists return avatar_already_exists
end end
end end

View file

@ -83,11 +83,11 @@ returns
=end =end
def self.ical_feeds def self.ical_feeds
data = YAML.load_file(Rails.root.join('config/holiday_calendars.yml')) data = YAML.load_file(Rails.root.join('config', 'holiday_calendars.yml'))
url = data['url'] url = data['url']
data['countries'].map do |country, domain| data['countries'].map do |country, domain|
[(url % { domain: domain }), country] [format(url, domain: domain), country]
end.to_h end.to_h
end end
@ -210,7 +210,7 @@ returns
end end
def self.fetch_parse(location) def self.fetch_parse(location)
if location =~ /^http/i if location.match?(/^http/i)
result = UserAgent.get(location) result = UserAgent.get(location)
if !result.success? if !result.success?
raise result.error raise result.error
@ -257,7 +257,7 @@ returns
end end
# ignore daylight saving time entries # ignore daylight saving time entries
return if comment =~ /(daylight saving|sommerzeit|summertime)/i return if comment.match?(/(daylight saving|sommerzeit|summertime)/i)
[day, comment] [day, comment]
end end

View file

@ -50,7 +50,6 @@ fetch one account
end end
begin begin
# we need to require each channel backend individually otherwise we get a # we need to require each channel backend individually otherwise we get a
# 'warning: toplevel constant Twitter referenced by Channel::Driver::Twitter' error e.g. # 'warning: toplevel constant Twitter referenced by Channel::Driver::Twitter' error e.g.
# so we have to convert the channel name to the filename via Rails String.underscore # so we have to convert the channel name to the filename via Rails String.underscore
@ -94,7 +93,6 @@ stream instance of account
adapter = options[:adapter] adapter = options[:adapter]
begin begin
# we need to require each channel backend individually otherwise we get a # we need to require each channel backend individually otherwise we get a
# 'warning: toplevel constant Twitter referenced by Channel::Driver::Twitter' error e.g. # 'warning: toplevel constant Twitter referenced by Channel::Driver::Twitter' error e.g.
# so we have to convert the channel name to the filename via Rails String.underscore # so we have to convert the channel name to the filename via Rails String.underscore
@ -264,7 +262,6 @@ send via account
result = nil result = nil
begin begin
# we need to require each channel backend individually otherwise we get a # we need to require each channel backend individually otherwise we get a
# 'warning: toplevel constant Twitter referenced by Channel::Driver::Twitter' error e.g. # 'warning: toplevel constant Twitter referenced by Channel::Driver::Twitter' error e.g.
# so we have to convert the channel name to the filename via Rails String.underscore # so we have to convert the channel name to the filename via Rails String.underscore

View file

@ -40,7 +40,7 @@ returns
end end
end end
if !access if !access
%w(inbound outbound).each do |key| %w[inbound outbound].each do |key|
if attributes['options'] && attributes['options'][key] && attributes['options'][key]['options'] if attributes['options'] && attributes['options'][key] && attributes['options'][key]['options']
attributes['options'][key]['options'].delete('password') attributes['options'][key]['options'].delete('password')
end end
@ -51,7 +51,7 @@ returns
end end
return data if !self['created_by_id'] && !self['updated_by_id'] return data if !self['created_by_id'] && !self['updated_by_id']
%w(created_by_id updated_by_id).each do |local_user_id| %w[created_by_id updated_by_id].each do |local_user_id|
next if !self[ local_user_id ] next if !self[ local_user_id ]
next if data[ User.to_app_model ] && data[ User.to_app_model ][ self[ local_user_id ] ] next if data[ User.to_app_model ] && data[ User.to_app_model ][ self[ local_user_id ] ]
user = User.lookup(id: self[ local_user_id ]) user = User.lookup(id: self[ local_user_id ])

View file

@ -60,8 +60,7 @@ class Channel::Driver::Facebook
true true
end end
def disconnect def disconnect; end
end
=begin =begin

View file

@ -104,7 +104,7 @@ example
# sort messages by date on server (if not supported), if not fetch messages via search (first in, first out) # sort messages by date on server (if not supported), if not fetch messages via search (first in, first out)
filter = ['ALL'] filter = ['ALL']
if keep_on_server && check_type != 'check' && check_type != 'verify' if keep_on_server && check_type != 'check' && check_type != 'verify'
filter = %w(NOT SEEN) filter = %w[NOT SEEN]
end end
begin begin
message_ids = @imap.sort(['DATE'], filter, 'US-ASCII') message_ids = @imap.sort(['DATE'], filter, 'US-ASCII')
@ -254,7 +254,7 @@ returns
# verify if message is already imported via same channel, if not, import it again # verify if message is already imported via same channel, if not, import it again
ticket = article.ticket ticket = article.ticket
if ticket && ticket.preferences && ticket.preferences[:channel_id].present? && channel.present? if ticket&.preferences && ticket.preferences[:channel_id].present? && channel.present?
return false if ticket.preferences[:channel_id] != channel[:id] return false if ticket.preferences[:channel_id] != channel[:id]
end end

View file

@ -27,7 +27,7 @@ class Channel::Driver::Smtp
return if Setting.get('import_mode') return if Setting.get('import_mode')
# set smtp defaults # set smtp defaults
if !options.key?(:port) || options[:port].empty? if !options.key?(:port) || options[:port].blank?
options[:port] = 25 options[:port] = 25
end end
if !options.key?(:ssl) if !options.key?(:ssl)

View file

@ -119,8 +119,8 @@ returns
end end
def disconnect def disconnect
@stream_client.disconnect if @stream_client @stream_client&.disconnect
@rest_client.disconnect if @rest_client @rest_client&.disconnect
end end
=begin =begin
@ -203,12 +203,11 @@ returns
stream_start stream_start
rescue Twitter::Error::Unauthorized => e rescue Twitter::Error::Unauthorized => e
Rails.logger.info "Unable to stream, try #{loop_count}, error #{e.inspect}" Rails.logger.info "Unable to stream, try #{loop_count}, error #{e.inspect}"
if loop_count < 2 if loop_count >= 2
Rails.logger.info "wait for #{sleep_on_unauthorized} sec. and try it again"
sleep sleep_on_unauthorized
else
raise "Unable to stream, try #{loop_count}, error #{e.inspect}" raise "Unable to stream, try #{loop_count}, error #{e.inspect}"
end end
Rails.logger.info "wait for #{sleep_on_unauthorized} sec. and try it again"
sleep sleep_on_unauthorized
end end
end end
end end
@ -233,7 +232,7 @@ returns
filter[:replies] = 'all' filter[:replies] = 'all'
end end
return if filter.empty? return if filter.blank?
@stream_client.client.user(filter) do |tweet| @stream_client.client.user(filter) do |tweet|
next if tweet.class != Twitter::Tweet && tweet.class != Twitter::DirectMessage next if tweet.class != Twitter::Tweet && tweet.class != Twitter::DirectMessage
@ -258,11 +257,9 @@ returns
# check if it's mention # check if it's mention
if sync['mentions'] && sync['mentions']['group_id'].present? if sync['mentions'] && sync['mentions']['group_id'].present?
hit = false hit = false
if tweet.user_mentions tweet.user_mentions&.each do |user|
tweet.user_mentions.each do |user| if user.id.to_s == @channel.options['user']['id'].to_s
if user.id.to_s == @channel.options['user']['id'].to_s hit = true
hit = true
end
end end
end end
if hit if hit
@ -299,7 +296,7 @@ returns
next if item['term'].blank? next if item['term'].blank?
next if item['term'] == '#' next if item['term'] == '#'
next if item['group_id'].blank? next if item['group_id'].blank?
if body =~ /#{item['term']}/ if body.match?(/#{item['term']}/)
hit = item hit = item
end end
end end

View file

@ -69,7 +69,7 @@ module Channel::EmailBuild
end end
# build email without any attachments # build email without any attachments
if !html_alternative && ( !attr[:attachments] || attr[:attachments].empty? ) if !html_alternative && attr[:attachments].blank?
mail.content_type 'text/plain; charset=UTF-8' mail.content_type 'text/plain; charset=UTF-8'
mail.body attr[:body] mail.body attr[:body]
return mail return mail
@ -84,19 +84,17 @@ module Channel::EmailBuild
html_container.add_part html_alternative html_container.add_part html_alternative
# place to add inline attachments related to html alternative # place to add inline attachments related to html alternative
if attr[:attachments] attr[:attachments]&.each do |attachment|
attr[:attachments].each do |attachment| next if attachment.class == Hash
next if attachment.class == Hash next if attachment.preferences['Content-ID'].blank?
next if attachment.preferences['Content-ID'].empty? attachment = Mail::Part.new do
attachment = Mail::Part.new do content_type attachment.preferences['Content-Type']
content_type attachment.preferences['Content-Type'] content_id "<#{attachment.preferences['Content-ID']}>"
content_id "<#{attachment.preferences['Content-ID']}>" content_disposition attachment.preferences['Content-Disposition'] || 'inline'
content_disposition attachment.preferences['Content-Disposition'] || 'inline' content_transfer_encoding 'binary'
content_transfer_encoding 'binary' body attachment.content.force_encoding('BINARY')
body attachment.content.force_encoding('BINARY')
end
html_container.add_part attachment
end end
html_container.add_part attachment
end end
alternative_bodies.add_part html_container alternative_bodies.add_part html_container
end end
@ -104,23 +102,21 @@ module Channel::EmailBuild
mail.add_part alternative_bodies mail.add_part alternative_bodies
# add attachments # add attachments
if attr[:attachments] attr[:attachments]&.each do |attachment|
attr[:attachments].each do |attachment| if attachment.class == Hash
if attachment.class == Hash attachment['content-id'] = nil
attachment['content-id'] = nil mail.attachments[ attachment[:filename] ] = attachment
mail.attachments[ attachment[:filename] ] = attachment else
else next if attachment.preferences['Content-ID'].present?
next if !attachment.preferences['Content-ID'].empty? filename = attachment.filename
filename = attachment.filename encoded_filename = Mail::Encodings.decode_encode filename, :encode
encoded_filename = Mail::Encodings.decode_encode filename, :encode disposition = attachment.preferences['Content-Disposition'] || 'attachment'
disposition = attachment.preferences['Content-Disposition'] || 'attachment' content_type = attachment.preferences['Content-Type'] || 'application/octet-stream'
content_type = attachment.preferences['Content-Type'] || 'application/octet-stream' mail.attachments[attachment.filename] = {
mail.attachments[attachment.filename] = { content_disposition: "#{disposition}; filename=\"#{encoded_filename}\"",
content_disposition: "#{disposition}; filename=\"#{encoded_filename}\"", content_type: "#{content_type}; filename=\"#{encoded_filename}\"",
content_type: "#{content_type}; filename=\"#{encoded_filename}\"", content: attachment.content
content: attachment.content }
}
end
end end
end end
mail mail
@ -137,7 +133,7 @@ returns
=end =end
def self.recipient_line(realname, email) def self.recipient_line(realname, email)
return "#{realname} <#{email}>" if realname =~ /^[A-z]+$/i return "#{realname} <#{email}>" if realname.match?(/^[A-z]+$/i)
"\"#{realname.gsub('"', '\"')}\" <#{email}>" "\"#{realname.gsub('"', '\"')}\" <#{email}>"
end end
@ -154,7 +150,7 @@ Check if string is a complete html document. If not, add head and css styles.
# apply mail client fixes # apply mail client fixes
html = Channel::EmailBuild.html_mail_client_fixes(html) html = Channel::EmailBuild.html_mail_client_fixes(html)
return html if html =~ /<html>/i return html if html.match?(/<html>/i)
# use block form because variable html could contain backslashes and e. g. '\1' that # use block form because variable html could contain backslashes and e. g. '\1' that
# must not be handled as back-references for regular expressions # must not be handled as back-references for regular expressions

View file

@ -94,7 +94,7 @@ class Channel::EmailParser
# verify content, ignore recipients with non email address # verify content, ignore recipients with non email address
['to', 'cc', 'delivered-to', 'x-original-to', 'envelope-to'].each do |field| ['to', 'cc', 'delivered-to', 'x-original-to', 'envelope-to'].each do |field|
next if data[field.to_sym].blank? next if data[field.to_sym].blank?
next if data[field.to_sym] =~ /@/ next if data[field.to_sym].match?(/@/)
data[field.to_sym] = '' data[field.to_sym] = ''
end end
@ -146,7 +146,7 @@ class Channel::EmailParser
if mail.multipart? if mail.multipart?
# html attachment/body may exists and will be converted to strict html # html attachment/body may exists and will be converted to strict html
if mail.html_part && mail.html_part.body if mail.html_part&.body
data[:body] = mail.html_part.body.to_s data[:body] = mail.html_part.body.to_s
data[:body] = Encode.conv(mail.html_part.charset.to_s, data[:body]) data[:body] = Encode.conv(mail.html_part.charset.to_s, data[:body])
data[:body] = data[:body].html2html_strict.to_s.force_encoding('utf-8') data[:body] = data[:body].html2html_strict.to_s.force_encoding('utf-8')
@ -196,17 +196,15 @@ class Channel::EmailParser
end end
# get attachments # get attachments
if mail.parts mail.parts&.each do |part|
mail.parts.each do |part|
# protect process to work fine with spam emails, see test/fixtures/mail15.box # protect process to work fine with spam emails, see test/fixtures/mail15.box
begin begin
attachs = _get_attachment(part, data[:attachments], mail) attachs = _get_attachment(part, data[:attachments], mail)
data[:attachments].concat(attachs) data[:attachments].concat(attachs)
rescue rescue
attachs = _get_attachment(part, data[:attachments], mail) attachs = _get_attachment(part, data[:attachments], mail)
data[:attachments].concat(attachs) data[:attachments].concat(attachs)
end
end end
end end
@ -306,10 +304,10 @@ class Channel::EmailParser
end end
# ignore text/plain attachments - already shown in view # ignore text/plain attachments - already shown in view
return [] if mail.text_part && mail.text_part.body.to_s == file.body.to_s return [] if mail.text_part&.body.to_s == file.body.to_s
# ignore text/html - html part, already shown in view # ignore text/html - html part, already shown in view
return [] if mail.html_part && mail.html_part.body.to_s == file.body.to_s return [] if mail.html_part&.body.to_s == file.body.to_s
# get file preferences # get file preferences
headers_store = {} headers_store = {}
@ -376,7 +374,7 @@ class Channel::EmailParser
# generate file name based on content type # generate file name based on content type
if filename.blank? && headers_store['Content-Type'].present? if filename.blank? && headers_store['Content-Type'].present?
if headers_store['Content-Type'] =~ %r{^message/rfc822}i if headers_store['Content-Type'].match?(%r{^message/rfc822}i)
begin begin
parser = Channel::EmailParser.new parser = Channel::EmailParser.new
mail_local = parser.parse(file.body.to_s) mail_local = parser.parse(file.body.to_s)
@ -406,13 +404,13 @@ class Channel::EmailParser
if filename.blank? if filename.blank?
map = { map = {
'message/delivery-status': ['txt', 'delivery-status'], 'message/delivery-status': ['txt', 'delivery-status'],
'text/plain': %w(txt document), 'text/plain': %w[txt document],
'text/html': %w(html document), 'text/html': %w[html document],
'video/quicktime': %w(mov video), 'video/quicktime': %w[mov video],
'image/jpeg': %w(jpg image), 'image/jpeg': %w[jpg image],
'image/jpg': %w(jpg image), 'image/jpg': %w[jpg image],
'image/png': %w(png image), 'image/png': %w[png image],
'image/gif': %w(gif image), 'image/gif': %w[gif image],
} }
map.each do |type, ext| map.each do |type, ext|
next if headers_store['Content-Type'] !~ /^#{Regexp.quote(type)}/i next if headers_store['Content-Type'] !~ /^#{Regexp.quote(type)}/i
@ -454,12 +452,12 @@ class Channel::EmailParser
end end
# get mime type # get mime type
if file.header[:content_type] && file.header[:content_type].string if file.header[:content_type]&.string
headers_store['Mime-Type'] = file.header[:content_type].string headers_store['Mime-Type'] = file.header[:content_type].string
end end
# get charset # get charset
if file.header && file.header.charset if file.header&.charset
headers_store['Charset'] = file.header.charset headers_store['Charset'] = file.header.charset
end end
@ -503,9 +501,8 @@ returns
_process(channel, msg) _process(channel, msg)
rescue => e rescue => e
# store unprocessable email for bug reporting # store unprocessable email for bug reporting
path = "#{Rails.root}/tmp/unprocessable_mail/" path = Rails.root.join('tmp', 'unprocessable_mail')
FileUtils.mkpath path FileUtils.mkpath path
md5 = Digest::MD5.hexdigest(msg) md5 = Digest::MD5.hexdigest(msg)
filename = "#{path}/#{md5}.eml" filename = "#{path}/#{md5}.eml"
@ -532,7 +529,7 @@ returns
Setting.where(area: 'Postmaster::PreFilter').order(:name).each do |setting| Setting.where(area: 'Postmaster::PreFilter').order(:name).each do |setting|
filters[setting.name] = Kernel.const_get(Setting.get(setting.name)) filters[setting.name] = Kernel.const_get(Setting.get(setting.name))
end end
filters.each do |_prio, backend| filters.each_value do |backend|
Rails.logger.debug "run postmaster pre filter #{backend}" Rails.logger.debug "run postmaster pre filter #{backend}"
begin begin
backend.run(channel, mail) backend.run(channel, mail)
@ -663,16 +660,14 @@ returns
article.save_as_raw(msg) article.save_as_raw(msg)
# store attachments # store attachments
if mail[:attachments] mail[:attachments]&.each do |attachment|
mail[:attachments].each do |attachment| Store.add(
Store.add( object: 'Ticket::Article',
object: 'Ticket::Article', o_id: article.id,
o_id: article.id, data: attachment[:data],
data: attachment[:data], filename: attachment[:filename],
filename: attachment[:filename], preferences: attachment[:preferences]
preferences: attachment[:preferences] )
)
end
end end
end end
end end
@ -682,7 +677,7 @@ returns
Setting.where(area: 'Postmaster::PostFilter').order(:name).each do |setting| Setting.where(area: 'Postmaster::PostFilter').order(:name).each do |setting|
filters[setting.name] = Kernel.const_get(Setting.get(setting.name)) filters[setting.name] = Kernel.const_get(Setting.get(setting.name))
end end
filters.each do |_prio, backend| filters.each_value do |backend|
Rails.logger.debug "run postmaster post filter #{backend}" Rails.logger.debug "run postmaster post filter #{backend}"
begin begin
backend.run(channel, mail, ticket, article, session_user) backend.run(channel, mail, ticket, article, session_user)
@ -765,7 +760,7 @@ returns
def set_attributes_by_x_headers(item_object, header_name, mail, suffix = false) def set_attributes_by_x_headers(item_object, header_name, mail, suffix = false)
# loop all x-zammad-header-* headers # loop all x-zammad-header-* headers
item_object.attributes.each do |key, _value| item_object.attributes.each_key do |key|
# ignore read only attributes # ignore read only attributes
next if key == 'updated_by_id' next if key == 'updated_by_id'
@ -862,9 +857,9 @@ module Mail
.+?(?=\=\?|$) # Plain String .+?(?=\=\?|$) # Plain String
)/xmi).map do |matches| )/xmi).map do |matches|
string, method = *matches string, method = *matches
if method == 'b' || method == 'B' if method == 'b' || method == 'B' # rubocop:disable Style/MultipleComparison
b_value_decode(string) b_value_decode(string)
elsif method == 'q' || method == 'Q' elsif method == 'q' || method == 'Q' # rubocop:disable Style/MultipleComparison
q_value_decode(string) q_value_decode(string)
else else
string string

View file

@ -25,7 +25,7 @@ module Channel::Filter::AutoResponseCheck
message_id = mail[ 'message_id'.to_sym ] message_id = mail[ 'message_id'.to_sym ]
if message_id if message_id
fqdn = Setting.get('fqdn') fqdn = Setting.get('fqdn')
return if message_id =~ /@#{Regexp.quote(fqdn)}/i return if message_id.match?(/@#{Regexp.quote(fqdn)}/i)
end end
mail[ 'x-zammad-send-auto-response'.to_sym ] = true mail[ 'x-zammad-send-auto-response'.to_sym ] = true

View file

@ -28,7 +28,7 @@ module Channel::Filter::BounceDeliveryPermanentFailed
# get recipient of origin article, if only one - mark this user to not sent notifications anymore # get recipient of origin article, if only one - mark this user to not sent notifications anymore
recipients = [] recipients = []
if article.sender.name == 'System' || article.sender.name == 'Agent' if article.sender.name == 'System' || article.sender.name == 'Agent'
%w(to cc).each do |line| %w[to cc].each do |line|
next if article[line].blank? next if article[line].blank?
recipients = [] recipients = []
begin begin

View file

@ -104,5 +104,6 @@ module Channel::Filter::FollowUpCheck
end end
end end
true
end end
end end

View file

@ -22,15 +22,15 @@ module Channel::Filter::IdentifySender
if !customer_user && mail[ 'x-zammad-customer-email'.to_sym ].present? if !customer_user && mail[ 'x-zammad-customer-email'.to_sym ].present?
customer_user = User.find_by(email: mail[ 'x-zammad-customer-email'.to_sym ]) customer_user = User.find_by(email: mail[ 'x-zammad-customer-email'.to_sym ])
end end
if !customer_user
# get correct customer # get correct customer
if !customer_user && Setting.get('postmaster_sender_is_agent_search_for_customer') == true
if mail[ 'x-zammad-ticket-create-article-sender'.to_sym ] == 'Agent' if mail[ 'x-zammad-ticket-create-article-sender'.to_sym ] == 'Agent'
# get first recipient and set customer # get first recipient and set customer
begin begin
to = 'raw-to'.to_sym to = 'raw-to'.to_sym
if mail[to] && mail[to].addrs if mail[to]&.addrs
items = mail[to].addrs items = mail[to].addrs
items.each do |item| items.each do |item|
@ -46,18 +46,21 @@ module Channel::Filter::IdentifySender
end end
end end
rescue => e rescue => e
Rails.logger.error 'ERROR: SenderIsSystemAddress: ' + e.inspect Rails.logger.error "SenderIsSystemAddress: ##{e.inspect}"
end end
end end
if !customer_user
customer_user = user_create(
login: mail[ 'x-zammad-customer-login'.to_sym ] || mail[ 'x-zammad-customer-email'.to_sym ] || mail[:from_email],
firstname: mail[ 'x-zammad-customer-firstname'.to_sym ] || mail[:from_display_name],
lastname: mail[ 'x-zammad-customer-lastname'.to_sym ],
email: mail[ 'x-zammad-customer-email'.to_sym ] || mail[:from_email],
)
end
end end
# take regular from as customer
if !customer_user
customer_user = user_create(
login: mail[ 'x-zammad-customer-login'.to_sym ] || mail[ 'x-zammad-customer-email'.to_sym ] || mail[:from_email],
firstname: mail[ 'x-zammad-customer-firstname'.to_sym ] || mail[:from_display_name],
lastname: mail[ 'x-zammad-customer-lastname'.to_sym ],
email: mail[ 'x-zammad-customer-email'.to_sym ] || mail[:from_email],
)
end
create_recipients(mail) create_recipients(mail)
mail[ 'x-zammad-ticket-customer_id'.to_sym ] = customer_user.id mail[ 'x-zammad-ticket-customer_id'.to_sym ] = customer_user.id
@ -83,6 +86,8 @@ module Channel::Filter::IdentifySender
if session_user if session_user
mail[ 'x-zammad-session-user-id'.to_sym ] = session_user.id mail[ 'x-zammad-session-user-id'.to_sym ] = session_user.id
end end
true
end end
# create to and cc user # create to and cc user
@ -159,7 +164,7 @@ module Channel::Filter::IdentifySender
role_ids = Role.signup_role_ids role_ids = Role.signup_role_ids
# fillup # fillup
%w(firstname lastname).each do |item| %w[firstname lastname].each do |item|
if data[item.to_sym].nil? if data[item.to_sym].nil?
data[item.to_sym] = '' data[item.to_sym] = ''
end end

View file

@ -9,12 +9,12 @@ module Channel::Filter::Match::EmailRegex
if regexp == false if regexp == false
match_rule_quoted = Regexp.quote(match_rule).gsub(/\\\*/, '.*') match_rule_quoted = Regexp.quote(match_rule).gsub(/\\\*/, '.*')
return true if value =~ /#{match_rule_quoted}/i return true if value.match?(/#{match_rule_quoted}/i)
return false return false
end end
begin begin
return true if value =~ /#{match_rule}/i return true if value.match?(/#{match_rule}/i)
return false return false
rescue => e rescue => e
message = "Can't use regex '#{match_rule}' on '#{value}': #{e.message}" message = "Can't use regex '#{match_rule}' on '#{value}': #{e.message}"

View file

@ -36,9 +36,7 @@ class Channel::Filter::MonitoringBase
key = key.downcase key = key.downcase
end end
value = $2 value = $2
if value value&.strip!
value.strip!
end
result[key] = value result[key] = value
end end
@ -70,9 +68,9 @@ class Channel::Filter::MonitoringBase
# possible event types https://mmonit.com/monit/documentation/#Setting-an-event-filter # possible event types https://mmonit.com/monit/documentation/#Setting-an-event-filter
if result['state'].blank? if result['state'].blank?
result['state'] = if mail[:body] =~ /\s(done|recovery|succeeded|bytes\sok|packets\sok)\s/ result['state'] = if mail[:body].match?(/\s(done|recovery|succeeded|bytes\sok|packets\sok)\s/)
'OK' 'OK'
elsif mail[:body] =~ /(instance\schanged\snot|Link\sup|Exists|Saturation\sok|Speed\sok)/ elsif mail[:body].match?(/(instance\schanged\snot|Link\sup|Exists|Saturation\sok|Speed\sok)/)
'OK' 'OK'
else else
'CRITICAL' 'CRITICAL'
@ -132,5 +130,6 @@ class Channel::Filter::MonitoringBase
return true return true
end end
true
end end
end end

View file

@ -18,12 +18,12 @@ module Channel::Filter::OutOfOfficeCheck
if mail[ 'auto-submitted'.to_sym ] if mail[ 'auto-submitted'.to_sym ]
# check zimbra out of office characteristics # check zimbra out of office characteristics
if mail[ 'auto-submitted'.to_sym ] =~ /vacation/i if mail[ 'auto-submitted'.to_sym ].match?(/vacation/i)
mail[ 'x-zammad-out-of-office'.to_sym ] = true mail[ 'x-zammad-out-of-office'.to_sym ] = true
end end
# check cloud out of office characteristics # check cloud out of office characteristics
if mail[ 'auto-submitted'.to_sym ] =~ /auto-replied;\sowner-email=/i if mail[ 'auto-submitted'.to_sym ].match?(/auto-replied;\sowner-email=/i)
mail[ 'x-zammad-out-of-office'.to_sym ] = true mail[ 'x-zammad-out-of-office'.to_sym ] = true
end end
@ -35,6 +35,7 @@ module Channel::Filter::OutOfOfficeCheck
return return
end end
true
end end
end end

View file

@ -7,7 +7,7 @@ module Channel::Filter::Trusted
# check if trust x-headers # check if trust x-headers
if !channel[:trusted] if !channel[:trusted]
mail.each do |key, _value| mail.each_key do |key|
next if key !~ /^x-zammad/i next if key !~ /^x-zammad/i
mail.delete(key) mail.delete(key)
end end

View file

@ -9,7 +9,7 @@ class Chat < ApplicationModel
# reconnect # reconnect
if session_id if session_id
chat_session = Chat::Session.find_by(session_id: session_id, state: %w(waiting running)) chat_session = Chat::Session.find_by(session_id: session_id, state: %w[waiting running])
if chat_session if chat_session
if chat_session.state == 'running' if chat_session.state == 'running'
@ -126,7 +126,7 @@ class Chat < ApplicationModel
end end
def self.active_chat_count def self.active_chat_count
Chat::Session.where(state: %w(waiting running)).count Chat::Session.where(state: %w[waiting running]).count
end end
def self.available_agents(diff = 2.minutes) def self.available_agents(diff = 2.minutes)
@ -153,7 +153,7 @@ class Chat < ApplicationModel
def self.seads_total(diff = 2.minutes) def self.seads_total(diff = 2.minutes)
total = 0 total = 0
available_agents(diff).each do |_user_id, concurrent| available_agents(diff).each_value do |concurrent|
total += concurrent total += concurrent
end end
total total

View file

@ -5,7 +5,7 @@ class Chat::Agent < ApplicationModel
end end
def active_chat_count def active_chat_count
Chat::Session.where(state: %w(waiting running), user_id: updated_by_id).count Chat::Session.where(state: %w[waiting running], user_id: updated_by_id).count
end end
def self.state(user_id, state = nil) def self.state(user_id, state = nil)

View file

@ -17,7 +17,7 @@ module CanSeed
end end
def seedfile def seedfile
"#{Rails.root}/db/seeds/#{name.pluralize.underscore.tr('/', '_')}.rb" Rails.root.join('db', 'seeds', "#{name.pluralize.underscore.tr('/', '_')}.rb").to_s
end end
end end
end end

View file

@ -35,12 +35,11 @@ log object update activity stream, if configured - will be executed automaticall
return true if !saved_changes? return true if !saved_changes?
ignored_attributes = self.class.instance_variable_get(:@activity_stream_attributes_ignored) || [] ignored_attributes = self.class.instance_variable_get(:@activity_stream_attributes_ignored) || []
ignored_attributes += %i(created_at updated_at created_by_id updated_by_id) ignored_attributes += %i[created_at updated_at created_by_id updated_by_id]
log = false log = false
saved_changes.each do |key, _value| saved_changes.each_key do |key|
next if ignored_attributes.include?(key.to_sym) next if ignored_attributes.include?(key.to_sym)
log = true log = true
end end
return true if !log return true if !log

View file

@ -40,11 +40,9 @@ log object update history with all updated attributes, if configured - will be e
# new record also triggers update, so ignore new records # new record also triggers update, so ignore new records
changes = saved_changes changes = saved_changes
if history_changes_last_done history_changes_last_done&.each do |key, value|
history_changes_last_done.each do |key, value| if changes.key?(key) && changes[key] == value
if changes.key?(key) && changes[key] == value changes.delete(key)
changes.delete(key)
end
end end
end end
self.history_changes_last_done = changes self.history_changes_last_done = changes
@ -53,7 +51,7 @@ log object update history with all updated attributes, if configured - will be e
return if changes['id'] && !changes['id'][0] return if changes['id'] && !changes['id'][0]
ignored_attributes = self.class.instance_variable_get(:@history_attributes_ignored) || [] ignored_attributes = self.class.instance_variable_get(:@history_attributes_ignored) || []
ignored_attributes += %i(created_at updated_at created_by_id updated_by_id) ignored_attributes += %i[created_at updated_at created_by_id updated_by_id]
changes.each do |key, value| changes.each do |key, value|

View file

@ -84,7 +84,7 @@ returns
def search_index_data def search_index_data
attributes = {} attributes = {}
%w(name note).each do |key| %w[name note].each do |key|
next if !self[key] next if !self[key]
next if self[key].respond_to?('blank?') && self[key].blank? next if self[key].respond_to?('blank?') && self[key].blank?
attributes[key] = self[key] attributes[key] = self[key]

View file

@ -108,11 +108,11 @@ returns
# get caller ids # get caller ids
caller_ids = [] caller_ids = []
attributes = record.attributes attributes = record.attributes
attributes.each do |_attribute, value| attributes.each_value do |value|
next if value.class != String next if value.class != String
next if value.empty? next if value.blank?
local_caller_ids = Cti::CallerId.extract_numbers(value) local_caller_ids = Cti::CallerId.extract_numbers(value)
next if local_caller_ids.empty? next if local_caller_ids.blank?
caller_ids = caller_ids.concat(local_caller_ids) caller_ids = caller_ids.concat(local_caller_ids)
end end
@ -233,23 +233,23 @@ returns
if user if user
comment += user.fullname comment += user.fullname
end end
elsif !record.comment.empty? elsif record.comment.present?
comment += record.comment comment += record.comment
end end
if record.level == 'known' if record.level == 'known'
if !from_comment_known.empty? if from_comment_known.present?
from_comment_known += ',' from_comment_known += ','
end end
from_comment_known += comment from_comment_known += comment
else else
if !from_comment_maybe.empty? if from_comment_maybe.present?
from_comment_maybe += ',' from_comment_maybe += ','
end end
from_comment_maybe += comment from_comment_maybe += comment
end end
end end
return [from_comment_known, preferences_known] if !from_comment_known.empty? return [from_comment_known, preferences_known] if from_comment_known.present?
return ["maybe #{from_comment_maybe}", preferences_maybe] if !from_comment_maybe.empty? return ["maybe #{from_comment_maybe}", preferences_maybe] if from_comment_maybe.present?
nil nil
end end

View file

@ -249,7 +249,7 @@ returns
assets = {} assets = {}
list.each do |item| list.each do |item|
next if !item.preferences next if !item.preferences
%w(from to).each do |direction| %w[from to].each do |direction|
next if !item.preferences[direction] next if !item.preferences[direction]
item.preferences[direction].each do |caller_id| item.preferences[direction].each do |caller_id|
next if !caller_id['user_id'] next if !caller_id['user_id']

View file

@ -47,7 +47,7 @@ check and if channel not exists reset configured channels for email addresses
return true if email.blank? return true if email.blank?
self.email = email.downcase.strip self.email = email.downcase.strip
raise Exceptions::UnprocessableEntity, 'Invalid email' if email !~ /@/ raise Exceptions::UnprocessableEntity, 'Invalid email' if email !~ /@/
raise Exceptions::UnprocessableEntity, 'Invalid email' if email =~ /\s/ raise Exceptions::UnprocessableEntity, 'Invalid email' if email.match?(/\s/)
true true
end end

View file

@ -68,7 +68,7 @@ class ExternalSync < ApplicationModel
break if !value break if !value
storable = value.class.ancestors.any? do |ancestor| storable = value.class.ancestors.any? do |ancestor|
%w(String Integer Float Bool Array).include?(ancestor.to_s) %w[String Integer Float Bool Array].include?(ancestor.to_s)
end end
if storable if storable

View file

@ -78,11 +78,9 @@ job.run(true)
self.running = true self.running = true
save! save!
if tickets tickets&.each do |ticket|
tickets.each do |ticket| Transaction.execute(disable_notification: disable_notification, reset_user_id: true) do
Transaction.execute(disable_notification: disable_notification, reset_user_id: true) do ticket.perform_changes(perform, 'job')
ticket.perform_changes(perform, 'job')
end
end end
end end

View file

@ -36,7 +36,7 @@ returns
data = assets_of_selector('condition', data) data = assets_of_selector('condition', data)
data = assets_of_selector('perform', data) data = assets_of_selector('perform', data)
end end
%w(created_by_id updated_by_id).each do |local_user_id| %w[created_by_id updated_by_id].each do |local_user_id|
next if !self[ local_user_id ] next if !self[ local_user_id ]
next if data[ User.to_app_model ][ self[ local_user_id ] ] next if data[ User.to_app_model ][ self[ local_user_id ] ]
user = User.lookup(id: self[ local_user_id ]) user = User.lookup(id: self[ local_user_id ])

View file

@ -71,7 +71,7 @@ all:
def self.load_from_file def self.load_from_file
version = Version.get version = Version.get
file = Rails.root.join("config/locales-#{version}.yml") file = Rails.root.join('config', "locales-#{version}.yml")
return false if !File.exist?(file) return false if !File.exist?(file)
data = YAML.load_file(file) data = YAML.load_file(file)
to_database(data) to_database(data)
@ -107,7 +107,7 @@ all:
raise "Can't load locales from #{url}" if !result raise "Can't load locales from #{url}" if !result
raise "Can't load locales from #{url}: #{result.error}" if !result.success? raise "Can't load locales from #{url}: #{result.error}" if !result.success?
file = Rails.root.join("config/locales-#{version}.yml") file = Rails.root.join('config', "locales-#{version}.yml")
File.open(file, 'w') do |out| File.open(file, 'w') do |out|
YAML.dump(result.data, out) YAML.dump(result.data, out)
end end

View file

@ -11,7 +11,7 @@ list all backend managed object
=end =end
def self.list_objects def self.list_objects
%w(Ticket TicketArticle User Organization Group) %w[Ticket TicketArticle User Organization Group]
end end
=begin =begin
@ -23,7 +23,7 @@ list all frontend managed object
=end =end
def self.list_frontend_objects def self.list_frontend_objects
%w(Ticket User Organization Group) %w[Ticket User Organization Group]
end end
end end

View file

@ -279,7 +279,7 @@ possible types
# if data_option has changed, store it for next migration # if data_option has changed, store it for next migration
if !force if !force
[:name, :display, :data_type, :position, :active].each do |key| %i[name display data_type position active].each do |key|
next if record[key] == data[key] next if record[key] == data[key]
data[:to_config] = true data[:to_config] = true
break break
@ -441,7 +441,7 @@ returns:
tag: item.data_type, tag: item.data_type,
#:null => item.null, #:null => item.null,
} }
if item.data_option[:permission] && item.data_option[:permission].any? if item.data_option[:permission]&.any?
next if !user next if !user
hint = false hint = false
item.data_option[:permission].each do |permission| item.data_option[:permission].each do |permission|
@ -459,7 +459,7 @@ returns:
permission_options.each do |permission, options| permission_options.each do |permission, options|
if permission == '-all-' if permission == '-all-'
data[:screen][screen] = options data[:screen][screen] = options
elsif user && user.permissions?(permission) elsif user&.permissions?(permission)
data[:screen][screen] = options data[:screen][screen] = options
end end
end end
@ -535,7 +535,7 @@ returns
=end =end
def self.pending_migration? def self.pending_migration?
return false if migrations.empty? return false if migrations.blank?
true true
end end
@ -601,21 +601,21 @@ to send no browser reload event, pass false
end end
data_type = nil data_type = nil
if attribute.data_type =~ /^input|select|tree_select|richtext|textarea|checkbox$/ if attribute.data_type.match?(/^input|select|tree_select|richtext|textarea|checkbox$/)
data_type = :string data_type = :string
elsif attribute.data_type =~ /^integer|user_autocompletion$/ elsif attribute.data_type.match?(/^integer|user_autocompletion$/)
data_type = :integer data_type = :integer
elsif attribute.data_type =~ /^boolean|active$/ elsif attribute.data_type.match?(/^boolean|active$/)
data_type = :boolean data_type = :boolean
elsif attribute.data_type =~ /^datetime$/ elsif attribute.data_type.match?(/^datetime$/)
data_type = :datetime data_type = :datetime
elsif attribute.data_type =~ /^date$/ elsif attribute.data_type.match?(/^date$/)
data_type = :date data_type = :date
end end
# change field # change field
if model.column_names.include?(attribute.name) if model.column_names.include?(attribute.name)
if attribute.data_type =~ /^input|select|tree_select|richtext|textarea|checkbox$/ if attribute.data_type.match?(/^input|select|tree_select|richtext|textarea|checkbox$/)
ActiveRecord::Migration.change_column( ActiveRecord::Migration.change_column(
model.table_name, model.table_name,
attribute.name, attribute.name,
@ -623,7 +623,7 @@ to send no browser reload event, pass false
limit: attribute.data_option[:maxlength], limit: attribute.data_option[:maxlength],
null: true null: true
) )
elsif attribute.data_type =~ /^integer|user_autocompletion|datetime|date$/ elsif attribute.data_type.match?(/^integer|user_autocompletion|datetime|date$/)
ActiveRecord::Migration.change_column( ActiveRecord::Migration.change_column(
model.table_name, model.table_name,
attribute.name, attribute.name,
@ -631,7 +631,7 @@ to send no browser reload event, pass false
default: attribute.data_option[:default], default: attribute.data_option[:default],
null: true null: true
) )
elsif attribute.data_type =~ /^boolean|active$/ elsif attribute.data_type.match?(/^boolean|active$/)
ActiveRecord::Migration.change_column( ActiveRecord::Migration.change_column(
model.table_name, model.table_name,
attribute.name, attribute.name,
@ -654,7 +654,7 @@ to send no browser reload event, pass false
end end
# create field # create field
if attribute.data_type =~ /^input|select|tree_select|richtext|textarea|checkbox$/ if attribute.data_type.match?(/^input|select|tree_select|richtext|textarea|checkbox$/)
ActiveRecord::Migration.add_column( ActiveRecord::Migration.add_column(
model.table_name, model.table_name,
attribute.name, attribute.name,
@ -662,7 +662,7 @@ to send no browser reload event, pass false
limit: attribute.data_option[:maxlength], limit: attribute.data_option[:maxlength],
null: true null: true
) )
elsif attribute.data_type =~ /^integer|user_autocompletion$/ elsif attribute.data_type.match?(/^integer|user_autocompletion$/)
ActiveRecord::Migration.add_column( ActiveRecord::Migration.add_column(
model.table_name, model.table_name,
attribute.name, attribute.name,
@ -670,7 +670,7 @@ to send no browser reload event, pass false
default: attribute.data_option[:default], default: attribute.data_option[:default],
null: true null: true
) )
elsif attribute.data_type =~ /^boolean|active$/ elsif attribute.data_type.match?(/^boolean|active$/)
ActiveRecord::Migration.add_column( ActiveRecord::Migration.add_column(
model.table_name, model.table_name,
attribute.name, attribute.name,
@ -678,7 +678,7 @@ to send no browser reload event, pass false
default: attribute.data_option[:default], default: attribute.data_option[:default],
null: true null: true
) )
elsif attribute.data_type =~ /^datetime|date$/ elsif attribute.data_type.match?(/^datetime|date$/)
ActiveRecord::Migration.add_column( ActiveRecord::Migration.add_column(
model.table_name, model.table_name,
attribute.name, attribute.name,
@ -727,26 +727,20 @@ to send no browser reload event, pass false
def check_name def check_name
return if !name return if !name
if name =~ /_(id|ids)$/i || name =~ /^id$/i
raise 'Name can\'t get used, *_id and *_ids are not allowed' raise 'Name can\'t get used, *_id and *_ids are not allowed' if name.match?(/_(id|ids)$/i) || name.match?(/^id$/i)
elsif name =~ /\s/ raise 'Spaces in name are not allowed' if name.match?(/\s/)
raise 'Spaces in name are not allowed' raise 'Only letters from a-z, numbers from 0-9, and _ are allowed' if !name.match?(/^[a-z0-9_]+$/)
elsif name !~ /^[a-z0-9_]+$/ raise 'At least one letters is needed' if !name.match?(/[a-z]/)
raise 'Only letters from a-z, numbers from 0-9, and _ are allowed'
elsif name !~ /[a-z]/
raise 'At least one letters is needed'
elsif name =~ /^(destroy|true|false|integer|select|drop|create|alter|index|table|varchar|blob|date|datetime|timestamp)$/
raise "#{name} is a reserved word, please choose a different one"
# do not allow model method names as attributes # do not allow model method names as attributes
else reserved_words = %w[destroy true false integer select drop create alter index table varchar blob date datetime timestamp]
model = Kernel.const_get(object_lookup.name) raise "#{name} is a reserved word, please choose a different one" if name.match?(/^(#{reserved_words.join('|')})$/)
record = model.new
if record.respond_to?(name.to_sym) && !record.attributes.key?(name) record = object_lookup.name.constantize.new
raise "#{name} is a reserved word, please choose a different one" return true if !record.respond_to?(name.to_sym)
end return true if record.attributes.key?(name)
end raise "#{name} is a reserved word, please choose a different one"
true
end end
def check_editable def check_editable
@ -783,7 +777,7 @@ to send no browser reload event, pass false
end end
if data_type == 'integer' if data_type == 'integer'
[:min, :max].each do |item| %i[min max].each do |item|
raise "Need data_option[#{item.inspect}] param" if !data_option[item] raise "Need data_option[#{item.inspect}] param" if !data_option[item]
raise "Invalid data_option[#{item.inspect}] param #{data_option[item]}" if data_option[item].to_s !~ /^\d+?$/ raise "Invalid data_option[#{item.inspect}] param #{data_option[item]}" if data_option[item].to_s !~ /^\d+?$/
end end
@ -817,6 +811,7 @@ to send no browser reload event, pass false
raise 'Need data_option[:diff] param in days' if data_option[:diff].nil? raise 'Need data_option[:diff] param in days' if data_option[:diff].nil?
end end
true
end end
end end

View file

@ -1,5 +1,3 @@
# encoding: utf-8
class Observer::Chat::Leave::BackgroundJob class Observer::Chat::Leave::BackgroundJob
def initialize(chat_session_id, client_id, session) def initialize(chat_session_id, client_id, session)
@chat_session_id = chat_session_id @chat_session_id = chat_session_id

View file

@ -27,7 +27,7 @@ class Observer::Organization::RefObjectTouch < ActiveRecord::Observer
Ticket.select('id').where(organization_id: record.id).pluck(:id).each do |ticket_id| Ticket.select('id').where(organization_id: record.id).pluck(:id).each do |ticket_id|
ticket = Ticket.find(ticket_id) ticket = Ticket.find(ticket_id)
ticket.with_lock do ticket.with_lock do
ticket.touch ticket.touch # rubocop:disable Rails/SkipsModelValidations
end end
end end
@ -35,7 +35,7 @@ class Observer::Organization::RefObjectTouch < ActiveRecord::Observer
User.select('id').where(organization_id: record.id).pluck(:id).each do |user_id| User.select('id').where(organization_id: record.id).pluck(:id).each do |user_id|
user = User.find(user_id) user = User.find(user_id)
user.with_lock do user.with_lock do
user.touch user.touch # rubocop:disable Rails/SkipsModelValidations
end end
end end
true true

View file

@ -33,9 +33,9 @@ class Observer::Sla::TicketRebuildEscalation < ActiveRecord::Observer
changed = false changed = false
fields_to_check = nil fields_to_check = nil
fields_to_check = if record.class == Sla fields_to_check = if record.class == Sla
%w(condition calendar_id first_response_time update_time solution_time) %w[condition calendar_id first_response_time update_time solution_time]
else else
%w(timezone business_hours default ical_url public_holidays) %w[timezone business_hours default ical_url public_holidays]
end end
fields_to_check.each do |item| fields_to_check.each do |item|
next if !record.saved_change_to_attribute(item) next if !record.saved_change_to_attribute(item)

View file

@ -1,6 +1,5 @@
class Observer::Sla::TicketRebuildEscalation::BackgroundJob class Observer::Sla::TicketRebuildEscalation::BackgroundJob
def initialize(_sla_id) def initialize(_sla_id); end
end
def perform def perform
Cache.delete('SLA::List::Active') Cache.delete('SLA::List::Active')

View file

@ -10,7 +10,7 @@ class Observer::Ticket::Article::CommunicateEmail < ActiveRecord::Observer
# only do send email if article got created via application_server (e. g. not # only do send email if article got created via application_server (e. g. not
# if article and sender type is set via *.postmaster) # if article and sender type is set via *.postmaster)
return if ApplicationHandleInfo.current.split('.')[1] == 'postmaster' return if ApplicationHandleInfo.postmaster?
# if sender is customer, do not communicate # if sender is customer, do not communicate
return if !record.sender_id return if !record.sender_id

View file

@ -90,7 +90,7 @@ class Observer::Ticket::Article::CommunicateEmail::BackgroundJob
# add history record # add history record
recipient_list = '' recipient_list = ''
[:to, :cc].each do |key| %i[to cc].each do |key|
next if !record[key] next if !record[key]
next if record[key] == '' next if record[key] == ''
@ -130,7 +130,7 @@ class Observer::Ticket::Article::CommunicateEmail::BackgroundJob
if local_record.preferences['delivery_retry'] > 3 if local_record.preferences['delivery_retry'] > 3
recipient_list = '' recipient_list = ''
[:to, :cc].each do |key| %i[to cc].each do |key|
next if !local_record[key] next if !local_record[key]
next if local_record[key] == '' next if local_record[key] == ''

View file

@ -12,7 +12,7 @@ class Observer::Ticket::Article::CommunicateFacebook < ActiveRecord::Observer
# only do send email if article got created via application_server (e. g. not # only do send email if article got created via application_server (e. g. not
# if article and sender type is set via *.postmaster) # if article and sender type is set via *.postmaster)
return if ApplicationHandleInfo.current.split('.')[1] == 'postmaster' return if ApplicationHandleInfo.postmaster?
# if sender is customer, do not communicate # if sender is customer, do not communicate
return if !record.sender_id return if !record.sender_id

View file

@ -10,7 +10,7 @@ class Observer::Ticket::Article::CommunicateTwitter < ActiveRecord::Observer
# only do send email if article got created via application_server (e. g. not # only do send email if article got created via application_server (e. g. not
# if article and sender type is set via *.postmaster) # if article and sender type is set via *.postmaster)
return if ApplicationHandleInfo.current.split('.')[1] == 'postmaster' return if ApplicationHandleInfo.postmaster?
# if sender is customer, do not communicate # if sender is customer, do not communicate
return if !record.sender_id return if !record.sender_id

View file

@ -10,7 +10,7 @@ class Observer::Ticket::Article::FillupFromEmail < ActiveRecord::Observer
# only do fill of email from if article got created via application_server (e. g. not # only do fill of email from if article got created via application_server (e. g. not
# if article and sender type is set via *.postmaster) # if article and sender type is set via *.postmaster)
return true if ApplicationHandleInfo.current.split('.')[1] == 'postmaster' return if ApplicationHandleInfo.postmaster?
# if sender is customer, do not change anything # if sender is customer, do not change anything
return true if !record.sender_id return true if !record.sender_id

View file

@ -10,7 +10,7 @@ class Observer::Ticket::Article::FillupFromGeneral < ActiveRecord::Observer
# only do fill of from if article got created via application_server (e. g. not # only do fill of from if article got created via application_server (e. g. not
# if article and sender type is set via *.postmaster) # if article and sender type is set via *.postmaster)
return true if ApplicationHandleInfo.current.split('.')[1] == 'postmaster' return if ApplicationHandleInfo.postmaster?
# set from on all article types excluding email|twitter status|twitter direct-message|facebook feed post|facebook feed comment # set from on all article types excluding email|twitter status|twitter direct-message|facebook feed post|facebook feed comment
return true if !record.type_id return true if !record.type_id

View file

@ -10,7 +10,7 @@ class Observer::Ticket::Article::FillupFromOriginById < ActiveRecord::Observer
# only do fill of from if article got created via application_server (e. g. not # only do fill of from if article got created via application_server (e. g. not
# if article and sender type is set via *.postmaster) # if article and sender type is set via *.postmaster)
return if ApplicationHandleInfo.current.split('.')[1] == 'postmaster' return if ApplicationHandleInfo.postmaster?
# check if origin_by_id exists # check if origin_by_id exists
return if record.origin_by_id.present? return if record.origin_by_id.present?

View file

@ -24,7 +24,7 @@ class Observer::Ticket::ArticleChanges < ActiveRecord::Observer
# save ticket # save ticket
if !changed if !changed
record.ticket.touch record.ticket.touch # rubocop:disable Rails/SkipsModelValidations
return return
end end
record.ticket.save record.ticket.save
@ -38,7 +38,7 @@ class Observer::Ticket::ArticleChanges < ActiveRecord::Observer
# save ticket # save ticket
if !changed if !changed
record.ticket.touch record.ticket.touch # rubocop:disable Rails/SkipsModelValidations
return return
end end
record.ticket.save! record.ticket.save!

View file

@ -24,26 +24,24 @@ class Observer::Ticket::RefObjectTouch < ActiveRecord::Observer
cutomer_id_changed = record.saved_changes['customer_id'] cutomer_id_changed = record.saved_changes['customer_id']
if cutomer_id_changed && cutomer_id_changed[0] != cutomer_id_changed[1] if cutomer_id_changed && cutomer_id_changed[0] != cutomer_id_changed[1]
if cutomer_id_changed[0] if cutomer_id_changed[0]
User.find(cutomer_id_changed[0]).touch User.find(cutomer_id_changed[0]).touch # rubocop:disable Rails/SkipsModelValidations
end end
end end
# touch new/current customer # touch new/current customer
if record.customer record.customer&.touch
record.customer.touch
end
# touch old organization if changed # touch old organization if changed
organization_id_changed = record.saved_changes['organization_id'] organization_id_changed = record.saved_changes['organization_id']
if organization_id_changed && organization_id_changed[0] != organization_id_changed[1] if organization_id_changed && organization_id_changed[0] != organization_id_changed[1]
if organization_id_changed[0] if organization_id_changed[0]
Organization.find(organization_id_changed[0]).touch Organization.find(organization_id_changed[0]).touch # rubocop:disable Rails/SkipsModelValidations
end end
end end
# touch new/current organization # touch new/current organization
return true if !record.organization return true if !record.organization
record.organization.touch record.organization.touch # rubocop:disable Rails/SkipsModelValidations
end end
end end

View file

@ -9,7 +9,7 @@ class Observer::Ticket::ResetNewState < ActiveRecord::Observer
return if Setting.get('import_mode') return if Setting.get('import_mode')
# only change state if not processed via postmaster # only change state if not processed via postmaster
return if ApplicationHandleInfo.current.split('.')[1] == 'postmaster' return if ApplicationHandleInfo.postmaster?
# if article in internal # if article in internal
return true if record.internal return true if record.internal

View file

@ -33,14 +33,14 @@ class Observer::Transaction < ActiveRecord::Observer
sync_backends = [] sync_backends = []
Setting.where(area: 'Transaction::Backend::Sync').order(:name).each do |setting| Setting.where(area: 'Transaction::Backend::Sync').order(:name).each do |setting|
backend = Setting.get(setting.name) backend = Setting.get(setting.name)
next if params[:disable] && params[:disable].include?(backend) next if params[:disable]&.include?(backend)
sync_backends.push Kernel.const_get(backend) sync_backends.push Kernel.const_get(backend)
end end
# get uniq objects # get uniq objects
list_objects = get_uniq_changes(list) list_objects = get_uniq_changes(list)
list_objects.each do |_object, objects| list_objects.each_value do |objects|
objects.each do |_id, item| objects.each_value do |item|
# execute sync backends # execute sync backends
sync_backends.each do |backend| sync_backends.each do |backend|
@ -215,7 +215,7 @@ class Observer::Transaction < ActiveRecord::Observer
end end
# do not send anything if nothing has changed # do not send anything if nothing has changed
return true if real_changes.empty? return true if real_changes.blank?
changed_by_id = nil changed_by_id = nil
changed_by_id = if record.respond_to?('updated_by_id') changed_by_id = if record.respond_to?('updated_by_id')

View file

@ -16,7 +16,7 @@ class Observer::User::Geo < ActiveRecord::Observer
# check if geo need to be updated # check if geo need to be updated
def check_geo(record) def check_geo(record)
location = %w(address street zip city country) location = %w[address street zip city country]
# check if geo update is needed based on old/new location # check if geo update is needed based on old/new location
if record.id if record.id
@ -45,7 +45,7 @@ class Observer::User::Geo < ActiveRecord::Observer
# update geo data of user # update geo data of user
def geo_update(record) def geo_update(record)
address = '' address = ''
location = %w(address street zip city country) location = %w[address street zip city country]
location.each do |item| location.each do |item|
next if record[item].blank? next if record[item].blank?
if address.present? if address.present?

View file

@ -29,7 +29,7 @@ class Observer::User::RefObjectTouch < ActiveRecord::Observer
# featrue used for different propose, do not touch references # featrue used for different propose, do not touch references
if User.where(organization_id: organization_id_changed[0]).count < 100 if User.where(organization_id: organization_id_changed[0]).count < 100
organization = Organization.find(organization_id_changed[0]) organization = Organization.find(organization_id_changed[0])
organization.touch organization.touch # rubocop:disable Rails/SkipsModelValidations
member_ids = organization.member_ids member_ids = organization.member_ids
end end
end end
@ -40,7 +40,7 @@ class Observer::User::RefObjectTouch < ActiveRecord::Observer
# featrue used for different propose, do not touch references # featrue used for different propose, do not touch references
if User.where(organization_id: record.organization_id).count < 100 if User.where(organization_id: record.organization_id).count < 100
record.organization.touch record.organization.touch # rubocop:disable Rails/SkipsModelValidations
member_ids += record.organization.member_ids member_ids += record.organization.member_ids
end end
end end
@ -48,7 +48,7 @@ class Observer::User::RefObjectTouch < ActiveRecord::Observer
# touch old/current customer # touch old/current customer
member_ids.uniq.each do |user_id| member_ids.uniq.each do |user_id|
next if user_id == record.id next if user_id == record.id
User.find(user_id).touch User.find(user_id).touch # rubocop:disable Rails/SkipsModelValidations
end end
true true
end end

View file

@ -55,7 +55,7 @@ returns
data[ app_model_organization ][ id ] = local_attributes data[ app_model_organization ][ id ] = local_attributes
end end
%w(created_by_id updated_by_id).each do |local_user_id| %w[created_by_id updated_by_id].each do |local_user_id|
next if !self[ local_user_id ] next if !self[ local_user_id ]
next if data[ app_model_user ][ self[ local_user_id ] ] next if data[ app_model_user ][ self[ local_user_id ] ]
user = User.lookup(id: self[ local_user_id ]) user = User.lookup(id: self[ local_user_id ])

View file

@ -17,26 +17,47 @@ class Overview < ApplicationModel
validates :name, presence: true validates :name, presence: true
before_create :fill_link_on_create, :fill_prio before_create :fill_link_on_create, :fill_prio
before_update :fill_link_on_update before_update :fill_link_on_update, :rearrangement
private private
def rearrangement
return true if !changes['prio']
prio = 0
Overview.all.order(prio: :asc, updated_at: :desc).pluck(:id).each do |overview_id|
prio += 1
next if id == overview_id
Overview.without_callback(:update, :before, :rearrangement) do
overview = Overview.find(overview_id)
next if overview.prio == prio
overview.prio = prio
overview.save!
end
end
end
def fill_prio def fill_prio
return true if prio return true if prio.present?
self.prio = 9999 self.prio = Overview.count + 1
true true
end end
def fill_link_on_create def fill_link_on_create
return true if link.present? self.link = if link.present?
self.link = link_name(name) link_name(link)
else
link_name(name)
end
true true
end end
def fill_link_on_update def fill_link_on_update
return true if !changes['name'] return true if !changes['name'] && !changes['link']
return true if changes['link'] self.link = if link.present?
self.link = link_name(name) link_name(link)
else
link_name(name)
end
true true
end end
@ -45,17 +66,21 @@ class Overview < ApplicationModel
local_link = local_link.parameterize(separator: '_') local_link = local_link.parameterize(separator: '_')
local_link.gsub!(/\s/, '_') local_link.gsub!(/\s/, '_')
local_link.gsub!(/_+/, '_') local_link.gsub!(/_+/, '_')
local_link = URI.escape(local_link) local_link = CGI.escape(local_link)
if local_link.blank? if local_link.blank?
local_link = id || rand(999) local_link = id || rand(999)
end end
check = true check = true
count = 0
local_lookup_link = local_link
while check while check
exists = Overview.find_by(link: local_link) count += 1
if exists && exists.id != id exists = Overview.find_by(link: local_lookup_link)
local_link = "#{local_link}_#{rand(999)}" if exists && exists.id != id # rubocop:disable Style/SafeNavigation
local_lookup_link = "#{local_link}_#{count}"
else else
check = false check = false
local_link = local_lookup_link
end end
end end
local_link local_link

View file

@ -34,19 +34,15 @@ returns
end end
if !data[ app_model_overview ][ id ] if !data[ app_model_overview ][ id ]
data[ app_model_overview ][ id ] = attributes_with_association_ids data[ app_model_overview ][ id ] = attributes_with_association_ids
if user_ids user_ids&.each do |local_user_id|
user_ids.each do |local_user_id| next if data[ app_model_user ][ local_user_id ]
next if data[ app_model_user ][ local_user_id ] user = User.lookup(id: local_user_id)
user = User.lookup(id: local_user_id) next if !user
next if !user data = user.assets(data)
data = user.assets(data)
end
end end
data = assets_of_selector('condition', data) data = assets_of_selector('condition', data)
end end
%w(created_by_id updated_by_id).each do |local_user_id| %w[created_by_id updated_by_id].each do |local_user_id|
next if !self[ local_user_id ] next if !self[ local_user_id ]
next if data[ app_model_user ][ self[ local_user_id ] ] next if data[ app_model_user ][ self[ local_user_id ] ]
user = User.lookup(id: self[ local_user_id ]) user = User.lookup(id: self[ local_user_id ])

Some files were not shown because too many files have changed in this diff Show more