From 7a8559e678db7671c161fca7de0ecdc7dea968db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bauer?= Date: Fri, 2 Dec 2016 12:24:00 +0100 Subject: [PATCH] refactored postinstall.sh --- .codeclimate.yml | 6 +- .csslintrc | 2 + .eslintignore | 1 + .eslintrc | 213 ++++++++++++++++++ .github_changelog_generator | 4 +- .travis.yml | 33 ++- README.md | 6 +- .../app/controllers/navigation.coffee | 21 +- .../javascripts/app/controllers/search.coffee | 15 +- .../app/lib/app_post/global_search.coffee | 49 ++-- .../javascripts/app/models/macro.coffee | 2 +- .../app/views/navigation/personal.jst.eco | 4 +- app/models/avatar.rb | 7 +- app/models/calendar.rb | 93 +------- app/models/channel/driver/facebook.rb | 3 +- app/models/channel/driver/imap.rb | 5 + app/models/channel/driver/pop3.rb | 7 +- app/models/channel/driver/sendmail.rb | 9 +- app/models/channel/driver/smtp.rb | 4 +- app/models/channel/driver/twitter.rb | 21 +- app/models/channel/email_parser.rb | 10 +- .../communicate_email/background_job.rb | 4 +- .../communicate_facebook/background_job.rb | 6 +- app/models/organization.rb | 3 +- app/models/ticket/escalation.rb | 2 +- app/models/ticket/number/date.rb | 2 +- app/models/ticket/number/increment.rb | 2 +- app/models/ticket/search_index.rb | 2 +- app/models/user.rb | 36 +-- app/models/user_device.rb | 6 +- config/database.yml.dist | 33 --- config/database.yml.test-mysql | 11 + config/database.yml.test-postgresql | 11 + config/holiday_calendars.yml | 78 +++++++ contrib/packager.io/config | 13 ++ contrib/packager.io/functions | 201 +++++++++++++++++ contrib/packager.io/postinstall.sh | 196 +++------------- test/browser/form_test.rb | 47 +++- test/browser_test_helper.rb | 33 ++- test/unit/ticket_overview_test.rb | 3 +- 40 files changed, 764 insertions(+), 440 deletions(-) create mode 100644 .csslintrc create mode 100644 .eslintignore create mode 100644 .eslintrc delete mode 100644 config/database.yml.dist create mode 100644 config/database.yml.test-mysql create mode 100644 config/database.yml.test-postgresql create mode 100644 config/holiday_calendars.yml create mode 100644 contrib/packager.io/config create mode 100644 contrib/packager.io/functions diff --git a/.codeclimate.yml b/.codeclimate.yml index 54e14b269..3991067f6 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -14,14 +14,12 @@ engines: languages: - ruby - javascript - - python - - php eslint: enabled: true fixme: enabled: true phpmd: - enabled: true + enabled: false rubocop: enabled: true ratings: @@ -38,8 +36,6 @@ ratings: - "**.js" - "**.jsx" - "**.module" - - "**.php" - - "**.py" exclude_paths: - config/ - db/ diff --git a/.csslintrc b/.csslintrc new file mode 100644 index 000000000..aacba956e --- /dev/null +++ b/.csslintrc @@ -0,0 +1,2 @@ +--exclude-exts=.min.css +--ignore=adjoining-classes,box-model,ids,order-alphabetical,unqualified-attributes diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 000000000..96212a359 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +**/*{.,-}min.js diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 000000000..9faa37508 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,213 @@ +ecmaFeatures: + modules: true + jsx: true + +env: + amd: true + browser: true + es6: true + jquery: true + node: true + +# http://eslint.org/docs/rules/ +rules: + # Possible Errors + comma-dangle: [2, never] + no-cond-assign: 2 + no-console: 0 + no-constant-condition: 2 + no-control-regex: 2 + no-debugger: 2 + no-dupe-args: 2 + no-dupe-keys: 2 + no-duplicate-case: 2 + no-empty: 2 + no-empty-character-class: 2 + no-ex-assign: 2 + no-extra-boolean-cast: 2 + no-extra-parens: 0 + no-extra-semi: 2 + no-func-assign: 2 + no-inner-declarations: [2, functions] + no-invalid-regexp: 2 + no-irregular-whitespace: 2 + no-negated-in-lhs: 2 + no-obj-calls: 2 + no-regex-spaces: 2 + no-sparse-arrays: 2 + no-unexpected-multiline: 2 + no-unreachable: 2 + use-isnan: 2 + valid-jsdoc: 0 + valid-typeof: 2 + + # Best Practices + accessor-pairs: 2 + block-scoped-var: 0 + complexity: [2, 6] + consistent-return: 0 + curly: 0 + default-case: 0 + dot-location: 0 + dot-notation: 0 + eqeqeq: 2 + guard-for-in: 2 + no-alert: 2 + no-caller: 2 + no-case-declarations: 2 + no-div-regex: 2 + no-else-return: 0 + no-empty-label: 2 + no-empty-pattern: 2 + no-eq-null: 2 + no-eval: 2 + no-extend-native: 2 + no-extra-bind: 2 + no-fallthrough: 2 + no-floating-decimal: 0 + no-implicit-coercion: 0 + no-implied-eval: 2 + no-invalid-this: 0 + no-iterator: 2 + no-labels: 0 + no-lone-blocks: 2 + no-loop-func: 2 + no-magic-number: 0 + no-multi-spaces: 0 + no-multi-str: 0 + no-native-reassign: 2 + no-new-func: 2 + no-new-wrappers: 2 + no-new: 2 + no-octal-escape: 2 + no-octal: 2 + no-proto: 2 + no-redeclare: 2 + no-return-assign: 2 + no-script-url: 2 + no-self-compare: 2 + no-sequences: 0 + no-throw-literal: 0 + no-unused-expressions: 2 + no-useless-call: 2 + no-useless-concat: 2 + no-void: 2 + no-warning-comments: 0 + no-with: 2 + radix: 2 + vars-on-top: 0 + wrap-iife: 2 + yoda: 0 + + # Strict + strict: 0 + + # Variables + init-declarations: 0 + no-catch-shadow: 2 + no-delete-var: 2 + no-label-var: 2 + no-shadow-restricted-names: 2 + no-shadow: 0 + no-undef-init: 2 + no-undef: 0 + no-undefined: 0 + no-unused-vars: 0 + no-use-before-define: 0 + + # Node.js and CommonJS + callback-return: 2 + global-require: 2 + handle-callback-err: 2 + no-mixed-requires: 0 + no-new-require: 0 + no-path-concat: 2 + no-process-exit: 2 + no-restricted-modules: 0 + no-sync: 0 + + # Stylistic Issues + array-bracket-spacing: 0 + block-spacing: 0 + brace-style: 0 + camelcase: 0 + comma-spacing: 0 + comma-style: 0 + computed-property-spacing: 0 + consistent-this: 0 + eol-last: 0 + func-names: 0 + func-style: 0 + id-length: 0 + id-match: 0 + indent: 0 + jsx-quotes: 0 + key-spacing: 0 + linebreak-style: 0 + lines-around-comment: 0 + max-depth: 0 + max-len: 0 + max-nested-callbacks: 0 + max-params: 0 + max-statements: [2, 30] + new-cap: 0 + new-parens: 0 + newline-after-var: 0 + no-array-constructor: 0 + no-bitwise: 0 + no-continue: 0 + no-inline-comments: 0 + no-lonely-if: 0 + no-mixed-spaces-and-tabs: 0 + no-multiple-empty-lines: 0 + no-negated-condition: 0 + no-nested-ternary: 0 + no-new-object: 0 + no-plusplus: 0 + no-restricted-syntax: 0 + no-spaced-func: 0 + no-ternary: 0 + no-trailing-spaces: 0 + no-underscore-dangle: 0 + no-unneeded-ternary: 0 + object-curly-spacing: 0 + one-var: 0 + operator-assignment: 0 + operator-linebreak: 0 + padded-blocks: 0 + quote-props: 0 + quotes: 0 + require-jsdoc: 0 + semi-spacing: 0 + semi: 0 + sort-vars: 0 + space-after-keywords: 0 + space-before-blocks: 0 + space-before-function-paren: 0 + space-before-keywords: 0 + space-in-parens: 0 + space-infix-ops: 0 + space-return-throw-case: 0 + space-unary-ops: 0 + spaced-comment: 0 + wrap-regex: 0 + + # ECMAScript 6 + arrow-body-style: 0 + arrow-parens: 0 + arrow-spacing: 0 + constructor-super: 0 + generator-star-spacing: 0 + no-arrow-condition: 0 + no-class-assign: 0 + no-const-assign: 0 + no-dupe-class-members: 0 + no-this-before-super: 0 + no-var: 0 + object-shorthand: 0 + prefer-arrow-callback: 0 + prefer-const: 0 + prefer-reflect: 0 + prefer-spread: 0 + prefer-template: 0 + require-yield: 0 diff --git a/.github_changelog_generator b/.github_changelog_generator index f2af86221..bfaec92a2 100644 --- a/.github_changelog_generator +++ b/.github_changelog_generator @@ -5,6 +5,6 @@ since-tag=1.0.0 bug-labels=bug,minor bug,security enhancement-labels=enhancement,feature issues-wo-labels=false -include-labels=security,trigger,UX/UI,admin area,API,blocker,browser,bug,channel,chat,duplicate,enhancement,feature,import,minor bug,notification,email filter,ticket templates -issue-line-labels=enhancement,feature,bug,minor bug,security +include-labels=security,trigger,UX/UI,admin area,API,browser,bug,channel,chat,email filter,enhancement,feature,import,minor bug,notification,email filter,ticket templates, +issue-line-labels=enhancement,feature,bug,minor bug,notification,reporting,security,ticket templates,translation,trigger,UX/UI exclude-tags=9.0.1,0.9.1,v0.1.8,v0.1.7,unittests_passed diff --git a/.travis.yml b/.travis.yml index 275f6cdd5..427cda408 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,20 @@ dist: trusty sudo: required notifications: - email: false + email: + - me+tv@zammad.com +env: + - DB=mysql + - DB=postgresql addons: + postgresql: "9.4" apt: packages: - mysql-server-5.6 - mysql-client-core-5.6 - mysql-client-5.6 services: + - postgresql - mysql language: ruby rvm: @@ -18,12 +24,17 @@ before_install: - sudo apt-get install -y curl git-core patch build-essential bison zlib1g-dev libssl-dev libxml2-dev libxml2-dev sqlite3 libsqlite3-dev autotools-dev libxslt1-dev libyaml-0-2 autoconf automake libreadline6-dev libyaml-dev libtool libgmp-dev libgdbm-dev libncurses5-dev pkg-config libffi-dev libmysqlclient-dev postfix - mysql -u root -e "CREATE USER 'some_user'@'localhost' IDENTIFIED BY 'some_pass';" - mysql -u root -e "GRANT ALL PRIVILEGES ON *.* TO 'some_user'@'localhost';" + - if [ "${DB}" = "mysql" ]; then mysql -u root -e "CREATE USER 'some_user'@'localhost' IDENTIFIED BY 'some_pass';"; fi + - if [ "${DB}" = "mysql" ]; then mysql -u root -e "GRANT ALL PRIVILEGES ON *.* TO 'some_user'@'localhost';"; fi + - if [ "${DB}" = "mysql" ]; then cp config/database.yml.test-mysql config/database.yml; fi + - if [ "${DB}" = "postgresql" ]; then psql -c 'create database zammad_test;' -U postgres; fi + - if [ "${DB}" = "postgresql" ]; then cp config/database.yml.test-postgresql config/database.yml; fi - export RAILS_ENV=test - - export EMAILHELPER_MAILBOX_1='unittestemailhelper01@znuny.com:somepass' - - cp config/database.yml.test config/database.yml install: -- bundle install --without postgres + - if [ "${DB}" = "mysql" ]; then bundle install --without postgres; fi + - if [ "${DB}" = "postgresql" ]; then bundle install; fi script: +- bundle exec rubocop - rake db:create - rake db:migrate - rake db:seed @@ -31,3 +42,17 @@ script: - rake test:controllers - rake assets:precompile - rake db:drop +- rake db:create +- rake db:migrate +- rake db:seed +- ruby -I test/ test/integration/auto_wizard_test.rb +- rake db:drop +- rake db:create +- rake db:migrate +- rake db:seed +- ruby -I test/ test/integration/geo_location_test.rb +- ruby -I test/ test/integration/geo_calendar_test.rb +- ruby -I test/ test/integration/user_agent_test.rb +- ruby -I test/ test/integration/user_device_controller_test.rb +- ruby -I test/ test/integration/sipgate_controller_test.rb +- rake db:drop diff --git a/README.md b/README.md index b560166ae..272fd950c 100644 --- a/README.md +++ b/README.md @@ -9,17 +9,20 @@ with a team of agents? You're going to love Zammad! + ## Statusbadges - Build: [![Build Status](https://travis-ci.org/zammad/zammad.svg?branch=develop)](https://travis-ci.org/zammad/zammad) - Code: [![Code Climate](https://codeclimate.com/github/zammad/zammad/badges/gpa.svg)](https://codeclimate.com/github/zammad/zammad) - Docs: [![Documentation Status](https://readthedocs.org/projects/zammad/badge/?version=latest)](https://docs.zammad.org) -- Docker Image: [![](https://images.microbadger.com/badges/image/zammad/zammad.svg)](https://microbadger.com/images/zammad/zammad) [![](https://images.microbadger.com/badges/version/zammad/zammad.svg)](https://microbadger.com/images/zammad/zammad) +- Docker Image: [![](https://images.microbadger.com/badges/image/zammad/zammad.svg)](https://microbadger.com/images/zammad/zammad) [![](https://images.microbadger.com/badges/version/zammad/zammad.svg)](https://hub.docker.com/r/zammad/zammad/) + ## Installing & Getting Started https://docs.zammad.org + ## Screenshots https://zammad.org/screenshots @@ -38,3 +41,4 @@ https://zammad.org/participate Thanks! ❤️ ❤️ ❤️ Your Zammad Team + diff --git a/app/assets/javascripts/app/controllers/navigation.coffee b/app/assets/javascripts/app/controllers/navigation.coffee index c63dd0427..8abf6f51a 100644 --- a/app/assets/javascripts/app/controllers/navigation.coffee +++ b/app/assets/javascripts/app/controllers/navigation.coffee @@ -25,6 +25,10 @@ class App.Navigation extends App.ControllerWidgetPermanent @throttledSearch = _.throttle @search, 200 + @globalSearch = new App.GlobalSearch( + render: @renderResult + ) + # rerender view, e. g. on langauge change @bind 'ui:rerender', => @renderMenu() @@ -127,15 +131,15 @@ class App.Navigation extends App.ControllerWidgetPermanent items = @getItems(navbar: @Config.get('NavBarRight')) # get open tabs to repopen on rerender - open_tab = {} + openTab = {} @$('.open').children('a').each( (i,d) -> href = $(d).attr('href') - open_tab[href] = true + openTab[href] = true ) @$('.navbar-items-personal').html App.view('navigation/personal')( - items: items - open_tab: open_tab + items: items + openTab: openTab ) # only start avatar widget on existing session @@ -151,6 +155,7 @@ class App.Navigation extends App.ControllerWidgetPermanent # remove result if not result exists if _.isEmpty(result) @searchContainer.removeClass('open') + @globalSearch.close() @searchResult.html('') return @@ -275,6 +280,7 @@ class App.Navigation extends App.ControllerWidgetPermanent emptyAndClose: => @searchInput.val('') @searchContainer.removeClass('filled').removeClass('open').removeClass('focused') + @globalSearch.close() # remove not needed popovers @delay(@anyPopoversDestroy, 100, 'removePopovers') @@ -282,6 +288,7 @@ class App.Navigation extends App.ControllerWidgetPermanent andClose: => @searchInput.blur() @searchContainer.removeClass('open') + @globalSearch.close() @delay(@anyPopoversDestroy, 100, 'removePopovers') search: => @@ -290,11 +297,7 @@ class App.Navigation extends App.ControllerWidgetPermanent return if query is @query @query = query @searchContainer.toggleClass('filled', !!@query) - - App.GlobalSearch.execute( - query: @query - render: @renderResult - ) + @globalSearch.search(query: @query) getItems: (data) -> navbar = _.values(data.navbar) diff --git a/app/assets/javascripts/app/controllers/search.coffee b/app/assets/javascripts/app/controllers/search.coffee index 90043b952..9a6f45052 100644 --- a/app/assets/javascripts/app/controllers/search.coffee +++ b/app/assets/javascripts/app/controllers/search.coffee @@ -1,5 +1,4 @@ class App.Search extends App.Controller - searchResultCache: {} elements: '.js-search': 'searchInput' @@ -25,6 +24,11 @@ class App.Search extends App.Controller @throttledSearch = _.throttle @search, 200 + @globalSearch = new App.GlobalSearch( + render: @renderResult + limit: 50 + ) + @render() # rerender view, e. g. on langauge change @@ -52,10 +56,11 @@ class App.Search extends App.Controller @navupdate(url: '#search', type: 'menu') return if _.isEmpty(params.query) @$('.js-search').val(params.query).trigger('change') + return if @shown @throttledSearch(true) hide: -> - # nothing + @shown = false changed: -> # nothing @@ -117,11 +122,7 @@ class App.Search extends App.Controller @query = query @updateTask() - App.GlobalSearch.execute( - query: @query - render: @renderResult - limit: 50 - ) + @globalSearch.search(query: @query) renderResult: (result = []) => @result = result diff --git a/app/assets/javascripts/app/lib/app_post/global_search.coffee b/app/assets/javascripts/app/lib/app_post/global_search.coffee index 42061f3f7..2724624fe 100644 --- a/app/assets/javascripts/app/lib/app_post/global_search.coffee +++ b/app/assets/javascripts/app/lib/app_post/global_search.coffee @@ -1,37 +1,27 @@ -class App.GlobalSearch - _instance = undefined - - @execute: (args) -> - if _instance == undefined - _instance ?= new _globalSearchSingleton - _instance.execute(args) - -class _globalSearchSingleton extends Spine.Module - +class App.GlobalSearch extends App.Controller constructor: -> - @searchResultCache = undefined - @searchResultCacheByKey = {} + super + @searchResultCache = {} + @lastQuery = undefined @apiPath = App.Config.get('api_path') + @ajaxId = "search-#{Math.floor( Math.random() * 999999 )}" - execute: (params) -> - query = params.query - render = params.render - limit = params.limit || 10 - cacheKey = "#{query}_#{limit}" + search: (params) => + query = params.query # use cache for search result currentTime = new Date - if @searchResultCacheByKey[cacheKey] && @searchResultCacheByKey[cacheKey].time > currentTime.setSeconds(currentTime.getSeconds() - 20) - @renderTry(render, @searchResultCacheByKey[cacheKey].result, cacheKey) + if @searchResultCache[query] && @searchResultCache[query].time > currentTime.setSeconds(currentTime.getSeconds() - 20) + @renderTry(@searchResultCache[query].result, query) return App.Ajax.request( - id: 'search' + id: @ajaxId type: 'GET' url: "#{@apiPath}/search" data: query: query - limit: limit + limit: @limit || 10 processData: true success: (data, status, xhr) => App.Collection.loadAssets(data.assets) @@ -49,21 +39,24 @@ class _globalSearchSingleton extends Spine.Module else App.Log.error('_globalSearchSingleton', "No such model App.#{item.type}") - @renderTry(render, result, cacheKey) + @renderTry(result, query) ) - renderTry: (render, result, cacheKey) => + renderTry: (result, query) => # if result hasn't changed, do not rerender diff = false - if @searchResultCache - diff = difference(@searchResultCache, result) + if @lastQuery is query && @searchResultCache[query] + diff = difference(@searchResultCache[query].result, result) return if diff isnt false && _.isEmpty(diff) + @lastQuery = query # cache search result - @searchResultCache = result - @searchResultCacheByKey[cacheKey] = + @searchResultCache[query] = result: result time: new Date - render(result) + @render(result) + + close: => + @lastQuery = undefined diff --git a/app/assets/javascripts/app/models/macro.coffee b/app/assets/javascripts/app/models/macro.coffee index 99a60c96f..593e1df6d 100644 --- a/app/assets/javascripts/app/models/macro.coffee +++ b/app/assets/javascripts/app/models/macro.coffee @@ -1,5 +1,5 @@ class App.Macro extends App.Model - @configure 'Macro', 'name', 'perform', 'active' + @configure 'Macro', 'name', 'perform', 'note', 'active' @extend Spine.Model.Ajax @url: @apiPath + '/macros' @configure_attributes = [ diff --git a/app/assets/javascripts/app/views/navigation/personal.jst.eco b/app/assets/javascripts/app/views/navigation/personal.jst.eco index 5a8aeb488..22377fe81 100644 --- a/app/assets/javascripts/app/views/navigation/personal.jst.eco +++ b/app/assets/javascripts/app/views/navigation/personal.jst.eco @@ -1,6 +1,6 @@ <% for item in @items: %> <% if item.child: %> -
  • +
  • <% if item.class is 'user': %> @@ -15,7 +15,7 @@
  • <% end %> <% if item.navheader: %> - + <% end %>
  • diff --git a/app/models/avatar.rb b/app/models/avatar.rb index 396683bb7..6ea423f41 100644 --- a/app/models/avatar.rb +++ b/app/models/avatar.rb @@ -21,8 +21,7 @@ add an avatar based on auto detection (email address) # return if we run import mode return if Setting.get('import_mode') - return if !data[:url] - return if data[:url].empty? + return if data[:url].blank? Avatar.add( object: data[:object], @@ -96,7 +95,7 @@ add avatar by url # check if avatar with url already exists avatar_already_exists = nil - if data[:source] && !data[:source].empty? + if data[:source].present? avatar_already_exists = Avatar.find_by( object_lookup_id: object_id, o_id: data[:o_id], @@ -105,7 +104,7 @@ add avatar by url end # fetch image based on http url - if data[:url] && data[:url] =~ /^http/ + if data[:url] =~ /^http/ # check if source ist already updated within last 2 minutes if avatar_already_exists && avatar_already_exists.source_url == data[:url] diff --git a/app/models/calendar.rb b/app/models/calendar.rb index c27d0fc64..460567cde 100644 --- a/app/models/calendar.rb +++ b/app/models/calendar.rb @@ -75,92 +75,19 @@ returnes preset of ical feeds returns { - 'US' => 'http://www.google.com/calendar/ical/en.usa%23holiday%40group.v.calendar.google.com/public/basic.ics', + 'http://www.google.com/calendar/ical/en.usa%23holiday%40group.v.calendar.google.com/public/basic.ics' => 'US', ... } =end def self.ical_feeds - gfeeds = { - 'Australia' => 'en.australian', - 'Austria' => 'de.austrian', - 'Argentina' => 'en.ar', - 'Bahamas' => 'en.bs', - 'Belarus' => 'en.by', - 'Brazil' => 'en.brazilian', - 'Bulgaria' => 'en.bulgarian', - 'Canada' => 'en.canadian', - 'China' => 'en.china', - 'Chile' => 'en.cl', - 'Costa Rica' => 'en.cr', - 'Colombia' => 'en.co', - 'Croatia' => 'en.croatian', - 'Cuba' => 'en.cu', - 'Cyprus' => 'de.cy', - 'Switzerland' => 'de.ch', - 'Denmark' => 'da.danish', - 'Netherlands' => 'nl.dutch', - 'Egypt' => 'en.eg', - 'Ethiopia' => 'en.et', - 'Ecuador' => 'en.ec', - 'Estonia' => 'en.ee', - 'Finland' => 'en.finnish', - 'France' => 'en.french', - 'Germany' => 'de.german', - 'Greece' => 'en.greek', - 'Ghana' => 'en.gh', - 'Hong Kong' => 'en.hong_kong', - 'Haiti' => 'en.ht', - 'Hungary' => 'en.hungarian', - 'India' => 'en.indian', - 'Indonesia' => 'en.indonesian', - 'Iran' => 'en.ir', - 'Ireland' => 'en.irish', - 'Italy' => 'it.italian', - 'Israel' => 'en.jewish', - 'Japan' => 'en.japanese', - 'Kuwait' => 'en.kw', - 'Latvia' => 'en.latvian', - 'Liechtenstein' => 'en.li', - 'Lithuania' => 'en.lithuanian', - 'Luxembourg' => 'en.lu', - 'Malaysia' => 'en.malaysia', - 'Mexico' => 'en.mexican', - 'Morocco' => 'en.ma', - 'Mauritius' => 'en.mu', - 'Moldova' => 'en.md', - 'New Zealand' => 'en.new_zealand', - 'Norway' => 'en.norwegian', - 'Philippines' => 'en.philippines', - 'Poland' => 'en.polish', - 'Portugal' => 'en.portuguese', - 'Pakistan' => 'en.pk', - 'Russia' => 'en.russian', - 'Senegal' => 'en.sn', - 'Singapore' => 'en.singapore', - 'South Africa' => 'en.sa', - 'South Korean' => 'en.south_korea', - 'Spain' => 'en.spain', - 'Slovakia' => 'en.slovak', - 'Serbia' => 'en.rs', - 'Slovenia' => 'en.slovenian', - 'Sweden' => 'en.swedish', - 'Taiwan' => 'en.taiwan', - 'Thai' => 'en.th', - 'Turkey' => 'en.turkish', - 'UK' => 'en.uk', - 'US' => 'en.usa', - 'Ukraine' => 'en.ukrainian', - 'Uruguay' => 'en.uy', - 'Vietnam' => 'en.vietnamese', - 'Venezuela' => 'en.ve', - } - all_feeds = {} - gfeeds.each { |key, name| - all_feeds["http://www.google.com/calendar/ical/#{name}%23holiday%40group.v.calendar.google.com/public/basic.ics"] = key - } - all_feeds + data = YAML.load_file(Rails.root.join('config/holiday_calendars.yml')) + url = data['url'] + + data['countries'].map do |country, domain| + [(url % { domain: domain }), country] + end.to_h end =begin @@ -201,7 +128,7 @@ returns =end def self.sync - Calendar.all.each(&:sync) + Calendar.find_each(&:sync) true end @@ -313,7 +240,7 @@ returns # if changed calendar is default, set all others default to false def sync_default return if !default - Calendar.all.each { |calendar| + Calendar.find_each { |calendar| next if calendar.id == id next if !calendar.default calendar.default = false @@ -331,7 +258,7 @@ returns # check if sla's are refer to an existing calendar default_calendar = Calendar.find_by(default: true) - Sla.all.each { |sla| + Sla.find_each { |sla| if !sla.calendar_id sla.calendar_id = default_calendar.id sla.save! diff --git a/app/models/channel/driver/facebook.rb b/app/models/channel/driver/facebook.rb index 62320b31d..4ec9447c3 100644 --- a/app/models/channel/driver/facebook.rb +++ b/app/models/channel/driver/facebook.rb @@ -82,8 +82,7 @@ class Channel::Driver::Facebook @sync['pages'].each { |page_to_sync_id, page_to_sync_params| page = get_page(page_to_sync_id) next if !page - next if !page_to_sync_params['group_id'] - next if page_to_sync_params['group_id'].empty? + next if page_to_sync_params['group_id'].blank? page_client = Facebook.new(page['access_token']) posts = page_client.client.get_connection('me', 'feed', fields: 'id,from,to,message,created_time,permalink_url,comments{id,from,to,message,created_time}') diff --git a/app/models/channel/driver/imap.rb b/app/models/channel/driver/imap.rb index 733efd836..0f55f9c9f 100644 --- a/app/models/channel/driver/imap.rb +++ b/app/models/channel/driver/imap.rb @@ -68,6 +68,11 @@ example end if options.key?(:port) && !options[:port].empty? port = options[:port] + + # disable ssl for non ssl ports + if port == 143 && !options.key?(:ssl) + ssl = false + end end Rails.logger.info "fetching imap (#{options[:host]}/#{options[:user]} port=#{port},ssl=#{ssl})" diff --git a/app/models/channel/driver/pop3.rb b/app/models/channel/driver/pop3.rb index a227b68eb..d8e3a37e8 100644 --- a/app/models/channel/driver/pop3.rb +++ b/app/models/channel/driver/pop3.rb @@ -51,8 +51,13 @@ returns ssl = false port = 110 end - if options.key?(:port) && !options[:port].empty? + if options.key?(:port) && options[:port].present? port = options[:port] + + # disable ssl for non ssl ports + if port == 110 && !options.key?(:ssl) + ssl = false + end end Rails.logger.info "fetching pop3 (#{options[:host]}/#{options[:user]} port=#{port},ssl=#{ssl})" diff --git a/app/models/channel/driver/sendmail.rb b/app/models/channel/driver/sendmail.rb index f94fd9d2c..9b040eb86 100644 --- a/app/models/channel/driver/sendmail.rb +++ b/app/models/channel/driver/sendmail.rb @@ -7,7 +7,14 @@ class Channel::Driver::Sendmail return if Setting.get('import_mode') mail = Channel::EmailBuild.build(attr, notification) - mail.delivery_method :sendmail + mail.delivery_method delivery_method mail.deliver end + + private + + def delivery_method + return :test if Rails.env.test? + :sendmail + end end diff --git a/app/models/channel/driver/smtp.rb b/app/models/channel/driver/smtp.rb index 23d6d5256..646706d25 100644 --- a/app/models/channel/driver/smtp.rb +++ b/app/models/channel/driver/smtp.rb @@ -30,8 +30,8 @@ class Channel::Driver::Smtp if !options.key?(:port) || options[:port].empty? options[:port] = 25 end - if !options.key?(:domain) + if !options.key?(:domain) # set fqdn, if local fqdn - use domain of sender fqdn = Setting.get('fqdn') if fqdn =~ /(localhost|\.local^|\.loc^)/i && (attr['from'] || attr[:from]) @@ -58,7 +58,7 @@ class Channel::Driver::Smtp } # add authentication only if needed - if options[:user] && !options[:user].empty? + if options[:user].present? smtp_params[:user_name] = options[:user] smtp_params[:password] = options[:password] smtp_params[:authentication] = options[:authentication] diff --git a/app/models/channel/driver/twitter.rb b/app/models/channel/driver/twitter.rb index cf0db3306..cce2b4cff 100644 --- a/app/models/channel/driver/twitter.rb +++ b/app/models/channel/driver/twitter.rb @@ -269,13 +269,10 @@ returns private def fetch_search - return if !@sync[:search] - return if @sync[:search].empty? + return if @sync[:search].blank? @sync[:search].each { |search| - next if !search[:term] - next if search[:term].to_s.empty? - next if !search[:group_id] - next if search[:group_id].to_s.empty? + next if search[:term].blank? + next if search[:group_id].blank? result_type = search[:type] || 'mixed' Rails.logger.debug " - searching for '#{search[:term]}'" older_import = 0 @@ -296,10 +293,8 @@ returns end def fetch_mentions - return if !@sync[:mentions] - return if @sync[:mentions].empty? - return if !@sync[:mentions][:group_id] - return if @sync[:mentions][:group_id].to_s.empty? + return if @sync[:mentions].blank? + return if @sync[:mentions][:group_id].blank? Rails.logger.debug ' - searching for mentions' older_import = 0 older_import_max = 20 @@ -318,10 +313,8 @@ returns end def fetch_direct_messages - return if !@sync[:direct_messages] - return if @sync[:direct_messages].empty? - return if !@sync[:direct_messages][:group_id] - return if @sync[:direct_messages][:group_id].to_s.empty? + return if @sync[:direct_messages].blank? + return if @sync[:direct_messages][:group_id].blank? Rails.logger.debug ' - searching for direct_messages' older_import = 0 older_import_max = 20 diff --git a/app/models/channel/email_parser.rb b/app/models/channel/email_parser.rb index 571f64645..e2d42fa26 100644 --- a/app/models/channel/email_parser.rb +++ b/app/models/channel/email_parser.rb @@ -74,9 +74,7 @@ class Channel::EmailParser mail = Mail.new(msg) # set all headers - mail.header.fields.each { |field| - next if !field.name - + mail.header.fields.select(&:name).each { |field| # full line, encode, ready for storage data[field.name.to_s.downcase.to_sym] = Encode.conv('utf8', field.to_s) @@ -318,12 +316,10 @@ class Channel::EmailParser end # for some broken sm mail clients (X-MimeOLE: Produced By Microsoft Exchange V6.5) - if !filename - filename = file.header[:content_location].to_s - end + filename ||= file.header[:content_location].to_s # generate file name - if !filename || filename.empty? + if filename.blank? attachment_count = 0 (1..1000).each { |count| filename_exists = false diff --git a/app/models/observer/ticket/article/communicate_email/background_job.rb b/app/models/observer/ticket/article/communicate_email/background_job.rb index 571cd0b18..888ffb903 100644 --- a/app/models/observer/ticket/article/communicate_email/background_job.rb +++ b/app/models/observer/ticket/article/communicate_email/background_job.rb @@ -23,9 +23,9 @@ class Observer::Ticket::Article::CommunicateEmail::BackgroundJob # send email if !ticket.group.email_address_id - log_error(record, "No email address definde for group id '#{ticket.group.id}'!") + log_error(record, "No email address defined for group id '#{ticket.group.id}'!") elsif !ticket.group.email_address.channel_id - log_error(record, "No channel definde for email_address id '#{ticket.group.email_address_id}'!") + log_error(record, "No channel defined for email_address id '#{ticket.group.email_address_id}'!") end channel = ticket.group.email_address.channel diff --git a/app/models/observer/ticket/article/communicate_facebook/background_job.rb b/app/models/observer/ticket/article/communicate_facebook/background_job.rb index bdbe1d1dd..c48d61e78 100644 --- a/app/models/observer/ticket/article/communicate_facebook/background_job.rb +++ b/app/models/observer/ticket/article/communicate_facebook/background_job.rb @@ -7,9 +7,7 @@ class Observer::Ticket::Article::CommunicateFacebook::BackgroundJob article = Ticket::Article.find(@article_id) # set retry count - if !article.preferences['delivery_retry'] - article.preferences['delivery_retry'] = 0 - end + article.preferences['delivery_retry'] ||= 0 article.preferences['delivery_retry'] += 1 ticket = Ticket.lookup(id: article.ticket_id) @@ -24,7 +22,7 @@ class Observer::Ticket::Article::CommunicateFacebook::BackgroundJob end # fill in_reply_to - if !article.in_reply_to || article.in_reply_to.empty? + if article.in_reply_to.blank? article.in_reply_to = ticket.articles.first.message_id end diff --git a/app/models/organization.rb b/app/models/organization.rb index ad984b287..d8af2a25c 100644 --- a/app/models/organization.rb +++ b/app/models/organization.rb @@ -25,8 +25,7 @@ class Organization < ApplicationModel private def domain_cleanup - return if !domain - return if domain.empty? + return if domain.blank? domain.gsub!(/@/, '') domain.gsub!(/\s*/, '') domain.strip! diff --git a/app/models/ticket/escalation.rb b/app/models/ticket/escalation.rb index a584930e7..8e21c786b 100644 --- a/app/models/ticket/escalation.rb +++ b/app/models/ticket/escalation.rb @@ -163,7 +163,7 @@ returns } } config.hours = hours - if !hours || hours.empty? + if hours.blank? raise "No configured hours found in calendar #{calendar.inspect}" end diff --git a/app/models/ticket/number/date.rb b/app/models/ticket/number/date.rb index 609488532..300d96b99 100644 --- a/app/models/ticket/number/date.rb +++ b/app/models/ticket/number/date.rb @@ -73,7 +73,7 @@ module Ticket::Number::Date end def check(string) - return if !string || string.empty? + return if string.blank? # get config system_id = Setting.get('system_id') || '' diff --git a/app/models/ticket/number/increment.rb b/app/models/ticket/number/increment.rb index 567d1358c..a84574c87 100644 --- a/app/models/ticket/number/increment.rb +++ b/app/models/ticket/number/increment.rb @@ -70,7 +70,7 @@ module Ticket::Number::Increment end def check(string) - return if !string || string.empty? + return if string.blank? # get config system_id = Setting.get('system_id') || '' diff --git a/app/models/ticket/search_index.rb b/app/models/ticket/search_index.rb index 9451ca405..43c5b6a81 100644 --- a/app/models/ticket/search_index.rb +++ b/app/models/ticket/search_index.rb @@ -21,7 +21,7 @@ returns # collect article data # add tags tags = Tag.tag_list(object: 'Ticket', o_id: id) - if tags && !tags.empty? + if tags.present? attributes[:tag] = tags end diff --git a/app/models/user.rb b/app/models/user.rb index 6d3714fc2..cd87c04e3 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -154,18 +154,7 @@ returns =end def role?(role_name) - - result = false - roles.each { |role| - if role_name.class == Array - next if !role_name.include?(role.name) - elsif role.name != role_name - next - end - result = true - break - } - result + roles.where(name: role_name).any? end =begin @@ -226,16 +215,13 @@ returns def self.authenticate(username, password) # do not authenticate with nothing - return if !username || username == '' - return if !password || password == '' + return if username.blank? || password.blank? # try to find user based on login user = User.find_by(login: username.downcase, active: true) # try second lookup with email - if !user - user = User.find_by(email: username.downcase, active: true) - end + user ||= User.find_by(email: username.downcase, active: true) # check failed logins max_login_failed = Setting.get('password_max_login_failed').to_i || 10 @@ -249,7 +235,7 @@ returns # set login failed +1 if !user_auth && user sleep 1 - user.login_failed = user.login_failed + 1 + user.login_failed += 1 user.save end @@ -454,15 +440,13 @@ returns =end def self.password_reset_new_token(username) - return if !username || username == '' + return if username.blank? # try to find user based on login user = User.find_by(login: username.downcase, active: true) # try second lookup with email - if !user - user = User.find_by(email: username.downcase, active: true) - end + user ||= User.find_by(email: username.downcase, active: true) # check if email address exists return if !user @@ -737,8 +721,7 @@ returns end def check_preferences_default - return if !@preferences_default - return if @preferences_default.empty? + return if @preferences_default.blank? preferences_tmp = @preferences_default.merge(preferences) self.preferences = preferences_tmp @@ -871,8 +854,7 @@ returns end def avatar_for_email_check - return if !email - return if email.empty? + return if email.blank? return if email !~ /@/ return if !changes['email'] && updated_at > Time.zone.now - 10.days @@ -900,7 +882,7 @@ returns def check_password # set old password again if not given - if password == '' || !password + if password.blank? # get current record if id diff --git a/app/models/user_device.rb b/app/models/user_device.rb index 402a25ea9..15d7b3698 100644 --- a/app/models/user_device.rb +++ b/app/models/user_device.rb @@ -22,9 +22,7 @@ store new device for user if device not already known def self.add(user_agent, ip, user_id, fingerprint, type) # since gem browser 2 is not handling nil for user_agent, set it to '' - if user_agent.nil? - user_agent = '' - end + user_agent ||= '' # get location info location_details = Service::GeoIp.location(ip) @@ -79,7 +77,7 @@ store new device for user if device not already known name = browser[:plattform] end if browser[:name] && browser[:name] != 'Other' - if name && !name.empty? + if name.present? name += ', ' end name += browser[:name] diff --git a/config/database.yml.dist b/config/database.yml.dist deleted file mode 100644 index 70dc993dc..000000000 --- a/config/database.yml.dist +++ /dev/null @@ -1,33 +0,0 @@ -production: - adapter: mysql2 - database: zammad_prod - pool: 50 - timeout: 5000 - encoding: utf8 - username: some_user - password: some_pass - host: 127.0.0.1 - -development: - adapter: mysql2 - database: zammad_development - pool: 50 - timeout: 5000 - encoding: utf8 - username: some_user - password: some_pass - host: 127.0.0.1 - -# Warning: The database defined as "test" will be erased and -# re-generated from your development database when you run "rake". -# Do not set this db to the same as development or production. -test: - adapter: mysql2 - database: zammad_test - pool: 50 - timeout: 5000 - encoding: utf8 - username: some_user - password: some_pass - host: 127.0.0.1 - diff --git a/config/database.yml.test-mysql b/config/database.yml.test-mysql new file mode 100644 index 000000000..f6b525b4c --- /dev/null +++ b/config/database.yml.test-mysql @@ -0,0 +1,11 @@ +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. +test: + adapter: mysql2 + database: zammad_test + pool: 50 + timeout: 5000 + encoding: utf8 + username: some_user + password: some_pass diff --git a/config/database.yml.test-postgresql b/config/database.yml.test-postgresql new file mode 100644 index 000000000..bda094235 --- /dev/null +++ b/config/database.yml.test-postgresql @@ -0,0 +1,11 @@ +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. +test: + adapter: postgresql + database: zammad_test + pool: 50 + timeout: 5000 + encoding: utf8 + username: postgres + password: diff --git a/config/holiday_calendars.yml b/config/holiday_calendars.yml new file mode 100644 index 000000000..c105772f3 --- /dev/null +++ b/config/holiday_calendars.yml @@ -0,0 +1,78 @@ +--- +# % character in the URL has to be escaped (% => %%) +url: "http://www.google.com/calendar/ical/%{domain}%%23holiday%%40group.v.calendar.google.com/public/basic.ics" + +# Mapping from country to domain +countries: + Australia: en.australian + Austria: de.austrian + Argentina: en.ar + Bahamas: en.bs + Belarus: en.by + Brazil: en.brazilian + Bulgaria: en.bulgarian + Canada: en.canadian + China: en.china + Chile: en.cl + Costa Rica: en.cr + Colombia: en.co + Croatia: en.croatian + Cuba: en.cu + Cyprus: de.cy + Switzerland: de.ch + Denmark: da.danish + Netherlands: nl.dutch + Egypt: en.eg + Ethiopia: en.et + Ecuador: en.ec + Estonia: en.ee + Finland: en.finnish + France: en.french + Germany: de.german + Greece: en.greek + Ghana: en.gh + Hong Kong: en.hong_kong + Haiti: en.ht + Hungary: en.hungarian + India: en.indian + Indonesia: en.indonesian + Iran: en.ir + Ireland: en.irish + Italy: it.italian + Israel: en.jewish + Japan: en.japanese + Kuwait: en.kw + Latvia: en.latvian + Liechtenstein: en.li + Lithuania: en.lithuanian + Luxembourg: en.lu + Malaysia: en.malaysia + Mexico: en.mexican + Morocco: en.ma + Mauritius: en.mu + Moldova: en.md + New Zealand: en.new_zealand + Norway: en.norwegian + Philippines: en.philippines + Poland: en.polish + Portugal: en.portuguese + Pakistan: en.pk + Russia: en.russian + Senegal: en.sn + Singapore: en.singapore + South Africa: en.sa + South Korean: en.south_korea + Spain: en.spain + Slovakia: en.slovak + Serbia: en.rs + Slovenia: en.slovenian + Sweden: en.swedish + Taiwan: en.taiwan + Thai: en.th + Turkey: en.turkish + UK: en.uk + US: en.usa + Ukraine: en.ukrainian + Uruguay: en.uy + Vietnam: en.vietnamese + Venezuela: en.ve diff --git a/contrib/packager.io/config b/contrib/packager.io/config new file mode 100644 index 000000000..ce0b90090 --- /dev/null +++ b/contrib/packager.io/config @@ -0,0 +1,13 @@ +#!/bin/bash +# +# packager.io postinstall script config +# + +ZAMMAD_DIR="/opt/zammad" +DB="zammad" +DB_USER="zammad" +MY_CNF="/etc/mysql/debian.cnf" +ZAMMAD_WEBS="1" +ZAMMAD_WEBSOCKETS="1" +ZAMMAD_WORKERS="1" +DEBUG_OUTPUT="no" diff --git a/contrib/packager.io/functions b/contrib/packager.io/functions new file mode 100644 index 000000000..8080b6d23 --- /dev/null +++ b/contrib/packager.io/functions @@ -0,0 +1,201 @@ +#!/bin/bash +# +# packager.io postinstall script functions +# + +function detect_os () { + . "/etc/os-release" + + if [ "${ID}" == "debian" ] || [ "${ID}" == "ubuntu" ]; then + OS="DEBIAN" + elif [ "${ID}" == "centos" ] || [ "${ID}" == "fedora" ] || [ "${ID}" == "rhel" ]; then + OS="REDHAT" + elif [ "${ID}" == "opensuse" ] || [ "${ID}" == "sles" ] || [ "${ID}" == "suse" ]; then + OS="SUSE" + else + OS="UNKNOWN" + fi + + if [ "${DEBUG_OUTPUT}" == "yes" ]; then + echo "OS is ${OS} based" + fi +} + +function detect_initcmd () { + if [ -n "$(which systemctl 2> /dev/null)" ]; then + INIT_CMD="systemctl" + elif [ -n "$(which initctl 2> /dev/null)" ]; then + INIT_CMD="initctl" + else + function sysvinit () { + service $2 $1 + } + INIT_CMD="sysvinit" + fi + + if [ "${DEBUG_OUTPUT}" == "yes" ]; then + echo "INIT CMD = ${INIT_CMD}" + fi +} + +function detect_database () { + if [ -n "$(which psql 2> /dev/null)" ]; then + ADAPTER="postgresql" + elif [ -n "$(which mysql 2> /dev/null)" ]; then + ADAPTER="mysql2" + fi + + if [ "${DEBUG_OUTPUT}" == "yes" ]; then + echo "Use ${ADAPTER} adapter in database.yml" + fi +} + +function detect_webserver () { + if [ -n "$(which nginx 2> /dev/null)" ] ; then + WEBSERVER="nginx" + WEBSERVER_CMD="nginx" + if [ "${OS}" == "DEBIAN" ]; then + WEBSERVER_CONF="/etc/nginx/sites-enabled/zammad.conf" + elif [ "${OS}" == "REDHAT" ]; then + WEBSERVER_CONF="/etc/nginx/conf.d/zammad.conf" + elif [ "${OS}" == "SUSE" ]; then + WEBSERVER_CONF="/etc/nginx/vhosts.d/zammad.conf" + fi + elif [ -n "$(which apache2 2> /dev/null)" ]; then + WEBSERVER="apache2" + WEBSERVER_CMD="apache2" + if [ "${OS}" == "DEBIAN" ]; then + WEBSERVER_CONF="/etc/apache2/sites-enabled/zammad.conf" + fi + elif [ -n "$(which httpd 2> /dev/null)" ]; then + WEBSERVER="apache2" + WEBSERVER_CMD="httpd" + if [ "${OS}" == "REDHAT" ]; then + WEBSERVER_CONF="/etc/httpd/conf.d/zammad.conf" + elif [ "${OS}" == "SUSE" ]; then + WEBSERVER_CONF="/etc/apache2/vhosts.d/zammad.conf" + fi + fi + + if [ "${DEBUG_OUTPUT}" == "yes" ]; then + echo "Webserver is ${WEBSERVER_CMD}" + fi +} + +function create_initscripts () { + echo "# (Re)creating init scripts" + zammad scale web=${ZAMMAD_WEBS} websocket=${ZAMMAD_WEBSOCKETS} worker=${ZAMMAD_WORKERS} + + echo "# Enabling Zammad on boot" + ${INIT_CMD} enable zammad +} + +function start_zammad () { + echo "# Starting Zammad" + ${INIT_CMD} start zammad +} + +function stop_zammad () { + echo "# Stopping Zammad" + ${INIT_CMD} stop zammad +} + +function create_database_password () { + DB_PASS="$(tr -dc A-Za-z0-9 < /dev/urandom | head -c10)" +} + +function create_postgresql_db () { + if [ -n "$(which postgresql-setup 2> /dev/null)" ]; then + echo "# Preparing postgresql server" + postgresql-setup initdb + fi + + echo "# Creating postgresql bootstart" + ${INIT_CMD} enable postgresql.service + + echo "# Restarting postgresql server" + ${INIT_CMD} restart postgresql + + echo "# Creating zammad postgresql db" + su - postgres -c "createdb -E UTF8 ${DB}" + + echo "# Creating zammad postgresql user" + echo "CREATE USER \"${DB_USER}\" WITH PASSWORD '${DB_PASS}';" | su - postgres -c psql + + echo "# Grant privileges to new postgresql user" + echo "GRANT ALL PRIVILEGES ON DATABASE \"${DB}\" TO \"${DB_USER}\";" | su - postgres -c psql +} + +function create_mysql_db () { + if [ -f "${MY_CNF}" ]; then + MYSQL_CREDENTIALS="--defaults-file=${MY_CNF}" + else + echo -n "Please enter your MySQL root password:" + read -s MYSQL_ROOT_PASS + MYSQL_CREDENTIALS="-u root -p${MYSQL_ROOT_PASS}" + fi + + echo "# Creating zammad mysql db" + mysql ${MYSQL_CREDENTIALS} -e "CREATE DATABASE ${DB} DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;" + + echo "# Creating zammad mysql user" + mysql ${MYSQL_CREDENTIALS} -e "CREATE USER \"${DB_USER}\"@\"${DB_HOST}\" IDENTIFIED BY \"${DB_PASS}\";" + + echo "# Grant privileges to new mysql user" + mysql ${MYSQL_CREDENTIALS} -e "GRANT ALL PRIVILEGES ON ${DB}.* TO \"${DB_USER}\"@\"${DB_HOST}\"; FLUSH PRIVILEGES;" +} + +function update_database_yml () { + if [ "${OS}" == "REDHAT" ] || [ "${OS}" == "SUSE" ]; then + if [ "${ADAPTER}" == "postgresql" ]; then + DB_PASS="" + fi + fi + + echo "# Updating database.yml" + sed -e "s/.*adapter:.*/ adapter: ${ADAPTER}/" \ + -e "s/.*username:.*/ username: ${DB_USER}/" \ + -e "s/.*password:.*/ password: ${DB_PASS}/" \ + -e "s/.*database:.*/ database: ${DB}/" < ${ZAMMAD_DIR}/config/database.yml.pkgr > ${ZAMMAD_DIR}/config/database.yml +} + +function initialise_database () { + zammad run rake db:migrate + zammad run rake db:seed +} + +function update_database () { + echo "# database.yml found. Updating db..." + zammad run rake db:migrate +} + +function create_webserver_config () { + if [ "${OS}" == "DEBIAN" ]; then + test -f /etc/${WEBSERVER}/sites-available/zammad.conf || cp ${ZAMMAD_DIR}/contrib/${WEBSERVER}/zammad.conf /etc/${WEBSERVER}/sites-available/zammad.conf + test -h ${WEBSERVER_CONF} || ln -s /etc/${WEBSERVER}/sites-available/zammad.conf ${WEBSERVER_CONF} + else + test -f ${WEBSERVER_CONF} || cp ${ZAMMAD_DIR}/contrib/${WEBSERVER}/zammad.conf ${WEBSERVER_CONF} + fi + + echo "# Creating webserver bootstart" + ${INIT_CMD} enable ${WEBSERVER_CMD} + + echo "# Restarting webserver ${WEBSERVER_CMD}" + ${INIT_CMD} restart ${WEBSERVER_CMD} +} + +function final_message () { + echo -e "####################################################################################" + echo -e "\nAdd your FQDN to servername directive in ${WEBSERVER_CONF}" + echo -e "and restart your webserver if you're not testing localy" + echo -e "or open http://localhost in your browser to start using Zammad.\n" + if [ "${OS}" == "REDHAT" ]; then + echo -e "\n Remember to enable selinux and firewall rules!\n" + echo -e "Use the follwing commands:" + echo -e " setsebool httpd_can_network_connect on -P" + echo -e " firewall-cmd --zone=public --add-port=80/tcp --permanent" + echo -e " firewall-cmd --zone=public --add-port=443/tcp --permanent" + echo -e " firewall-cmd --reload\n" + fi + echo -e "####################################################################################" +} diff --git a/contrib/packager.io/postinstall.sh b/contrib/packager.io/postinstall.sh index 16f8d6f33..8e520725a 100755 --- a/contrib/packager.io/postinstall.sh +++ b/contrib/packager.io/postinstall.sh @@ -5,189 +5,47 @@ PATH=/opt/zammad/bin:/opt/zammad/vendor/bundle/bin:/sbin:/bin:/usr/sbin:/usr/bin: -ZAMMAD_DIR="/opt/zammad" -DB="zammad_production" -DB_USER="zammad" -MY_CNF="/etc/mysql/debian.cnf" +set -e -# check which init system is used -if [ -n "$(which systemctl 2> /dev/null)" ]; then - INIT_CMD="systemctl" -elif [ -n "$(which initctl 2> /dev/null)" ]; then - INIT_CMD="initctl" -else - function sysvinit () { - service $2 $1 - } - INIT_CMD="sysvinit" -fi +# import config +. /opt/zammad/contrib/packager.io/config -echo "# (Re)creating init scripts" -zammad scale web=1 websocket=1 worker=1 +# import functions +. /opt/zammad/contrib/packager.io/functions -echo "# Enabling Zammad on boot" -${INIT_CMD} enable zammad +detect_os -echo "# Stopping Zammad" -${INIT_CMD} stop zammad +detect_initcmd + +detect_database + +detect_webserver + +create_initscripts + +stop_zammad # check if database.yml exists if [ -f ${ZAMMAD_DIR}/config/database.yml ]; then - # db migration - echo "# database.yml found. Updating db..." - zammad run rake db:migrate + update_database else - echo "# database.yml not found. Creating db..." + create_database_password - # create new password - DB_PASS="$(tr -dc A-Za-z0-9 < /dev/urandom | head -c10)" - - # postgresql - if [ -n "$(which psql 2> /dev/null)" ]; then + if [ "${ADAPTER}" == "postgresql" ]; then echo "# Installing zammad on postgresql" - - # centos - if [ -n "$(which postgresql-setup 2> /dev/null)" ]; then - echo "# Preparing postgresql server" - postgresql-setup initdb - - echo "# Backuping postgres config" - test -f /var/lib/pgsql/data/pg_hba.conf.bak || cp /var/lib/pgsql/data/pg_hba.conf /var/lib/pgsql/data/pg_hba.conf.bak - - echo "# Allow login via username and password in postgresql" - sed 's/ident/trust/g' < /var/lib/pgsql/data/pg_hba.conf.bak > /var/lib/pgsql/data/pg_hba.conf - fi - - # centos / ubuntu / sles - echo "# Creating postgresql bootstart" - ${INIT_CMD} enable postgresql.service - - echo "# Restarting postgresql server" - ${INIT_CMD} restart postgresql - - echo "# Creating zammad postgresql db" - su - postgres -c "createdb -E UTF8 ${DB}" - - echo "# Creating zammad postgresql user" - echo "CREATE USER \"${DB_USER}\" WITH PASSWORD '${DB_PASS}';" | su - postgres -c psql - - echo "# Grant privileges to new postgresql user" - echo "GRANT ALL PRIVILEGES ON DATABASE \"${DB}\" TO \"${DB_USER}\";" | su - postgres -c psql - - echo "# Updating database.yml" - sed -e "s/.*adapter:.*/ adapter: postgresql/" \ - -e "s/.*username:.*/ username: ${DB_USER}/" \ - -e "s/.*password:.*/ password: ${DB_PASS}/" \ - -e "s/.*database:.*/ database: ${DB}/" < ${ZAMMAD_DIR}/config/database.yml.dist > ${ZAMMAD_DIR}/config/database.yml - - # mysql / mariadb - elif [ -n "$(which mysql 2> /dev/null)" ];then - echo "# Installing zammad on mysql" - - if [ -f "${MY_CNF}" ]; then - MYSQL_CREDENTIALS="--defaults-file=${MY_CNF}" - else - echo -n "Please enter your MySQL root password:" - read -s MYSQL_ROOT_PASS - MYSQL_CREDENTIALS="-u root -p${MYSQL_ROOT_PASS}" - fi - - echo "# Creating zammad mysql db" - mysql ${MYSQL_CREDENTIALS} -e "CREATE DATABASE ${DB} DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;" - - echo "# Creating zammad mysql user" - mysql ${MYSQL_CREDENTIALS} -e "CREATE USER \"${DB_USER}\"@\"${DB_HOST}\" IDENTIFIED BY \"${DB_PASS}\";" - - echo "# Grant privileges to new mysql user" - mysql ${MYSQL_CREDENTIALS} -e "GRANT ALL PRIVILEGES ON ${DB}.* TO \"${DB_USER}\"@\"${DB_HOST}\"; FLUSH PRIVILEGES;" - - echo "# Updating database.yml" - sed -e "s/.*adapter:.*/ adapter: mysql2/" \ - -e "s/.*username:.*/ username: ${DB_USER}/" \ - -e "s/.*password:.*/ password: ${DB_PASS}/" \ - -e "s/.*database:.*/ database: ${DB}/" < ${ZAMMAD_DIR}/config/database.yml.dist > ${ZAMMAD_DIR}/config/database.yml - - # sqlite / no local db - elif [ -n "$(which sqlite 2> /dev/null)" ];then - echo "# Installing zammad on sqlite" - echo "# In fact this does nothing at the moment. use this to install zammad without a local database. sqlite should only be used in dev environment anyway." + create_postgresql_db + elif [ "${ADAPTER}" == "mysql2" ]; then + echo "# Installing zammad on mysql" + create_mysql_db fi - # fill database - zammad run rake db:migrate - zammad run rake db:seed + update_database_yml + initialise_database fi -echo "# Starting Zammad" -${INIT_CMD} start zammad +start_zammad -# on centos, allow nginx to connect to application server -if [ -n "$(which setsebool 2> /dev/null)" ]; then - echo "# Adding SE Linux rules" - setsebool httpd_can_network_connect on -P -fi +create_webserver_config -# on centos, open port 80 and 443 -if [ -n "$(which firewall-cmd 2> /dev/null)" ]; then - echo "# Adding firewall rules" - firewall-cmd --zone=public --add-port=80/tcp --permanent - firewall-cmd --zone=public --add-port=443/tcp --permanent - firewall-cmd --reload -fi - -# copy webserver config -if [ -n "$(which apache2 2> /dev/null)" ] || [ -n "$(which httpd 2> /dev/null)" ] || [ -n "$(which nginx 2> /dev/null)" ] ; then - # Nginx - # debian / ubuntu - if [ -d /etc/nginx/sites-enabled ]; then - WEBSERVER_CONF="/etc/nginx/sites-enabled/zammad.conf" - WEBSERVER_CMD="nginx" - test -f /etc/nginx/sites-available/zammad.conf || cp ${ZAMMAD_DIR}/contrib/nginx/zammad.conf /etc/nginx/sites-available/zammad.conf - test -h ${WEBSERVER_CONF} || ln -s /etc/nginx/sites-available/zammad.conf ${WEBSERVER_CONF} - # centos - elif [ -d /etc/nginx/conf.d ]; then - WEBSERVER_CONF="/etc/nginx/conf.d/zammad.conf" - WEBSERVER_CMD="nginx" - test -f ${WEBSERVER_CONF} || cp ${ZAMMAD_DIR}/contrib/nginx/zammad.conf ${WEBSERVER_CONF} - elif [ -d /etc/YaST2 ]; then - WEBSERVER_CONF="/etc/nginx/vhosts.d/zammad.conf" - WEBSERVER_CMD="nginx" - test -d /etc/nginx/vhosts.d || mkdir -p /etc/nginx/vhosts.d - test -f ${WEBSERVER_CONF} || cp ${ZAMMAD_DIR}/contrib/nginx/zammad.conf ${WEBSERVER_CONF} - - # Apache2 - # debian / ubuntu - elif [ -d /etc/apache2/sites-enabled ]; then - WEBSERVER_CONF="/etc/apache2/sites-enabled/zammad.conf" - WEBSERVER_CMD="apache2" - test -f /etc/apache2/sites-available/zammad.conf || cp ${ZAMMAD_DIR}/contrib/apache2/zammad.conf /etc/apache2/sites-available/zammad.conf - test -h ${WEBSERVER_CONF} || ln -s /etc/apache2/sites-available/zammad.conf ${WEBSERVER_CONF} - - echo "# Activating Apache2 modules" - a2enmod proxy - a2enmod proxy_http - a2enmod proxy_wstunnel - # centos - elif [ -d /etc/httpd/conf.d ]; then - WEBSERVER_CONF="/etc/httpd/conf.d/zammad.conf" - WEBSERVER_CMD="httpd" - test -f ${WEBSERVER_CONF} || cp ${ZAMMAD_DIR}/contrib/apache2/zammad.conf ${WEBSERVER_CONF} - fi - - echo "# Creating webserver bootstart" - ${INIT_CMD} enable ${WEBSERVER_CMD} - - echo "# Restarting webserver ${WEBSERVER_CMD}" - ${INIT_CMD} restart ${WEBSERVER_CMD} - - echo -e "####################################################################################" - echo -e "\nAdd your FQDN to servername directive in ${WEBSERVER_CONF}" - echo -e "and restart your webserver if you're not testing localy" - echo -e "or open http://localhost in your browser to start using Zammad.\n" - echo -e "####################################################################################" -else - echo -e "####################################################################################" - echo -e "\nOpen http://localhost:3000 in your browser to start using Zammad.\n" - echo -e "####################################################################################" -fi +final_message diff --git a/test/browser/form_test.rb b/test/browser/form_test.rb index 0a761f4b0..5bb89f5d0 100644 --- a/test/browser/form_test.rb +++ b/test/browser/form_test.rb @@ -52,10 +52,14 @@ class FormTest < TestCase browser: agent, css: 'body div.zammad-form-modal button[type="submit"]', ) - exists( + watch_for( browser: agent, css: 'body div.zammad-form-modal .has-error [name="body"]', ) + watch_for_disappear( + browser: agent, + css: 'body div.zammad-form-modal button[type="submit"][disabled]', + ) set( browser: agent, css: 'body div.zammad-form-modal [name="body"]', @@ -70,10 +74,14 @@ class FormTest < TestCase browser: agent, css: 'body div.zammad-form-modal button[type="submit"]', ) - exists( + watch_for( browser: agent, css: 'body div.zammad-form-modal .has-error [name="email"]', ) + watch_for_disappear( + browser: agent, + css: 'body div.zammad-form-modal button[type="submit"][disabled]', + ) set( browser: agent, css: 'body div.zammad-form-modal [name="email"]', @@ -83,10 +91,14 @@ class FormTest < TestCase browser: agent, css: 'body div.zammad-form-modal button[type="submit"]', ) - exists( + watch_for( browser: agent, css: 'body div.zammad-form-modal .has-error [name="email"]', ) + watch_for_disappear( + browser: agent, + css: 'body div.zammad-form-modal button[type="submit"][disabled]', + ) set( browser: agent, css: 'body div.zammad-form-modal [name="email"]', @@ -111,8 +123,7 @@ class FormTest < TestCase browser: customer, url: "#{browser_url}/assets/form/form.html", ) - sleep 4 - match( + watch_for( browser: customer, css: '.js-logDisplay', value: 'Faild to load form config, feature is disabled', @@ -143,7 +154,7 @@ class FormTest < TestCase browser: customer, css: '#feedback-form-modal', ) - exists( + watch_for( browser: customer, css: 'body div.zammad-form-modal', ) @@ -252,10 +263,14 @@ class FormTest < TestCase browser: customer, css: 'body div.zammad-form-modal button[type="submit"]', ) - exists( + watch_for( browser: customer, css: 'body div.zammad-form-modal .has-error [name="name"]', ) + watch_for_disappear( + browser: customer, + css: 'body div.zammad-form-modal button[type="submit"][disabled]', + ) set( browser: customer, css: 'body div.zammad-form-modal [name="name"]', @@ -270,10 +285,14 @@ class FormTest < TestCase browser: customer, css: 'body div.zammad-form-modal button[type="submit"]', ) - exists( + watch_for( browser: customer, css: 'body div.zammad-form-modal .has-error [name="body"]', ) + watch_for_disappear( + browser: customer, + css: 'body div.zammad-form-modal button[type="submit"][disabled]', + ) set( browser: customer, css: 'body div.zammad-form-modal [name="body"]', @@ -288,10 +307,14 @@ class FormTest < TestCase browser: customer, css: 'body div.zammad-form-modal button[type="submit"]', ) - exists( + watch_for( browser: customer, css: 'body div.zammad-form-modal .has-error [name="email"]', ) + watch_for_disappear( + browser: customer, + css: 'body div.zammad-form-modal button[type="submit"][disabled]', + ) set( browser: customer, css: 'body div.zammad-form-modal [name="email"]', @@ -301,10 +324,14 @@ class FormTest < TestCase browser: customer, css: 'body div.zammad-form-modal button[type="submit"]', ) - exists( + watch_for( browser: customer, css: 'body div.zammad-form-modal .has-error [name="email"]', ) + watch_for_disappear( + browser: customer, + css: 'body div.zammad-form-modal button[type="submit"][disabled]', + ) set( browser: customer, css: 'body div.zammad-form-modal [name="email"]', diff --git a/test/browser_test_helper.rb b/test/browser_test_helper.rb index bab23df05..974094733 100644 --- a/test/browser_test_helper.rb +++ b/test/browser_test_helper.rb @@ -1240,18 +1240,26 @@ class TestCase < Test::Unit::TestCase if element #&& element.displayed? begin - # match pn attribute - text = if params[:attribute] - element.attribute(params[:attribute]) - elsif params[:css] =~ /(input|textarea)/i - element.attribute('value') - else - element.text - end - if text =~ /#{params[:value]}/i - assert(true, "'#{params[:value]}' found in '#{text}'") + # watch for selector + if !params[:attribute] && !params[:value] + assert(true, "'#{params[:css]}' found") sleep 0.5 return true + + # match pn attribute + else + text = if params[:attribute] + element.attribute(params[:attribute]) + elsif params[:css] =~ /(input|textarea)/i + element.attribute('value') + else + element.text + end + if text =~ /#{params[:value]}/i + assert(true, "'#{params[:value]}' found in '#{text}'") + sleep 0.5 + return true + end end rescue # try again @@ -1260,7 +1268,10 @@ class TestCase < Test::Unit::TestCase sleep 0.5 } screenshot(browser: instance, comment: 'watch_for_failed') - raise "'#{params[:value]}' found in '#{text}'" + if !params[:attribute] && !params[:value] + raise "'#{params[:css]}' not found" + end + raise "'#{params[:value]}' not found in '#{text}'" end =begin diff --git a/test/unit/ticket_overview_test.rb b/test/unit/ticket_overview_test.rb index c31952e26..de881b401 100644 --- a/test/unit/ticket_overview_test.rb +++ b/test/unit/ticket_overview_test.rb @@ -548,7 +548,7 @@ class TicketOverviewTest < ActiveSupport::TestCase assert_equal(result[2][:tickets].class, Array) assert(result[2][:tickets].empty?) - sleep 1 + travel_to Time.zone.now + 1.second # because of mysql millitime issues ticket3 = Ticket.create( title: 'overview test 3', group: Group.lookup(name: 'OverviewTest'), @@ -571,6 +571,7 @@ class TicketOverviewTest < ActiveSupport::TestCase updated_by_id: 1, created_by_id: 1, ) + travel_back result = Ticket::Overviews.index(agent1) assert_equal(result[0][:overview][:id], overview1.id)