Compare commits
36 Commits
develop
...
stable-2.8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
809b8acada | ||
|
|
58f3f3fef8 | ||
|
|
b62a26c75a | ||
|
|
bee2e2c956 | ||
|
|
48c6e6fe31 | ||
|
|
a4fd51fdd4 | ||
|
|
0a33761db9 | ||
|
|
8b96ca3acf | ||
|
|
ad390e9f35 | ||
|
|
844aa77a3a | ||
|
|
81b38b603e | ||
|
|
e2f1419f5e | ||
|
|
acdd35af31 | ||
|
|
6bee27ddb8 | ||
|
|
69afbcaf56 | ||
|
|
6e29f40d98 | ||
|
|
1e5cc73625 | ||
|
|
fe7ba93908 | ||
|
|
246f644d0d | ||
|
|
c39804acbd | ||
|
|
629c561c28 | ||
|
|
9bcd07c7db | ||
|
|
b36f6e2558 | ||
|
|
2e2b578ef7 | ||
|
|
1736ce5b2a | ||
|
|
41fa35c3ad | ||
|
|
e3bc6b8845 | ||
|
|
f25737a848 | ||
|
|
b329dcfb4a | ||
|
|
467ea4e417 | ||
|
|
33c77b0986 | ||
|
|
ec9e35b5e2 | ||
|
|
cf663b9fdf | ||
|
|
3f1b35c0eb | ||
|
|
272eecf94f | ||
|
|
1e5bc8fcbf |
67
.circleci/config.yml
Normal file
67
.circleci/config.yml
Normal file
@@ -0,0 +1,67 @@
|
||||
version: 2.1
|
||||
jobs:
|
||||
lint-scripts:
|
||||
docker:
|
||||
- image: koalaman/shellcheck-alpine
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: lint-scripts
|
||||
command: .circleci/lint-scripts.sh
|
||||
|
||||
install-mysql:
|
||||
docker:
|
||||
- image: circleci/ruby:2.4.4
|
||||
- image: circleci/mysql:5.7-ram
|
||||
command: --max_allowed_packet=64MB
|
||||
environment:
|
||||
MYSQL_DATABASE: zammad_test
|
||||
MYSQL_USER: zammad_test
|
||||
MYSQL_PASSWORD: zammad_test
|
||||
environment:
|
||||
RAILS_ENV: test
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: install-mysql
|
||||
command: .circleci/install.sh
|
||||
|
||||
install-postgresql:
|
||||
docker:
|
||||
- image: circleci/ruby:2.4.4
|
||||
- image: circleci/postgres:11-ram
|
||||
environment:
|
||||
POSTGRES_DB: zammad_test
|
||||
POSTGRES_USER: zammad_test
|
||||
POSTGRES_PASSWORD: zammad_test
|
||||
environment:
|
||||
RAILS_ENV: test
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: install-postgresql
|
||||
command: .circleci/install.sh
|
||||
|
||||
docker-image-build:
|
||||
machine: true
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: docker-image-build
|
||||
command: .circleci/docker-image-build.sh
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
install_unittest_dockerbuild:
|
||||
jobs:
|
||||
- lint-scripts
|
||||
- install-mysql:
|
||||
requires:
|
||||
- lint-scripts
|
||||
- install-postgresql:
|
||||
requires:
|
||||
- lint-scripts
|
||||
- docker-image-build:
|
||||
requires:
|
||||
- install-mysql
|
||||
- install-postgresql
|
||||
39
.circleci/docker-image-build.sh
Executable file
39
.circleci/docker-image-build.sh
Executable file
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# build zammads docker & docker-compose images
|
||||
|
||||
set -o errexit
|
||||
set -o pipefail
|
||||
|
||||
REPO_ROOT="$(git rev-parse --show-toplevel)"
|
||||
GITHUB_REPO_USER="zammad"
|
||||
ZAMMAD_VERSION="$(git describe --tags | sed -e 's/-[a-z0-9]\{8,\}.*//g')"
|
||||
export ZAMMAD_VERSION
|
||||
|
||||
if [ "${CIRCLE_BRANCH}" == 'develop' ]; then
|
||||
BUILD_SCRIPT="scripts/build_image.sh"
|
||||
DOCKER_REPOSITORY="zammad"
|
||||
export DOCKER_REPOSITORY
|
||||
GITHUB_REPOSITORY="zammad-docker"
|
||||
elif [ "${CIRCLE_BRANCH}" == 'stable' ]; then
|
||||
BUILD_SCRIPT="hooks/build"
|
||||
DOCKER_REPOSITORY="zammad-docker-compose"
|
||||
export DOCKER_REPOSITORY
|
||||
GITHUB_REPOSITORY="zammad-docker-compose"
|
||||
else
|
||||
echo "branch is ${CIRCLE_BRANCH}... no docker image build needed..."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# dockerhub auth
|
||||
echo "${DOCKER_PASSWORD}" | docker login --username="${DOCKER_USERNAME}" --password-stdin
|
||||
|
||||
# clone docker repo
|
||||
git clone https://github.com/"${GITHUB_REPO_USER}"/"${GITHUB_REPOSITORY}"
|
||||
|
||||
# enter dockerfile dir
|
||||
cd "${REPO_ROOT}/${GITHUB_REPOSITORY}"
|
||||
|
||||
# build & push docker image
|
||||
# shellcheck disable=SC1090
|
||||
source "${REPO_ROOT}/${GITHUB_REPOSITORY}/${BUILD_SCRIPT}"
|
||||
41
.circleci/install.sh
Executable file
41
.circleci/install.sh
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# install & unit test zammad
|
||||
#
|
||||
|
||||
set -o errexit
|
||||
set -o pipefail
|
||||
|
||||
DB_CONFIG="test:\n adapter: postgresql\n database: zammad_test\n host: 127.0.0.1\n pool: 50\n timeout: 5000\n encoding: utf8\n username: zammad_test\n password: zammad_test"
|
||||
|
||||
# install build dependencies
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --no-install-recommends autoconf automake autotools-dev bison build-essential curl git-core libffi-dev libgdbm-dev libgmp-dev libmariadbclient-dev-compat libncurses5-dev libreadline-dev libsqlite3-dev libssl-dev libtool libxml2-dev libxslt1-dev libyaml-0-2 libyaml-dev patch pkg-config postfix sqlite3 zlib1g-dev
|
||||
|
||||
if [ "${CIRCLE_JOB}" == "install-mysql" ]; then
|
||||
DB_ADAPTER="mysql2"
|
||||
INSTALL_OPTION="postgres"
|
||||
elif [ "${CIRCLE_JOB}" == "install-postgresql" ]; then
|
||||
DB_ADAPTER="postgresql"
|
||||
INSTALL_OPTION="mysql"
|
||||
else
|
||||
echo "nothing to do for circle ci job ${CIRCLE_JOB}..."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# create db config
|
||||
echo -e "${DB_CONFIG}" | sed "s/adapter: postgresql/adapter: ${DB_ADAPTER}/g" > config/database.yml
|
||||
|
||||
# install zammad
|
||||
bundle install --without "${INSTALL_OPTION}"
|
||||
|
||||
# unit tests
|
||||
bundle exec rubocop
|
||||
rake db:migrate
|
||||
rake db:seed
|
||||
bundle exec rspec -t ~type:system
|
||||
bundle exec rake db:environment:set RAILS_ENV=test
|
||||
rake db:reset
|
||||
rake test:units
|
||||
ruby -I test/ test/integration/object_manager_test.rb
|
||||
ruby -I test/ test/integration/package_test.rb
|
||||
18
.circleci/lint-scripts.sh
Executable file
18
.circleci/lint-scripts.sh
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# lint bash scripts
|
||||
#
|
||||
|
||||
set -o errexit
|
||||
|
||||
CONFIG_DIR="./.circleci"
|
||||
TMP_FILE="$(mktemp)"
|
||||
|
||||
find "${CONFIG_DIR}" -type f -name "*.sh" > "${TMP_FILE}"
|
||||
|
||||
while read -r FILE; do
|
||||
echo lint "${FILE}"
|
||||
shellcheck -x "${FILE}"
|
||||
done < "${TMP_FILE}"
|
||||
|
||||
rm "${TMP_FILE}"
|
||||
459
.gitlab-ci.yml
459
.gitlab-ci.yml
@@ -1,6 +1,23 @@
|
||||
variables:
|
||||
Z_LOCALES: "en-us:de-de"
|
||||
image: registry.znuny.com/docker/zammad-ruby:2.4.4
|
||||
|
||||
# Global variables added to the ENV of each job
|
||||
variables:
|
||||
# for faster translation loading
|
||||
Z_LOCALES: "en-us:de-de"
|
||||
# Browser tests and variables
|
||||
RAILS_SERVE_STATIC_FILES: "true"
|
||||
REMOTE_URL: "http://selenium:24444/wd/hub"
|
||||
TZ: "Europe/London"
|
||||
# docker elgalu/selenium variables for parallel browser instance creation
|
||||
MAX_INSTANCES: "50"
|
||||
MAX_SESSIONS: "50"
|
||||
# docker-imap-devel variables required for browser tests
|
||||
MAILNAME: "mail.test.dc.zammad.com"
|
||||
MAILBOX_INIT: "zammad@mail.test.dc.zammad.com:zammad"
|
||||
MAIL_ADDRESS: "zammad@mail.test.dc.zammad.com"
|
||||
MAIL_PASS: "zammad"
|
||||
|
||||
# Artifacts are stored for failed jobs for 2 days
|
||||
.artifacts_error_template: &artifacts_error
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
@@ -9,13 +26,43 @@ variables:
|
||||
- tmp/screenshot*
|
||||
- log/*.log
|
||||
|
||||
before_script:
|
||||
- ruby -v
|
||||
- which ruby
|
||||
- env
|
||||
- test -n "$RNAME" && script/build/test_db_config.sh
|
||||
- test -n "$RNAME" && bundle install -j $(nproc)
|
||||
# Workaround to enable usage of mixed SSH and Docker GitLab CI runners
|
||||
.docker_env_template: &docker_env
|
||||
tags:
|
||||
- docker
|
||||
|
||||
# Workaround for blocked port 25 access on cloud provider infrastructure
|
||||
.requires_mail_port_access_template: &requires_mail_port_access
|
||||
tags:
|
||||
- mail
|
||||
|
||||
.base_env_template: &base_env
|
||||
<<: *docker_env
|
||||
<<: *artifacts_error
|
||||
|
||||
# General required Docker services for different DB envs
|
||||
.services_mysql_template: &services_mysql
|
||||
services:
|
||||
- name: registry.znuny.com/docker/zammad-mysql:latest
|
||||
alias: mysql
|
||||
|
||||
.services_postgresql_template: &services_postgresql
|
||||
services:
|
||||
- name: registry.znuny.com/docker/zammad-postgresql:latest
|
||||
alias: postgresql
|
||||
|
||||
# Cache gems in between jobs and pipelines
|
||||
cache:
|
||||
key: "ruby24"
|
||||
paths:
|
||||
- vendor/ruby
|
||||
|
||||
# Initialize application env
|
||||
before_script:
|
||||
- bundle install -j $(nproc) --path vendor
|
||||
- bundle exec ruby script/build/database_config.rb
|
||||
|
||||
# Stages
|
||||
stages:
|
||||
- pre
|
||||
- test
|
||||
@@ -24,31 +71,33 @@ stages:
|
||||
|
||||
# pre stage
|
||||
|
||||
pre:rubocop:
|
||||
# Workaround to enable usage of mixed SSH and Docker GitLab CI runners
|
||||
.pre_stage_template: &pre_stage
|
||||
<<: *docker_env
|
||||
stage: pre
|
||||
tags:
|
||||
- core
|
||||
before_script:
|
||||
- '' # disable before_script for pre "non-application" env
|
||||
|
||||
pre:rubocop:
|
||||
<<: *pre_stage
|
||||
script:
|
||||
- bundle install -j $(nproc) --path vendor
|
||||
- bundle exec rubocop
|
||||
|
||||
pre:coffeelint:
|
||||
stage: pre
|
||||
tags:
|
||||
- core
|
||||
<<: *pre_stage
|
||||
script:
|
||||
- coffeelint app/
|
||||
|
||||
pre:bundle-audit:
|
||||
stage: pre
|
||||
tags:
|
||||
- core
|
||||
<<: *pre_stage
|
||||
script:
|
||||
- gem install bundler-audit
|
||||
- bundle-audit update
|
||||
- bundle-audit
|
||||
|
||||
pre:github:
|
||||
stage: pre
|
||||
<<: *pre_stage
|
||||
tags:
|
||||
- deploy
|
||||
script:
|
||||
@@ -59,253 +108,189 @@ pre:github:
|
||||
## RSpec
|
||||
|
||||
.script_rspec_template: &script_rspec_definition
|
||||
<<: *artifacts_error
|
||||
<<: *base_env
|
||||
variables:
|
||||
RAILS_ENV: "test"
|
||||
script:
|
||||
- rake zammad:db:init
|
||||
- bundle exec rake zammad:db:init
|
||||
- bundle exec rspec
|
||||
- rake db:drop
|
||||
|
||||
test:rspec:mysql:
|
||||
stage: test
|
||||
tags:
|
||||
- core
|
||||
- mysql
|
||||
<<: *services_mysql
|
||||
<<: *script_rspec_definition
|
||||
|
||||
test:rspec:postgresql:
|
||||
stage: test
|
||||
tags:
|
||||
- core
|
||||
- postgresql
|
||||
<<: *services_postgresql
|
||||
<<: *script_rspec_definition
|
||||
|
||||
## Unit and Controller tests
|
||||
|
||||
.script_unit_template: &script_unit_definition
|
||||
<<: *artifacts_error
|
||||
<<: *base_env
|
||||
variables:
|
||||
RAILS_ENV: "test"
|
||||
script:
|
||||
- rake zammad:db:init
|
||||
- rake test:units
|
||||
- ruby -I test/ test/integration/object_manager_test.rb
|
||||
- ruby -I test/ test/integration/object_manager_attributes_controller_test.rb
|
||||
- ruby -I test/ test/integration/package_test.rb
|
||||
- ruby -I test/ test/integration/monitoring_controller_test.rb
|
||||
- rake db:drop
|
||||
- bundle exec rake zammad:db:init
|
||||
- bundle exec rake test:units
|
||||
- bundle exec ruby -I test/ test/integration/object_manager_test.rb
|
||||
- bundle exec ruby -I test/ test/integration/object_manager_attributes_controller_test.rb
|
||||
- bundle exec ruby -I test/ test/integration/package_test.rb
|
||||
- bundle exec ruby -I test/ test/integration/monitoring_controller_test.rb
|
||||
|
||||
test:unit:mysql:
|
||||
stage: test
|
||||
tags:
|
||||
- core
|
||||
- mysql
|
||||
<<: *services_mysql
|
||||
<<: *script_unit_definition
|
||||
|
||||
test:unit:postgresql:
|
||||
stage: test
|
||||
tags:
|
||||
- core
|
||||
- postgresql
|
||||
<<: *services_postgresql
|
||||
<<: *script_unit_definition
|
||||
|
||||
## Integration tests
|
||||
|
||||
test:integration:email_helper_deliver:
|
||||
<<: *artifacts_error
|
||||
.test_integration_template: &test_integration_definition
|
||||
<<: *base_env
|
||||
<<: *services_postgresql
|
||||
stage: test
|
||||
variables:
|
||||
RAILS_ENV: "test"
|
||||
tags:
|
||||
- core
|
||||
|
||||
test:integration:email_helper_deliver:
|
||||
<<: *test_integration_definition
|
||||
<<: *requires_mail_port_access
|
||||
script:
|
||||
- rake zammad:db:unseeded
|
||||
- ruby -I test/ test/integration/email_helper_test.rb
|
||||
- ruby -I test/ test/integration/email_deliver_test.rb
|
||||
- ruby -I test/ test/integration/email_keep_on_server_test.rb
|
||||
- rake db:drop
|
||||
- bundle exec rake zammad:db:unseeded
|
||||
- bundle exec ruby -I test/ test/integration/email_helper_test.rb
|
||||
- bundle exec ruby -I test/ test/integration/email_deliver_test.rb
|
||||
- bundle exec ruby -I test/ test/integration/email_keep_on_server_test.rb
|
||||
|
||||
test:integration:facebook:
|
||||
<<: *artifacts_error
|
||||
stage: test
|
||||
variables:
|
||||
RAILS_ENV: "test"
|
||||
tags:
|
||||
- core-facebook
|
||||
<<: *test_integration_definition
|
||||
script:
|
||||
- rake zammad:db:init
|
||||
- ruby -I test/ test/integration/facebook_test.rb
|
||||
- rake db:drop
|
||||
- bundle exec rake zammad:db:init
|
||||
- bundle exec ruby -I test/ test/integration/facebook_test.rb
|
||||
allow_failure: true
|
||||
|
||||
test:integration:geo:
|
||||
<<: *artifacts_error
|
||||
stage: test
|
||||
variables:
|
||||
RAILS_ENV: "test"
|
||||
tags:
|
||||
- core
|
||||
<<: *test_integration_definition
|
||||
script:
|
||||
- rake zammad:db:unseeded
|
||||
- ruby -I test/ test/integration/geo_calendar_test.rb
|
||||
- ruby -I test/ test/integration/geo_location_test.rb
|
||||
- ruby -I test/ test/integration/geo_ip_test.rb
|
||||
- rake db:drop
|
||||
- bundle exec rake zammad:db:unseeded
|
||||
- bundle exec ruby -I test/ test/integration/geo_calendar_test.rb
|
||||
- bundle exec ruby -I test/ test/integration/geo_location_test.rb
|
||||
- bundle exec ruby -I test/ test/integration/geo_ip_test.rb
|
||||
|
||||
test:integration:user_agent:
|
||||
<<: *artifacts_error
|
||||
stage: test
|
||||
variables:
|
||||
RAILS_ENV: "test"
|
||||
tags:
|
||||
- core
|
||||
<<: *test_integration_definition
|
||||
script:
|
||||
- rake zammad:db:unseeded
|
||||
- ruby -I test/ test/integration/user_agent_test.rb
|
||||
- bundle exec rake zammad:db:unseeded
|
||||
- bundle exec ruby -I test/ test/integration/user_agent_test.rb
|
||||
- export ZAMMAD_PROXY_TEST=true
|
||||
- ruby -I test/ test/integration/user_agent_test.rb
|
||||
- rake db:drop
|
||||
- bundle exec ruby -I test/ test/integration/user_agent_test.rb
|
||||
allow_failure: true
|
||||
|
||||
test:integration:user_device:
|
||||
<<: *artifacts_error
|
||||
stage: test
|
||||
variables:
|
||||
RAILS_ENV: "test"
|
||||
tags:
|
||||
- core
|
||||
<<: *test_integration_definition
|
||||
script:
|
||||
- rake zammad:db:unseeded
|
||||
- ruby -I test/ test/integration/user_device_controller_test.rb
|
||||
- rake db:drop
|
||||
- bundle exec rake zammad:db:unseeded
|
||||
- bundle exec ruby -I test/ test/integration/user_device_controller_test.rb
|
||||
|
||||
test:integration:slack:
|
||||
<<: *artifacts_error
|
||||
stage: test
|
||||
variables:
|
||||
RAILS_ENV: "test"
|
||||
tags:
|
||||
- core
|
||||
<<: *test_integration_definition
|
||||
script:
|
||||
- rake zammad:db:unseeded
|
||||
- bundle exec rake zammad:db:unseeded
|
||||
- echo "gem 'slack-api'" >> Gemfile.local
|
||||
- bundle install -j $(nproc)
|
||||
- ruby -I test test/integration/slack_test.rb
|
||||
- rake db:drop
|
||||
- bundle exec ruby -I test test/integration/slack_test.rb
|
||||
|
||||
test:integration:clearbit:
|
||||
<<: *artifacts_error
|
||||
stage: test
|
||||
variables:
|
||||
RAILS_ENV: "test"
|
||||
tags:
|
||||
- core
|
||||
<<: *test_integration_definition
|
||||
script:
|
||||
- rake zammad:db:unseeded
|
||||
- ruby -I test test/integration/clearbit_test.rb
|
||||
- rake db:drop
|
||||
- bundle exec rake zammad:db:unseeded
|
||||
- bundle exec ruby -I test test/integration/clearbit_test.rb
|
||||
allow_failure: true
|
||||
|
||||
test:integration:telegram:
|
||||
<<: *artifacts_error
|
||||
stage: test
|
||||
variables:
|
||||
RAILS_ENV: "test"
|
||||
tags:
|
||||
- core
|
||||
<<: *test_integration_definition
|
||||
script:
|
||||
- rake zammad:db:init
|
||||
- ruby -I test test/integration/telegram_controller_test.rb
|
||||
- rake db:drop
|
||||
- bundle exec rake zammad:db:init
|
||||
- bundle exec ruby -I test test/integration/telegram_controller_test.rb
|
||||
|
||||
test:integration:twilio:
|
||||
<<: *artifacts_error
|
||||
stage: test
|
||||
variables:
|
||||
RAILS_ENV: "test"
|
||||
tags:
|
||||
- core
|
||||
<<: *test_integration_definition
|
||||
script:
|
||||
- rake zammad:db:init
|
||||
- ruby -I test test/integration/twilio_sms_controller_test.rb
|
||||
- rake db:drop
|
||||
- bundle exec rake zammad:db:init
|
||||
- bundle exec ruby -I test test/integration/twilio_sms_controller_test.rb
|
||||
|
||||
test:integration:idoit:
|
||||
<<: *artifacts_error
|
||||
stage: test
|
||||
variables:
|
||||
RAILS_ENV: "test"
|
||||
tags:
|
||||
- core
|
||||
<<: *test_integration_definition
|
||||
script:
|
||||
- rake zammad:db:init
|
||||
- ruby -I test test/integration/idoit_controller_test.rb
|
||||
- rake db:drop
|
||||
- bundle exec rake zammad:db:init
|
||||
- bundle exec ruby -I test test/integration/idoit_controller_test.rb
|
||||
|
||||
### Elasticsearch
|
||||
|
||||
.script_elasticsearch_template: &script_elasticsearch_definition
|
||||
<<: *artifacts_error
|
||||
<<: *base_env
|
||||
stage: test
|
||||
variables:
|
||||
RAILS_ENV: "test"
|
||||
ES_INDEX_RAND: "true"
|
||||
ES_URL: "http://localhost:9200"
|
||||
ES_URL: "http://elasticsearch:9200"
|
||||
script:
|
||||
- rake zammad:db:unseeded
|
||||
- ruby -I test/ test/integration/elasticsearch_active_test.rb
|
||||
- ruby -I test/ test/integration/elasticsearch_test.rb
|
||||
- ruby -I test/ test/integration/report_test.rb
|
||||
- bundle exec rake zammad:db:unseeded
|
||||
- bundle exec ruby -I test/ test/integration/elasticsearch_active_test.rb
|
||||
- bundle exec ruby -I test/ test/integration/elasticsearch_test.rb
|
||||
- bundle exec ruby -I test/ test/integration/report_test.rb
|
||||
- bundle exec rspec --tag searchindex
|
||||
- rake db:drop
|
||||
|
||||
test:integration:es_mysql:
|
||||
tags:
|
||||
- core
|
||||
- mysql
|
||||
<<: *script_elasticsearch_definition
|
||||
services:
|
||||
- name: registry.znuny.com/docker/zammad-mysql:latest
|
||||
alias: mysql
|
||||
- name: registry.znuny.com/docker/zammad-elasticsearch:latest
|
||||
alias: elasticsearch
|
||||
|
||||
test:integration:es_postgresql:
|
||||
tags:
|
||||
- core
|
||||
- postgresql
|
||||
<<: *script_elasticsearch_definition
|
||||
services:
|
||||
- name: registry.znuny.com/docker/zammad-postgresql:latest
|
||||
alias: postgresql
|
||||
- name: registry.znuny.com/docker/zammad-elasticsearch:latest
|
||||
alias: elasticsearch
|
||||
|
||||
### Zendesk
|
||||
|
||||
.script_integration_zendesk_template: &script_integration_zendesk_definition
|
||||
<<: *artifacts_error
|
||||
<<: *base_env
|
||||
<<: *services_postgresql
|
||||
stage: test
|
||||
variables:
|
||||
RAILS_ENV: "test"
|
||||
script:
|
||||
- rake zammad:db:unseeded
|
||||
- ruby -I test/ test/integration/zendesk_import_test.rb
|
||||
- rake db:drop
|
||||
- bundle exec rake zammad:db:unseeded
|
||||
- bundle exec ruby -I test/ test/integration/zendesk_import_test.rb
|
||||
allow_failure: true
|
||||
|
||||
test:integration:zendesk_mysql:
|
||||
tags:
|
||||
- core
|
||||
- mysql
|
||||
<<: *services_mysql
|
||||
<<: *script_integration_zendesk_definition
|
||||
|
||||
test:integration:zendesk_postgresql:
|
||||
tags:
|
||||
- core
|
||||
- postgresql
|
||||
<<: *services_postgresql
|
||||
<<: *script_integration_zendesk_definition
|
||||
|
||||
### OTRS
|
||||
|
||||
.script_integration_otrs_template: &script_integration_otrs_definition
|
||||
<<: *artifacts_error
|
||||
<<: *base_env
|
||||
stage: test
|
||||
script:
|
||||
- rake zammad:db:unseeded
|
||||
- ruby -I test/ test/integration/otrs_import_test.rb
|
||||
- rake db:drop
|
||||
- bundle exec rake zammad:db:unseeded
|
||||
- bundle exec ruby -I test/ test/integration/otrs_import_test.rb
|
||||
|
||||
.variables_integration_otrs_6_template: &variables_integration_otrs_6_definition
|
||||
variables:
|
||||
@@ -313,54 +298,45 @@ test:integration:zendesk_postgresql:
|
||||
IMPORT_OTRS_ENDPOINT: "https://vz1185.test.znuny.com/otrs/public.pl?Action=ZammadMigrator"
|
||||
|
||||
test:integration:otrs_6_mysql:
|
||||
tags:
|
||||
- core
|
||||
- mysql
|
||||
<<: *services_mysql
|
||||
<<: *script_integration_otrs_definition
|
||||
<<: *variables_integration_otrs_6_definition
|
||||
|
||||
test:integration:otrs_6_postgresql:
|
||||
tags:
|
||||
- core
|
||||
- postgresql
|
||||
<<: *services_postgresql
|
||||
<<: *script_integration_otrs_definition
|
||||
<<: *variables_integration_otrs_6_definition
|
||||
|
||||
test:integration:otrs_5:
|
||||
tags:
|
||||
- core
|
||||
<<: *services_postgresql
|
||||
variables:
|
||||
RAILS_ENV: "test"
|
||||
IMPORT_OTRS_ENDPOINT: "http://vz1109.demo.znuny.com/otrs/public.pl?Action=ZammadMigrator"
|
||||
<<: *script_integration_otrs_definition
|
||||
|
||||
test:integration:otrs_4:
|
||||
tags:
|
||||
- core
|
||||
<<: *services_postgresql
|
||||
variables:
|
||||
RAILS_ENV: "test"
|
||||
IMPORT_OTRS_ENDPOINT: "http://vz383.demo.znuny.com/otrs/public.pl?Action=ZammadMigrator"
|
||||
<<: *script_integration_otrs_definition
|
||||
|
||||
test:integration:otrs_33:
|
||||
tags:
|
||||
- core
|
||||
<<: *services_postgresql
|
||||
variables:
|
||||
RAILS_ENV: "test"
|
||||
IMPORT_OTRS_ENDPOINT: "http://vz305.demo.znuny.com/otrs/public.pl?Action=ZammadMigrator"
|
||||
<<: *script_integration_otrs_definition
|
||||
|
||||
test:integration:otrs_32:
|
||||
tags:
|
||||
- core
|
||||
<<: *services_postgresql
|
||||
variables:
|
||||
RAILS_ENV: "test"
|
||||
IMPORT_OTRS_ENDPOINT: "http://vz382.demo.znuny.com/otrs/public.pl?Action=ZammadMigrator"
|
||||
<<: *script_integration_otrs_definition
|
||||
|
||||
test:integration:otrs_31:
|
||||
tags:
|
||||
- core
|
||||
<<: *services_postgresql
|
||||
variables:
|
||||
RAILS_ENV: "test"
|
||||
IMPORT_OTRS_ENDPOINT: "http://vz381.demo.znuny.com/otrs/public.pl?Action=ZammadMigrator"
|
||||
@@ -371,15 +347,14 @@ test:integration:otrs_31:
|
||||
## preparation (asset precompile)
|
||||
|
||||
browser:build:
|
||||
<<: *base_env
|
||||
<<: *services_postgresql
|
||||
stage: test
|
||||
tags:
|
||||
- core
|
||||
variables:
|
||||
RAILS_ENV: "production"
|
||||
script:
|
||||
- rake zammad:db:unseeded
|
||||
- rake assets:precompile
|
||||
- rake db:drop
|
||||
- bundle exec rake zammad:db:unseeded
|
||||
- bundle exec rake assets:precompile
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
paths:
|
||||
@@ -390,13 +365,11 @@ browser:build:
|
||||
## Browser core tests
|
||||
|
||||
.variables_browser_template: &variables_browser_definition
|
||||
RAILS_SERVE_STATIC_FILES: "true"
|
||||
RAILS_ENV: "production"
|
||||
BROWSER_URL: "http://$IP:$BROWSER_PORT"
|
||||
APP_RESTART_CMD: "rake zammad:ci:app:restart"
|
||||
APP_RESTART_CMD: "bundle exec rake zammad:ci:app:restart"
|
||||
|
||||
.test_browser_core_template: &test_browser_core_definition
|
||||
<<: *artifacts_error
|
||||
<<: *base_env
|
||||
stage: browser-core
|
||||
dependencies:
|
||||
- browser:build
|
||||
@@ -405,47 +378,42 @@ browser:build:
|
||||
|
||||
test:browser:integration:api_client_ruby:
|
||||
<<: *test_browser_core_definition
|
||||
<<: *services_postgresql
|
||||
variables:
|
||||
<<: *variables_browser_definition
|
||||
TEST_URL: "http://$IP:$BROWSER_PORT/"
|
||||
tags:
|
||||
- browser
|
||||
script:
|
||||
- RAILS_ENV=test rake db:create
|
||||
- RAILS_ENV=test bundle exec rake db:create
|
||||
- cp contrib/auto_wizard_test.json auto_wizard.json
|
||||
- rake zammad:ci:test:start
|
||||
- git clone git@github.com:zammad/zammad-api-client-ruby.git || rake zammad:ci:test:fail
|
||||
- bundle exec rake zammad:ci:test:start
|
||||
- git clone https://github.com/zammad/zammad-api-client-ruby.git
|
||||
- cd zammad-api-client-ruby
|
||||
- bundle install -j $(nproc)
|
||||
- bundle exec rspec || (cd .. && rake zammad:ci:test:fail)
|
||||
- cd .. && rake zammad:ci:test:stop
|
||||
- bundle exec rspec
|
||||
|
||||
test:browser:integration:api_client_php:
|
||||
<<: *test_browser_core_definition
|
||||
<<: *services_postgresql
|
||||
variables:
|
||||
<<: *variables_browser_definition
|
||||
ZAMMAD_PHP_API_CLIENT_UNIT_TESTS_URL: "http://$IP:$BROWSER_PORT"
|
||||
ZAMMAD_PHP_API_CLIENT_UNIT_TESTS_URL: "http://localhost:3000"
|
||||
ZAMMAD_PHP_API_CLIENT_UNIT_TESTS_USERNAME: "master@example.com"
|
||||
ZAMMAD_PHP_API_CLIENT_UNIT_TESTS_PASSWORD: "test"
|
||||
tags:
|
||||
- browser
|
||||
script:
|
||||
- RAILS_ENV=test rake db:create
|
||||
- rake zammad:ci:test:start zammad:setup:auto_wizard
|
||||
- git clone git@github.com:zammad/zammad-api-client-php || rake zammad:ci:test:fail
|
||||
- RAILS_ENV=test bundle exec rake db:create
|
||||
- bundle exec rake zammad:ci:test:start zammad:setup:auto_wizard
|
||||
- git clone https://github.com/zammad/zammad-api-client-php.git
|
||||
- php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
|
||||
- php composer-setup.php --install-dir=/usr/local/bin
|
||||
- ln -s /usr/local/bin/composer.phar /usr/local/bin/composer
|
||||
- cd zammad-api-client-php
|
||||
- composer install
|
||||
- vendor/bin/phpunit || (cd .. && rake zammad:ci:test:fail)
|
||||
- cd .. && rake zammad:ci:test:stop
|
||||
- vendor/bin/phpunit
|
||||
|
||||
### Browser test slices
|
||||
|
||||
#### Templates
|
||||
|
||||
.script_browser_slice_template: &script_browser_slice_definition
|
||||
stage: browser-core
|
||||
dependencies:
|
||||
- browser:build
|
||||
script:
|
||||
# temporary workaround to check Yahoo! mailbox only in test:browser:core:ff_3_* tests
|
||||
- if [[ $CI_JOB_NAME != test:browser:core:ff_3_* ]]; then unset MAILBOX_AUTO1 ; fi
|
||||
@@ -454,24 +422,35 @@ test:browser:integration:api_client_php:
|
||||
- if [[ $CI_JOB_NAME != test:browser:core:ff_3_* ]]; then unset MAILBOX_MANUAL2 ; fi
|
||||
- env
|
||||
- script/build/test_slice_tests.sh $TEST_SLICE
|
||||
- RAILS_ENV=test rake db:create
|
||||
- rake zammad:ci:test:start[with_elasticsearch]
|
||||
- rake test:browser || rake zammad:ci:test:fail
|
||||
- rake zammad:ci:test:stop
|
||||
- RAILS_ENV=test bundle exec rake db:create
|
||||
- bundle exec rake zammad:ci:test:start[with_elasticsearch]
|
||||
- bundle exec rake test:browser
|
||||
|
||||
.test_browser_core_postgresql_template: &test_browser_core_postgresql_definition
|
||||
<<: *test_browser_core_definition
|
||||
tags:
|
||||
- browser
|
||||
- postgresql
|
||||
<<: *script_browser_slice_definition
|
||||
services:
|
||||
- name: registry.znuny.com/docker/zammad-postgresql:latest
|
||||
alias: postgresql
|
||||
- name: registry.znuny.com/docker/zammad-elasticsearch:latest
|
||||
alias: elasticsearch
|
||||
- name: docker.io/elgalu/selenium:3.141.59-p8
|
||||
alias: selenium
|
||||
- name: registry.znuny.com/docker/docker-imap-devel:latest
|
||||
alias: mail
|
||||
|
||||
.test_browser_core_mysql_template: &test_browser_core_mysql_definition
|
||||
<<: *test_browser_core_definition
|
||||
tags:
|
||||
- browser
|
||||
- mysql
|
||||
<<: *script_browser_slice_definition
|
||||
services:
|
||||
- name: registry.znuny.com/docker/zammad-mysql:latest
|
||||
alias: mysql
|
||||
- name: registry.znuny.com/docker/zammad-elasticsearch:latest
|
||||
alias: elasticsearch
|
||||
- name: docker.io/elgalu/selenium:3.141.59-p8
|
||||
alias: selenium
|
||||
- name: registry.znuny.com/docker/docker-imap-devel:latest
|
||||
alias: mail
|
||||
|
||||
#### Firefox
|
||||
|
||||
@@ -491,6 +470,7 @@ test:browser:core:ff_2_mysql:
|
||||
|
||||
test:browser:core:ff_3_mysql:
|
||||
<<: *test_browser_core_mysql_definition
|
||||
<<: *requires_mail_port_access
|
||||
variables:
|
||||
<<: *variables_browser_definition
|
||||
BROWSER: "firefox"
|
||||
@@ -533,6 +513,7 @@ test:browser:core:ff_2_postgresql:
|
||||
|
||||
test:browser:core:ff_3_postgresql:
|
||||
<<: *test_browser_core_postgresql_definition
|
||||
<<: *requires_mail_port_access
|
||||
variables:
|
||||
<<: *variables_browser_definition
|
||||
BROWSER: "firefox"
|
||||
@@ -647,28 +628,34 @@ test:browser:core:chrome_6_postgresql:
|
||||
|
||||
### Auto wizard
|
||||
|
||||
.auto_wizard_services_template: &auto_wizard_services
|
||||
services:
|
||||
- name: registry.znuny.com/docker/zammad-postgresql:latest
|
||||
alias: postgresql
|
||||
- name: docker.io/elgalu/selenium:3.141.59-p8
|
||||
alias: selenium
|
||||
|
||||
.test_browser_integration_template: &test_browser_integration_definition
|
||||
<<: *artifacts_error
|
||||
<<: *base_env
|
||||
<<: *auto_wizard_services
|
||||
stage: browser-integration
|
||||
dependencies:
|
||||
- browser:build
|
||||
|
||||
.script_integration_auto_wizard_template: &script_integration_auto_wizard_definition
|
||||
script:
|
||||
- RAILS_ENV=test rake db:create
|
||||
- RAILS_ENV=test bundle exec rake db:create
|
||||
- cp $AUTO_WIZARD_FILE auto_wizard.json
|
||||
- rake zammad:ci:test:start[with_elasticsearch]
|
||||
- ruby -I test/ $TEST_FILE || rake zammad:ci:test:fail
|
||||
- rake zammad:ci:test:stop
|
||||
- bundle exec rake zammad:ci:test:start
|
||||
- bundle exec ruby -I test/ $TEST_FILE
|
||||
|
||||
.browser_core_auto_wizard_template: &browser_core_auto_wizard_definition
|
||||
<<: *test_browser_core_definition
|
||||
<<: *auto_wizard_services
|
||||
<<: *script_integration_auto_wizard_definition
|
||||
|
||||
test:browser:autowizard_chrome:
|
||||
<<: *browser_core_auto_wizard_definition
|
||||
tags:
|
||||
- browser
|
||||
variables:
|
||||
<<: *variables_browser_definition
|
||||
BROWSER: "chrome"
|
||||
@@ -677,8 +664,6 @@ test:browser:autowizard_chrome:
|
||||
|
||||
test:browser:autowizard_ff:
|
||||
<<: *browser_core_auto_wizard_definition
|
||||
tags:
|
||||
- browser
|
||||
variables:
|
||||
<<: *variables_browser_definition
|
||||
BROWSER: "firefox"
|
||||
@@ -693,9 +678,6 @@ test:browser:autowizard_ff:
|
||||
|
||||
test:browser:integration:twitter_chrome:
|
||||
<<: *browser_integration_auto_wizard_definition
|
||||
tags:
|
||||
- browser
|
||||
- twitter
|
||||
variables:
|
||||
<<: *variables_browser_definition
|
||||
BROWSER: "chrome"
|
||||
@@ -704,9 +686,6 @@ test:browser:integration:twitter_chrome:
|
||||
|
||||
test:browser:integration:twitter_ff:
|
||||
<<: *browser_integration_auto_wizard_definition
|
||||
tags:
|
||||
- browser
|
||||
- twitter
|
||||
variables:
|
||||
<<: *variables_browser_definition
|
||||
BROWSER: "firefox"
|
||||
@@ -715,9 +694,6 @@ test:browser:integration:twitter_ff:
|
||||
|
||||
test:browser:integration:facebook_chrome:
|
||||
<<: *browser_integration_auto_wizard_definition
|
||||
tags:
|
||||
- browser
|
||||
- facebook
|
||||
variables:
|
||||
<<: *variables_browser_definition
|
||||
BROWSER: "chrome"
|
||||
@@ -726,9 +702,6 @@ test:browser:integration:facebook_chrome:
|
||||
|
||||
test:browser:integration:facebook_ff:
|
||||
<<: *browser_integration_auto_wizard_definition
|
||||
tags:
|
||||
- browser
|
||||
- facebook
|
||||
variables:
|
||||
<<: *variables_browser_definition
|
||||
BROWSER: "firefox"
|
||||
@@ -737,8 +710,6 @@ test:browser:integration:facebook_ff:
|
||||
|
||||
test:browser:integration:idoit_chrome:
|
||||
<<: *browser_integration_auto_wizard_definition
|
||||
tags:
|
||||
- browser
|
||||
variables:
|
||||
<<: *variables_browser_definition
|
||||
BROWSER: "chrome"
|
||||
@@ -749,17 +720,15 @@ test:browser:integration:idoit_chrome:
|
||||
|
||||
.variables_browser_import_template: &variables_browser_import_definition
|
||||
BROWSER: "chrome"
|
||||
BROWSER_URL: "http://$IP:$BROWSER_PORT"
|
||||
RAILS_SERVE_STATIC_FILES: "true"
|
||||
RAILS_ENV: "production"
|
||||
|
||||
.browser_integration_import_template: &browser_integration_import_definition
|
||||
<<: *test_browser_integration_definition
|
||||
tags:
|
||||
- browser
|
||||
script:
|
||||
- RAILS_ENV=test rake db:create
|
||||
- rake zammad:ci:test:start
|
||||
- ruby -I test/ $TEST_FILE
|
||||
- rake zammad:ci:test:stop
|
||||
- RAILS_ENV=test bundle exec rake db:create
|
||||
- bundle exec rake zammad:ci:test:start
|
||||
- bundle exec ruby -I test/ $TEST_FILE
|
||||
|
||||
test:browser:integration:otrs_chrome:
|
||||
<<: *browser_integration_import_definition
|
||||
|
||||
@@ -10,6 +10,7 @@ AllCops:
|
||||
- 'bin/rake'
|
||||
- 'bin/spring'
|
||||
- 'db/schema.rb'
|
||||
- 'vendor/**/*'
|
||||
|
||||
Rails:
|
||||
Enabled: true
|
||||
|
||||
74
.travis.yml
74
.travis.yml
@@ -1,74 +0,0 @@
|
||||
dist: trusty
|
||||
sudo: false
|
||||
notifications:
|
||||
email:
|
||||
- me+tv@zammad.com
|
||||
env:
|
||||
- DB=mysql
|
||||
- DB=postgresql
|
||||
addons:
|
||||
postgresql: "9.4"
|
||||
apt:
|
||||
packages:
|
||||
- autoconf
|
||||
- automake
|
||||
- autotools-dev
|
||||
- bison
|
||||
- build-essential
|
||||
- curl
|
||||
- git-core
|
||||
- libffi-dev
|
||||
- libgdbm-dev
|
||||
- libgmp-dev
|
||||
- libmysqlclient-dev
|
||||
- libncurses5-dev
|
||||
- libreadline6-dev
|
||||
- libsqlite3-dev
|
||||
- libssl-dev
|
||||
- libtool
|
||||
- libxml2-dev
|
||||
- libxslt1-dev
|
||||
- libyaml-0-2
|
||||
- libyaml-dev
|
||||
- mysql-client-5.6
|
||||
- mysql-client-core-5.6
|
||||
- mysql-server-5.6
|
||||
- patch
|
||||
- pkg-config
|
||||
- postfix
|
||||
- sqlite3
|
||||
- zlib1g-dev
|
||||
services:
|
||||
- postgresql
|
||||
- mysql
|
||||
language: ruby
|
||||
rvm:
|
||||
- 2.4.4
|
||||
before_install:
|
||||
- gem update --system # Due to: https://github.com/travis-ci/travis-ci/issues/8978
|
||||
- git fetch --unshallow
|
||||
- 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 contrib/travis-ci.org/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 contrib/travis-ci.org/database.yml.test-postgresql config/database.yml; fi
|
||||
- export RAILS_ENV=test
|
||||
- export ZAMMAD_VERSION=$(git describe --tags | sed -e 's/-[a-z0-9]\{8,\}.*//g')
|
||||
install:
|
||||
- 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
|
||||
- bundle exec rspec
|
||||
- bundle exec rake db:environment:set RAILS_ENV=test
|
||||
- rake db:reset
|
||||
- rake test:units
|
||||
- ruby -I test/ test/integration/object_manager_test.rb
|
||||
- ruby -I test/ test/integration/package_test.rb
|
||||
after_success:
|
||||
- if [ "${DB}" = "mysql" ]; then contrib/travis-ci.org/trigger_docker_image_build.sh; fi
|
||||
- if [ "${DB}" = "mysql" ]; then contrib/travis-ci.org/trigger_docker_image_compose_build.sh; fi
|
||||
- if [ "${DB}" = "mysql" ]; then contrib/travis-ci.org/trigger_docker_image_univention_build.sh; fi
|
||||
48
CHANGELOG.md
48
CHANGELOG.md
@@ -1,15 +1,51 @@
|
||||
# Change Log
|
||||
|
||||
## [2.8.0](https://github.com/zammad/zammad/tree/2.8.0) (2018-xx-xx)
|
||||
[Full Changelog](https://github.com/zammad/zammad/compare/2.7.0...2.8.0)
|
||||
## [2.8.1](https://github.com/zammad/zammad/tree/2.8.1) (2019-02-14)
|
||||
[Full Changelog](https://github.com/zammad/zammad/compare/2.8.0...2.8.1)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
**Fixed bugs:**
|
||||
- Increased timeout for big attachments [2440](https://github.com/zammad/zammad/pull/2440)
|
||||
- Zammad Icon (Bird) on page top left disappears and does not come back [2419](https://github.com/zammad/zammad/issues/2419) [[UX/UI](https://github.com/zammad/zammad/labels/UX/UI)] [[bug](https://github.com/zammad/zammad/labels/bug)] [[regression](https://github.com/zammad/zammad/labels/regression)]
|
||||
- Unable to show ticket history [2420](https://github.com/zammad/zammad/issues/2420) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Missing table name quoting causes MySQL 8 incompatibility [2418](https://github.com/zammad/zammad/issues/2418) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- i-doit version >= 1.12 integration requests fail with 'Can’t fetch objects from...' [2412](https://github.com/zammad/zammad/issues/2412) [[bug](https://github.com/zammad/zammad/labels/bug)] [[integration](https://github.com/zammad/zammad/labels/integration)]
|
||||
- Unable to load Zammad in web browser, because of online notification of ticket which was already deleted in the meantime [2405](https://github.com/zammad/zammad/issues/2405) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Missing custom object in database causes error on export in time_accounting [2398](https://github.com/zammad/zammad/issues/2398) [[bug](https://github.com/zammad/zammad/labels/bug)] [[time accounting](https://github.com/zammad/zammad/labels/time accounting)]
|
||||
- Unable to process emails without From (but with Sender) header. [2397](https://github.com/zammad/zammad/issues/2397) [[bug](https://github.com/zammad/zammad/labels/bug)] [[mail processing](https://github.com/zammad/zammad/labels/mail processing)]
|
||||
- Search term is deleted after I opened a object/ticket [2395](https://github.com/zammad/zammad/issues/2395) [[regression](https://github.com/zammad/zammad/labels/regression)]
|
||||
- Jump to bottom after article has been created to show that the article has been saved. [2394](https://github.com/zammad/zammad/issues/2394)
|
||||
- Missing translation for Full-Quote-Text "on xy wrote" [2344](https://github.com/zammad/zammad/issues/2344) [[UX/UI](https://github.com/zammad/zammad/labels/UX/UI)] [[translation](https://github.com/zammad/zammad/labels/translation)]
|
||||
|
||||
|
||||
## [2.8.0](https://github.com/zammad/zammad/tree/2.8.0) (2018-12-03)
|
||||
[Full Changelog](https://github.com/zammad/zammad/compare/2.7.0...2.8.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
- Twitter Account Activity API support [2023](https://github.com/zammad/zammad/issues/2023) [[channel](https://github.com/zammad/zammad/labels/channel)] [[enhancement](https://github.com/zammad/zammad/labels/enhancement)]
|
||||
- On large database indexes at missing [2368](https://github.com/zammad/zammad/issues/2368) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)]
|
||||
- Elasticsearch payload is going to big if a ticket has more then 9000 articles [2345](https://github.com/zammad/zammad/issues/2345) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)]
|
||||
- Logs flooded with article autosave data [2363](https://github.com/zammad/zammad/issues/2363) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)]
|
||||
- Increased popup width for text modules or placeholder list [2335](https://github.com/zammad/zammad/pull/2335) [[UX/UI](https://github.com/zammad/zammad/labels/UX/UI)] [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[frontend](https://github.com/zammad/zammad/labels/frontend)]
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
|
||||
|
||||
|
||||
- Unable to process html email with 2k links in an acceptable time [2374](https://github.com/zammad/zammad/issues/2374) [[bug](https://github.com/zammad/zammad/labels/bug)] [[needs verification](https://github.com/zammad/zammad/labels/needs verification)]
|
||||
- Column width is resized to a non readable minimum [2031](https://github.com/zammad/zammad/issues/2031) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Zendesk-Import fails for User & Organizations if Plan is below "Team" [2262](https://github.com/zammad/zammad/issues/2262) [[bug](https://github.com/zammad/zammad/labels/bug)] [[import](https://github.com/zammad/zammad/labels/import)]
|
||||
- Update italian translations for chat messages [2359](https://github.com/zammad/zammad/pull/2359)
|
||||
- Chat does not work due to errors in WebSocket (Database connection) [2353](https://github.com/zammad/zammad/issues/2353) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- selecting the overviews on the I Pad does not work [2330](https://github.com/zammad/zammad/issues/2330) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Update de.html.erb [2348](https://github.com/zammad/zammad/pull/2348)
|
||||
- Lost DB connection causes jobs to not be processed anymore [2343](https://github.com/zammad/zammad/issues/2343) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Role-Filter shows inactive Roles [2332](https://github.com/zammad/zammad/issues/2332) [[admin area](https://github.com/zammad/zammad/labels/admin area)] [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- IMAP fetch stops because of request timeout [2321](https://github.com/zammad/zammad/issues/2321) [[bug](https://github.com/zammad/zammad/labels/bug)] [[channel](https://github.com/zammad/zammad/labels/channel)]
|
||||
- Object country already exists [2333](https://github.com/zammad/zammad/issues/2333) [[bug](https://github.com/zammad/zammad/labels/bug)] [[object manager attribute](https://github.com/zammad/zammad/labels/object manager attribute)]
|
||||
- Upgrade to Zammad 2.7 was not possible (migration 20180220171219 CheckForObjectAttributes failed) [2318](https://github.com/zammad/zammad/issues/2318) [[bug](https://github.com/zammad/zammad/labels/bug)] [[migration](https://github.com/zammad/zammad/labels/migration)]
|
||||
- Unable to import (update) users with email addresses als lookup index written in upper letters [2329](https://github.com/zammad/zammad/issues/2329) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Websocket messages are not working correctly via Ajax long polling (e. g. multiple browser tabs can get opened with one session). [2327](https://github.com/zammad/zammad/issues/2327) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Improved error handling of invalid tag for text modules and add current time format (to not use 2018-10-31T08:02:21.917Z format) [2324](https://github.com/zammad/zammad/issues/2324) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- incorrect notification when closing a tab after setting up an object [2042](https://github.com/zammad/zammad/issues/2042) [[bug](https://github.com/zammad/zammad/labels/bug)] [[frontend](https://github.com/zammad/zammad/labels/frontend)] [[object manager attribute](https://github.com/zammad/zammad/labels/object manager attribute)]
|
||||
- Ticket list in overview of customer and organisation random order [2296](https://github.com/zammad/zammad/issues/2296) [[bug](https://github.com/zammad/zammad/labels/bug)] [[frontend](https://github.com/zammad/zammad/labels/frontend)]
|
||||
- ObjectManager Attribute Select used in trigger will show internal ID instead of value [1568](https://github.com/zammad/zammad/issues/1568) [[bug](https://github.com/zammad/zammad/labels/bug)] [[object manager attribute](https://github.com/zammad/zammad/labels/object manager attribute)] [[trigger](https://github.com/zammad/zammad/labels/trigger)]
|
||||
- Can't forward E-Mail in special cases within Firefox [2305](https://github.com/zammad/zammad/issues/2305) [[bug](https://github.com/zammad/zammad/labels/bug)] [[frontend](https://github.com/zammad/zammad/labels/frontend)]
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
Zammad is a web based open source helpdesk/customer support system with many
|
||||
features to manage customer communication via several channels like telephone,
|
||||
facebook, twitter, chat and e-mails. It is distributed under the GNU AFFERO
|
||||
General Public License (AGPL).
|
||||
facebook, twitter, chat and e-mails. It is distributed under version 3 of the
|
||||
GNU AFFERO General Public License (GNU AGPLv3).
|
||||
|
||||
Do you receive many e-mails and want to answer them with a team of agents?
|
||||
|
||||
@@ -11,7 +11,7 @@ You're going to love Zammad!
|
||||
|
||||
## Status
|
||||
|
||||
- Build: [](https://travis-ci.org/zammad/zammad)
|
||||
- Build: [](https://circleci.com/gh/zammad/zammad)
|
||||
- Code: [](https://codeclimate.com/github/zammad/zammad) [](https://coveralls.io/github/zammad/zammad)
|
||||
- Docs: [](https://docs.zammad.org)
|
||||
- Issues: [](https://github.com/zammad/zammad/issues "Percentage of issues still open") [](https://github.com/zammad/zammad/issues?q=is%3Aissue+is%3Aclosed "Average time to resolve an issue")
|
||||
@@ -44,4 +44,3 @@ https://zammad.org/participate
|
||||
Thanks! ❤️ ❤️ ❤️
|
||||
|
||||
Your Zammad Team
|
||||
|
||||
|
||||
@@ -23,17 +23,26 @@ class App.TicketMerge extends App.ControllerModal
|
||||
@render()
|
||||
)
|
||||
|
||||
onShown: (e) =>
|
||||
super
|
||||
later = =>
|
||||
if @tableCustomerTickets
|
||||
@tableCustomerTickets.show()
|
||||
if @tableRecentViewedTickets
|
||||
@tableRecentViewedTickets.show()
|
||||
@delay(later, 300)
|
||||
|
||||
content: =>
|
||||
content = $( App.view('agent_ticket_merge')() )
|
||||
|
||||
new App.TicketList(
|
||||
@tableCustomerTickets = new App.TicketList(
|
||||
tableId: 'ticket-merge-customer-tickets'
|
||||
el: content.find('#ticket-merge-customer-tickets')
|
||||
ticket_ids: @ticket_ids_by_customer
|
||||
radio: true
|
||||
)
|
||||
|
||||
new App.TicketList(
|
||||
@tableRecentViewedTickets = new App.TicketList(
|
||||
tableId: 'ticket-merge-recent-tickets'
|
||||
el: content.find('#ticket-merge-recent-tickets')
|
||||
ticket_ids: @ticket_ids_recent_viewed
|
||||
|
||||
@@ -18,7 +18,7 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
||||
'focus #global-search': 'searchFocus'
|
||||
'blur #global-search': 'searchBlur'
|
||||
'keyup #global-search': 'listNavigate'
|
||||
'click .js-global-search-result': 'emptyAndClose'
|
||||
'click .js-global-search-result': 'emptyAndCloseDelayed'
|
||||
'click .js-details-link': 'openExtendedSearch'
|
||||
'change .js-menu .js-switch input': 'switch'
|
||||
|
||||
@@ -162,7 +162,7 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
||||
renderResult: (result = [], noChange) =>
|
||||
if noChange
|
||||
return
|
||||
|
||||
|
||||
@removePopovers()
|
||||
|
||||
# remove result if not result exists
|
||||
@@ -202,18 +202,18 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
||||
$('#app').append @notificationWidget.el
|
||||
|
||||
searchFocus: (e) =>
|
||||
@query = '' # reset query cache
|
||||
@clearDelay('emptyAndCloseDelayed')
|
||||
@throttledSearch()
|
||||
App.PopoverProvidable.anyPopoversDestroy()
|
||||
@searchContainer.addClass('focused')
|
||||
@selectAll(e)
|
||||
|
||||
searchBlur: (e) =>
|
||||
# delay to be able to click x
|
||||
update = =>
|
||||
query = @searchInput.val().trim()
|
||||
if !query
|
||||
@emptyAndClose()
|
||||
return
|
||||
|
||||
# delay to be able to "click/execute" x if query is ''
|
||||
update = =>
|
||||
if @searchInput.val().trim() is ''
|
||||
@emptyAndClose()
|
||||
@delay(update, 100, 'removeFocused')
|
||||
|
||||
listNavigate: (e) =>
|
||||
@@ -231,9 +231,9 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
||||
href = @$('.global-search-result .nav-tab.is-hover').attr('href')
|
||||
if href
|
||||
@navigate(href)
|
||||
@emptyAndCloseDelayed()
|
||||
else
|
||||
@openExtendedSearch()
|
||||
@emptyAndClose()
|
||||
return
|
||||
|
||||
# on other keys, show result
|
||||
@@ -277,16 +277,21 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
||||
@scrollToIfNeeded(prev, false)
|
||||
|
||||
emptyAndClose: =>
|
||||
@andClose()
|
||||
@andEmpty()
|
||||
|
||||
emptyAndCloseDelayed: =>
|
||||
@andClose()
|
||||
delay = =>
|
||||
@andEmpty()
|
||||
@delay(delay, 60000, 'emptyAndCloseDelayed')
|
||||
|
||||
andEmpty: =>
|
||||
@query = ''
|
||||
@searchInput.val('')
|
||||
@searchContainer.removeClass('focused filled open no-match loading')
|
||||
@globalSearch.close()
|
||||
@delayedRemoveAnyPopover()
|
||||
|
||||
andClose: =>
|
||||
@query = ''
|
||||
@searchInput.blur()
|
||||
@searchContainer.removeClass('open no-match loading')
|
||||
@searchContainer.removeClass('focused filled open no-match loading')
|
||||
@globalSearch.close()
|
||||
@delayedRemoveAnyPopover()
|
||||
|
||||
@@ -301,9 +306,10 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
||||
@query = query
|
||||
|
||||
if @query == ''
|
||||
@searchContainer.removeClass('open')
|
||||
@searchContainer.removeClass('open loading')
|
||||
return
|
||||
|
||||
@searchContainer.addClass('open')
|
||||
@globalSearch.search(query: @query)
|
||||
|
||||
filterNavbar: (values, user, parent = null) ->
|
||||
@@ -460,7 +466,7 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
||||
if e
|
||||
e.preventDefault()
|
||||
query = @searchInput.val()
|
||||
@searchInput.val('').blur()
|
||||
@emptyAndClose()
|
||||
if query
|
||||
@navigate("#search/#{encodeURIComponent(query)}")
|
||||
return
|
||||
|
||||
@@ -239,6 +239,17 @@ class App.TicketZoom extends App.Controller
|
||||
return if !@attributeBar
|
||||
@attributeBar.start()
|
||||
|
||||
# scroll to article if given
|
||||
scrollToPosition: (position, delay, article_id) =>
|
||||
scrollToDelay = =>
|
||||
if position is 'article'
|
||||
@scrollToArticle(article_id)
|
||||
@positionPageHeaderUpdate()
|
||||
return
|
||||
@scrollToBottom()
|
||||
@positionPageHeaderUpdate()
|
||||
@delay(scrollToDelay, delay, 'scrollToPosition')
|
||||
|
||||
pagePosition: (params = {}) =>
|
||||
|
||||
# remember for later
|
||||
@@ -251,34 +262,23 @@ class App.TicketZoom extends App.Controller
|
||||
article_id = @pagePositionData
|
||||
@pagePositionData = undefined
|
||||
|
||||
# scroll to article if given
|
||||
scrollToPosition = (position, delay) =>
|
||||
scrollToDelay = =>
|
||||
if position is 'article'
|
||||
@scrollToArticle(article_id)
|
||||
@positionPageHeaderUpdate()
|
||||
return
|
||||
@scrollToBottom()
|
||||
@positionPageHeaderUpdate()
|
||||
@delay(scrollToDelay, delay, 'scrollToPosition')
|
||||
|
||||
# trigger shown to article
|
||||
if !@shown
|
||||
@shown = true
|
||||
App.Event.trigger('ui::ticket::shown', { ticket_id: @ticket_id })
|
||||
scrollToPosition('bottom', 50)
|
||||
@scrollToPosition('bottom', 50, article_id)
|
||||
return
|
||||
|
||||
# scroll to article if given
|
||||
if article_id && article_id isnt @last_article_id
|
||||
@last_article_id = article_id
|
||||
scrollToPosition('article', 300)
|
||||
@scrollToPosition('article', 300, article_id)
|
||||
return
|
||||
|
||||
# scroll to end if new article has been added
|
||||
if !@last_ticket_article_ids || !_.isEqual(_.sortBy(@last_ticket_article_ids), _.sortBy(@ticket_article_ids))
|
||||
@last_ticket_article_ids = @ticket_article_ids
|
||||
scrollToPosition('bottom', 100)
|
||||
@scrollToPosition('bottom', 100, article_id)
|
||||
return
|
||||
|
||||
setPosition: (position) =>
|
||||
@@ -915,6 +915,7 @@ class App.TicketZoom extends App.Controller
|
||||
@autosaveStart()
|
||||
@muteTask()
|
||||
@submitEnable(e)
|
||||
@scrollToPosition('bottom', 50)
|
||||
|
||||
error: (settings, details) =>
|
||||
error = undefined
|
||||
|
||||
@@ -180,7 +180,11 @@ class EmailReply extends App.Controller
|
||||
day: 'numeric'
|
||||
year: 'numeric'
|
||||
}
|
||||
new Date(date_string).toLocaleTimeString('en-US', options)
|
||||
locale = App.i18n.get() || 'en-US'
|
||||
try
|
||||
new Date(date_string).toLocaleTimeString(locale, options)
|
||||
catch e
|
||||
new Date(date_string).toLocaleTimeString('en-US', options)
|
||||
|
||||
@emailForward: (ticket, article, ui) ->
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div class="alert alert--danger hidden" role="alert"></div>
|
||||
<p>
|
||||
<%- @T('The tutorial on how to manage a %s is hosted on our [online documentation](https://docs.zammad.org/en/latest/channel-telegram.html).', 'Telegram Bot') %>
|
||||
<%- @T('The tutorial on how to manage a %s is hosted on our [online documentation](https://zammad-admin-documentation.readthedocs.io/en/latest/channels-telegram.html).', 'Telegram Bot') %>
|
||||
</p>
|
||||
<fieldset>
|
||||
<h2><%- @T('Enter your %s App Keys', 'Telegram') %></h2>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</div>
|
||||
|
||||
<% if @external_credential && @external_credential.credentials && !@external_credential.credentials.webhook_id: %>
|
||||
<div class="alert alert--warning" role="alert"><%- @T('Your Twitter-App is not using the Twitter Account Activity API yet and is therefore limited to search terms only. Please refer to the documentation %l on how to update your account.', 'https://docs.zammad.org/en/latest/channel-twitter.html') %></div>
|
||||
<div class="alert alert--warning" role="alert"><%- @T('Your Twitter-App is not using the Twitter Account Activity API yet and is therefore limited to search terms only. Please refer to the documentation %l on how to update your account.', 'https://zammad-admin-documentation.readthedocs.io/en/latest/channels-twitter.html') %></div>
|
||||
<% end %>
|
||||
|
||||
<div class="page-content">
|
||||
|
||||
@@ -314,10 +314,7 @@ curl http://localhost/api/v1/organization/{id} -v -u #{login}:#{password} -H "Co
|
||||
organization = Organization.find(params[:id])
|
||||
|
||||
# get history of organization
|
||||
history = organization.history_get(true)
|
||||
|
||||
# return result
|
||||
render json: history
|
||||
render json: organization.history_get(true)
|
||||
end
|
||||
|
||||
# @path [GET] /organizations/import_example
|
||||
|
||||
@@ -219,6 +219,7 @@ class ReportsController < ApplicationController
|
||||
# needs to be skipped
|
||||
objects = ObjectManager::Attribute.where(editable: true,
|
||||
active: true,
|
||||
to_create: false,
|
||||
object_lookup_id: ObjectLookup.lookup(name: 'Ticket').id)
|
||||
.pluck(:name, :display, :data_type, :data_option)
|
||||
.map { |name, display, data_type, data_option| { name: name, display: display, data_type: data_type, data_option: data_option } }
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
class SessionsController < ApplicationController
|
||||
prepend_before_action :authentication_check, only: %i[switch_to_user list delete]
|
||||
skip_before_action :verify_csrf_token, only: %i[create show destroy create_omniauth failure_omniauth create_sso]
|
||||
skip_before_action :verify_csrf_token, only: %i[show destroy create_omniauth failure_omniauth create_sso]
|
||||
|
||||
# "Create" a login, aka "log the user in"
|
||||
def create
|
||||
|
||||
@@ -294,10 +294,7 @@ class TicketsController < ApplicationController
|
||||
access!(ticket, 'read')
|
||||
|
||||
# get history of ticket
|
||||
history = ticket.history_get(true)
|
||||
|
||||
# return result
|
||||
render json: history
|
||||
render json: ticket.history_get(true)
|
||||
end
|
||||
|
||||
# GET /api/v1/ticket_related/1
|
||||
|
||||
@@ -165,6 +165,7 @@ class TimeAccountingsController < ApplicationController
|
||||
]
|
||||
objects = ObjectManager::Attribute.where(editable: true,
|
||||
active: true,
|
||||
to_create: false,
|
||||
object_lookup_id: ObjectLookup.lookup(name: 'Ticket').id)
|
||||
.pluck(:name, :display, :data_type, :data_option)
|
||||
.map { |name, display, data_type, data_option| { name: name, display: display, data_type: data_type, data_option: data_option } }
|
||||
|
||||
@@ -502,10 +502,7 @@ class UsersController < ApplicationController
|
||||
user = User.find(params[:id])
|
||||
|
||||
# get history of user
|
||||
history = user.history_get(true)
|
||||
|
||||
# return result
|
||||
render json: history
|
||||
render json: user.history_get(true)
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
@@ -49,6 +49,9 @@ add a new activity entry for an object
|
||||
permission_id = permission.id
|
||||
end
|
||||
|
||||
# check if object for online notification exists
|
||||
exists_by_object_and_id?(data[:object], data[:o_id])
|
||||
|
||||
# check newest entry - is needed
|
||||
result = ActivityStream.where(
|
||||
o_id: data[:o_id],
|
||||
|
||||
@@ -18,6 +18,7 @@ class ApplicationModel < ActiveRecord::Base
|
||||
include ApplicationModel::ChecksImport
|
||||
include ApplicationModel::CanTouchReferences
|
||||
include ApplicationModel::CanQueryCaseInsensitiveWhereOrSql
|
||||
include ApplicationModel::HasExistsCheckByObjectAndId
|
||||
|
||||
self.abstract_class = true
|
||||
end
|
||||
|
||||
@@ -145,7 +145,9 @@ get assets of object list
|
||||
def assets_of_object_list(list, assets = {})
|
||||
list.each do |item|
|
||||
require_dependency item['object'].to_filename
|
||||
record = Kernel.const_get(item['object']).find(item['o_id'])
|
||||
record = Kernel.const_get(item['object']).lookup(id: item['o_id'])
|
||||
next if record.blank?
|
||||
|
||||
assets = record.assets(assets)
|
||||
if item['created_by_id'].present?
|
||||
user = User.find(item['created_by_id'])
|
||||
|
||||
@@ -134,7 +134,7 @@ returns
|
||||
next if association_attributes_ignored.include?(assoc_name)
|
||||
|
||||
eager_load.push(assoc_name)
|
||||
pluck.push("#{assoc.table_name}.id AS #{assoc_name}")
|
||||
pluck.push("#{ActiveRecord::Base.connection.quote_table_name(assoc.table_name)}.id AS #{ActiveRecord::Base.connection.quote_table_name(assoc_name)}")
|
||||
keys.push("#{assoc_name.to_s.singularize}_ids")
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
module ApplicationModel::HasExistsCheckByObjectAndId
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
class_methods do
|
||||
|
||||
=begin
|
||||
|
||||
verify if referenced object exists
|
||||
|
||||
success = Model.exists_by_object_and_id('Ticket', 123)
|
||||
|
||||
returns
|
||||
|
||||
# true or will raise an exception
|
||||
|
||||
=end
|
||||
|
||||
def exists_by_object_and_id?(object, o_id)
|
||||
|
||||
begin
|
||||
local_class = object.constantize
|
||||
rescue => e
|
||||
raise "Unable for get an instance of '#{object}': #{e.inspect}"
|
||||
end
|
||||
if !local_class.exists?(o_id)
|
||||
raise ActiveRecord::RecordNotFound, "Unable for find reference object '#{object}.exists?(#{o_id})!"
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -177,10 +177,12 @@ returns
|
||||
next if !track_retweets? && tweet.retweet?
|
||||
|
||||
# ignore older messages
|
||||
if (@channel.created_at - 15.days) > tweet.created_at.dup.utc || older_import >= older_import_max
|
||||
older_import += 1
|
||||
Rails.logger.debug { "tweet to old: #{tweet.id}/#{tweet.created_at}" }
|
||||
next
|
||||
if @sync[:import_older_tweets] != true
|
||||
if (@channel.created_at - 15.days) > tweet.created_at.dup.utc || older_import >= older_import_max
|
||||
older_import += 1
|
||||
Rails.logger.debug { "tweet to old: #{tweet.id}/#{tweet.created_at}" }
|
||||
next
|
||||
end
|
||||
end
|
||||
|
||||
next if @client.locale_sender?(tweet) && own_tweet_already_imported?(tweet)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
class Channel::EmailParser
|
||||
EMAIL_REGEX = /.+@.+/
|
||||
RECIPIENT_FIELDS = %w[to cc delivered-to x-original-to envelope-to].freeze
|
||||
SENDER_FIELDS = %w[from reply-to return-path].freeze
|
||||
SENDER_FIELDS = %w[from reply-to return-path sender].freeze
|
||||
|
||||
=begin
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ module HasGroups
|
||||
# @return [ActiveRecord::AssociationRelation<[<Group]>] List of Groups with :through attributes
|
||||
def access(*access)
|
||||
table_name = proxy_association.owner.class.group_through.table_name
|
||||
query = select("groups.*, #{table_name}.*")
|
||||
query = select("#{ActiveRecord::Base.connection.quote_table_name('groups')}.*, #{ActiveRecord::Base.connection.quote_table_name(table_name)}.*")
|
||||
return query if access.blank?
|
||||
|
||||
access.push('full') if !access.include?('full')
|
||||
|
||||
@@ -204,12 +204,14 @@ returns
|
||||
=end
|
||||
|
||||
def history_get(fulldata = false)
|
||||
relation_object = self.class.instance_variable_get(:@history_relation_object) || nil
|
||||
|
||||
if !fulldata
|
||||
return History.list(self.class.name, self['id'])
|
||||
return History.list(self.class.name, self['id'], relation_object)
|
||||
end
|
||||
|
||||
# get related objects
|
||||
history = History.list(self.class.name, self['id'], nil, true)
|
||||
history = History.list(self.class.name, self['id'], relation_object, true)
|
||||
history[:list].each do |item|
|
||||
record = Kernel.const_get(item['object']).find(item['o_id'])
|
||||
|
||||
@@ -242,5 +244,21 @@ end
|
||||
def history_attributes_ignored(*attributes)
|
||||
@history_attributes_ignored = attributes
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
serve methode to ignore model attributes in historization
|
||||
|
||||
class Model < ApplicationModel
|
||||
include HasHistory
|
||||
history_relation_object 'Some::Relation::Object'
|
||||
end
|
||||
|
||||
=end
|
||||
|
||||
def history_relation_object(attribute)
|
||||
@history_relation_object = attribute
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -40,19 +40,19 @@ add a new history entry for an object
|
||||
return if Setting.get('import_mode') && !data[:id]
|
||||
|
||||
# lookups
|
||||
if data[:history_type]
|
||||
if data[:history_type].present?
|
||||
history_type = type_lookup(data[:history_type])
|
||||
end
|
||||
if data[:history_object]
|
||||
if data[:history_object].present?
|
||||
history_object = object_lookup(data[:history_object])
|
||||
end
|
||||
related_history_object_id = nil
|
||||
if data[:related_history_object]
|
||||
if data[:related_history_object].present?
|
||||
related_history_object = object_lookup(data[:related_history_object])
|
||||
related_history_object_id = related_history_object.id
|
||||
end
|
||||
history_attribute_id = nil
|
||||
if data[:history_attribute]
|
||||
if data[:history_attribute].present?
|
||||
history_attribute = attribute_lookup(data[:history_attribute])
|
||||
history_attribute_id = history_attribute.id
|
||||
end
|
||||
@@ -80,11 +80,11 @@ add a new history entry for an object
|
||||
if history_record
|
||||
history_record.update!(record)
|
||||
else
|
||||
record_new = History.create(record)
|
||||
record_new = History.create!(record)
|
||||
if record[:id]
|
||||
record_new.id = record[:id]
|
||||
end
|
||||
record_new.save
|
||||
record_new.save!
|
||||
end
|
||||
end
|
||||
|
||||
@@ -148,7 +148,7 @@ returns
|
||||
=end
|
||||
|
||||
def self.list(requested_object, requested_object_id, related_history_object = nil, assets = nil)
|
||||
if !related_history_object
|
||||
if related_history_object.blank?
|
||||
history_object = object_lookup(requested_object)
|
||||
history = History.where(history_object_id: history_object.id)
|
||||
.where(o_id: requested_object_id)
|
||||
@@ -220,14 +220,10 @@ returns
|
||||
def self.type_lookup(name)
|
||||
# lookup
|
||||
history_type = History::Type.lookup(name: name)
|
||||
if history_type
|
||||
return history_type
|
||||
end
|
||||
return history_type if history_type
|
||||
|
||||
# create
|
||||
History::Type.create(
|
||||
name: name
|
||||
)
|
||||
History::Type.create!(name: name)
|
||||
end
|
||||
|
||||
def self.object_lookup_id(id)
|
||||
@@ -237,14 +233,10 @@ returns
|
||||
def self.object_lookup(name)
|
||||
# lookup
|
||||
history_object = History::Object.lookup(name: name)
|
||||
if history_object
|
||||
return history_object
|
||||
end
|
||||
return history_object if history_object
|
||||
|
||||
# create
|
||||
History::Object.create(
|
||||
name: name
|
||||
)
|
||||
History::Object.create!(name: name)
|
||||
end
|
||||
|
||||
def self.attribute_lookup_id(id)
|
||||
@@ -254,14 +246,10 @@ returns
|
||||
def self.attribute_lookup(name)
|
||||
# lookup
|
||||
history_attribute = History::Attribute.lookup(name: name)
|
||||
if history_attribute
|
||||
return history_attribute
|
||||
end
|
||||
return history_attribute if history_attribute
|
||||
|
||||
# create
|
||||
History::Attribute.create(
|
||||
name: name
|
||||
)
|
||||
History::Attribute.create!(name: name)
|
||||
end
|
||||
|
||||
class Object < ApplicationModel
|
||||
|
||||
@@ -41,6 +41,9 @@ add a new online notification for this user
|
||||
object_id = ObjectLookup.by_name(data[:object])
|
||||
end
|
||||
|
||||
# check if object for online notification exists
|
||||
exists_by_object_and_id?(data[:object], data[:o_id])
|
||||
|
||||
record = {
|
||||
o_id: data[:o_id],
|
||||
object_lookup_id: object_id,
|
||||
|
||||
@@ -15,9 +15,11 @@ class RecentView < ApplicationModel
|
||||
def self.log(object, o_id, user)
|
||||
return if !access(object, o_id, user)
|
||||
|
||||
RecentView.create(o_id: o_id,
|
||||
recent_view_object_id: ObjectLookup.by_name(object),
|
||||
created_by_id: user.id)
|
||||
exists_by_object_and_id?(object, o_id)
|
||||
|
||||
RecentView.create!(o_id: o_id,
|
||||
recent_view_object_id: ObjectLookup.by_name(object),
|
||||
created_by_id: user.id)
|
||||
end
|
||||
|
||||
def self.log_destroy(requested_object, requested_object_id)
|
||||
|
||||
@@ -53,6 +53,8 @@ class Ticket < ApplicationModel
|
||||
:article_count,
|
||||
:preferences
|
||||
|
||||
history_relation_object 'Ticket::Article'
|
||||
|
||||
belongs_to :group
|
||||
belongs_to :organization
|
||||
has_many :articles, class_name: 'Ticket::Article', after_add: :cache_update, after_remove: :cache_update, dependent: :destroy, inverse_of: :ticket
|
||||
@@ -888,7 +890,7 @@ perform changes on ticket
|
||||
next if value['value'].blank?
|
||||
next if value['value'] != 'delete'
|
||||
|
||||
logger.debug { "Deleted ticket from #{perform_origin} #{perform.inspect} Ticket.find(#{id})" }
|
||||
logger.info { "Deleted ticket from #{perform_origin} #{perform.inspect} Ticket.find(#{id})" }
|
||||
destroy!
|
||||
next
|
||||
end
|
||||
@@ -1168,27 +1170,6 @@ result
|
||||
Ticket::Article.where(ticket_id: id).order(:created_at, :id)
|
||||
end
|
||||
|
||||
def history_get(fulldata = false)
|
||||
list = History.list(self.class.name, self['id'], 'Ticket::Article')
|
||||
return list if !fulldata
|
||||
|
||||
# get related objects
|
||||
assets = {}
|
||||
list.each do |item|
|
||||
record = Kernel.const_get(item['object']).find(item['o_id'])
|
||||
assets = record.assets(assets)
|
||||
|
||||
if item['related_object']
|
||||
record = Kernel.const_get(item['related_object']).find( item['related_o_id'])
|
||||
assets = record.assets(assets)
|
||||
end
|
||||
end
|
||||
{
|
||||
history: list,
|
||||
assets: assets,
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_generate
|
||||
|
||||
@@ -248,7 +248,7 @@ function setup_elasticsearch () {
|
||||
|
||||
yes | /usr/share/elasticsearch/bin/elasticsearch-plugin -s install ingest-attachment
|
||||
|
||||
if [ "${ES_CONNECTION}" == "http://127.0.0.1:9200" ]; then
|
||||
if [ "${ES_CONNECTION}" == "http://127.0.0.1:9200" ] || [ "${ES_CONNECTION}" == "http://localhost:9200" ]; then
|
||||
${INIT_CMD} restart elasticsearch
|
||||
else
|
||||
echo -e "\n It seems you're running an external Elasticsearch server on ${ES_CONNECTION}"
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
# 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
|
||||
@@ -1,11 +0,0 @@
|
||||
# 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:
|
||||
@@ -1,18 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# trigger build of https://github.com/zammad/zammad-docker on https://travis-ci.org/zammad/zammad-docker and upload it to https://hub.docker.com/r/zammad/zammad
|
||||
#
|
||||
|
||||
REPO_USER="zammad"
|
||||
REPO="zammad-docker"
|
||||
BRANCH="master"
|
||||
|
||||
if [ "${TRAVIS_BRANCH}" == 'develop' ]; then
|
||||
curl -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Travis-API-Version: 3" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: token ${TRAVIS_API_TOKEN}" \
|
||||
-d '{"request":{ "message": "'"${TRAVIS_COMMIT_MESSAGE}"'","branch":"'${BRANCH}'","config":{"env":{"ZAMMAD_VERSION":"'${ZAMMAD_VERSION}'"}}}}' \
|
||||
"https://api.travis-ci.org/repo/${REPO_USER}%2F${REPO}/requests"
|
||||
fi
|
||||
@@ -1,18 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# trigger build of https://github.com/zammad/zammad-docker-compose on https://travis-ci.org/zammad/zammad-docker-compose and upload it to https://hub.docker.com/r/zammad/zammad-docker-compose/
|
||||
#
|
||||
|
||||
REPO_USER="zammad"
|
||||
REPO="zammad-docker-compose"
|
||||
BRANCH="master"
|
||||
|
||||
if [ "${TRAVIS_BRANCH}" == 'stable' ]; then
|
||||
curl -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Travis-API-Version: 3" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: token ${TRAVIS_API_TOKEN}" \
|
||||
-d '{"request":{ "message": "'"${TRAVIS_COMMIT_MESSAGE}"'","branch":"'${BRANCH}'","config":{"env":{"ZAMMAD_VERSION":"'${ZAMMAD_VERSION}'"}}}}' \
|
||||
"https://api.travis-ci.org/repo/${REPO_USER}%2F${REPO}/requests"
|
||||
fi
|
||||
@@ -1,18 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# trigger build of https://github.com/zammad/zammad-docker-univention on https://travis-ci.org/zammad/zammad-docker-univention and upload it to https://hub.docker.com/r/zammad/zammad-docker-univention
|
||||
#
|
||||
|
||||
REPO_USER="zammad"
|
||||
REPO="zammad-docker-univention"
|
||||
BRANCH="master"
|
||||
|
||||
if [ "${TRAVIS_BRANCH}" == 'stable' ]; then
|
||||
curl -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Travis-API-Version: 3" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: token ${TRAVIS_API_TOKEN}" \
|
||||
-d '{"request":{ "message": "'"${TRAVIS_COMMIT_MESSAGE}"'","branch":"'${BRANCH}'","config":{"env":{"ZAMMAD_VERSION":"'${ZAMMAD_VERSION}'"}}}}' \
|
||||
"https://api.travis-ci.org/repo/${REPO_USER}%2F${REPO}/requests"
|
||||
fi
|
||||
@@ -109,6 +109,10 @@ or with filter:
|
||||
method: method,
|
||||
params: params,
|
||||
version: '2.0',
|
||||
# the id attribute is required by the JSON-RPC standard
|
||||
# but i-doit doesn't actually use it so we send a hard coded id
|
||||
# see issue #2412 and community topic for further information
|
||||
id: 42,
|
||||
},
|
||||
{
|
||||
json: true,
|
||||
|
||||
@@ -210,7 +210,7 @@ retunes
|
||||
=end
|
||||
|
||||
def self.already_sent?(ticket, recipient, type)
|
||||
result = ticket.history_get()
|
||||
result = ticket.history_get
|
||||
count = 0
|
||||
result.each do |item|
|
||||
next if item['type'] != 'notification'
|
||||
|
||||
@@ -36,8 +36,8 @@ class Sequencer
|
||||
resource.content_url,
|
||||
{},
|
||||
{
|
||||
open_timeout: 10,
|
||||
read_timeout: 60,
|
||||
open_timeout: 20,
|
||||
read_timeout: 240,
|
||||
},
|
||||
)
|
||||
end
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace :zammad do
|
||||
|
||||
next if args[:elasticsearch] != 'with_elasticsearch'
|
||||
|
||||
Setting.set('es_url', 'http://localhost:9200')
|
||||
Setting.set('es_url', 'http://elasticsearch:9200')
|
||||
Setting.set('es_index', "browser_test_#{ENV['CI_BUILD_ID']}")
|
||||
|
||||
Rake::Task['searchindex:rebuild'].invoke
|
||||
|
||||
@@ -348,9 +348,9 @@ test("check pretty date", function() {
|
||||
if (diff < (60 * 60 * 24 * 6))
|
||||
string = weekday + ' ' + date.getHours() + ':' + (date.getMinutes() < 10 ? '0':'') + date.getMinutes()
|
||||
else if (current.getYear() == date.getYear())
|
||||
string = weekday + ' ' + date.getDate() + '. ' + month + ' ' + (H < 10 ? '0':'') + H + ":" + (M < 10 ? '0':'') + M
|
||||
string = weekday + ' ' + date.getDate() + '. ' + month + ' ' + H + ":" + (M < 10 ? '0':'') + M
|
||||
else
|
||||
string = weekday + ' ' + (m < 10 ? '0':'') + m + '/' + (d < 10 ? '0':'') + d + '/' + (yfull) + ' ' + (H < 10 ? '0':'') + H + ":" + (M < 10 ? '0':'') + M
|
||||
string = weekday + ' ' + (m < 10 ? '0':'') + m + '/' + (d < 10 ? '0':'') + d + '/' + (yfull) + ' ' + H + ":" + (M < 10 ? '0':'') + M
|
||||
return string;
|
||||
}
|
||||
|
||||
|
||||
38
script/build/database_config.rb
Normal file
38
script/build/database_config.rb
Normal file
@@ -0,0 +1,38 @@
|
||||
require 'yaml'
|
||||
|
||||
cnf = YAML.load_file(File.join(__dir__, '../../config/database/database.yml'))
|
||||
|
||||
cnf.delete('default')
|
||||
|
||||
hostsfile = '/etc/hosts'
|
||||
database = %w[postgresql mysql].find do |possible_database|
|
||||
File.foreach(hostsfile).any? { |l| l[possible_database] }
|
||||
end
|
||||
|
||||
raise "Can't find any supported database in #{hostsfile}." if database.nil?
|
||||
|
||||
db_settings_map = {
|
||||
'postgresql' => {
|
||||
'adapter' => 'postgresql',
|
||||
'username' => 'zammad',
|
||||
'password' => 'zammad',
|
||||
'host' => 'postgresql', # db alias from gitlab-ci.yml
|
||||
},
|
||||
'mysql' => {
|
||||
'adapter' => 'mysql2',
|
||||
'username' => 'root',
|
||||
'password' => 'zammad',
|
||||
'host' => 'mysql', # db alias from gitlab-ci.yml
|
||||
}
|
||||
}
|
||||
|
||||
# fetch DB settings from settings map and fallback to postgresql
|
||||
db_settings = db_settings_map.fetch(database) { db_settings_map['postgresql'] }
|
||||
|
||||
%w[development test production].each do |environment|
|
||||
cnf[environment].merge!(db_settings)
|
||||
end
|
||||
|
||||
File.open('config/database.yml', 'w') do |file|
|
||||
file.write(Psych.dump(cnf))
|
||||
end
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
rake db:drop RAILS_ENV=test
|
||||
rake db:drop RAILS_ENV=production
|
||||
@@ -1,74 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ "$RNAME" == '' ]; then
|
||||
echo "ERROR: Env RNAME is missing!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$RDB" == '' ]; then
|
||||
echo "ERROR: Env RDB is missing!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export RAND=`perl -e 'print int(rand(999999999))'`
|
||||
DBNAME="$RNAME-$RAND"
|
||||
DBFILE=config/database.yml
|
||||
DB_PRODUCTION=$DBNAME"_production"
|
||||
DB_TEST=$DBNAME"_test"
|
||||
DB_DEVELOPMENT=$DBNAME"_development"
|
||||
|
||||
echo "Creating $DBFILE for $RDB tests with $DBNAME"
|
||||
|
||||
if [ "$RDB" == 'mysql' ]; then
|
||||
echo "production:" > $DBFILE
|
||||
echo " adapter: mysql2" >> $DBFILE
|
||||
echo " database: $DB_PRODUCTION" >> $DBFILE
|
||||
echo " pool: 50" >> $DBFILE
|
||||
echo " timeout: 5000" >> $DBFILE
|
||||
echo " encoding: utf8" >> $DBFILE
|
||||
echo " username: root" >> $DBFILE
|
||||
echo " password:" >> $DBFILE
|
||||
echo "test:" >> $DBFILE
|
||||
echo " adapter: mysql2" >> $DBFILE
|
||||
echo " database: $DB_TEST" >> $DBFILE
|
||||
echo " pool: 50" >> $DBFILE
|
||||
echo " timeout: 5000" >> $DBFILE
|
||||
echo " encoding: utf8" >> $DBFILE
|
||||
echo " username: root" >> $DBFILE
|
||||
echo " password:" >> $DBFILE
|
||||
echo "development:" >> $DBFILE
|
||||
echo " adapter: mysql2" >> $DBFILE
|
||||
echo " database: $DB_DEVELOPMENT" >> $DBFILE
|
||||
echo " pool: 50" >> $DBFILE
|
||||
echo " timeout: 5000" >> $DBFILE
|
||||
echo " encoding: utf8" >> $DBFILE
|
||||
echo " username: root" >> $DBFILE
|
||||
echo " password:" >> $DBFILE
|
||||
fi
|
||||
|
||||
if [ "$RDB" == 'postgresql' ]; then
|
||||
echo "production:" > $DBFILE
|
||||
echo " adapter: postgresql" >> $DBFILE
|
||||
echo " database: $DB_PRODUCTION" >> $DBFILE
|
||||
echo " pool: 50" >> $DBFILE
|
||||
echo " timeout: 5000" >> $DBFILE
|
||||
echo " encoding: utf8" >> $DBFILE
|
||||
echo " username: gitlab-runner" >> $DBFILE
|
||||
echo " password:" >> $DBFILE
|
||||
echo "test:" >> $DBFILE
|
||||
echo " adapter: postgresql" >> $DBFILE
|
||||
echo " database: $DB_TEST" >> $DBFILE
|
||||
echo " pool: 50" >> $DBFILE
|
||||
echo " timeout: 5000" >> $DBFILE
|
||||
echo " encoding: utf8" >> $DBFILE
|
||||
echo " username: gitlab-runner" >> $DBFILE
|
||||
echo " password:" >> $DBFILE
|
||||
echo "development:" >> $DBFILE
|
||||
echo " adapter: postgresql" >> $DBFILE
|
||||
echo " database: $DB_DEVELOPMENT" >> $DBFILE
|
||||
echo " pool: 50" >> $DBFILE
|
||||
echo " timeout: 5000" >> $DBFILE
|
||||
echo " encoding: utf8" >> $DBFILE
|
||||
echo " username: gitlab-runner" >> $DBFILE
|
||||
echo " password:" >> $DBFILE
|
||||
fi
|
||||
@@ -1,36 +0,0 @@
|
||||
#!/bin/bash
|
||||
RAILS_ENV=$1
|
||||
APP_PORT=$2
|
||||
WS_PORT=$3
|
||||
EXIT=$4 || 0
|
||||
WITH_DB=$5 || 0
|
||||
WITH_ELASTICSEARCH=$6 || 0
|
||||
|
||||
SERVER_PID='tmp/pids/server.pid'
|
||||
LOG_HOST='cilog@schneeberg.znuny.com'
|
||||
|
||||
bundle exec script/scheduler.rb stop
|
||||
bundle exec script/websocket-server.rb stop
|
||||
kill $(cat $SERVER_PID)
|
||||
|
||||
sleep 5
|
||||
if [ -f $SERVER_PID ]; then
|
||||
kill -9 $(cat $SERVER_PID)
|
||||
fi
|
||||
|
||||
if test $WITH_DB -eq 1; then
|
||||
script/build/test_cleanup.sh
|
||||
fi
|
||||
|
||||
if test $WITH_ELASTICSEARCH -eq 1; then
|
||||
rake searchindex:drop
|
||||
fi
|
||||
|
||||
# if build has failed, copy logs for analyzing
|
||||
if test $EXIT -eq 1; then
|
||||
ssh $LOG_HOST "mkdir -p logs/$CI_BUILD_ID"
|
||||
scp -C log/* $LOG_HOST:logs/$CI_BUILD_ID/
|
||||
scp -C tmp/screenshot* $LOG_HOST:logs/$CI_BUILD_ID/
|
||||
fi
|
||||
|
||||
exit $EXIT
|
||||
@@ -1,33 +0,0 @@
|
||||
#!/bin/bash
|
||||
RAILS_ENV=$1
|
||||
APP_PORT=$2
|
||||
WS_PORT=$3
|
||||
WITH_DB=$4 || 0
|
||||
WITH_ELASTICSEARCH=$5 || 0
|
||||
|
||||
if test $WITH_DB -eq 1; then
|
||||
script/bootstrap.sh
|
||||
fi
|
||||
|
||||
export ZAMMAD_SETTING_TTL=15
|
||||
|
||||
rails r "Setting.set('developer_mode', true)"
|
||||
rails r "Setting.set('websocket_port', '$WS_PORT')"
|
||||
rails r "Setting.set('fqdn', '$IP:$BROWSER_PORT')"
|
||||
rails r "Setting.set('chat_agent_idle_timeout', '45')"
|
||||
|
||||
if test $WITH_ELASTICSEARCH -eq 1; then
|
||||
rails r "Setting.set('es_url', 'http://localhost:9200')"
|
||||
rails r "Setting.set('es_index', 'browser_test_$CI_BUILD_ID')"
|
||||
rake searchindex:rebuild
|
||||
fi
|
||||
|
||||
echo "env used for script/build/test_startup.sh $1 $2 $3"
|
||||
echo "export RAILS_ENV=$RAILS_ENV"
|
||||
echo "export IP=$IP"
|
||||
echo "export BROWSER_PORT=$BROWSER_PORT"
|
||||
|
||||
#rails s puma -d --pid tmp/pids/server.pid --bind 0.0.0.0 --port $APP_PORT
|
||||
bundle exec puma --pidfile tmp/pids/server.pid -d -p $APP_PORT -e $RAILS_ENV
|
||||
bundle exec script/websocket-server.rb start -d -p $WS_PORT
|
||||
bundle exec script/scheduler.rb start
|
||||
@@ -0,0 +1,32 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Sequencer::Unit::Import::Zendesk::Ticket::Comment::Attachment::Request, sequencer: :unit do
|
||||
|
||||
context 'when fetching large attachements from Zendesk' do
|
||||
|
||||
before(:all) do
|
||||
|
||||
described_class.class_eval do
|
||||
|
||||
private
|
||||
|
||||
def failed?
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def mock_parameters
|
||||
{
|
||||
resource: double(
|
||||
content_url: ''
|
||||
)
|
||||
}
|
||||
end
|
||||
|
||||
it 'open timeout should be 20s and read timeout should be 240s' do
|
||||
expect(UserAgent).to receive(:get).with(any_args, { open_timeout: 20, read_timeout: 240 })
|
||||
process(mock_parameters)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -21,6 +21,7 @@ RSpec.describe ::Channel::Driver::Twitter do
|
||||
id: 'system_id',
|
||||
},
|
||||
sync: {
|
||||
import_older_tweets: true,
|
||||
track_retweets: true,
|
||||
search: [
|
||||
{
|
||||
|
||||
@@ -2,6 +2,17 @@ require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Api Auth', type: :request do
|
||||
|
||||
around(:each) do |example|
|
||||
orig = ActionController::Base.allow_forgery_protection
|
||||
|
||||
begin
|
||||
ActionController::Base.allow_forgery_protection = true
|
||||
example.run
|
||||
ensure
|
||||
ActionController::Base.allow_forgery_protection = orig
|
||||
end
|
||||
end
|
||||
|
||||
let(:admin_user) do
|
||||
create(:admin_user)
|
||||
end
|
||||
@@ -369,7 +380,10 @@ RSpec.describe 'Api Auth', type: :request do
|
||||
it 'does session auth - admin' do
|
||||
create(:admin_user, login: 'api-admin@example.com', password: 'adminpw')
|
||||
|
||||
post '/api/v1/signin', params: { username: 'api-admin@example.com', password: 'adminpw', fingerprint: '123456789' }
|
||||
get '/'
|
||||
token = response.headers['CSRF-TOKEN']
|
||||
|
||||
post '/api/v1/signin', params: { username: 'api-admin@example.com', password: 'adminpw', fingerprint: '123456789' }, headers: { 'X-CSRF-Token' => token }
|
||||
expect(response.header.key?('Access-Control-Allow-Origin')).to be_falsey
|
||||
expect(response).to have_http_status(201)
|
||||
|
||||
|
||||
@@ -452,6 +452,22 @@ RSpec.describe 'Organization', type: :request, searchindex: true do
|
||||
|
||||
end
|
||||
|
||||
it 'does organization history' do
|
||||
organization1 = create(
|
||||
:organization,
|
||||
name: 'some org',
|
||||
)
|
||||
|
||||
authenticated_as(agent_user)
|
||||
get "/api/v1/organizations/history/#{organization1.id}", params: {}, as: :json
|
||||
expect(response).to have_http_status(200)
|
||||
expect(json_response).to be_a_kind_of(Hash)
|
||||
expect(json_response['history'].class).to eq(Array)
|
||||
expect(json_response['assets'].class).to eq(Hash)
|
||||
expect(json_response['assets']['Ticket']).to be_nil
|
||||
expect(json_response['assets']['Organization'][organization1.id.to_s]).not_to be_nil
|
||||
end
|
||||
|
||||
it 'does csv example - customer no access' do
|
||||
authenticated_as(customer_user)
|
||||
get '/api/v1/organizations/import_example', params: {}, as: :json
|
||||
|
||||
@@ -2078,6 +2078,30 @@ RSpec.describe 'Ticket', type: :request do
|
||||
expect(json_response).to be_a_kind_of(Hash)
|
||||
expect(json_response['tickets']).to eq([ticket2.id, ticket1.id])
|
||||
end
|
||||
|
||||
it 'does ticket history ' do
|
||||
ticket1 = create(
|
||||
:ticket,
|
||||
title: 'some title',
|
||||
group: ticket_group,
|
||||
customer_id: customer_user.id,
|
||||
)
|
||||
create(
|
||||
:ticket_article,
|
||||
type: Ticket::Article::Type.lookup(name: 'note'),
|
||||
sender: Ticket::Article::Sender.lookup(name: 'Customer'),
|
||||
ticket_id: ticket1.id,
|
||||
)
|
||||
|
||||
authenticated_as(agent_user)
|
||||
get "/api/v1/ticket_history/#{ticket1.id}", params: {}, as: :json
|
||||
expect(response).to have_http_status(200)
|
||||
expect(json_response).to be_a_kind_of(Hash)
|
||||
expect(json_response['history'].class).to eq(Array)
|
||||
expect(json_response['assets'].class).to eq(Hash)
|
||||
expect(json_response['assets']['User'][customer_user.id.to_s]).not_to be_nil
|
||||
expect(json_response['assets']['Ticket'][ticket1.id.to_s]).not_to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe 'stats' do
|
||||
|
||||
@@ -39,5 +39,27 @@ RSpec.describe 'Time Accounting API endpoints', type: :request do
|
||||
expect(response['Content-Type']).to eq('application/vnd.ms-excel')
|
||||
end
|
||||
end
|
||||
|
||||
# Regression test for issue #2398 - Missing custom object in database causes error on export in time_accounting
|
||||
# This test is identical to the above one, except with the added step of a pending migration in the beginning
|
||||
context 'with pending attribute migrations, requesting a log report download' do
|
||||
it 'responds with an Excel spreadsheet' do
|
||||
ObjectManager::Attribute.add attributes_for :object_manager_attribute_select
|
||||
|
||||
group = create(:group)
|
||||
ticket = create(:ticket, state: Ticket::State.lookup(name: 'open'), customer: customer )
|
||||
article = create(:ticket_article, ticket: ticket, type: Ticket::Article::Type.lookup(name: 'note') )
|
||||
|
||||
create(:ticket_time_accounting, ticket_id: ticket.id, ticket_article_id: article.id)
|
||||
|
||||
authenticated_as(admin)
|
||||
get "/api/v1/time_accounting/log/by_ticket/#{year}/#{month}?download=true", params: {}
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(response['Content-Disposition']).to be_truthy
|
||||
expect(response['Content-Disposition']).to eq("attachment; filename=\"by_ticket-#{year}-#{month}.xls\"")
|
||||
expect(response['Content-Type']).to eq('application/vnd.ms-excel')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -919,6 +919,25 @@ RSpec.describe 'User', type: :request, searchindex: true do
|
||||
user2.destroy!
|
||||
end
|
||||
|
||||
it 'does user history' do
|
||||
user1 = create(
|
||||
:customer_user,
|
||||
login: 'history@example.com',
|
||||
firstname: 'History',
|
||||
lastname: 'Customer1',
|
||||
email: 'history@example.com',
|
||||
)
|
||||
|
||||
authenticated_as(agent_user)
|
||||
get "/api/v1/users/history/#{user1.id}", params: {}, as: :json
|
||||
expect(response).to have_http_status(200)
|
||||
expect(json_response).to be_a_kind_of(Hash)
|
||||
expect(json_response['history'].class).to eq(Array)
|
||||
expect(json_response['assets'].class).to eq(Hash)
|
||||
expect(json_response['assets']['Ticket']).to be_nil
|
||||
expect(json_response['assets']['User'][user1.id.to_s]).not_to be_nil
|
||||
end
|
||||
|
||||
it 'does user search sortable' do
|
||||
firstname = "user_search_sortable #{rand(999_999_999)}"
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ VCR.configure do |config|
|
||||
config.ignore_request do |request|
|
||||
uri = URI(request.uri)
|
||||
|
||||
['zammad.com', 'google.com'].any? do |site|
|
||||
['zammad.com', 'google.com', 'elasticsearch', 'selenium'].any? do |site|
|
||||
uri.host.include?(site)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -98,13 +98,7 @@ class AdminChannelEmailTest < TestCase
|
||||
value: 'Users',
|
||||
)
|
||||
click(css: '.modal button.js-submit')
|
||||
sleep 2
|
||||
|
||||
watch_for_disappear(
|
||||
css: '.modal',
|
||||
)
|
||||
sleep 2
|
||||
exists_not(css: '.modal')
|
||||
modal_disappear(timeout: 20)
|
||||
|
||||
watch_for(
|
||||
css: '.content.active',
|
||||
|
||||
@@ -11,7 +11,7 @@ class AdminPermissionsGranularVsFullTest < TestCase
|
||||
)
|
||||
tasks_close_all()
|
||||
|
||||
click(css: '.user-menu a[title=Admin')
|
||||
click(css: 'a[href="#manage"]')
|
||||
click(css: '.content.active a[href="#manage/groups"]')
|
||||
click(css: '.content.active a[data-type="new"]')
|
||||
|
||||
@@ -21,26 +21,34 @@ class AdminPermissionsGranularVsFullTest < TestCase
|
||||
element.clear
|
||||
element.send_keys(new_group_name)
|
||||
click(css: '.modal button.js-submit')
|
||||
|
||||
sleep(1)
|
||||
modal_disappear
|
||||
|
||||
click(css: '.content.active a[href="#manage/users"]')
|
||||
|
||||
user_css = '.user-list .js-tableBody tr td'
|
||||
watch_for(css: user_css)
|
||||
click(css: user_css)
|
||||
@browser.find_elements(css: '.content.active .user-list td:first-child').each do |entry|
|
||||
next if entry.text.strip != 'master@example.com'
|
||||
|
||||
entry.click
|
||||
break
|
||||
end
|
||||
|
||||
modal_ready
|
||||
|
||||
scroll_script = "var el = document.getElementsByClassName('modal')[0];"
|
||||
scroll_script += 'el.scrollTo(0, el.scrollHeight);'
|
||||
|
||||
@browser.execute_script scroll_script
|
||||
|
||||
group = @browser.find_elements(css: '.modal .settings-list tbody tr').find do |el|
|
||||
el.find_element(css: 'td').text == new_group_name
|
||||
end
|
||||
|
||||
if !group
|
||||
screenshot(comment: 'group_not_found')
|
||||
raise "Can't find group #{new_group_name}"
|
||||
end
|
||||
|
||||
toggle_checkbox(group, 'full')
|
||||
sleep(1)
|
||||
assert(checkbox_is_selected(group, 'full'))
|
||||
|
||||
@@ -129,4 +129,76 @@ class AgentTicketEmailReplyKeepBodyTest < TestCase
|
||||
assert match[1]
|
||||
assert Time.zone.parse(match[1])
|
||||
end
|
||||
|
||||
# Regression test for issue #2344 - Missing translation for Full-Quote-Text "on xy wrote"
|
||||
def test_full_quote_german_locale
|
||||
@browser = instance = browser_instance
|
||||
login(
|
||||
username: 'master@example.com',
|
||||
password: 'test',
|
||||
url: browser_url,
|
||||
)
|
||||
tasks_close_all()
|
||||
|
||||
ticket_open_by_title(
|
||||
title: 'Welcome to Zammad',
|
||||
)
|
||||
watch_for(
|
||||
css: '.content.active .js-settingContainer .js-setting .dropdown-icon',
|
||||
)
|
||||
|
||||
# enable email full quote in the ticket zoom config page
|
||||
scroll_to(
|
||||
position: 'botton',
|
||||
css: '.content.active .js-settingContainer .js-setting .dropdown-icon',
|
||||
)
|
||||
click(css: '.content.active .js-settingContainer .js-setting .dropdown-icon')
|
||||
modal_ready()
|
||||
select(
|
||||
css: '.modal #ui_ticket_zoom_article_email_full_quote select[name="ui_ticket_zoom_article_email_full_quote"]',
|
||||
value: 'yes'
|
||||
)
|
||||
click(
|
||||
css: '.modal #ui_ticket_zoom_article_email_full_quote .btn[type="submit"]',
|
||||
)
|
||||
modal_close()
|
||||
modal_disappear()
|
||||
|
||||
exists(css: '.content.active .ticket-article [data-type="emailReply"]')
|
||||
|
||||
# switch user profile language to German
|
||||
switch_language(
|
||||
data: {
|
||||
language: 'Deutsch'
|
||||
},
|
||||
)
|
||||
|
||||
ticket_open_by_title(
|
||||
title: 'Welcome to Zammad',
|
||||
)
|
||||
|
||||
scroll_to(
|
||||
position: 'botton',
|
||||
css: '.content.active .ticket-article [data-type="emailReply"]',
|
||||
)
|
||||
click(css: '.content.active .ticket-article [data-type="emailReply"]')
|
||||
|
||||
full_text = @browser.find_element(css: '.content.active .article-new .articleNewEdit-body').text
|
||||
|
||||
match = full_text.match(/\nAm (.*?), schrieb Nicole Braun:/)
|
||||
assert match
|
||||
|
||||
datestamp = match[1]
|
||||
assert datestamp
|
||||
assert Time.zone.parse(datestamp)
|
||||
day_of_week = datestamp.split(',').first
|
||||
assert %w[Montag Dienstag Mittwoch Donnerstag Freitag Samstag Sonntag].include? day_of_week
|
||||
|
||||
# switch user profile language to English again for other tests
|
||||
switch_language(
|
||||
data: {
|
||||
language: 'English (United States)'
|
||||
},
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -103,6 +103,9 @@ class AgentTicketTagTest < TestCase
|
||||
browser: browser2,
|
||||
number: ticket3[:number],
|
||||
)
|
||||
empty_search(
|
||||
browser: browser2,
|
||||
)
|
||||
|
||||
# set tag #1
|
||||
click(
|
||||
@@ -272,6 +275,9 @@ class AgentTicketTagTest < TestCase
|
||||
browser: browser2,
|
||||
number: ticket3[:number],
|
||||
)
|
||||
empty_search(
|
||||
browser: browser2,
|
||||
)
|
||||
|
||||
# verify tags
|
||||
tags_verify(
|
||||
@@ -353,7 +359,7 @@ class AgentTicketTagTest < TestCase
|
||||
end
|
||||
|
||||
def test_b_tags
|
||||
tag_prefix = "tag#{rand(999_999_999)}"
|
||||
tag_prefix = "tag#{rand(1000)}"
|
||||
|
||||
@browser = browser_instance
|
||||
login(
|
||||
|
||||
@@ -63,6 +63,7 @@ class MaintenanceLoginMessageTest < TestCase
|
||||
watch_for_disappear(
|
||||
browser: browser2,
|
||||
css: '.js-maintenanceLogin',
|
||||
timeout: 30,
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
@@ -46,7 +46,15 @@ class TestCase < Test::Unit::TestCase
|
||||
end
|
||||
|
||||
def browser_url
|
||||
ENV['BROWSER_URL'] || 'http://localhost:3000'
|
||||
return ENV['BROWSER_URL'] if ENV['BROWSER_URL'].present?
|
||||
|
||||
"http://#{host}:3000"
|
||||
end
|
||||
|
||||
def host
|
||||
return 'localhost' if ENV['CI'].blank?
|
||||
|
||||
Socket.ip_address_list.detect(&:ipv4_private?).ip_address
|
||||
end
|
||||
|
||||
def browser_instance
|
||||
@@ -75,10 +83,10 @@ class TestCase < Test::Unit::TestCase
|
||||
begin
|
||||
local_browser = browser_instance_remote
|
||||
break
|
||||
rescue
|
||||
rescue => e
|
||||
wait_until_ready = rand(5..13)
|
||||
log('browser_instance', { rescure: true, count: count, sleep: wait_until_ready, exception: e })
|
||||
sleep wait_until_ready
|
||||
log('browser_instance', { rescure: true, count: count, sleep: wait_until_ready })
|
||||
end
|
||||
end
|
||||
|
||||
@@ -93,10 +101,22 @@ class TestCase < Test::Unit::TestCase
|
||||
if ENV['BROWSER_VERSION']
|
||||
caps.version = ENV['BROWSER_VERSION']
|
||||
end
|
||||
|
||||
# (ironically) required for timeout checks
|
||||
# https://github.com/zalando/zalenium/issues/469#issuecomment-371417340
|
||||
# https://opensource.zalando.com/zalenium/#usage
|
||||
caps['idleTimeout'] = 300
|
||||
|
||||
http_client = Selenium::WebDriver::Remote::Http::Default.new(
|
||||
open_timeout: 120,
|
||||
read_timeout: 120
|
||||
)
|
||||
|
||||
local_browser = Selenium::WebDriver.for(
|
||||
:remote,
|
||||
url: ENV['REMOTE_URL'],
|
||||
desired_capabilities: caps,
|
||||
http_client: http_client,
|
||||
)
|
||||
@browsers[local_browser.hash] = local_browser
|
||||
browser_instance_preferences(local_browser)
|
||||
@@ -2647,18 +2667,9 @@ wait untill text in selector disabppears
|
||||
element.send_keys(params[:number])
|
||||
sleep 3
|
||||
|
||||
empty_search(browser: instance)
|
||||
|
||||
# search by number again
|
||||
element = instance.find_elements(css: '#global-search')[0]
|
||||
element.click
|
||||
element.clear
|
||||
element.send_keys(params[:number])
|
||||
sleep 1
|
||||
|
||||
# open ticket
|
||||
#instance.find_element(partial_link_text: params[:number] } ).click
|
||||
instance.execute_script("$(\".js-global-search-result a:contains('#{params[:number]}') .nav-tab-icon\").first().click()")
|
||||
instance.execute_script("$(\".js-global-search-result a:contains('#{params[:number]}') .nav-tab-name\").first().click()")
|
||||
watch_for(
|
||||
browser: instance,
|
||||
css: '.content.active .ticketZoom-header .ticket-number'
|
||||
@@ -2695,7 +2706,7 @@ wait untill text in selector disabppears
|
||||
|
||||
# open ticket
|
||||
#instance.find_element(partial_link_text: params[:title] } ).click
|
||||
instance.execute_script("$(\".js-global-search-result a:contains('#{params[:title]}') .nav-tab-icon\").click()")
|
||||
instance.execute_script("$(\".js-global-search-result a:contains('#{params[:title]}') .nav-tab-name\").first().click()")
|
||||
sleep 1
|
||||
title = instance.find_elements(css: '.content.active .ticketZoom-header .js-objectTitle')[0].text
|
||||
if !title.match?(/#{params[:title]}/)
|
||||
@@ -2782,7 +2793,7 @@ wait untill text in selector disabppears
|
||||
element.send_keys(params[:value])
|
||||
sleep 2
|
||||
#instance.find_element(partial_link_text: params[:value] } ).click
|
||||
instance.execute_script("$(\".js-global-search-result a:contains('#{params[:value]}') .nav-tab-icon\").click()")
|
||||
instance.execute_script("$(\".js-global-search-result a:contains('#{params[:value]}') .nav-tab-name\").first().click()")
|
||||
watch_for(
|
||||
browser: instance,
|
||||
css: '.content.active h1'
|
||||
@@ -2818,7 +2829,7 @@ wait untill text in selector disabppears
|
||||
sleep 3
|
||||
|
||||
#instance.find_element(partial_link_text: params[:value]).click
|
||||
instance.execute_script("$(\".js-global-search-result a:contains('#{params[:value]}') .nav-tab-icon\").click()")
|
||||
instance.execute_script("$(\".js-global-search-result a:contains('#{params[:value]}') .nav-tab-name\").first().click()")
|
||||
watch_for(
|
||||
browser: instance,
|
||||
css: '.content.active h1'
|
||||
@@ -4440,6 +4451,55 @@ wait untill text in selector disabppears
|
||||
scope.find_element(css: "input[value=#{value}]").property('checked')
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
Switch the current logged in user's profile language to a new language
|
||||
|
||||
switch_language(
|
||||
browser: browser2,
|
||||
data: {
|
||||
language: 'Deutsch'
|
||||
},
|
||||
)
|
||||
|
||||
IMPORTANT REMINDER! At the end of tests, the caller must manually set the language back to English again:
|
||||
|
||||
switch_language(
|
||||
browser: browser2,
|
||||
data: {
|
||||
language: 'English (United States)'
|
||||
},
|
||||
)
|
||||
|
||||
Failure to switch back to English will cause large amounts of subsequent tests to fail due to the UI language differences.
|
||||
|
||||
=end
|
||||
|
||||
def switch_language(params = {})
|
||||
switch_window_focus(params)
|
||||
log('switch_language', params)
|
||||
|
||||
instance = params[:browser] || @browser
|
||||
data = params[:data]
|
||||
|
||||
click(browser: instance, css: '#navigation .user-menu .js-avatar')
|
||||
|
||||
click(browser: instance, css: '#navigation .user-menu a[href="#profile"]')
|
||||
|
||||
select(
|
||||
browser: instance,
|
||||
css: '.content.active .searchableSelect-shadow',
|
||||
value: data[:language],
|
||||
)
|
||||
|
||||
click(browser: instance, css: '.content.active .btn--primary')
|
||||
|
||||
watch_for(
|
||||
browser: instance,
|
||||
css: '#notify',
|
||||
)
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
Retrieve a hash of all the avaiable Zammad settings and their current values.
|
||||
|
||||
@@ -75,7 +75,7 @@ class IdoitControllerTest < ActionDispatch::IntegrationTest
|
||||
assert_equal('Not authorized (user)!', result['error'])
|
||||
|
||||
stub_request(:post, "#{@endpoint}src/jsonrpc.php")
|
||||
.with(body: "{\"method\":\"cmdb.object_types\",\"params\":{\"apikey\":\"#{@token}\"},\"version\":\"2.0\"}")
|
||||
.with(body: "{\"method\":\"cmdb.object_types\",\"params\":{\"apikey\":\"#{@token}\"},\"version\":\"2.0\",\"id\":42}")
|
||||
.to_return(status: 200, body: read_messaage('object_types_response'), headers: {})
|
||||
|
||||
admin_credentials = ActionController::HttpAuthentication::Basic.encode_credentials('idoit-admin@example.com', 'adminpw')
|
||||
@@ -114,7 +114,7 @@ class IdoitControllerTest < ActionDispatch::IntegrationTest
|
||||
test 'list all object types' do
|
||||
|
||||
stub_request(:post, "#{@endpoint}src/jsonrpc.php")
|
||||
.with(body: "{\"method\":\"cmdb.object_types\",\"params\":{\"apikey\":\"#{@token}\"},\"version\":\"2.0\"}")
|
||||
.with(body: "{\"method\":\"cmdb.object_types\",\"params\":{\"apikey\":\"#{@token}\"},\"version\":\"2.0\",\"id\":42}")
|
||||
.to_return(status: 200, body: read_messaage('object_types_response'), headers: {})
|
||||
|
||||
agent_credentials = ActionController::HttpAuthentication::Basic.encode_credentials('idoit-agent@example.com', 'agentpw')
|
||||
@@ -156,7 +156,7 @@ class IdoitControllerTest < ActionDispatch::IntegrationTest
|
||||
test 'query objects' do
|
||||
|
||||
stub_request(:post, "#{@endpoint}src/jsonrpc.php")
|
||||
.with(body: "{\"method\":\"cmdb.objects\",\"params\":{\"apikey\":\"#{@token}\",\"filter\":{\"ids\":[\"33\"]}},\"version\":\"2.0\"}")
|
||||
.with(body: "{\"method\":\"cmdb.objects\",\"params\":{\"apikey\":\"#{@token}\",\"filter\":{\"ids\":[\"33\"]}},\"version\":\"2.0\",\"id\":42}")
|
||||
.to_return(status: 200, body: read_messaage('object_types_filter_response'), headers: {})
|
||||
|
||||
agent_credentials = ActionController::HttpAuthentication::Basic.encode_credentials('idoit-agent@example.com', 'agentpw')
|
||||
|
||||
@@ -107,6 +107,45 @@ Some Textäöü",
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
data: "Sender: me_sender@example.com
|
||||
To: customer@example.com
|
||||
Subject: äöü some subject 3
|
||||
|
||||
Some Textäöü",
|
||||
channel: {
|
||||
trusted: false,
|
||||
},
|
||||
success: true,
|
||||
result: {
|
||||
0 => {
|
||||
priority: '2 normal',
|
||||
title: 'äöü some subject 3',
|
||||
},
|
||||
1 => {
|
||||
body: 'Some Textäöü',
|
||||
sender: 'Customer',
|
||||
type: 'email',
|
||||
internal: false,
|
||||
},
|
||||
},
|
||||
verify: {
|
||||
users: [
|
||||
{
|
||||
firstname: '',
|
||||
lastname: '',
|
||||
fullname: 'me@example.com',
|
||||
email: 'me@example.com',
|
||||
},
|
||||
{
|
||||
firstname: '',
|
||||
lastname: '',
|
||||
fullname: 'customer@example.com',
|
||||
email: 'customer@example.com',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
data: "From: me@example.com
|
||||
To: customer@example.com
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
require 'test_helper'
|
||||
|
||||
class HistoryTest < ActiveSupport::TestCase
|
||||
current_user = User.lookup(email: 'nicole.braun@zammad.org')
|
||||
|
||||
test 'ticket' do
|
||||
current_user = User.lookup(email: 'nicole.braun@zammad.org')
|
||||
tests = [
|
||||
|
||||
# test 1
|
||||
@@ -188,6 +188,7 @@ class HistoryTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
test 'user' do
|
||||
current_user = User.lookup(email: 'nicole.braun@zammad.org')
|
||||
name = rand(999_999)
|
||||
tests = [
|
||||
|
||||
@@ -275,6 +276,7 @@ class HistoryTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
test 'organization' do
|
||||
current_user = User.lookup(email: 'nicole.braun@zammad.org')
|
||||
tests = [
|
||||
|
||||
# test 1
|
||||
@@ -337,6 +339,57 @@ class HistoryTest < ActiveSupport::TestCase
|
||||
organizations.each(&:destroy!)
|
||||
end
|
||||
|
||||
test 'ticket assets' do
|
||||
UserInfo.current_user_id = 1
|
||||
agent1 = User.create!(
|
||||
login: 'agent1@example.com',
|
||||
firstname: 'agent',
|
||||
lastname: '1',
|
||||
email: 'agent1@example.com',
|
||||
password: 'agentpw',
|
||||
active: true,
|
||||
roles: Role.where(name: %w[Agent Admin]),
|
||||
groups: Group.all,
|
||||
)
|
||||
current_user = User.lookup(email: 'nicole.braun@zammad.org')
|
||||
UserInfo.current_user_id = current_user.id
|
||||
|
||||
ticket = Ticket.create!(
|
||||
title: 'test 1',
|
||||
group: Group.first,
|
||||
customer_id: current_user.id,
|
||||
state: Ticket::State.lookup(name: 'new'),
|
||||
priority: Ticket::Priority.lookup(name: '2 normal'),
|
||||
)
|
||||
article = Ticket::Article.create!(
|
||||
ticket_id: ticket.id,
|
||||
from: 'some_customer_com-1@example.com',
|
||||
to: 'some_zammad_com-1@example.com',
|
||||
subject: 'com test 1',
|
||||
message_id: 'some@id_com_1',
|
||||
body: 'some message 123',
|
||||
internal: false,
|
||||
sender: Ticket::Article::Sender.find_by(name: 'Customer'),
|
||||
type: Ticket::Article::Type.find_by(name: 'email'),
|
||||
)
|
||||
|
||||
# verify if user of history record is in assets
|
||||
UserInfo.current_user_id = agent1.id
|
||||
ticket.state = Ticket::State.find_by(name: 'closed')
|
||||
ticket.save!
|
||||
|
||||
# update updated_by (to not include agent1 in assets by ticket)
|
||||
UserInfo.current_user_id = current_user.id
|
||||
ticket.priority = Ticket::Priority.find_by(name: '3 high')
|
||||
ticket.save!
|
||||
|
||||
history = ticket.history_get(true)
|
||||
assert(history[:assets][:User][current_user.id])
|
||||
assert(history[:assets][:User][agent1.id])
|
||||
assert(history[:assets][:Ticket][ticket.id])
|
||||
assert(history[:assets][:TicketArticle][article.id])
|
||||
end
|
||||
|
||||
def history_check(history_list, history_check)
|
||||
history_check.each do |check_item|
|
||||
match = false
|
||||
|
||||
@@ -8,32 +8,32 @@ class NotificationFactoryMailerTemplateTest < ActiveSupport::TestCase
|
||||
|
||||
groups = Group.where(name: 'Users')
|
||||
roles = Role.where(name: 'Agent')
|
||||
agent1 = User.create_or_update(
|
||||
login: 'notification-template-agent1@example.com',
|
||||
firstname: 'Notification<b>xxx</b>',
|
||||
lastname: 'Agent1<b>yyy</b>',
|
||||
email: 'notification-template-agent1@example.com',
|
||||
password: 'agentpw',
|
||||
active: true,
|
||||
roles: roles,
|
||||
groups: groups,
|
||||
preferences: {
|
||||
agent1 = User.create!(
|
||||
login: 'notification-template-agent1@example.com',
|
||||
firstname: 'Notification<b>xxx</b>',
|
||||
lastname: 'Agent1<b>yyy</b>',
|
||||
email: 'notification-template-agent1@example.com',
|
||||
password: 'agentpw',
|
||||
active: true,
|
||||
roles: roles,
|
||||
groups: groups,
|
||||
preferences: {
|
||||
locale: 'de-de',
|
||||
},
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
|
||||
agent_current_user = User.create_or_update(
|
||||
login: 'notification-template-current_user@example.com',
|
||||
firstname: 'Notification Current',
|
||||
lastname: 'User',
|
||||
email: 'notification-template-current_user@example.com',
|
||||
password: 'agentpw',
|
||||
active: true,
|
||||
roles: roles,
|
||||
groups: groups,
|
||||
preferences: {
|
||||
agent_current_user = User.create!(
|
||||
login: 'notification-template-current_user@example.com',
|
||||
firstname: 'Notification Current',
|
||||
lastname: 'User',
|
||||
email: 'notification-template-current_user@example.com',
|
||||
password: 'agentpw',
|
||||
active: true,
|
||||
roles: roles,
|
||||
groups: groups,
|
||||
preferences: {
|
||||
locale: 'de-de',
|
||||
},
|
||||
updated_by_id: 1,
|
||||
|
||||
@@ -83,34 +83,34 @@ class NotificationFactoryMailerTest < ActiveSupport::TestCase
|
||||
|
||||
groups = Group.all
|
||||
roles = Role.where(name: 'Agent')
|
||||
agent1 = User.create_or_update(
|
||||
login: 'notification-settings-agent1@example.com',
|
||||
firstname: 'Notification<b>xxx</b>',
|
||||
lastname: 'Agent1',
|
||||
email: 'notification-settings-agent1@example.com',
|
||||
password: 'agentpw',
|
||||
active: true,
|
||||
roles: roles,
|
||||
groups: groups,
|
||||
agent1 = User.create!(
|
||||
login: 'notification-settings-agent1@example.com',
|
||||
firstname: 'Notification<b>xxx</b>',
|
||||
lastname: 'Agent1',
|
||||
email: 'notification-settings-agent1@example.com',
|
||||
password: 'agentpw',
|
||||
active: true,
|
||||
roles: roles,
|
||||
groups: groups,
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
|
||||
agent2 = User.create_or_update(
|
||||
login: 'notification-settings-agent2@example.com',
|
||||
firstname: 'Notification<b>xxx</b>',
|
||||
lastname: 'Agent2',
|
||||
email: 'notification-settings-agent2@example.com',
|
||||
password: 'agentpw',
|
||||
active: true,
|
||||
roles: roles,
|
||||
groups: groups,
|
||||
agent2 = User.create!(
|
||||
login: 'notification-settings-agent2@example.com',
|
||||
firstname: 'Notification<b>xxx</b>',
|
||||
lastname: 'Agent2',
|
||||
email: 'notification-settings-agent2@example.com',
|
||||
password: 'agentpw',
|
||||
active: true,
|
||||
roles: roles,
|
||||
groups: groups,
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
|
||||
group_notification_setting = Group.create_or_update(
|
||||
name: 'NotificationSetting',
|
||||
group_notification_setting = Group.create!(
|
||||
name: 'NotificationSetting',
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
|
||||
@@ -538,10 +538,22 @@ class OnlineNotificationTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
test 'cleanup check' do
|
||||
|
||||
ticket1 = Ticket.create(
|
||||
group: @group,
|
||||
customer_id: @customer_user.id,
|
||||
owner_id: User.lookup(login: '-').id,
|
||||
title: 'Unit Test 1 (äöüß)!',
|
||||
state_id: Ticket::State.lookup(name: 'closed').id,
|
||||
priority_id: Ticket::Priority.lookup(name: '2 normal').id,
|
||||
updated_by_id: @agent_user1.id,
|
||||
created_by_id: @agent_user1.id,
|
||||
)
|
||||
|
||||
online_notification1 = OnlineNotification.add(
|
||||
type: 'create',
|
||||
object: 'Ticket',
|
||||
o_id: 123,
|
||||
o_id: ticket1.id,
|
||||
seen: false,
|
||||
user_id: @agent_user1.id,
|
||||
created_by_id: 1,
|
||||
@@ -552,7 +564,7 @@ class OnlineNotificationTest < ActiveSupport::TestCase
|
||||
online_notification2 = OnlineNotification.add(
|
||||
type: 'create',
|
||||
object: 'Ticket',
|
||||
o_id: 123,
|
||||
o_id: ticket1.id,
|
||||
seen: true,
|
||||
user_id: @agent_user1.id,
|
||||
created_by_id: 1,
|
||||
@@ -563,7 +575,7 @@ class OnlineNotificationTest < ActiveSupport::TestCase
|
||||
online_notification3 = OnlineNotification.add(
|
||||
type: 'create',
|
||||
object: 'Ticket',
|
||||
o_id: 123,
|
||||
o_id: ticket1.id,
|
||||
seen: false,
|
||||
user_id: @agent_user1.id,
|
||||
created_by_id: 1,
|
||||
@@ -574,7 +586,7 @@ class OnlineNotificationTest < ActiveSupport::TestCase
|
||||
online_notification4 = OnlineNotification.add(
|
||||
type: 'create',
|
||||
object: 'Ticket',
|
||||
o_id: 123,
|
||||
o_id: ticket1.id,
|
||||
seen: true,
|
||||
user_id: @agent_user1.id,
|
||||
created_by_id: @agent_user1.id,
|
||||
@@ -585,7 +597,7 @@ class OnlineNotificationTest < ActiveSupport::TestCase
|
||||
online_notification5 = OnlineNotification.add(
|
||||
type: 'create',
|
||||
object: 'Ticket',
|
||||
o_id: 123,
|
||||
o_id: ticket1.id,
|
||||
seen: true,
|
||||
user_id: @agent_user1.id,
|
||||
created_by_id: @agent_user2.id,
|
||||
@@ -596,7 +608,7 @@ class OnlineNotificationTest < ActiveSupport::TestCase
|
||||
online_notification6 = OnlineNotification.add(
|
||||
type: 'create',
|
||||
object: 'Ticket',
|
||||
o_id: 123,
|
||||
o_id: ticket1.id,
|
||||
seen: true,
|
||||
user_id: @agent_user1.id,
|
||||
created_by_id: @agent_user1.id,
|
||||
@@ -607,7 +619,7 @@ class OnlineNotificationTest < ActiveSupport::TestCase
|
||||
online_notification7 = OnlineNotification.add(
|
||||
type: 'create',
|
||||
object: 'Ticket',
|
||||
o_id: 123,
|
||||
o_id: ticket1.id,
|
||||
seen: true,
|
||||
user_id: @agent_user1.id,
|
||||
created_by_id: @agent_user2.id,
|
||||
@@ -628,4 +640,32 @@ class OnlineNotificationTest < ActiveSupport::TestCase
|
||||
OnlineNotification.destroy_all
|
||||
end
|
||||
|
||||
test 'not existing object ref' do
|
||||
assert_raises(RuntimeError) do
|
||||
OnlineNotification.add(
|
||||
type: 'create',
|
||||
object: 'TicketNotExisting',
|
||||
o_id: 123,
|
||||
seen: false,
|
||||
user_id: @agent_user1.id,
|
||||
created_by_id: 1,
|
||||
updated_by_id: 1,
|
||||
created_at: Time.zone.now - 10.months,
|
||||
updated_at: Time.zone.now - 10.months,
|
||||
)
|
||||
end
|
||||
assert_raises(ActiveRecord::RecordNotFound) do
|
||||
OnlineNotification.add(
|
||||
type: 'create',
|
||||
object: 'Ticket',
|
||||
o_id: 123,
|
||||
seen: false,
|
||||
user_id: @agent_user1.id,
|
||||
created_by_id: 1,
|
||||
updated_by_id: 1,
|
||||
created_at: Time.zone.now - 10.months,
|
||||
updated_at: Time.zone.now - 10.months,
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user