Compare commits
100 Commits
develop
...
stable-5.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
315231a13f | ||
|
|
d074a0f4ba | ||
|
|
b4371d8cd2 | ||
|
|
6c9a7f63c6 | ||
|
|
7970365324 | ||
|
|
77cb782c15 | ||
|
|
4e46055a5f | ||
|
|
16d7d92e05 | ||
|
|
32d8f2134b | ||
|
|
87e34244ea | ||
|
|
9554bea47e | ||
|
|
484a9612f0 | ||
|
|
641e30a83d | ||
|
|
6c798a44f7 | ||
|
|
31bb4528f8 | ||
|
|
abd77d8ef3 | ||
|
|
26ede5ac81 | ||
|
|
bac4630642 | ||
|
|
b1f09d0bb9 | ||
|
|
bc57522b16 | ||
|
|
2499951c9b | ||
|
|
a086426c62 | ||
|
|
5ab2a47f16 | ||
|
|
efe3734b03 | ||
|
|
974963ae73 | ||
|
|
b5a8419ed6 | ||
|
|
0a95b233ee | ||
|
|
2a1f5a6017 | ||
|
|
be48ff8983 | ||
|
|
d4dddcd02f | ||
|
|
7a4b59260e | ||
|
|
b713f6c239 | ||
|
|
1730fd6975 | ||
|
|
c6b4e01c67 | ||
|
|
9365e0b8c4 | ||
|
|
be633550d1 | ||
|
|
7739671083 | ||
|
|
43f0c68be3 | ||
|
|
5a04c99daf | ||
|
|
643aba6ba4 | ||
|
|
e007a1b2f6 | ||
|
|
8a6d537fa4 | ||
|
|
66e352353d | ||
|
|
e1cc346bd5 | ||
|
|
d32793df5a | ||
|
|
cc56ac9d6b | ||
|
|
250409bba3 | ||
|
|
0890075286 | ||
|
|
c296586b3c | ||
|
|
851923a521 | ||
|
|
55dcec124b | ||
|
|
977e051711 | ||
|
|
d43de943f9 | ||
|
|
ff3cdefe75 | ||
|
|
eb1b06553b | ||
|
|
de558484d9 | ||
|
|
f81f424d1c | ||
|
|
76c35debac | ||
|
|
4658f66128 | ||
|
|
1ca664c4ce | ||
|
|
8b8dd950c6 | ||
|
|
fed4961ee6 | ||
|
|
55747df058 | ||
|
|
e4ea402c80 | ||
|
|
157ee553d9 | ||
|
|
9751abba5d | ||
|
|
9c5ddd7df0 | ||
|
|
72d0b369b4 | ||
|
|
86ee652728 | ||
|
|
3caa400407 | ||
|
|
90fef43ec6 | ||
|
|
2fb8d15c59 | ||
|
|
e2cdf130d7 | ||
|
|
450bf629cb | ||
|
|
942f9a561e | ||
|
|
6d0887658e | ||
|
|
f7f668628d | ||
|
|
e62a5b28a8 | ||
|
|
fb8a1f2c13 | ||
|
|
a5ddd88417 | ||
|
|
caad8d0b00 | ||
|
|
e3688a2e74 | ||
|
|
769dbf3f07 | ||
|
|
7cb6020345 | ||
|
|
a20295dc48 | ||
|
|
acee82255f | ||
|
|
0f1a3375ec | ||
|
|
6e2b74ff5c | ||
|
|
8cf501bd74 | ||
|
|
11c3cd4f13 | ||
|
|
49605b87f5 | ||
|
|
7416b4c539 | ||
|
|
4a1c36f51e | ||
|
|
0c5284ba01 | ||
|
|
8a09511ae1 | ||
|
|
38c232c3af | ||
|
|
0951e05943 | ||
|
|
8d706a0b0f | ||
|
|
7e73bd7891 | ||
|
|
7f28bf522c |
19
.github/workflows/docker-release.yaml
vendored
19
.github/workflows/docker-release.yaml
vendored
@@ -30,6 +30,20 @@ jobs:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Login to Quay.io
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: quay.io
|
||||
username: ${{ secrets.QUAY_USERNAME }}
|
||||
password: ${{ secrets.QUAY_ROBOT_TOKEN }}
|
||||
|
||||
- name: Get version tag in the old way
|
||||
run: echo ZAMMAD_VERSION="$(git describe --tags | sed -e 's/-[a-z0-9]\{8,\}.*//g')" >> $GITHUB_ENV
|
||||
|
||||
@@ -38,7 +52,10 @@ jobs:
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
index.docker.io/zammad/zammad-docker-compose
|
||||
ghcr.io/${{ github.repository_owner }}/zammad
|
||||
index.docker.io/${{ github.repository_owner }}/zammad
|
||||
index.docker.io/${{ github.repository_owner }}/zammad-docker-compose
|
||||
quay.io/${{ github.repository_owner }}/zammad
|
||||
tags: |
|
||||
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'stable') }}
|
||||
type=raw,value=${{ env.ZAMMAD_VERSION }},enable=${{ github.ref == format('refs/heads/{0}', 'stable') }}
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
rules:
|
||||
- if: $BROWSER_TEST_FILTER
|
||||
when: never
|
||||
- if: $JOB_FILTER && $JOB_FILTER !~ /^rspec:integration/
|
||||
when: never
|
||||
- if: $CI_COMMIT_REF_NAME =~ /^private/
|
||||
allow_failure: true
|
||||
- when: on_success
|
||||
|
||||
@@ -25,6 +25,12 @@
|
||||
CI_PROXY_USER: 'zammad'
|
||||
CI_PROXY_PASSWORD: 'zammad'
|
||||
|
||||
.variables_idoit:
|
||||
variables:
|
||||
IDOIT_API_CATEGORY: "Building"
|
||||
IDOIT_API_ENDPOINT: "http://ci-service-idoit:80"
|
||||
IDOIT_API_TOKEN: "admin"
|
||||
|
||||
.variables_auth:
|
||||
variables:
|
||||
KEYCLOAK_BASE_URL: http://auth:8080
|
||||
@@ -76,3 +82,7 @@
|
||||
auth:
|
||||
name: $CI_REGISTRY/docker/zammad-auth:stable
|
||||
alias: auth
|
||||
|
||||
idoit:
|
||||
name: $CI_REGISTRY/docker/zammad-idoit:stable
|
||||
alias: ci-service-idoit
|
||||
|
||||
@@ -5,7 +5,10 @@ workflow:
|
||||
# (see https://docs.gitlab.com/ee/user/project/push_options.html)
|
||||
- if: $JOB_FILTER || $BROWSER_TEST_FILTER
|
||||
when: always
|
||||
# Avoid duplicate branch and MR pipelines for push events.
|
||||
# Avoid duplicate branch and MR pipelines for push events to branches with an open MR.
|
||||
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"
|
||||
when: never
|
||||
# Don't create branch pipelines for pushes to private branches (as there will also be a MR for them).
|
||||
- if: $CI_COMMIT_BRANCH =~ /^(private|cherry-pick-|renovate|dependabot)/ && $CI_PIPELINE_SOURCE == "push"
|
||||
when: never
|
||||
- when: always
|
||||
@@ -9,12 +9,22 @@
|
||||
RAILS_ENV: "production"
|
||||
APP_RESTART_CMD: 'bundle exec rake environment zammad:ci:app:restart'
|
||||
script:
|
||||
- script/build/test_slice_tests.sh $TEST_SLICE
|
||||
- RAILS_ENV=test bundle exec rake db:create
|
||||
- echo -e "\\e[0Ksection_start:`date +%s`:zammad_ci_test_start[collapsed=true]\\r\\e[0Kbundle exec rake zammad:ci:test:start"
|
||||
- bundle exec rake zammad:ci:test:start[with_elasticsearch]
|
||||
- echo -e "\\e[0Ksection_end:`date +%s`:zammad_ci_test_start\\r\\e[0K"
|
||||
- bundle exec rails test --fail-fast test/browser --profile
|
||||
- |
|
||||
script/build/test_slice_tests.sh $TEST_SLICE
|
||||
# Tests in the first slice do not expect for the auto wizard to be run.
|
||||
if [ $TEST_SLICE = 1 ]
|
||||
then
|
||||
echo -e "\\e[0Ksection_start:`date +%s`:zammad_ci_test_start[collapsed=true]\\r\\e[0Kbundle exec rake zammad:ci:test:start"
|
||||
bundle exec rake zammad:ci:test:start[with_elasticsearch]
|
||||
echo -e "\\e[0Ksection_end:`date +%s`:zammad_ci_test_start\\r\\e[0K"
|
||||
else
|
||||
echo -e "\\e[0Ksection_start:`date +%s`:zammad_ci_test_prepare[collapsed=true]\\r\\e[0Kbundle exec rake zammad:ci:test:prepare zammad:setup:auto_wizard zammad:ci:app:start"
|
||||
# Deconstruct zammad:ci:test:start command, so it starts the server only after the auto wizard has run.
|
||||
# This prevents instability due to `ZAMMAD_SETTING_TTL` not kicking in.
|
||||
bundle exec rake zammad:ci:test:prepare[with_elasticsearch] zammad:setup:auto_wizard[contrib/auto_wizard_browser_test.json] zammad:ci:app:start
|
||||
echo -e "\\e[0Ksection_end:`date +%s`:zammad_ci_test_prepare\\r\\e[0K"
|
||||
fi
|
||||
bundle exec rails test --fail-fast test/browser --profile
|
||||
|
||||
.template_browser-core_chrome:
|
||||
extends:
|
||||
|
||||
@@ -10,19 +10,23 @@ capybara:integration:chrome:
|
||||
- .template_browser-core_capybara_chrome
|
||||
- .template_browser-core_capybara_integration
|
||||
- .variables_auth
|
||||
- .variables_idoit
|
||||
services:
|
||||
- !reference [.services, postgresql]
|
||||
- !reference [.services, selenium-chrome]
|
||||
- !reference [.services, redis]
|
||||
- !reference [.services, auth]
|
||||
- !reference [.services, idoit]
|
||||
|
||||
capybara:integration:firefox:
|
||||
extends:
|
||||
- .template_browser-core_capybara_firefox
|
||||
- .template_browser-core_capybara_integration
|
||||
- .variables_auth
|
||||
- .variables_idoit
|
||||
services:
|
||||
- !reference [.services, mysql]
|
||||
- !reference [.services, selenium-firefox]
|
||||
- !reference [.services, redis]
|
||||
- !reference [.services, auth]
|
||||
- !reference [.services, idoit]
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
'integration:minitest:idoit':
|
||||
extends:
|
||||
- .template_browser-integration_chrome
|
||||
variables:
|
||||
TEST_FILE: "test/integration/idoit_browser_test.rb"
|
||||
@@ -6,7 +6,7 @@
|
||||
rules:
|
||||
- if: $CI_COMMIT_REF_NAME =~ /^stable/
|
||||
when: never
|
||||
- if: $CI_COMMIT_REF_NAME =~ /^private/
|
||||
- if: $CI_COMMIT_REF_NAME =~ /^(private|cherry-pick-)/
|
||||
when: manual
|
||||
allow_failure: true
|
||||
- when: on_success
|
||||
|
||||
38
.pkgr.yml
38
.pkgr.yml
@@ -15,8 +15,8 @@ targets:
|
||||
- imlib2
|
||||
- shared-mime-info
|
||||
build_dependencies:
|
||||
- https://download.fedoraproject.org/pub/epel/7/x86_64/Packages/i/imlib2-1.4.5-9.el7.x86_64.rpm
|
||||
- https://download.fedoraproject.org/pub/epel/7/x86_64/Packages/i/imlib2-devel-1.4.5-9.el7.x86_64.rpm
|
||||
- https://download.fedoraproject.org/pub/epel/7/x86_64/Packages/i/imlib2-1.4.9-8.el7.x86_64.rpm
|
||||
- https://download.fedoraproject.org/pub/epel/7/x86_64/Packages/i/imlib2-devel-1.4.9-8.el7.x86_64.rpm
|
||||
- shared-mime-info
|
||||
centos-8:
|
||||
dependencies:
|
||||
@@ -32,18 +32,6 @@ targets:
|
||||
- https://download.fedoraproject.org/pub/epel/8/Everything/x86_64/Packages/i/imlib2-1.4.9-8.el8.x86_64.rpm
|
||||
- https://download.fedoraproject.org/pub/epel/8/Everything/x86_64/Packages/i/imlib2-devel-1.4.9-8.el8.x86_64.rpm
|
||||
- shared-mime-info
|
||||
debian-9:
|
||||
dependencies:
|
||||
- curl
|
||||
- elasticsearch|elasticsearch-oss
|
||||
- nginx|apache2
|
||||
- postgresql|mariadb-server
|
||||
- libimlib2
|
||||
- shared-mime-info
|
||||
build_dependencies:
|
||||
- libimlib2
|
||||
- libimlib2-dev
|
||||
- shared-mime-info
|
||||
debian-10:
|
||||
dependencies:
|
||||
- curl
|
||||
@@ -125,11 +113,33 @@ targets:
|
||||
- libImlib2-1
|
||||
- imlib2
|
||||
build_dependencies:
|
||||
# Add packages required for build that are not in the official SLES repo.
|
||||
# Direct URLs must be used since we cannot add repos on packager.io
|
||||
# (would require a paid SLES account and credential management on packager.io).
|
||||
- https://ftp.gwdg.de/pub/opensuse/discontinued/distribution/12.3/repo/oss/suse/x86_64/imlib2-1.4.5-12.1.1.x86_64.rpm
|
||||
- https://ftp.gwdg.de/pub/opensuse/discontinued/distribution/12.3/repo/oss/suse/x86_64/imlib2-devel-1.4.5-12.1.1.x86_64.rpm
|
||||
- https://ftp.gwdg.de/pub/opensuse/discontinued/distribution/12.3/repo/oss/suse/x86_64/imlib2-filters-1.4.5-12.1.1.x86_64.rpm
|
||||
- https://ftp.gwdg.de/pub/opensuse/discontinued/distribution/12.3/repo/oss/suse/x86_64/libImlib2-1-1.4.5-12.1.1.x86_64.rpm
|
||||
- shared-mime-info
|
||||
sles-15:
|
||||
dependencies:
|
||||
- curl
|
||||
- elasticsearch
|
||||
- nginx
|
||||
- postgresql-server
|
||||
- libImlib2-1
|
||||
- imlib2
|
||||
- shared-mime-info
|
||||
build_dependencies:
|
||||
# Add packages required for build that are not in the official SLES repo.
|
||||
# Direct URLs must be used since we cannot add repos on packager.io
|
||||
# (would require a paid SLES account and credential management on packager.io).
|
||||
- https://ftp.lysator.liu.se/pub/opensuse/ports/aarch64/distribution/leap/15.4/repo/oss/x86_64/imlib2-1.4.10-1.28.x86_64.rpm
|
||||
- https://ftp.lysator.liu.se/pub/opensuse/ports/aarch64/distribution/leap/15.4/repo/oss/x86_64/imlib2-devel-1.4.10-1.28.x86_64.rpm
|
||||
- https://ftp.lysator.liu.se/pub/opensuse/ports/aarch64/distribution/leap/15.4/repo/oss/x86_64/imlib2-filters-1.4.10-1.28.x86_64.rpm
|
||||
- https://ftp.lysator.liu.se/pub/opensuse/ports/aarch64/distribution/leap/15.4/repo/oss/x86_64/libImlib2-1-1.4.10-1.28.x86_64.rpm
|
||||
- shared-mime-info
|
||||
- libmariadb-devel
|
||||
before:
|
||||
- contrib/packager.io/before.sh
|
||||
after:
|
||||
|
||||
107
CHANGELOG.md
107
CHANGELOG.md
@@ -1,8 +1,113 @@
|
||||
# Change Log
|
||||
|
||||
## [5.4.0](https://github.com/zammad/zammad/tree/5.4.0) (2023-xx-xx)
|
||||
## [5.4.1](https://github.com/zammad/zammad/tree/5.4.1) (2023-04-12)
|
||||
[Full Changelog](https://github.com/zammad/zammad/compare/5.4.0...5.4.1)
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- Triggers without configured action inside condition are executed differently compared to 5.3 [4550](https://github.com/zammad/zammad/issues/4550) [[bug](https://github.com/zammad/zammad/labels/bug)] [[blocker](https://github.com/zammad/zammad/labels/blocker)] [[trigger](https://github.com/zammad/zammad/labels/trigger)] [[ticket](https://github.com/zammad/zammad/labels/ticket)]
|
||||
- Allow logout for SAML accounts without set idp_slo_service_url [4548](https://github.com/zammad/zammad/issues/4548) [[bug](https://github.com/zammad/zammad/labels/bug)] [[blocker](https://github.com/zammad/zammad/labels/blocker)] [[SAML](https://github.com/zammad/zammad/labels/SAML)]
|
||||
- Change of the pre-condition dropdown value in expert mode is not saved [4532](https://github.com/zammad/zammad/issues/4532) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[data loss](https://github.com/zammad/zammad/labels/data%20loss)]
|
||||
- Request one-time admin password link diverts user's attention [4536](https://github.com/zammad/zammad/issues/4536) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)]
|
||||
- "Type application/netcdf is already registered as a variant of application/netcdf." when using Zammad console [4038](https://github.com/zammad/zammad/issues/4038) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- rake zammad:db:pgloader fails if no host value is set in config [4526](https://github.com/zammad/zammad/issues/4526) [[bug](https://github.com/zammad/zammad/labels/bug)] [[migration / update](https://github.com/zammad/zammad/labels/migration%20%2F%20update)]
|
||||
- Priority icons in ticket overviews have lost their color [4384](https://github.com/zammad/zammad/issues/4384) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)]
|
||||
- Previewing forms in admin UI looks broken in dark mode [4372](https://github.com/zammad/zammad/issues/4372) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[channel](https://github.com/zammad/zammad/labels/channel)] [[admin area](https://github.com/zammad/zammad/labels/admin%20area)] [[dark mode](https://github.com/zammad/zammad/labels/dark%20mode)]
|
||||
- Can't skip wizard any more with sendmail when error message occurs [4525](https://github.com/zammad/zammad/issues/4525) [[bug](https://github.com/zammad/zammad/labels/bug)] [[blocker](https://github.com/zammad/zammad/labels/blocker)] [[channel](https://github.com/zammad/zammad/labels/channel)] [[admin area](https://github.com/zammad/zammad/labels/admin%20area)] [[notification](https://github.com/zammad/zammad/labels/notification)]
|
||||
- Alphabetical listing of organizations in admin area [4520](https://github.com/zammad/zammad/issues/4520) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
|
||||
## [5.4.0](https://github.com/zammad/zammad/tree/5.4.0) (2023-03-14)
|
||||
[Full Changelog](https://github.com/zammad/zammad/compare/5.3.0...5.4.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Feature: Add explanation above ticket note [4326](https://github.com/zammad/zammad/pull/4326) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[ticket](https://github.com/zammad/zammad/labels/ticket)]
|
||||
- Public link _blank option setting - don't have "display" as wording [4369](https://github.com/zammad/zammad/issues/4369) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[translation](https://github.com/zammad/zammad/labels/translation)]
|
||||
- DataPrivacy tasks never are cleaned up [4437](https://github.com/zammad/zammad/issues/4437) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[data privacy](https://github.com/zammad/zammad/labels/data%20privacy)]
|
||||
- Improve UI for the Exchange OAuth configuration [4435](https://github.com/zammad/zammad/issues/4435) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[admin area](https://github.com/zammad/zammad/labels/admin%20area)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[core](https://github.com/zammad/zammad/labels/core)]
|
||||
- Copy and paste ticket number into ticket link dialog [4364](https://github.com/zammad/zammad/issues/4364) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[ticket](https://github.com/zammad/zammad/labels/ticket)]
|
||||
- SAML: Support of custom attribute in name identifier [4411](https://github.com/zammad/zammad/issues/4411) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[SAML](https://github.com/zammad/zammad/labels/SAML)]
|
||||
- SAML Single Logout [4412](https://github.com/zammad/zammad/issues/4412) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[SAML](https://github.com/zammad/zammad/labels/SAML)]
|
||||
- Automatic third-party account linking notification [4410](https://github.com/zammad/zammad/issues/4410) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[authentication](https://github.com/zammad/zammad/labels/authentication)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Make conditions AND/OR and thus enable several conditions of same type [2185](https://github.com/zammad/zammad/issues/2185) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[trigger](https://github.com/zammad/zammad/labels/trigger)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- Inconsistent screen view with active attribute for organizations and users [4505](https://github.com/zammad/zammad/issues/4505) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[object manager attribute](https://github.com/zammad/zammad/labels/object%20manager%20attribute)]
|
||||
- Disable expert mode for time accounting conditions [4509](https://github.com/zammad/zammad/issues/4509) [[bug](https://github.com/zammad/zammad/labels/bug)] [[time accounting](https://github.com/zammad/zammad/labels/time%20accounting)]
|
||||
- Adding ticket Tags attribute to conditions in expert mode results in an error [4507](https://github.com/zammad/zammad/issues/4507) [[bug](https://github.com/zammad/zammad/labels/bug)] [[admin area](https://github.com/zammad/zammad/labels/admin%20area)]
|
||||
- New selector: "contains" not working like before for url-fields [4498](https://github.com/zammad/zammad/issues/4498) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Typing the text attribute in the ticket changes the displayed name of the ticket in the activity stream [4329](https://github.com/zammad/zammad/issues/4329) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- New article visibility is not persisted in taskbar [4488](https://github.com/zammad/zammad/issues/4488) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Excel-Export in reporting exports only first 10 tickets [4493](https://github.com/zammad/zammad/issues/4493) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Switching on/off integrations (e.g. LDAP + Exchange) leads to unpredictable results [4181](https://github.com/zammad/zammad/issues/4181) [[bug](https://github.com/zammad/zammad/labels/bug)] [[admin area](https://github.com/zammad/zammad/labels/admin%20area)] [[integration](https://github.com/zammad/zammad/labels/integration)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Tickets through mail with multiple groups in To: and CC: will all receive the ticket and create "ticketmail" users for each other [2307](https://github.com/zammad/zammad/issues/2307) [[bug](https://github.com/zammad/zammad/labels/bug)] [[channel](https://github.com/zammad/zammad/labels/channel)]
|
||||
- OTRS import: Wrong next StateID for pending close states [1887](https://github.com/zammad/zammad/issues/1887) [[bug](https://github.com/zammad/zammad/labels/bug)] [[import](https://github.com/zammad/zammad/labels/import)]
|
||||
- OTRS migration fails with ForeignKeyViolation [1713](https://github.com/zammad/zammad/issues/1713) [[bug](https://github.com/zammad/zammad/labels/bug)] [[import](https://github.com/zammad/zammad/labels/import)]
|
||||
- Failing HTML-Processing denies user to access the mail [2706](https://github.com/zammad/zammad/issues/2706) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[mail processing](https://github.com/zammad/zammad/labels/mail%20processing)] [[performance](https://github.com/zammad/zammad/labels/performance)]
|
||||
- Overview grouping does not work with multi_tree_select [4408](https://github.com/zammad/zammad/issues/4408) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Search doesn't show tickets belonging to secondary organizations [4425](https://github.com/zammad/zammad/issues/4425) [[bug](https://github.com/zammad/zammad/labels/bug)] [[search](https://github.com/zammad/zammad/labels/search)]
|
||||
- Role defined in snake_case applies markdown formatting (underline) in user permission settings [4354](https://github.com/zammad/zammad/issues/4354) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- The word "action" is not a reserved word in object attributes [4405](https://github.com/zammad/zammad/issues/4405) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Show live users on both desktop and mobile [4476](https://github.com/zammad/zammad/issues/4476) [[feature backlog](https://github.com/zammad/zammad/labels/feature%20backlog)] [[mobile](https://github.com/zammad/zammad/labels/mobile)]
|
||||
- Group edit dialog shows ??? in email select box [4475](https://github.com/zammad/zammad/issues/4475) [[bug](https://github.com/zammad/zammad/labels/bug)] [[blocker](https://github.com/zammad/zammad/labels/blocker)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[regression](https://github.com/zammad/zammad/labels/regression)]
|
||||
- Search without filters in KB should always get sorted by relevance instead of updated_at [4456](https://github.com/zammad/zammad/issues/4456) [[bug](https://github.com/zammad/zammad/labels/bug)] [[search](https://github.com/zammad/zammad/labels/search)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[knowledge base](https://github.com/zammad/zammad/labels/knowledge%20base)]
|
||||
- KB article html contains two h1 tags (SEO) [4455](https://github.com/zammad/zammad/issues/4455) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[knowledge base](https://github.com/zammad/zammad/labels/knowledge%20base)] [[good first issue](https://github.com/zammad/zammad/labels/good%20first%20issue)]
|
||||
- JS Error: Cannot read properties of null (reading 'trigger') [4422](https://github.com/zammad/zammad/issues/4422) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Zammad looses EXIF Tags from Images taken and sent with an iPhone [4347](https://github.com/zammad/zammad/issues/4347) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Zendesk crash on ticket import: undefined method `id' for nil:NilClass [4470](https://github.com/zammad/zammad/issues/4470) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Not possible to select multiple values in a multi-tree select when a workflow with a select action is executed [4465](https://github.com/zammad/zammad/issues/4465) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[form](https://github.com/zammad/zammad/labels/form)] [[core workflows](https://github.com/zammad/zammad/labels/core%20workflows)]
|
||||
- Multiselect field defaults to nil instead of [] [4442](https://github.com/zammad/zammad/issues/4442) [[bug](https://github.com/zammad/zammad/labels/bug)] [[object manager attribute](https://github.com/zammad/zammad/labels/object%20manager%20attribute)]
|
||||
- RSS feed tokens expired [4461](https://github.com/zammad/zammad/issues/4461) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[knowledge base](https://github.com/zammad/zammad/labels/knowledge%20base)]
|
||||
- Nulloption from screen is currently not used in the core workflow backend [4415](https://github.com/zammad/zammad/issues/4415) [[bug](https://github.com/zammad/zammad/labels/bug)] [[core workflows](https://github.com/zammad/zammad/labels/core%20workflows)]
|
||||
- mail_delivery_failed attribute blocks trigger based mails if days left is negative [4459](https://github.com/zammad/zammad/issues/4459) [[bug](https://github.com/zammad/zammad/labels/bug)] [[trigger](https://github.com/zammad/zammad/labels/trigger)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- [REVIEW] Fix/trigger variables missing [3225](https://github.com/zammad/zammad/pull/3225)
|
||||
- Error while processing S/MIME signed emails when the sender name is different than CN [4457](https://github.com/zammad/zammad/issues/4457) [[bug](https://github.com/zammad/zammad/labels/bug)] [[mail processing](https://github.com/zammad/zammad/labels/mail%20processing)] [[smime](https://github.com/zammad/zammad/labels/smime)]
|
||||
- Exchange Oauth token update job is always marked as failed job when it's not configured [4454](https://github.com/zammad/zammad/issues/4454) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Zammad adopts white/light gray font color when copying a text in dark mode [4445](https://github.com/zammad/zammad/issues/4445) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- OTRS Import is not using source "RealTillTimeNotUsed" attribute information in target "pending_time" attribute [4439](https://github.com/zammad/zammad/issues/4439) [[bug](https://github.com/zammad/zammad/labels/bug)] [[import](https://github.com/zammad/zammad/labels/import)]
|
||||
- OTRS Import is not using (agent&customer) article creator information [4438](https://github.com/zammad/zammad/issues/4438) [[bug](https://github.com/zammad/zammad/labels/bug)] [[import](https://github.com/zammad/zammad/labels/import)]
|
||||
- Open ticket indicator does not get colored when ticket count is 3 with enabled colored indicators [4387](https://github.com/zammad/zammad/issues/4387) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)]
|
||||
- timezone_default stays unset if you're spawning Zammad via auto_wizard.json [4436](https://github.com/zammad/zammad/issues/4436) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[regression](https://github.com/zammad/zammad/labels/regression)]
|
||||
- CC field cannot be customized in the new ticket templates [4421](https://github.com/zammad/zammad/issues/4421) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Missing rake task to fix json values migrated from maria/mysql to postgres [4431](https://github.com/zammad/zammad/issues/4431) [[bug](https://github.com/zammad/zammad/labels/bug)] [[blocker](https://github.com/zammad/zammad/labels/blocker)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[migration / update](https://github.com/zammad/zammad/labels/migration%20%2F%20update)]
|
||||
- Zammad 5.3.1 patch (and security) upgrade needs Redis >=7.0.0 [4443](https://github.com/zammad/zammad/issues/4443) [[bug](https://github.com/zammad/zammad/labels/bug)] [[regression](https://github.com/zammad/zammad/labels/regression)]
|
||||
- Taskbar has unsaved changes (but noting has changed) when mutiselect field exists (annoying modal dialog pops up on every ticket) [4404](https://github.com/zammad/zammad/issues/4404) [[bug](https://github.com/zammad/zammad/labels/bug)] [[ticket](https://github.com/zammad/zammad/labels/ticket)] [[object manager attribute](https://github.com/zammad/zammad/labels/object%20manager%20attribute)]
|
||||
- Taskbar is not marked as having changes if one of multiselect selections is unselected [4441](https://github.com/zammad/zammad/issues/4441) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Use third-party application name in automatic linking notifications [4434](https://github.com/zammad/zammad/issues/4434) [[notification](https://github.com/zammad/zammad/labels/notification)] [[authentication](https://github.com/zammad/zammad/labels/authentication)] [[SAML](https://github.com/zammad/zammad/labels/SAML)]
|
||||
- Ticket fields are readonly for users with secondary organizations on tickets created by another user [4426](https://github.com/zammad/zammad/issues/4426) [[bug](https://github.com/zammad/zammad/labels/bug)] [[ticket](https://github.com/zammad/zammad/labels/ticket)]
|
||||
- Freshdesk custom field types which can not be mapped will abort the complete import [4342](https://github.com/zammad/zammad/issues/4342) [[bug](https://github.com/zammad/zammad/labels/bug)] [[import](https://github.com/zammad/zammad/labels/import)]
|
||||
- Exchange integration requires OAuth instead of basic authentication [3971](https://github.com/zammad/zammad/issues/3971) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- SMIME: No verification if the mail sender is the signer. [4212](https://github.com/zammad/zammad/issues/4212) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[smime](https://github.com/zammad/zammad/labels/smime)]
|
||||
- Redis database content keeps growing forever [4349](https://github.com/zammad/zammad/issues/4349) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Zammad assumes caller_locations's path exists on disk [4356](https://github.com/zammad/zammad/issues/4356) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Invalid SAML session identifier used. [4427](https://github.com/zammad/zammad/issues/4427) [[bug](https://github.com/zammad/zammad/labels/bug)] [[authentication](https://github.com/zammad/zammad/labels/authentication)]
|
||||
- Agents cannot reopen tickets when group follow-up setting is set to "do not reopen" [4386](https://github.com/zammad/zammad/issues/4386) [[bug](https://github.com/zammad/zammad/labels/bug)] [[blocker](https://github.com/zammad/zammad/labels/blocker)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Can not use RSS feed in Microsoft Teams (invalid url) [4403](https://github.com/zammad/zammad/issues/4403) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[knowledge base](https://github.com/zammad/zammad/labels/knowledge%20base)]
|
||||
- JS error on user save: Uncaught TypeError: Cannot read properties of null (reading 'length') [4419](https://github.com/zammad/zammad/issues/4419) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Ticket templates are missing active flag [4381](https://github.com/zammad/zammad/issues/4381) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)] [[admin area](https://github.com/zammad/zammad/labels/admin%20area)] [[ticket templates](https://github.com/zammad/zammad/labels/ticket%20templates)]
|
||||
- Ticket selector allows for duplicate attributes with expert mode switched off [4414](https://github.com/zammad/zammad/issues/4414) [[bug](https://github.com/zammad/zammad/labels/bug)] [[admin area](https://github.com/zammad/zammad/labels/admin%20area)]
|
||||
- Overview ticket preview should also load on saved objects [4413](https://github.com/zammad/zammad/issues/4413) [[bug](https://github.com/zammad/zammad/labels/bug)] [[admin area](https://github.com/zammad/zammad/labels/admin%20area)]
|
||||
- Ticket updates without articles do provide article variables set [3902](https://github.com/zammad/zammad/issues/3902) [[bug](https://github.com/zammad/zammad/labels/bug)] [[trigger](https://github.com/zammad/zammad/labels/trigger)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- OTRS migration from lower then OTRS 6 doesn't import article creation time [4400](https://github.com/zammad/zammad/issues/4400) [[bug](https://github.com/zammad/zammad/labels/bug)] [[import](https://github.com/zammad/zammad/labels/import)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Sync with computer always ends in light mode [4365](https://github.com/zammad/zammad/issues/4365) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)]
|
||||
- Appearance setting within profile not available to customers [4368](https://github.com/zammad/zammad/issues/4368) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)]
|
||||
- The local time zone overwrites the one set in Zammad [4377](https://github.com/zammad/zammad/issues/4377) [[bug](https://github.com/zammad/zammad/labels/bug)] [[blocker](https://github.com/zammad/zammad/labels/blocker)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- HTML escaping is shown in the frontend for overview settings [4366](https://github.com/zammad/zammad/issues/4366) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)]
|
||||
- Text attribute inputs longer than maxlength is silently truncated [2150](https://github.com/zammad/zammad/issues/2150) [[bug](https://github.com/zammad/zammad/labels/bug)] [[object manager attribute](https://github.com/zammad/zammad/labels/object%20manager%20attribute)]
|
||||
- Overview sorting shown to customer roles if set but empty [4367](https://github.com/zammad/zammad/issues/4367) [[bug](https://github.com/zammad/zammad/labels/bug)] [[blocker](https://github.com/zammad/zammad/labels/blocker)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)]
|
||||
- Administrative password reset does not provide token [4370](https://github.com/zammad/zammad/issues/4370) [[bug](https://github.com/zammad/zammad/labels/bug)] [[security](https://github.com/zammad/zammad/labels/security)] [[blocker](https://github.com/zammad/zammad/labels/blocker)]
|
||||
- Zammad-scheduler constantly crashes if user have unknown timezone [4320](https://github.com/zammad/zammad/issues/4320) [[bug](https://github.com/zammad/zammad/labels/bug)] [[blocker](https://github.com/zammad/zammad/labels/blocker)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
- Avatar highlight gets lost when leaving hover area even through context menu is active [4363](https://github.com/zammad/zammad/issues/4363) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)]
|
||||
- "My Replacement Tickets" overview is shown even if I'm not selected for replacement. [4248](https://github.com/zammad/zammad/issues/4248) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Variables within Trigger and Scheduler behave differently between subject and body [3013](https://github.com/zammad/zammad/issues/3013) [[bug](https://github.com/zammad/zammad/labels/bug)] [[trigger](https://github.com/zammad/zammad/labels/trigger)]
|
||||
- Remove spaces before ** in SLA description text [4337](https://github.com/zammad/zammad/issues/4337) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Fix spacing between asterisks and text. Fix #4337 [4338](https://github.com/zammad/zammad/pull/4338)
|
||||
- Background worker aborts due to file locking error [4294](https://github.com/zammad/zammad/issues/4294) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Ticket templates are missing pending till option [4318](https://github.com/zammad/zammad/issues/4318) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Word wrap in Knowledge Base with tables from mobile view perspective [4334](https://github.com/zammad/zammad/issues/4334) [[bug](https://github.com/zammad/zammad/labels/bug)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)] [[knowledge base](https://github.com/zammad/zammad/labels/knowledge%20base)]
|
||||
- Read-only view for tickets contains misleading elements [1679](https://github.com/zammad/zammad/issues/1679) [[bug](https://github.com/zammad/zammad/labels/bug)] [[UX/UI](https://github.com/zammad/zammad/labels/UX%2FUI)]
|
||||
- Wrong value in session timeout [4322](https://github.com/zammad/zammad/issues/4322) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Updating group settings causes huge numbers of delayed jobs [4306](https://github.com/zammad/zammad/issues/4306) [[bug](https://github.com/zammad/zammad/labels/bug)] [[search](https://github.com/zammad/zammad/labels/search)] [[prioritised by payment](https://github.com/zammad/zammad/labels/prioritised%20by%20payment)]
|
||||
|
||||
|
||||
|
||||
6
Gemfile
6
Gemfile
@@ -6,6 +6,12 @@ source 'https://rubygems.org'
|
||||
ruby '3.1.3'
|
||||
gem 'rails', '~> 6.1.0'
|
||||
|
||||
# TEMPORARY Security updates from Ruby 3.1.4. Can be removed when updating from Ruby 3.1.3 to a higher version.
|
||||
# See also: https://www.ruby-lang.org/en/news/2023/03/30/ruby-3-1-4-released/
|
||||
gem 'time', '>= 0.2.2'
|
||||
gem 'uri', '>= 0.12.1'
|
||||
# END TEMPORARY
|
||||
|
||||
# core - rails additions
|
||||
gem 'activerecord-import'
|
||||
gem 'activerecord-session_store'
|
||||
|
||||
120
Gemfile.lock
120
Gemfile.lock
@@ -15,52 +15,52 @@ GEM
|
||||
simple_po_parser (~> 1.1.6)
|
||||
aasm (5.5.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
actioncable (6.1.7.2)
|
||||
actionpack (= 6.1.7.2)
|
||||
activesupport (= 6.1.7.2)
|
||||
actioncable (6.1.7.3)
|
||||
actionpack (= 6.1.7.3)
|
||||
activesupport (= 6.1.7.3)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (>= 0.6.1)
|
||||
actionmailbox (6.1.7.2)
|
||||
actionpack (= 6.1.7.2)
|
||||
activejob (= 6.1.7.2)
|
||||
activerecord (= 6.1.7.2)
|
||||
activestorage (= 6.1.7.2)
|
||||
activesupport (= 6.1.7.2)
|
||||
actionmailbox (6.1.7.3)
|
||||
actionpack (= 6.1.7.3)
|
||||
activejob (= 6.1.7.3)
|
||||
activerecord (= 6.1.7.3)
|
||||
activestorage (= 6.1.7.3)
|
||||
activesupport (= 6.1.7.3)
|
||||
mail (>= 2.7.1)
|
||||
actionmailer (6.1.7.2)
|
||||
actionpack (= 6.1.7.2)
|
||||
actionview (= 6.1.7.2)
|
||||
activejob (= 6.1.7.2)
|
||||
activesupport (= 6.1.7.2)
|
||||
actionmailer (6.1.7.3)
|
||||
actionpack (= 6.1.7.3)
|
||||
actionview (= 6.1.7.3)
|
||||
activejob (= 6.1.7.3)
|
||||
activesupport (= 6.1.7.3)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
actionpack (6.1.7.2)
|
||||
actionview (= 6.1.7.2)
|
||||
activesupport (= 6.1.7.2)
|
||||
actionpack (6.1.7.3)
|
||||
actionview (= 6.1.7.3)
|
||||
activesupport (= 6.1.7.3)
|
||||
rack (~> 2.0, >= 2.0.9)
|
||||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||
actiontext (6.1.7.2)
|
||||
actionpack (= 6.1.7.2)
|
||||
activerecord (= 6.1.7.2)
|
||||
activestorage (= 6.1.7.2)
|
||||
activesupport (= 6.1.7.2)
|
||||
actiontext (6.1.7.3)
|
||||
actionpack (= 6.1.7.3)
|
||||
activerecord (= 6.1.7.3)
|
||||
activestorage (= 6.1.7.3)
|
||||
activesupport (= 6.1.7.3)
|
||||
nokogiri (>= 1.8.5)
|
||||
actionview (6.1.7.2)
|
||||
activesupport (= 6.1.7.2)
|
||||
actionview (6.1.7.3)
|
||||
activesupport (= 6.1.7.3)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
||||
activejob (6.1.7.2)
|
||||
activesupport (= 6.1.7.2)
|
||||
activejob (6.1.7.3)
|
||||
activesupport (= 6.1.7.3)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (6.1.7.2)
|
||||
activesupport (= 6.1.7.2)
|
||||
activerecord (6.1.7.2)
|
||||
activemodel (= 6.1.7.2)
|
||||
activesupport (= 6.1.7.2)
|
||||
activemodel (6.1.7.3)
|
||||
activesupport (= 6.1.7.3)
|
||||
activerecord (6.1.7.3)
|
||||
activemodel (= 6.1.7.3)
|
||||
activesupport (= 6.1.7.3)
|
||||
activerecord-import (1.4.1)
|
||||
activerecord (>= 4.2)
|
||||
activerecord-nulldb-adapter (0.8.0)
|
||||
@@ -71,14 +71,14 @@ GEM
|
||||
multi_json (~> 1.11, >= 1.11.2)
|
||||
rack (>= 2.0.8, < 3)
|
||||
railties (>= 5.2.4.1)
|
||||
activestorage (6.1.7.2)
|
||||
actionpack (= 6.1.7.2)
|
||||
activejob (= 6.1.7.2)
|
||||
activerecord (= 6.1.7.2)
|
||||
activesupport (= 6.1.7.2)
|
||||
activestorage (6.1.7.3)
|
||||
actionpack (= 6.1.7.3)
|
||||
activejob (= 6.1.7.3)
|
||||
activerecord (= 6.1.7.3)
|
||||
activesupport (= 6.1.7.3)
|
||||
marcel (~> 1.0)
|
||||
mini_mime (>= 1.1.0)
|
||||
activesupport (6.1.7.2)
|
||||
activesupport (6.1.7.3)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 1.6, < 2)
|
||||
minitest (>= 5.1)
|
||||
@@ -278,7 +278,7 @@ GEM
|
||||
method_source (1.0.0)
|
||||
mime-types (3.4.1)
|
||||
mime-types-data (~> 3.2015)
|
||||
mime-types-data (3.2022.0105)
|
||||
mime-types-data (3.2023.0218.1)
|
||||
mini_mime (1.1.2)
|
||||
mini_portile2 (2.8.1)
|
||||
minitest (5.17.0)
|
||||
@@ -306,7 +306,7 @@ GEM
|
||||
net-smtp (0.3.3)
|
||||
net-protocol
|
||||
nio4r (2.5.8)
|
||||
nokogiri (1.13.10)
|
||||
nokogiri (1.14.3)
|
||||
mini_portile2 (~> 2.8.0)
|
||||
racc (~> 1.4)
|
||||
nori (2.6.0)
|
||||
@@ -394,27 +394,27 @@ GEM
|
||||
pundit-matchers (1.8.4)
|
||||
rspec-rails (>= 3.0.0)
|
||||
racc (1.6.2)
|
||||
rack (2.2.6.2)
|
||||
rack (2.2.6.4)
|
||||
rack-attack (6.6.1)
|
||||
rack (>= 1.0, < 3)
|
||||
rack-proxy (0.7.6)
|
||||
rack
|
||||
rack-test (2.0.2)
|
||||
rack (>= 1.3)
|
||||
rails (6.1.7.2)
|
||||
actioncable (= 6.1.7.2)
|
||||
actionmailbox (= 6.1.7.2)
|
||||
actionmailer (= 6.1.7.2)
|
||||
actionpack (= 6.1.7.2)
|
||||
actiontext (= 6.1.7.2)
|
||||
actionview (= 6.1.7.2)
|
||||
activejob (= 6.1.7.2)
|
||||
activemodel (= 6.1.7.2)
|
||||
activerecord (= 6.1.7.2)
|
||||
activestorage (= 6.1.7.2)
|
||||
activesupport (= 6.1.7.2)
|
||||
rails (6.1.7.3)
|
||||
actioncable (= 6.1.7.3)
|
||||
actionmailbox (= 6.1.7.3)
|
||||
actionmailer (= 6.1.7.3)
|
||||
actionpack (= 6.1.7.3)
|
||||
actiontext (= 6.1.7.3)
|
||||
actionview (= 6.1.7.3)
|
||||
activejob (= 6.1.7.3)
|
||||
activemodel (= 6.1.7.3)
|
||||
activerecord (= 6.1.7.3)
|
||||
activestorage (= 6.1.7.3)
|
||||
activesupport (= 6.1.7.3)
|
||||
bundler (>= 1.15.0)
|
||||
railties (= 6.1.7.2)
|
||||
railties (= 6.1.7.3)
|
||||
sprockets-rails (>= 2.0.0)
|
||||
rails-controller-testing (1.0.5)
|
||||
actionpack (>= 5.0.1.rc1)
|
||||
@@ -425,9 +425,9 @@ GEM
|
||||
nokogiri (>= 1.6)
|
||||
rails-html-sanitizer (1.4.4)
|
||||
loofah (~> 2.19, >= 2.19.1)
|
||||
railties (6.1.7.2)
|
||||
actionpack (= 6.1.7.2)
|
||||
activesupport (= 6.1.7.2)
|
||||
railties (6.1.7.3)
|
||||
actionpack (= 6.1.7.3)
|
||||
activesupport (= 6.1.7.3)
|
||||
method_source
|
||||
rake (>= 12.2)
|
||||
thor (~> 1.0)
|
||||
@@ -552,9 +552,9 @@ GEM
|
||||
thor (1.2.1)
|
||||
thread_safe (0.3.6)
|
||||
tilt (2.0.11)
|
||||
time (0.2.1)
|
||||
time (0.2.2)
|
||||
date
|
||||
timeout (0.3.1)
|
||||
timeout (0.3.2)
|
||||
twilio-ruby (5.74.3)
|
||||
faraday (>= 0.9, < 3.0)
|
||||
jwt (>= 1.5, <= 2.6)
|
||||
@@ -581,7 +581,7 @@ GEM
|
||||
unicorn (6.1.0)
|
||||
kgio (~> 2.6)
|
||||
raindrops (~> 0.7)
|
||||
uri (0.12.0)
|
||||
uri (0.12.1)
|
||||
vcr (6.1.0)
|
||||
version_gem (1.1.1)
|
||||
viewpoint (1.1.1)
|
||||
@@ -725,10 +725,12 @@ DEPENDENCIES
|
||||
terser
|
||||
test-unit
|
||||
thor
|
||||
time (>= 0.2.2)
|
||||
twilio-ruby
|
||||
twitter
|
||||
tzinfo-data
|
||||
unicorn
|
||||
uri (>= 0.12.1)
|
||||
vcr
|
||||
viewpoint
|
||||
vite_rails
|
||||
|
||||
@@ -345,7 +345,7 @@ class App.Controller extends Spine.Controller
|
||||
|
||||
prepareForObjectListItem: (item) ->
|
||||
item.link = ''
|
||||
item.title = '???'
|
||||
item.title = '-'
|
||||
|
||||
# convert backend name space to local name space
|
||||
item.object = item.object.replace('::', '')
|
||||
|
||||
@@ -131,6 +131,10 @@ class ChannelAccountOverview extends App.ControllerSubContent
|
||||
@error_code = undefined
|
||||
new App.AdminConsentInfo(container: @container)
|
||||
|
||||
if @error_code is 'user_mismatch'
|
||||
@error_code = undefined
|
||||
new App.UserMismatchInfo(container: @container)
|
||||
|
||||
show: (params) =>
|
||||
for key, value of params
|
||||
if key isnt 'el' && key isnt 'shown' && key isnt 'match'
|
||||
@@ -448,4 +452,16 @@ class App.AdminConsentInfo extends App.ControllerModal
|
||||
onSubmit: =>
|
||||
@close()
|
||||
|
||||
class App.UserMismatchInfo extends App.ControllerModal
|
||||
buttonClose: true
|
||||
small: true
|
||||
buttonSubmit: __('Close')
|
||||
head: __('User Mismatch')
|
||||
|
||||
content: ->
|
||||
App.view('microsoft365/user_mismatch')()
|
||||
|
||||
onSubmit: =>
|
||||
@close()
|
||||
|
||||
App.Config.set('microsoft365', { prio: 5000, name: __('Microsoft 365'), parent: '#channels', target: '#channels/microsoft365', controller: App.ChannelMicrosoft365, permission: ['admin.channel_microsoft365'] }, 'NavBarAdmin')
|
||||
|
||||
@@ -363,7 +363,7 @@ class ConnectionWizard extends App.ControllerWizardModal
|
||||
@wizardConfig.endpoint = params.endpoint
|
||||
@wizardConfig.disable_ssl_verify = params.disable_ssl_verify
|
||||
|
||||
if params.authentication_method is 'basic'
|
||||
if @wizardConfig.auth_type is 'basic'
|
||||
@wizardConfig.user = params.user
|
||||
@wizardConfig.password = params.password
|
||||
|
||||
@@ -411,6 +411,13 @@ class ConnectionWizard extends App.ControllerWizardModal
|
||||
data: JSON.stringify(@wizardConfig)
|
||||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
if data.result isnt 'ok'
|
||||
@handleCertificateIssue(
|
||||
message: data.message
|
||||
wizardClass: 'js-discover'
|
||||
)
|
||||
return
|
||||
|
||||
@wizardConfig.wizardData = {}
|
||||
@wizardConfig.wizardData.backend_folders = data.folders || []
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ class App.UiElement.ApplicationSelector
|
||||
# ignore passwords and relations
|
||||
if config.type isnt 'password' && config.name.substr(config.name.length-4,4) isnt '_ids' && config.searchable isnt false
|
||||
config.default = undefined
|
||||
if config.type is 'email' || config.type is 'tel'
|
||||
if config.type is 'email' || config.type is 'tel' || config.type is 'url'
|
||||
config.type = 'text'
|
||||
if config.tag is 'select'
|
||||
config.multiple = true
|
||||
@@ -258,6 +258,11 @@ class App.UiElement.ApplicationSelector
|
||||
@saveParams(item)
|
||||
)
|
||||
|
||||
# change pre-condition selector
|
||||
item.off('change.application_selector', '.js-preCondition select').on('change.application_selector', '.js-preCondition select', =>
|
||||
@saveParams(item)
|
||||
)
|
||||
|
||||
# change attribute value
|
||||
item.off('change.application_selector keyup.application_selector', '.js-value .form-control').on('change.application_selector keyup.application_selector', '.js-value .form-control', =>
|
||||
@saveParams(item)
|
||||
|
||||
@@ -157,7 +157,7 @@ class App.UiElement.core_workflow_condition extends App.UiElement.ApplicationSel
|
||||
# ignore passwords and relations
|
||||
if config.type isnt 'password' && config.name.substr(config.name.length-4,4) isnt '_ids' && config.searchable isnt false
|
||||
config.default = undefined
|
||||
if config.type is 'email' || config.type is 'tel'
|
||||
if config.type is 'email' || config.type is 'tel' || config.type is 'url'
|
||||
config.type = 'text'
|
||||
if config.tag.match(/^(tree_)?select$/)
|
||||
config.multiple = true
|
||||
|
||||
@@ -274,6 +274,11 @@ class App.UiElement.ticket_selector extends App.UiElement.ApplicationSelector
|
||||
@saveParams(item, params, attribute)
|
||||
)
|
||||
|
||||
# change pre-condition selector
|
||||
item.off('change.application_selector', '.js-preCondition select').on('change.application_selector', '.js-preCondition select', =>
|
||||
@saveParams(item, params, attribute)
|
||||
)
|
||||
|
||||
# change attribute value
|
||||
item.off('change.application_selector keyup.application_selector', '.js-value .form-control').on('change.application_selector keyup.application_selector', '.js-value .form-control', =>
|
||||
@saveParams(item, params, attribute)
|
||||
@@ -765,6 +770,8 @@ class App.UiElement.ticket_selector extends App.UiElement.ApplicationSelector
|
||||
value.value = element.find('.js-value .js-objectId').val()
|
||||
else if element.find('.js-value .js-shadow')?.val()
|
||||
value.value = element.find('.js-value .js-shadow').val()
|
||||
else if element.find('.js-value input.form-control')?.val()
|
||||
value.value = element.find('.js-value input.form-control').val()
|
||||
else if element.find('.js-value .form-control')?.val()
|
||||
value.value = element.find('.js-value .form-control').val()
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
# coffeelint: disable=camel_case_classes
|
||||
class App.UiElement.ticket_selector_simple extends App.UiElement.ApplicationSelector
|
||||
@@ -2,8 +2,6 @@ class App.OrganizationProfile extends App.Controller
|
||||
constructor: (params) ->
|
||||
super
|
||||
|
||||
@authenticateCheckRedirect()
|
||||
|
||||
# fetch new data if needed
|
||||
App.Organization.full(@organization_id, @render)
|
||||
|
||||
@@ -45,18 +43,18 @@ class App.OrganizationProfile extends App.Controller
|
||||
organization: organization
|
||||
))
|
||||
|
||||
new Organization(
|
||||
new App.OrganizationProfileOrganization(
|
||||
object_id: organization.id
|
||||
el: elLocal.find('.js-name')
|
||||
)
|
||||
|
||||
new Object(
|
||||
new App.OrganizationProfileObject(
|
||||
el: elLocal.find('.js-object-container')
|
||||
object_id: organization.id
|
||||
taskKey: @taskKey
|
||||
)
|
||||
|
||||
new ActionRow(
|
||||
new App.OrganizationProfileActionRow(
|
||||
el: elLocal.find('.js-action')
|
||||
object_id: organization.id
|
||||
)
|
||||
@@ -78,169 +76,14 @@ class App.OrganizationProfile extends App.Controller
|
||||
currentPosition: =>
|
||||
@$('.profile').scrollTop()
|
||||
|
||||
class ActionRow extends App.ControllerObserverActionRow
|
||||
model: 'Organization'
|
||||
observe:
|
||||
member_ids: true
|
||||
|
||||
showHistory: (organization) =>
|
||||
new App.OrganizationHistory(
|
||||
organization_id: organization.id
|
||||
container: @el.closest('.content')
|
||||
)
|
||||
|
||||
editOrganization: (organization) =>
|
||||
new App.ControllerGenericEdit(
|
||||
id: organization.id
|
||||
genericObject: 'Organization'
|
||||
screen: 'edit'
|
||||
pageData:
|
||||
title: __('Organizations')
|
||||
object: __('Organization')
|
||||
objects: __('Organizations')
|
||||
container: @el.closest('.content')
|
||||
)
|
||||
|
||||
actions: (organization) =>
|
||||
actions = [
|
||||
{
|
||||
name: 'history'
|
||||
title: __('History')
|
||||
callback: @showHistory
|
||||
}
|
||||
]
|
||||
|
||||
if organization.isAccessibleBy(App.User.current(), 'change')
|
||||
actions.unshift {
|
||||
name: 'edit'
|
||||
title: __('Edit')
|
||||
callback: @editOrganization
|
||||
}
|
||||
|
||||
actions
|
||||
|
||||
class Object extends App.ControllerObserver
|
||||
memberLimit: 10
|
||||
model: 'Organization'
|
||||
observe:
|
||||
member_ids: true
|
||||
observeNot:
|
||||
cid: true
|
||||
created_at: true
|
||||
created_by_id: true
|
||||
updated_at: true
|
||||
updated_by_id: true
|
||||
preferences: true
|
||||
source: true
|
||||
image_source: true
|
||||
|
||||
events:
|
||||
'click .js-showMoreMembers': 'showMoreMembers'
|
||||
'focusout [contenteditable]': 'update'
|
||||
|
||||
showMoreMembers: (e) ->
|
||||
@preventDefaultAndStopPropagation(e)
|
||||
@memberLimit = (parseInt(@memberLimit / 100) + 1) * 100
|
||||
@renderMembers()
|
||||
|
||||
renderMembers: ->
|
||||
elLocal = @el
|
||||
@organization.members(0, @memberLimit, (users) ->
|
||||
members = []
|
||||
for user in users
|
||||
el = $('<div></div>')
|
||||
new Member(
|
||||
object_id: user.id
|
||||
el: el
|
||||
)
|
||||
members.push el
|
||||
elLocal.find('.js-userList').html(members)
|
||||
)
|
||||
|
||||
if @organization.member_ids.length <= @memberLimit
|
||||
@el.find('.js-showMoreMembers').parent().addClass('hidden')
|
||||
else
|
||||
@el.find('.js-showMoreMembers').parent().removeClass('hidden')
|
||||
|
||||
render: (organization) =>
|
||||
if organization
|
||||
@organization = organization
|
||||
|
||||
# update taskbar with new meta data
|
||||
App.TaskManager.touch(@taskKey)
|
||||
|
||||
# get display data
|
||||
organizationData = []
|
||||
for attributeName, attributeConfig of App.Organization.attributesGet('view')
|
||||
|
||||
# check if value for _id exists
|
||||
name = attributeName
|
||||
nameNew = name.substr(0, name.length - 3)
|
||||
if nameNew of @organization
|
||||
name = nameNew
|
||||
|
||||
# add to show if value exists
|
||||
if (@organization[name] || attributeConfig.tag is 'richtext') && attributeConfig.shown
|
||||
|
||||
# do not show firstname and lastname / already show via diplayName()
|
||||
if name isnt 'name'
|
||||
organizationData.push attributeConfig
|
||||
|
||||
elLocal = $(App.view('organization_profile/object')(
|
||||
organization: @organization
|
||||
organizationData: organizationData
|
||||
))
|
||||
|
||||
@html elLocal
|
||||
|
||||
@renderMembers()
|
||||
|
||||
@$('[contenteditable]').ce({
|
||||
mode: 'textonly'
|
||||
multiline: true
|
||||
maxlength: 250
|
||||
})
|
||||
|
||||
update: (e) =>
|
||||
name = $(e.target).attr('data-name')
|
||||
value = $(e.target).html()
|
||||
org = App.Organization.find(@object_id)
|
||||
if org[name] isnt value
|
||||
@lastAttributes[name] = value
|
||||
data = {}
|
||||
data[name] = value
|
||||
org.updateAttributes(data)
|
||||
@log 'debug', 'update', name, value, org
|
||||
|
||||
class Organization extends App.ControllerObserver
|
||||
model: 'Organization'
|
||||
observe:
|
||||
name: true
|
||||
|
||||
render: (organization) =>
|
||||
@html App.Utils.htmlEscape(organization.displayName())
|
||||
|
||||
class Member extends App.ControllerObserver
|
||||
model: 'User'
|
||||
observe:
|
||||
firstname: true
|
||||
lastname: true
|
||||
login: true
|
||||
email: true
|
||||
active: true
|
||||
image: true
|
||||
globalRerender: false
|
||||
|
||||
render: (user) =>
|
||||
@html App.view('organization_profile/member')(
|
||||
user: user
|
||||
)
|
||||
|
||||
class Router extends App.ControllerPermanent
|
||||
requiredPermission: 'ticket.agent'
|
||||
constructor: (params) ->
|
||||
super
|
||||
|
||||
# check authentication
|
||||
@authenticateCheckRedirect()
|
||||
|
||||
# cleanup params
|
||||
clean_params =
|
||||
organization_id: params.organization_id
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
class App.OrganizationProfileActionRow extends App.ControllerObserverActionRow
|
||||
model: 'Organization'
|
||||
observe:
|
||||
member_ids: true
|
||||
|
||||
showHistory: (organization) =>
|
||||
new App.OrganizationHistory(
|
||||
organization_id: organization.id
|
||||
container: @el.closest('.content')
|
||||
)
|
||||
|
||||
editOrganization: (organization) =>
|
||||
new App.ControllerGenericEdit(
|
||||
id: organization.id
|
||||
genericObject: 'Organization'
|
||||
screen: 'edit'
|
||||
pageData:
|
||||
title: __('Organizations')
|
||||
object: __('Organization')
|
||||
objects: __('Organizations')
|
||||
container: @el.closest('.content')
|
||||
)
|
||||
|
||||
actions: (organization) =>
|
||||
actions = [
|
||||
{
|
||||
name: 'history'
|
||||
title: __('History')
|
||||
callback: @showHistory
|
||||
}
|
||||
]
|
||||
|
||||
if organization.isAccessibleBy(App.User.current(), 'change')
|
||||
actions.unshift {
|
||||
name: 'edit'
|
||||
title: __('Edit')
|
||||
callback: @editOrganization
|
||||
}
|
||||
|
||||
actions
|
||||
@@ -0,0 +1,15 @@
|
||||
class App.OrganizationProfileMember extends App.ControllerObserver
|
||||
model: 'User'
|
||||
observe:
|
||||
firstname: true
|
||||
lastname: true
|
||||
login: true
|
||||
email: true
|
||||
active: true
|
||||
image: true
|
||||
globalRerender: false
|
||||
|
||||
render: (user) =>
|
||||
@html App.view('organization_profile/member')(
|
||||
user: user
|
||||
)
|
||||
@@ -0,0 +1,92 @@
|
||||
class App.OrganizationProfileObject extends App.ControllerObserver
|
||||
memberLimit: 10
|
||||
model: 'Organization'
|
||||
observe:
|
||||
member_ids: true
|
||||
observeNot:
|
||||
cid: true
|
||||
created_at: true
|
||||
created_by_id: true
|
||||
updated_at: true
|
||||
updated_by_id: true
|
||||
preferences: true
|
||||
source: true
|
||||
image_source: true
|
||||
|
||||
events:
|
||||
'click .js-showMoreMembers': 'showMoreMembers'
|
||||
'focusout [contenteditable]': 'update'
|
||||
|
||||
showMoreMembers: (e) ->
|
||||
@preventDefaultAndStopPropagation(e)
|
||||
@memberLimit = (parseInt(@memberLimit / 100) + 1) * 100
|
||||
@renderMembers()
|
||||
|
||||
renderMembers: ->
|
||||
elLocal = @el
|
||||
@organization.members(0, @memberLimit, (users) ->
|
||||
members = []
|
||||
for user in users
|
||||
el = $('<div></div>')
|
||||
new App.OrganizationProfileMember(
|
||||
object_id: user.id
|
||||
el: el
|
||||
)
|
||||
members.push el
|
||||
elLocal.find('.js-userList').html(members)
|
||||
)
|
||||
|
||||
if @organization.member_ids.length <= @memberLimit
|
||||
@el.find('.js-showMoreMembers').parent().addClass('hidden')
|
||||
else
|
||||
@el.find('.js-showMoreMembers').parent().removeClass('hidden')
|
||||
|
||||
render: (organization) =>
|
||||
if organization
|
||||
@organization = organization
|
||||
|
||||
# update taskbar with new meta data
|
||||
App.TaskManager.touch(@taskKey)
|
||||
|
||||
# get display data
|
||||
organizationData = []
|
||||
for attributeName, attributeConfig of App.Organization.attributesGet('view')
|
||||
|
||||
# check if value for _id exists
|
||||
name = attributeName
|
||||
nameNew = name.substr(0, name.length - 3)
|
||||
if nameNew of @organization
|
||||
name = nameNew
|
||||
|
||||
# add to show if value exists
|
||||
if (@organization[name] || attributeConfig.tag is 'richtext') && attributeConfig.shown
|
||||
|
||||
# do not show firstname and lastname / already show via diplayName()
|
||||
if name isnt 'name'
|
||||
organizationData.push attributeConfig
|
||||
|
||||
elLocal = $(App.view('organization_profile/object')(
|
||||
organization: @organization
|
||||
organizationData: organizationData
|
||||
))
|
||||
|
||||
@html elLocal
|
||||
|
||||
@renderMembers()
|
||||
|
||||
@$('[contenteditable]').ce({
|
||||
mode: 'textonly'
|
||||
multiline: true
|
||||
maxlength: 250
|
||||
})
|
||||
|
||||
update: (e) =>
|
||||
name = $(e.target).attr('data-name')
|
||||
value = $(e.target).html()
|
||||
org = App.Organization.find(@object_id)
|
||||
if org[name] isnt value
|
||||
@lastAttributes[name] = value
|
||||
data = {}
|
||||
data[name] = value
|
||||
org.updateAttributes(data)
|
||||
@log 'debug', 'update', name, value, org
|
||||
@@ -0,0 +1,7 @@
|
||||
class App.OrganizationProfileOrganization extends App.ControllerObserver
|
||||
model: 'Organization'
|
||||
observe:
|
||||
name: true
|
||||
|
||||
render: (organization) =>
|
||||
@html App.Utils.htmlEscape(organization.displayName())
|
||||
@@ -17,9 +17,6 @@ class App.Search extends App.Controller
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
# check authentication
|
||||
@authenticateCheckRedirect()
|
||||
|
||||
current = App.TaskManager.get(@taskKey).state
|
||||
if current && current.query
|
||||
@query = current.query
|
||||
@@ -352,9 +349,14 @@ class App.Search extends App.Controller
|
||||
@savedOrderBy[model] = { order: table.lastOrderBy, direction: table.lastOrderDirection }
|
||||
|
||||
class Router extends App.ControllerPermanent
|
||||
requiredPermission: ['*']
|
||||
|
||||
constructor: (params) ->
|
||||
super
|
||||
|
||||
# check authentication
|
||||
@authenticateCheckRedirect()
|
||||
|
||||
query = undefined
|
||||
if !_.isEmpty(params.query)
|
||||
query = decodeURIComponent(params.query)
|
||||
|
||||
@@ -17,9 +17,6 @@ class App.TicketZoom extends App.Controller
|
||||
constructor: (params) ->
|
||||
super
|
||||
|
||||
# check authentication
|
||||
@authenticateCheckRedirect()
|
||||
|
||||
@formMeta = undefined
|
||||
@ticket_id = parseInt(params.ticket_id)
|
||||
@article_id = params.article_id
|
||||
@@ -746,9 +743,21 @@ class App.TicketZoom extends App.Controller
|
||||
if currentParams.ticket
|
||||
@formDiffSimplifyEmptyValues(currentParams)
|
||||
|
||||
articleDiff = @forRemoveMeta(App.Utils.formDiff(currentParams.article, currentStore.article))
|
||||
|
||||
if articleDiff.type
|
||||
articleDiff.internal = currentParams.article.internal
|
||||
|
||||
articleDiffKeys = _.keys(articleDiff)
|
||||
contentKeys = _.difference(articleDiffKeys, ['type', 'internal'])
|
||||
|
||||
if _.isEmpty(contentKeys)
|
||||
delete articleDiff.type
|
||||
delete articleDiff.internal
|
||||
|
||||
{
|
||||
ticket: @forRemoveMeta(App.Utils.formDiff(currentParams.ticket, currentStore.ticket))
|
||||
article: @forRemoveMeta(App.Utils.formDiff(currentParams.article, currentStore.article))
|
||||
article: articleDiff
|
||||
}
|
||||
|
||||
formDiffSimplifyEmptyValues: (params) ->
|
||||
@@ -1230,6 +1239,9 @@ class TicketZoomRouter extends App.ControllerPermanent
|
||||
constructor: (params) ->
|
||||
super
|
||||
|
||||
# check authentication
|
||||
@authenticateCheckRedirect()
|
||||
|
||||
return @byNumber(params) if params.ticket_number
|
||||
@byTicketId(params)
|
||||
|
||||
|
||||
@@ -185,6 +185,9 @@ class App.TicketZoomArticleNew extends App.Controller
|
||||
@setArticleTypePre(@type)
|
||||
@setArticleTypePost(@type)
|
||||
|
||||
if @defaults.internal != undefined
|
||||
@setArticleInternal(@defaults.internal)
|
||||
|
||||
new App.WidgetAvatar(
|
||||
el: @$('.js-avatar')
|
||||
object_id: App.Session.get('id')
|
||||
@@ -347,6 +350,8 @@ class App.TicketZoomArticleNew extends App.Controller
|
||||
else
|
||||
@setArticleInternal(false)
|
||||
|
||||
@textarea.trigger('change.local')
|
||||
|
||||
showSelectableArticleType: (event) =>
|
||||
event.stopPropagation()
|
||||
@el.find('.js-articleTypes').removeClass('is-hidden')
|
||||
|
||||
@@ -103,7 +103,7 @@ class TimeAccounting extends App.ControllerSubContent
|
||||
)
|
||||
|
||||
configure_attributes = [
|
||||
{ name: 'condition', display: __('Conditions for affected objects'), tag: 'ticket_selector', null: false, preview: false, action: false, hasChanged: false },
|
||||
{ name: 'condition', display: __('Conditions for affected objects'), tag: 'ticket_selector_simple', null: false, preview: false, action: false, hasChanged: false },
|
||||
]
|
||||
|
||||
filter_params = App.Setting.get('time_accounting_selector')
|
||||
|
||||
@@ -46,18 +46,18 @@ class App.UserProfile extends App.Controller
|
||||
user: user
|
||||
))
|
||||
|
||||
new User(
|
||||
new App.UserProfileUser(
|
||||
object_id: user.id
|
||||
el: elLocal.find('.js-profileName')
|
||||
)
|
||||
|
||||
new Object(
|
||||
new App.UserProfileObject(
|
||||
el: elLocal.find('.js-object-container')
|
||||
object_id: user.id
|
||||
taskKey: @taskKey
|
||||
)
|
||||
|
||||
new ActionRow(
|
||||
new App.UserProfileActionRow(
|
||||
el: elLocal.find('.js-action')
|
||||
object_id: user.id
|
||||
)
|
||||
@@ -79,215 +79,6 @@ class App.UserProfile extends App.Controller
|
||||
currentPosition: =>
|
||||
@$('.profile').scrollTop()
|
||||
|
||||
class ActionRow extends App.ControllerObserverActionRow
|
||||
model: 'User'
|
||||
observe:
|
||||
verified: true
|
||||
source: true
|
||||
organization_id: true
|
||||
|
||||
showHistory: (user) =>
|
||||
new App.UserHistory(
|
||||
user_id: user.id
|
||||
container: @el.closest('.content')
|
||||
)
|
||||
|
||||
editUser: (user) =>
|
||||
user.secondaryOrganizations(0, 1000, =>
|
||||
new App.ControllerGenericEdit(
|
||||
id: user.id
|
||||
genericObject: 'User'
|
||||
screen: 'edit'
|
||||
pageData:
|
||||
title: __('Users')
|
||||
object: __('User')
|
||||
objects: __('Users')
|
||||
container: @el.closest('.content')
|
||||
)
|
||||
)
|
||||
|
||||
newTicket: (user) =>
|
||||
@navigate("ticket/create/customer/#{user.id}")
|
||||
|
||||
resendVerificationEmail: (user) =>
|
||||
@ajax(
|
||||
id: 'email_verify_send'
|
||||
type: 'POST'
|
||||
url: @apiPath + '/users/email_verify_send'
|
||||
data: JSON.stringify(email: user.email)
|
||||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
@notify
|
||||
type: 'success'
|
||||
msg: App.i18n.translateContent('Email sent to "%s". Please let the user verify their email account.', user.email)
|
||||
removeAll: true
|
||||
error: (data, status, xhr) =>
|
||||
@notify
|
||||
type: 'error'
|
||||
msg: App.i18n.translateContent('Failed to send email to "%s". Please contact an administrator.', user.email)
|
||||
removeAll: true
|
||||
)
|
||||
|
||||
actions: (user) =>
|
||||
actions = [
|
||||
{
|
||||
name: 'history'
|
||||
title: __('History')
|
||||
callback: @showHistory
|
||||
}
|
||||
{
|
||||
name: 'ticket'
|
||||
title: __('New Ticket')
|
||||
callback: @newTicket
|
||||
}
|
||||
]
|
||||
|
||||
if user.isAccessibleBy(App.User.current(), 'change')
|
||||
actions.unshift {
|
||||
name: 'edit'
|
||||
title: __('Edit')
|
||||
callback: @editUser
|
||||
}
|
||||
|
||||
if user.verified isnt true && user.source is 'signup'
|
||||
actions.push({
|
||||
name: 'resend_verification_email'
|
||||
title: __('Resend verification email')
|
||||
callback: @resendVerificationEmail
|
||||
})
|
||||
|
||||
if @permissionCheck('admin.data_privacy')
|
||||
actions.push {
|
||||
title: __('Delete')
|
||||
name: 'delete'
|
||||
callback: =>
|
||||
@navigate "#system/data_privacy/#{user.id}"
|
||||
}
|
||||
|
||||
actions
|
||||
|
||||
class Object extends App.ControllerObserver
|
||||
organizationLimit: 3
|
||||
|
||||
model: 'User'
|
||||
observeNot:
|
||||
cid: true
|
||||
created_at: true
|
||||
created_by_id: true
|
||||
updated_at: true
|
||||
updated_by_id: true
|
||||
preferences: true
|
||||
password: true
|
||||
last_login: true
|
||||
login_failed: true
|
||||
source: true
|
||||
image_source: true
|
||||
|
||||
events:
|
||||
'click .js-showMoreOrganizations a': 'showMoreOrganizations'
|
||||
'focusout [contenteditable]': 'update'
|
||||
|
||||
render: (user) =>
|
||||
if user
|
||||
@user = user
|
||||
|
||||
# update taskbar with new meta data
|
||||
App.TaskManager.touch(@taskKey)
|
||||
|
||||
# get display data
|
||||
userData = []
|
||||
for attributeName, attributeConfig of App.User.attributesGet('view')
|
||||
|
||||
# check if value for _id exists
|
||||
name = attributeName
|
||||
nameNew = name.substr(0, name.length - 3)
|
||||
if nameNew of user
|
||||
name = nameNew
|
||||
|
||||
# add to show if value exists
|
||||
if (user[name] || attributeConfig.tag is 'richtext') && attributeConfig.shown
|
||||
|
||||
# do not show firstname and lastname / already show via diplayName()
|
||||
if name isnt 'firstname' && name isnt 'lastname' && name isnt 'organization'
|
||||
userData.push attributeConfig
|
||||
|
||||
@html App.view('user_profile/object')(
|
||||
user: user
|
||||
userData: userData
|
||||
)
|
||||
@renderOrganizations()
|
||||
|
||||
@$('[contenteditable]').ce({
|
||||
mode: 'textonly'
|
||||
multiline: true
|
||||
maxlength: 250
|
||||
})
|
||||
|
||||
showMoreOrganizations: (e) ->
|
||||
@preventDefaultAndStopPropagation(e)
|
||||
@organizationLimit = (parseInt(@organizationLimit / 100) + 1) * 100
|
||||
@renderOrganizations()
|
||||
|
||||
renderOrganizations: ->
|
||||
elLocal = @el
|
||||
@user.secondaryOrganizations(0, @organizationLimit, (secondaryOrganizations) ->
|
||||
organizations = []
|
||||
for organization in secondaryOrganizations
|
||||
el = $('<li></li>')
|
||||
new Organization(
|
||||
object_id: organization.id
|
||||
el: el
|
||||
)
|
||||
organizations.push el
|
||||
|
||||
elLocal.find('.js-organizationList li').not('.js-showMoreOrganizations').remove()
|
||||
elLocal.find('.js-organizationList').prepend(organizations)
|
||||
)
|
||||
|
||||
if @user.organization_ids && @user.organization_ids.length < @organizationLimit
|
||||
@el.find('.js-showMoreOrganizations').addClass('hidden')
|
||||
else
|
||||
@el.find('.js-showMoreOrganizations').removeClass('hidden')
|
||||
|
||||
update: (e) =>
|
||||
name = $(e.target).attr('data-name')
|
||||
value = $(e.target).html()
|
||||
user = App.User.find(@object_id)
|
||||
if user[name] isnt value
|
||||
@lastAttributes[name] = value
|
||||
data = {}
|
||||
data[name] = value
|
||||
user.updateAttributes(data)
|
||||
@log 'debug', 'update', name, value, user
|
||||
|
||||
class Organization extends App.ControllerObserver
|
||||
model: 'Organization'
|
||||
observe:
|
||||
name: true
|
||||
|
||||
render: (organization) =>
|
||||
@html App.view('user_profile/organization')(
|
||||
organization: organization
|
||||
)
|
||||
|
||||
class User extends App.ControllerObserver
|
||||
model: 'User'
|
||||
observe:
|
||||
firstname: true
|
||||
lastname: true
|
||||
organization_id: true
|
||||
image: true
|
||||
|
||||
render: (user) =>
|
||||
if user.organization_id
|
||||
new Organization(
|
||||
object_id: user.organization_id
|
||||
el: @el.siblings('.js-organization')
|
||||
)
|
||||
|
||||
@html App.view('user_profile/name')(
|
||||
user: user
|
||||
)
|
||||
|
||||
class Router extends App.ControllerPermanent
|
||||
requiredPermission: 'ticket.agent'
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
class App.UserProfileActionRow extends App.ControllerObserverActionRow
|
||||
model: 'User'
|
||||
observe:
|
||||
verified: true
|
||||
source: true
|
||||
organization_id: true
|
||||
|
||||
showHistory: (user) =>
|
||||
new App.UserHistory(
|
||||
user_id: user.id
|
||||
container: @el.closest('.content')
|
||||
)
|
||||
|
||||
editUser: (user) =>
|
||||
user.secondaryOrganizations(0, 1000, =>
|
||||
new App.ControllerGenericEdit(
|
||||
id: user.id
|
||||
genericObject: 'User'
|
||||
screen: 'edit'
|
||||
pageData:
|
||||
title: __('Users')
|
||||
object: __('User')
|
||||
objects: __('Users')
|
||||
container: @el.closest('.content')
|
||||
)
|
||||
)
|
||||
|
||||
newTicket: (user) =>
|
||||
@navigate("ticket/create/customer/#{user.id}")
|
||||
|
||||
resendVerificationEmail: (user) =>
|
||||
@ajax(
|
||||
id: 'email_verify_send'
|
||||
type: 'POST'
|
||||
url: @apiPath + '/users/email_verify_send'
|
||||
data: JSON.stringify(email: user.email)
|
||||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
@notify
|
||||
type: 'success'
|
||||
msg: App.i18n.translateContent('Email sent to "%s". Please let the user verify their email account.', user.email)
|
||||
removeAll: true
|
||||
error: (data, status, xhr) =>
|
||||
@notify
|
||||
type: 'error'
|
||||
msg: App.i18n.translateContent('Failed to send email to "%s". Please contact an administrator.', user.email)
|
||||
removeAll: true
|
||||
)
|
||||
|
||||
actions: (user) =>
|
||||
actions = [
|
||||
{
|
||||
name: 'history'
|
||||
title: __('History')
|
||||
callback: @showHistory
|
||||
}
|
||||
{
|
||||
name: 'ticket'
|
||||
title: __('New Ticket')
|
||||
callback: @newTicket
|
||||
}
|
||||
]
|
||||
|
||||
if user.isAccessibleBy(App.User.current(), 'change')
|
||||
actions.unshift {
|
||||
name: 'edit'
|
||||
title: __('Edit')
|
||||
callback: @editUser
|
||||
}
|
||||
|
||||
if user.verified isnt true && user.source is 'signup'
|
||||
actions.push({
|
||||
name: 'resend_verification_email'
|
||||
title: __('Resend verification email')
|
||||
callback: @resendVerificationEmail
|
||||
})
|
||||
|
||||
if @permissionCheck('admin.data_privacy')
|
||||
actions.push {
|
||||
title: __('Delete')
|
||||
name: 'delete'
|
||||
callback: =>
|
||||
@navigate "#system/data_privacy/#{user.id}"
|
||||
}
|
||||
|
||||
actions
|
||||
@@ -0,0 +1,93 @@
|
||||
class App.UserProfileObject extends App.ControllerObserver
|
||||
organizationLimit: 3
|
||||
|
||||
model: 'User'
|
||||
observeNot:
|
||||
cid: true
|
||||
created_at: true
|
||||
created_by_id: true
|
||||
updated_at: true
|
||||
updated_by_id: true
|
||||
preferences: true
|
||||
password: true
|
||||
last_login: true
|
||||
login_failed: true
|
||||
source: true
|
||||
image_source: true
|
||||
|
||||
events:
|
||||
'click .js-showMoreOrganizations a': 'showMoreOrganizations'
|
||||
'focusout [contenteditable]': 'update'
|
||||
|
||||
render: (user) =>
|
||||
if user
|
||||
@user = user
|
||||
|
||||
# update taskbar with new meta data
|
||||
App.TaskManager.touch(@taskKey)
|
||||
|
||||
# get display data
|
||||
userData = []
|
||||
for attributeName, attributeConfig of App.User.attributesGet('view')
|
||||
|
||||
# check if value for _id exists
|
||||
name = attributeName
|
||||
nameNew = name.substr(0, name.length - 3)
|
||||
if nameNew of user
|
||||
name = nameNew
|
||||
|
||||
# add to show if value exists
|
||||
if (user[name] || attributeConfig.tag is 'richtext') && attributeConfig.shown
|
||||
|
||||
# do not show firstname and lastname / already show via diplayName()
|
||||
if name isnt 'firstname' && name isnt 'lastname' && name isnt 'organization'
|
||||
userData.push attributeConfig
|
||||
|
||||
@html App.view('user_profile/object')(
|
||||
user: user
|
||||
userData: userData
|
||||
)
|
||||
@renderOrganizations()
|
||||
|
||||
@$('[contenteditable]').ce({
|
||||
mode: 'textonly'
|
||||
multiline: true
|
||||
maxlength: 250
|
||||
})
|
||||
|
||||
showMoreOrganizations: (e) ->
|
||||
@preventDefaultAndStopPropagation(e)
|
||||
@organizationLimit = (parseInt(@organizationLimit / 100) + 1) * 100
|
||||
@renderOrganizations()
|
||||
|
||||
renderOrganizations: ->
|
||||
elLocal = @el
|
||||
@user.secondaryOrganizations(0, @organizationLimit, (secondaryOrganizations) ->
|
||||
organizations = []
|
||||
for organization in secondaryOrganizations
|
||||
el = $('<li></li>')
|
||||
new App.UserProfileOrganization(
|
||||
object_id: organization.id
|
||||
el: el
|
||||
)
|
||||
organizations.push el
|
||||
|
||||
elLocal.find('.js-organizationList li').not('.js-showMoreOrganizations').remove()
|
||||
elLocal.find('.js-organizationList').prepend(organizations)
|
||||
)
|
||||
|
||||
if @user.organization_ids && @user.organization_ids.length < @organizationLimit
|
||||
@el.find('.js-showMoreOrganizations').addClass('hidden')
|
||||
else
|
||||
@el.find('.js-showMoreOrganizations').removeClass('hidden')
|
||||
|
||||
update: (e) =>
|
||||
name = $(e.target).attr('data-name')
|
||||
value = $(e.target).html()
|
||||
user = App.User.find(@object_id)
|
||||
if user[name] isnt value
|
||||
@lastAttributes[name] = value
|
||||
data = {}
|
||||
data[name] = value
|
||||
user.updateAttributes(data)
|
||||
@log 'debug', 'update', name, value, user
|
||||
@@ -0,0 +1,9 @@
|
||||
class App.UserProfileOrganization extends App.ControllerObserver
|
||||
model: 'Organization'
|
||||
observe:
|
||||
name: true
|
||||
|
||||
render: (organization) =>
|
||||
@html App.view('user_profile/organization')(
|
||||
organization: organization
|
||||
)
|
||||
@@ -0,0 +1,18 @@
|
||||
class App.UserProfileUser extends App.ControllerObserver
|
||||
model: 'User'
|
||||
observe:
|
||||
firstname: true
|
||||
lastname: true
|
||||
organization_id: true
|
||||
image: true
|
||||
|
||||
render: (user) =>
|
||||
if user.organization_id
|
||||
new App.UserProfileOrganization(
|
||||
object_id: user.organization_id
|
||||
el: @el.siblings('.js-organization')
|
||||
)
|
||||
|
||||
@html App.view('user_profile/name')(
|
||||
user: user
|
||||
)
|
||||
@@ -404,4 +404,4 @@ class Modal extends App.ControllerModal
|
||||
head: __('Lost network connection!')
|
||||
|
||||
content: ->
|
||||
__('Trying to reconnect…')
|
||||
App.i18n.translateInline('Trying to reconnect…')
|
||||
|
||||
1768
app/assets/javascripts/app/lib/base/ua-parser.js
vendored
1768
app/assets/javascripts/app/lib/base/ua-parser.js
vendored
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,7 @@ class App.Model extends Spine.Model
|
||||
@constructor.className
|
||||
|
||||
displayName: ->
|
||||
return @name || '???'
|
||||
return @name || '-'
|
||||
|
||||
# shows the icon representing the object itself (e. g. the organization icon in organization profile or ticket sidebar)
|
||||
icon: (user) ->
|
||||
|
||||
@@ -17,5 +17,5 @@ class App.Channel extends App.Model
|
||||
else
|
||||
name += " (#{@options.outbound.adapter})"
|
||||
if name == ''
|
||||
name = '???'
|
||||
name = '-'
|
||||
name
|
||||
@@ -5,6 +5,8 @@ class App.EmailAddress extends App.Model
|
||||
|
||||
displayName: ->
|
||||
if @realname
|
||||
# Do not use App.Utils.buildEmailAddress here because we don't build an email address and the
|
||||
# quoting would confuse sorting in the GUI.
|
||||
return "#{@realname} <#{@email}>"
|
||||
@email
|
||||
|
||||
|
||||
@@ -389,4 +389,4 @@ class App.Ticket extends App.Model
|
||||
attrs
|
||||
|
||||
displayName: ->
|
||||
return @title || '???'
|
||||
return @title || '-'
|
||||
|
||||
@@ -32,7 +32,7 @@ class App.TicketArticle extends App.Model
|
||||
ticket = App.Ticket.findNative(@ticket_id)
|
||||
if ticket
|
||||
return ticket.title
|
||||
'???'
|
||||
'-'
|
||||
|
||||
iconActivity: (user) ->
|
||||
return if !user
|
||||
|
||||
@@ -416,10 +416,6 @@ class App.User extends App.Model
|
||||
@current: App.Session.get
|
||||
|
||||
displayName: ->
|
||||
if @realname
|
||||
# Do not use App.Utils.buildEmailAddress here because we don't build an email address and the
|
||||
# quoting would confuse sorting in the GUI.
|
||||
return "#{@realname} <#{@email}>"
|
||||
if !_.isEmpty(@firstname)
|
||||
name = @firstname
|
||||
if !_.isEmpty(@lastname)
|
||||
@@ -435,7 +431,7 @@ class App.User extends App.Model
|
||||
return @phone
|
||||
if @login
|
||||
return @login
|
||||
return '???'
|
||||
return '-'
|
||||
|
||||
displayNameLong: ->
|
||||
if !_.isEmpty(@firstname)
|
||||
@@ -461,4 +457,4 @@ class App.User extends App.Model
|
||||
return @phone
|
||||
if @login
|
||||
return @login
|
||||
return '???'
|
||||
return '-'
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
</div>
|
||||
<div class="wizard-controls center">
|
||||
<a class="btn btn--text btn--secondary" href="#getting_started/base"><%- @T('Go Back') %></a>
|
||||
<a class="btn align-right" href="#getting_started/channel"><%- @T( 'Skip' ) %></a>
|
||||
<button class="btn btn--primary align-right"><%- @T('Continue') %></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<div class="wizard-body vertical justified">
|
||||
<div class="alert alert--danger hide" role="alert"></div>
|
||||
|
||||
<p><%- @T('Please enter the endpoint and select the authentication method for accessing Exchange Web Services.') %></p>
|
||||
<p><%- @T('Please enter the endpoint for accessing Exchange Web Services.') %></p>
|
||||
<table class="settings-list" style="width: 100%;">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
@@ -99,8 +99,8 @@
|
||||
|
||||
<% if !user_show_password_login: %>
|
||||
<p>
|
||||
<%- @T('If you have problems with the third-party login you can request a one-time password login as an admin.') %>
|
||||
<a href="#admin_password_auth"><%- @T('Request the password login here.') %></a>
|
||||
<%- @T('If you have problems with the third-party login you can request a one-time password login as an admin.') %><br>
|
||||
<a class="text-muted" href="#admin_password_auth"><%- @T('Request the password login here.') %></a>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<p>
|
||||
<%- @T('The entered user for reauthentication differs from the user that was used for setting up your Microsoft365 channel initially.') %><br><br>
|
||||
<%- @T('To avoid fetching an incorrect Microsoft365 mailbox, the reauthentication process was aborted.') %><br><br>
|
||||
<%- @T('Please start the reauthentication again and enter the correct credentials.') %>
|
||||
</p>
|
||||
@@ -8,7 +8,6 @@ $mobileNavigationWidthOpen: 220px;
|
||||
|
||||
:root {
|
||||
--button-action-color: hsl(0, 0%, 60%);
|
||||
--button-border: hsla(0, 0%, 0%, 0.1);
|
||||
--button-background: white;
|
||||
--button-background-active: hsl(0, 0, 98%);
|
||||
--button-active: hsl(204, 7%, 28%);
|
||||
@@ -87,7 +86,6 @@ $mobileNavigationWidthOpen: 220px;
|
||||
// dark mode
|
||||
[data-theme='dark'] {
|
||||
--button-action-color: hsl(0, 0%, 80%);
|
||||
--button-border: hsl(230, 4%, 20%);
|
||||
--button-background: hsla(0, 0%, 100%, 0.03);
|
||||
--button-background-active: hsla(0, 0%, 100%, 0.015);
|
||||
--button-active: hsla(0, 0%, 100%, 0.1);
|
||||
@@ -443,14 +441,6 @@ ul {
|
||||
z-index: 1100;
|
||||
}
|
||||
|
||||
.u-high-priority-color {
|
||||
fill: $high-priority-color;
|
||||
}
|
||||
|
||||
.u-low-priority-color {
|
||||
fill: $low-priority-color;
|
||||
}
|
||||
|
||||
.clickCatcher {
|
||||
top: 0;
|
||||
left: 0;
|
||||
@@ -610,7 +600,7 @@ pre code {
|
||||
padding: 10px 24px 9px;
|
||||
color: var(--text-normal);
|
||||
background: var(--button-background);
|
||||
border: 1px solid var(--button-border);
|
||||
border: 1px solid var(--border);
|
||||
outline: none !important;
|
||||
border-radius: 4px;
|
||||
text-align: center;
|
||||
@@ -1198,7 +1188,7 @@ pre code {
|
||||
}
|
||||
|
||||
.status-field {
|
||||
border: 1px solid var(--button-border);
|
||||
border: 1px solid var(--border);
|
||||
background: var(--button-background);
|
||||
display: flex;
|
||||
height: 34px;
|
||||
@@ -2513,6 +2503,10 @@ input.has-error {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.zammad-form-modal-body {
|
||||
background: var(--background-primary) !important;
|
||||
}
|
||||
|
||||
/* use on input[type=radio] */
|
||||
.primary-email-switch {
|
||||
display: none;
|
||||
@@ -3242,6 +3236,10 @@ kbd {
|
||||
|
||||
a {
|
||||
color: var(--text-inverted);
|
||||
|
||||
&.text-muted {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6082,6 +6080,14 @@ a.list-group-item.active > .badge,
|
||||
color: var(--danger-color);
|
||||
}
|
||||
|
||||
.u-high-priority-color {
|
||||
fill: $high-priority-color;
|
||||
}
|
||||
|
||||
.u-low-priority-color {
|
||||
fill: $low-priority-color;
|
||||
}
|
||||
|
||||
.stat-widgets {
|
||||
margin: -7px -7px 20px;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,10 @@ class Integration::SMIMEController < ApplicationController
|
||||
end
|
||||
|
||||
def certificate_list
|
||||
render json: SMIMECertificate.all
|
||||
all = SMIMECertificate.all.map do |cert|
|
||||
cert.attributes.merge({ 'subject_alternative_name' => cert.email_addresses })
|
||||
end
|
||||
render json: all
|
||||
end
|
||||
|
||||
def certificate_delete
|
||||
|
||||
@@ -62,8 +62,12 @@ class SessionsController < ApplicationController
|
||||
ENV['FAKE_SELENIUM_LOGIN_PENDING'] = nil # rubocop:disable Rails/EnvironmentVariableAccess
|
||||
end
|
||||
|
||||
if session['saml_uid'] || session['saml_session_index']
|
||||
return saml_destroy
|
||||
if (session['saml_uid'] || session['saml_session_index']) && SamlDatabase.setup.fetch('idp_slo_service_url', nil)
|
||||
begin
|
||||
return saml_destroy
|
||||
rescue => e
|
||||
Rails.logger.error "SAML SLO failed: #{e.message}"
|
||||
end
|
||||
end
|
||||
|
||||
reset_session
|
||||
|
||||
@@ -1006,23 +1006,26 @@ curl http://localhost/api/v1/users/avatar -v -u #{login}:#{password} -H "Content
|
||||
raise Exceptions::UnprocessableEntity, __("The required parameter 'signup' is missing.")
|
||||
end
|
||||
|
||||
# only allow fixed fields
|
||||
# TODO: https://github.com/zammad/zammad/issues/3295
|
||||
new_params = clean_user_params.slice(:firstname, :lastname, :email, :password)
|
||||
|
||||
# check if user already exists
|
||||
if clean_user_params[:email].blank?
|
||||
if new_params[:email].blank?
|
||||
raise Exceptions::UnprocessableEntity, __('Attribute \'email\' required!')
|
||||
end
|
||||
|
||||
email_taken_by = User.find_by email: clean_user_params[:email].downcase.strip
|
||||
email_taken_by = User.find_by email: new_params[:email].downcase.strip
|
||||
|
||||
result = PasswordPolicy.new(clean_user_params[:password])
|
||||
result = PasswordPolicy.new(new_params[:password])
|
||||
if !result.valid?
|
||||
render json: { error: result.error }, status: :unprocessable_entity
|
||||
return
|
||||
end
|
||||
|
||||
user = User.new(clean_user_params)
|
||||
user.associations_from_param(params)
|
||||
user.role_ids = Role.signup_role_ids
|
||||
user.source = 'signup'
|
||||
user = User.new(new_params)
|
||||
user.role_ids = Role.signup_role_ids
|
||||
user.source = 'signup'
|
||||
|
||||
if email_taken_by # show fake OK response to avoid leaking that email is already in use
|
||||
user.skip_ensure_uniq_email = true
|
||||
|
||||
@@ -8,6 +8,6 @@ export const userDisplayName = (user: Partial<User>): string => {
|
||||
|
||||
return (
|
||||
[fullname, email, phone, login].find((elem) => elem && !isEmpty(elem)) ||
|
||||
'???'
|
||||
'-'
|
||||
)
|
||||
}
|
||||
|
||||
@@ -291,7 +291,9 @@ example
|
||||
msg = nil
|
||||
begin
|
||||
timeout(FETCH_MSG_TIMEOUT) do
|
||||
msg = @imap.fetch(message_id, 'RFC822')[0].attr['RFC822']
|
||||
# https://github.com/zammad/zammad/issues/4589
|
||||
key = options['host'] == 'imap.mail.me.com' ? 'BODY[]' : 'RFC822'
|
||||
msg = @imap.fetch(message_id, key)[0].attr[key]
|
||||
end
|
||||
rescue Timeout::Error => e
|
||||
Rails.logger.error "Unable to fetch email from #{count}/#{count_all} from server (#{options[:host]}/#{options[:user]}): #{e.inspect}"
|
||||
|
||||
@@ -17,8 +17,6 @@ class Organization < ApplicationModel
|
||||
|
||||
include HasTransactionDispatcher
|
||||
|
||||
default_scope { order(:id) }
|
||||
|
||||
has_many :members, class_name: 'User'
|
||||
has_and_belongs_to_many :secondary_members, class_name: 'User'
|
||||
has_many :tickets, class_name: 'Ticket'
|
||||
|
||||
@@ -289,6 +289,7 @@ subsequently in a separate step.
|
||||
end
|
||||
|
||||
# update package state
|
||||
package_db.reload
|
||||
package_db.state = 'installed'
|
||||
package_db.save
|
||||
end
|
||||
@@ -349,18 +350,23 @@ returns
|
||||
Package::Migration.migrate(package['name'], 'reverse')
|
||||
end
|
||||
|
||||
package['files'].each do |file|
|
||||
permission = file['permission'] || '644'
|
||||
content = Base64.decode64(file['content'])
|
||||
_delete_file(file['location'], permission, content)
|
||||
record = Package.find_by(
|
||||
name: package['name'],
|
||||
version: package['version'],
|
||||
)
|
||||
|
||||
if record.state == 'installed'
|
||||
package['files'].each do |file|
|
||||
permission = file['permission'] || '644'
|
||||
content = Base64.decode64(file['content'])
|
||||
_delete_file(file['location'], permission, content)
|
||||
end
|
||||
end
|
||||
|
||||
# delete package
|
||||
if !data[:reinstall]
|
||||
record = Package.find_by(
|
||||
name: package['name'],
|
||||
version: package['version'],
|
||||
)
|
||||
if data[:reinstall]
|
||||
record.update(state: 'uninstalled')
|
||||
else
|
||||
record.destroy
|
||||
end
|
||||
|
||||
|
||||
@@ -834,7 +834,7 @@ perform active triggers on ticket
|
||||
user = User.lookup(id: user_id)
|
||||
|
||||
# verify is condition is matching
|
||||
ticket_count, tickets = Ticket.selectors(trigger.condition, limit: 1, execution_time: true, current_user: user, access: 'ignore', ticket_action: type, ticket_id: ticket.id, article_id: article&.id, changes: item[:changes])
|
||||
ticket_count, tickets = Ticket.selectors(trigger.condition, limit: 1, execution_time: true, current_user: user, access: 'ignore', ticket_action: type, ticket_id: ticket.id, article_id: article&.id, changes: item[:changes], changes_required: true)
|
||||
|
||||
next if ticket_count.blank?
|
||||
next if ticket_count.zero?
|
||||
|
||||
@@ -36,10 +36,10 @@ class Ticket::Article < ApplicationModel
|
||||
belongs_to :origin_by, class_name: 'User', optional: true
|
||||
|
||||
before_validation :check_mentions, on: :create
|
||||
before_save :touch_ticket_if_needed
|
||||
before_create :check_subject, :check_body, :check_message_id_md5
|
||||
before_update :check_subject, :check_body, :check_message_id_md5
|
||||
after_destroy :store_delete, :update_time_units
|
||||
after_commit :ticket_touch, if: :persisted?
|
||||
|
||||
store :preferences
|
||||
|
||||
@@ -387,9 +387,7 @@ returns
|
||||
Ticket::TimeAccounting.update_ticket(ticket)
|
||||
end
|
||||
|
||||
def touch_ticket_if_needed
|
||||
return if !internal_changed?
|
||||
|
||||
ticket&.touch # rubocop:disable Rails/SkipsModelValidations
|
||||
def ticket_touch
|
||||
ticket.touch # rubocop:disable Rails/SkipsModelValidations
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
|
||||
|
||||
class Ticket::Selector::Base
|
||||
attr_accessor :selector, :options
|
||||
attr_accessor :selector, :options, :changed_attributes
|
||||
|
||||
def initialize(selector:, options:)
|
||||
if selector.respond_to?(:permit!)
|
||||
@@ -35,43 +35,63 @@ class Ticket::Selector::Base
|
||||
@selector = result
|
||||
end
|
||||
|
||||
def set_static_conditions # rubocop:disable Metrics/AbcSize
|
||||
return if %i[ticket_id article_id exclude_merged].none? { |key| options[key].present? }
|
||||
def set_static_conditions
|
||||
conditions = static_conditions_ticket + static_conditions_article + static_conditions_merged + static_conditions_ticket_update
|
||||
return if conditions.blank?
|
||||
|
||||
new_selector = {
|
||||
@selector = {
|
||||
operator: 'AND',
|
||||
conditions: []
|
||||
conditions: conditions + [@selector]
|
||||
}
|
||||
end
|
||||
|
||||
if options[:ticket_id].present?
|
||||
new_selector[:conditions] << {
|
||||
def static_conditions_ticket
|
||||
return [] if options[:ticket_id].blank?
|
||||
|
||||
[
|
||||
{
|
||||
name: 'ticket.id',
|
||||
operator: 'is',
|
||||
value: options[:ticket_id]
|
||||
}
|
||||
end
|
||||
]
|
||||
end
|
||||
|
||||
if options[:article_id].present?
|
||||
new_selector[:conditions] << {
|
||||
def static_conditions_article
|
||||
return [] if options[:article_id].blank?
|
||||
|
||||
[
|
||||
{
|
||||
name: 'article.id',
|
||||
operator: 'is',
|
||||
value: options[:article_id]
|
||||
}
|
||||
end
|
||||
]
|
||||
end
|
||||
|
||||
if options[:exclude_merged].present?
|
||||
new_selector[:conditions] << {
|
||||
def static_conditions_merged
|
||||
return [] if options[:exclude_merged].blank?
|
||||
|
||||
[
|
||||
{
|
||||
name: 'ticket_state.name',
|
||||
operator: 'is not',
|
||||
value: Ticket::StateType.find_by(name: 'merged').states.pluck(:name),
|
||||
}
|
||||
end
|
||||
]
|
||||
end
|
||||
|
||||
if @selector[:conditions].present?
|
||||
new_selector[:conditions] << @selector
|
||||
end
|
||||
# https://github.com/zammad/zammad/issues/4550
|
||||
def static_conditions_ticket_update
|
||||
return [] if options[:ticket_action] != 'update' || options[:changes_required].blank?
|
||||
|
||||
@selector = new_selector
|
||||
[
|
||||
{
|
||||
name: 'ticket.action',
|
||||
operator: 'is',
|
||||
value: 'update'
|
||||
}
|
||||
]
|
||||
end
|
||||
|
||||
def check_changes
|
||||
|
||||
@@ -238,7 +238,11 @@ class Ticket::Selector::SearchIndex < Ticket::Selector::Base
|
||||
query_must_not.push t
|
||||
end
|
||||
elsif ['contains all', 'contains one', 'contains all not', 'contains one not'].include?(data[:operator])
|
||||
values = data[:value].split(',').map(&:strip)
|
||||
values = data[:value]
|
||||
if data[:value].is_a?(String)
|
||||
values = values.split(',').map(&:strip)
|
||||
end
|
||||
|
||||
t[:query_string] = {}
|
||||
case data[:operator]
|
||||
when 'contains all'
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
# Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
|
||||
|
||||
class Ticket::Selector::Sql < Ticket::Selector::Base
|
||||
attr_accessor :final_query, :final_bind_params, :final_tables, :final_tables_query, :changed_attributes
|
||||
attr_accessor :final_query, :final_bind_params, :final_tables
|
||||
|
||||
def get
|
||||
@final_query = []
|
||||
@final_bind_params = []
|
||||
@final_tables = []
|
||||
@final_tables_query = []
|
||||
@final_query = run(selector, 0)
|
||||
[query_sql, final_bind_params, tables_sql]
|
||||
rescue InvalidCondition => e
|
||||
@@ -19,26 +18,22 @@ class Ticket::Selector::Sql < Ticket::Selector::Base
|
||||
end
|
||||
|
||||
def query_sql
|
||||
[
|
||||
final_tables_query.join(' AND ').presence,
|
||||
final_query.presence,
|
||||
].compact.join(' AND ')
|
||||
Array(final_query).join(' AND ')
|
||||
end
|
||||
|
||||
def tables_sql
|
||||
return '' if final_tables.blank?
|
||||
|
||||
", #{final_tables.join(', ')}"
|
||||
" #{final_tables.join(' ')}"
|
||||
end
|
||||
|
||||
def run(block, level)
|
||||
if block.key?(:conditions)
|
||||
run_block(block, level)
|
||||
else
|
||||
query, bind_params, tables, tables_query = condition_sql(block)
|
||||
query, bind_params, tables = condition_sql(block)
|
||||
@final_bind_params += bind_params
|
||||
@final_tables |= tables
|
||||
@final_tables_query |= tables_query
|
||||
query
|
||||
end
|
||||
end
|
||||
@@ -70,7 +65,6 @@ class Ticket::Selector::Sql < Ticket::Selector::Base
|
||||
# remember query and bind params
|
||||
query = []
|
||||
tables = []
|
||||
tables_query = []
|
||||
bind_params = []
|
||||
like = Rails.application.config.db_like
|
||||
attribute_table, attribute_name = block_condition[:name].split('.')
|
||||
@@ -79,27 +73,27 @@ class Ticket::Selector::Sql < Ticket::Selector::Base
|
||||
return if !attribute_name
|
||||
return if !attribute_table
|
||||
|
||||
sql_helper = SqlHelper.new(object: Ticket)
|
||||
if attribute_table && attribute_table != 'execution_time' && tables.exclude?(attribute_table) && !(attribute_table == 'ticket' && attribute_name != 'mention_user_ids') && !(attribute_table == 'ticket' && attribute_name == 'mention_user_ids' && block_condition[:pre_condition] == 'not_set')
|
||||
case attribute_table
|
||||
when 'customer'
|
||||
tables |= ['users customers']
|
||||
tables_query |= ['tickets.customer_id = customers.id']
|
||||
tables |= ['INNER JOIN users customers ON tickets.customer_id = customers.id']
|
||||
sql_helper = SqlHelper.new(object: User, table_name: 'customers')
|
||||
when 'organization'
|
||||
tables |= ['organizations']
|
||||
tables_query |= ['tickets.organization_id = organizations.id']
|
||||
tables |= ['LEFT JOIN organizations ON tickets.organization_id = organizations.id']
|
||||
sql_helper = SqlHelper.new(object: Organization)
|
||||
when 'owner'
|
||||
tables |= ['users owners']
|
||||
tables_query |= ['tickets.owner_id = owners.id']
|
||||
tables |= ['INNER JOIN users owners ON tickets.owner_id = owners.id']
|
||||
sql_helper = SqlHelper.new(object: User, table_name: 'owners')
|
||||
when 'article'
|
||||
tables |= ['ticket_articles articles']
|
||||
tables_query |= ['tickets.id = articles.ticket_id']
|
||||
tables |= ['INNER JOIN ticket_articles articles ON tickets.id = articles.ticket_id']
|
||||
sql_helper = SqlHelper.new(object: Ticket::Article)
|
||||
when 'ticket_state'
|
||||
tables |= ['ticket_states']
|
||||
tables_query |= ['tickets.state_id = ticket_states.id']
|
||||
tables |= ['INNER JOIN ticket_states ON tickets.state_id = ticket_states.id']
|
||||
sql_helper = SqlHelper.new(object: Ticket::State)
|
||||
when 'ticket'
|
||||
if attribute_name == 'mention_user_ids'
|
||||
tables |= ['mentions']
|
||||
tables_query |= ["tickets.id = mentions.mentionable_id AND mentions.mentionable_type = 'Ticket'"]
|
||||
tables |= ["LEFT JOIN mentions ON tickets.id = mentions.mentionable_id AND mentions.mentionable_type = 'Ticket'"]
|
||||
end
|
||||
else
|
||||
raise "invalid selector #{attribute_table}, #{attribute_name}"
|
||||
@@ -300,25 +294,20 @@ class Ticket::Selector::Sql < Ticket::Selector::Base
|
||||
)"
|
||||
bind_params.push block_condition[:value].count
|
||||
bind_params.push block_condition[:value]
|
||||
elsif Ticket.column_names.include?(attribute_name)
|
||||
query << SqlHelper.new(object: Ticket).array_contains_all(attribute_name, block_condition[:value])
|
||||
elsif sql_helper.containable?(attribute_name)
|
||||
query << sql_helper.array_contains_all(attribute_name, block_condition[:value])
|
||||
end
|
||||
elsif block_condition[:operator] == 'contains one' && attribute_table == 'ticket'
|
||||
if attribute_name == 'tags'
|
||||
tables |= %w[tag_objects tag_items tags]
|
||||
query << "
|
||||
tickets.id = tags.o_id AND
|
||||
tag_objects.id = tags.tag_object_id AND
|
||||
tag_objects.name = 'Ticket' AND
|
||||
tag_items.id = tags.tag_item_id AND
|
||||
tag_items.name IN (?)"
|
||||
elsif block_condition[:operator] == 'contains one'
|
||||
if attribute_name == 'tags' && attribute_table == 'ticket'
|
||||
tables |= ["LEFT JOIN tags ON tickets.id = tags.o_id LEFT JOIN tag_objects ON tag_objects.id = tags.tag_object_id AND tag_objects.name = 'Ticket' LEFT JOIN tag_items ON tag_items.id = tags.tag_item_id"]
|
||||
query << 'tag_items.name IN (?)'
|
||||
|
||||
bind_params.push block_condition[:value]
|
||||
elsif Ticket.column_names.include?(attribute_name)
|
||||
query << SqlHelper.new(object: Ticket).array_contains_one(attribute_name, block_condition[:value])
|
||||
elsif sql_helper.containable?(attribute_name)
|
||||
query << sql_helper.array_contains_one(attribute_name, block_condition[:value])
|
||||
end
|
||||
elsif block_condition[:operator] == 'contains all not' && attribute_table == 'ticket'
|
||||
if attribute_name == 'tags'
|
||||
elsif block_condition[:operator] == 'contains all not'
|
||||
if attribute_name == 'tags' && attribute_table == 'ticket'
|
||||
query << "0 = (
|
||||
SELECT
|
||||
COUNT(*)
|
||||
@@ -334,11 +323,11 @@ class Ticket::Selector::Sql < Ticket::Selector::Base
|
||||
tag_items.name IN (?)
|
||||
)"
|
||||
bind_params.push block_condition[:value]
|
||||
elsif Ticket.column_names.include?(attribute_name)
|
||||
query << SqlHelper.new(object: Ticket).array_contains_all(attribute_name, block_condition[:value], negated: true)
|
||||
elsif sql_helper.containable?(attribute_name)
|
||||
query << sql_helper.array_contains_all(attribute_name, block_condition[:value], negated: true)
|
||||
end
|
||||
elsif block_condition[:operator] == 'contains one not' && attribute_table == 'ticket'
|
||||
if attribute_name == 'tags'
|
||||
elsif block_condition[:operator] == 'contains one not'
|
||||
if attribute_name == 'tags' && attribute_table == 'ticket'
|
||||
query << "(
|
||||
SELECT
|
||||
COUNT(*)
|
||||
@@ -354,8 +343,8 @@ class Ticket::Selector::Sql < Ticket::Selector::Base
|
||||
tag_items.name IN (?)
|
||||
) BETWEEN 0 AND 0"
|
||||
bind_params.push block_condition[:value]
|
||||
elsif Ticket.column_names.include?(attribute_name)
|
||||
query << SqlHelper.new(object: Ticket).array_contains_one(attribute_name, block_condition[:value], negated: true)
|
||||
elsif sql_helper.containable?(attribute_name)
|
||||
query << sql_helper.array_contains_one(attribute_name, block_condition[:value], negated: true)
|
||||
end
|
||||
elsif block_condition[:operator] == 'today'
|
||||
Time.use_zone(Setting.get('timezone_default_sanitized').presence) do
|
||||
@@ -402,7 +391,7 @@ class Ticket::Selector::Sql < Ticket::Selector::Base
|
||||
raise "Invalid operator '#{block_condition[:operator]}' for '#{block_condition[:value].inspect}'"
|
||||
end
|
||||
|
||||
[query, bind_params, tables, tables_query]
|
||||
[query, bind_params, tables]
|
||||
end
|
||||
|
||||
def range(selector)
|
||||
|
||||
@@ -42,16 +42,9 @@ returns
|
||||
data[ app_model ][ id ] = local_attributes
|
||||
|
||||
# get linked accounts
|
||||
local_attributes['accounts'] = Rails.cache.fetch("User/authorizations/#{cache_key_with_version}") do
|
||||
local_accounts = {}
|
||||
authorizations = self.authorizations
|
||||
authorizations.each do |authorization|
|
||||
local_accounts[authorization.provider] = {
|
||||
uid: authorization[:uid],
|
||||
username: authorization[:username]
|
||||
}
|
||||
end
|
||||
local_accounts
|
||||
accounts = assets_accounts
|
||||
if accounts.present?
|
||||
local_attributes['accounts'] = accounts
|
||||
end
|
||||
|
||||
# get roles
|
||||
@@ -112,5 +105,21 @@ returns
|
||||
attributes = super
|
||||
attributes.slice('id', 'firstname', 'lastname', 'image', 'image_source', 'active')
|
||||
end
|
||||
|
||||
def assets_accounts
|
||||
return nil if UserInfo.assets.present? && !UserInfo.assets.agent? && UserInfo.current_user_id != id
|
||||
|
||||
Rails.cache.fetch("User/authorizations/#{cache_key_with_version}") do
|
||||
local_accounts = {}
|
||||
authorizations = self.authorizations
|
||||
authorizations.each do |authorization|
|
||||
local_accounts[authorization.provider] = {
|
||||
uid: authorization[:uid],
|
||||
username: authorization[:username]
|
||||
}
|
||||
end
|
||||
local_accounts
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,6 +8,7 @@ class User
|
||||
attributes = super
|
||||
attributes['fullname'] = fullname
|
||||
attributes.delete('password')
|
||||
attributes['preferences']&.delete('signature_detection')
|
||||
|
||||
if include_references
|
||||
attributes['permissions'] = []
|
||||
|
||||
@@ -11,10 +11,7 @@ class Ticket::ArticlePolicy < ApplicationPolicy
|
||||
end
|
||||
|
||||
def update?
|
||||
return false if !access?(__method__)
|
||||
return true if user.permissions?(['ticket.agent', 'admin'])
|
||||
|
||||
not_authorized('ticket.agent or admin permission required')
|
||||
ticket_policy.agent_update_access?
|
||||
end
|
||||
|
||||
def destroy?
|
||||
@@ -57,9 +54,12 @@ class Ticket::ArticlePolicy < ApplicationPolicy
|
||||
end
|
||||
|
||||
def access?(query)
|
||||
ticket = Ticket.lookup(id: record.ticket_id)
|
||||
return false if record.internal == true && !TicketPolicy.new(user, ticket).agent_read_access?
|
||||
return false if record.internal && !ticket_policy.agent_read_access?
|
||||
|
||||
Pundit.authorize(user, ticket, query)
|
||||
ticket_policy.send(query)
|
||||
end
|
||||
|
||||
def ticket_policy
|
||||
@ticket_policy ||= TicketPolicy.new(user, Ticket.lookup(id: record.ticket_id))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -83,7 +83,7 @@ class Service::Ticket::Article::Create < Service::BaseWithCurrentUser
|
||||
return user.phone if user.phone.present?
|
||||
return user.login if user.login.present?
|
||||
|
||||
'???'
|
||||
'-'
|
||||
end
|
||||
|
||||
def attachments(article, attachments_raw)
|
||||
|
||||
16
app/views/mailer/admin_password_auth/cs.html.erb
Normal file
16
app/views/mailer/admin_password_auth/cs.html.erb
Normal file
@@ -0,0 +1,16 @@
|
||||
Obnovení Vašeho hesla na webu #{config.product_name}
|
||||
|
||||
<div>Dobrý den, #{user.firstname},</div>
|
||||
<br>
|
||||
<div>Obdrželi jsme požadavek na změnu Vašeho hesla na webu #{config.product_name} k účtu <b>#{user.login}</b>.</div>
|
||||
<br>
|
||||
<div>Pokud opravdu chcete resetovat heslo, klikněte na odkaz níže (nebo zkopírujte a vložte URL odkazu do svého prohlížeče):</div>
|
||||
<br>
|
||||
<div><a href="#{config.http_type}://#{config.fqdn}/#password_reset_verify/#{token.name}">#{config.http_type}://#{config.fqdn}/#password_reset_verify/#{token.name}</a></div>
|
||||
<br>
|
||||
<div>Tento odkaz Vás přesměruje na stránku, kde můžete nastavit nové heslo.</div>
|
||||
<br>
|
||||
<div>Pokud heslo nechcete změnit, tuto zprávu ignorujte (nevyužívejte výše zmíněného odkazu) a Vaše heslo bude zachováno.</div>
|
||||
<br>
|
||||
<div>S pozdravem,<br>
|
||||
Tým aplikace #{config.product_name}</div>
|
||||
15
app/views/mailer/admin_password_auth/hu.html.erb
Normal file
15
app/views/mailer/admin_password_auth/hu.html.erb
Normal file
@@ -0,0 +1,15 @@
|
||||
Rendszergazdai bejelentkezés a következő rendszerbe: #{config.product_name}
|
||||
|
||||
<div>Üdvözöljük #{user.firstname},</div>
|
||||
<br>
|
||||
<div>Egy rendszergazdai bejelentkezési kérelmet kaptunk az Ön #{config.product_name} fiókjához <b>#{user.login}</b>.</div>
|
||||
<br>
|
||||
<div>Kérjük, a folytatáshoz kattintson az alábbi hivatkozásra (vagy másolja be az URL címet a böngészőjébe):</div>
|
||||
<br>
|
||||
<div><a href="#{config.http_type}://#{config.fqdn}/#login/admin/#{token.name}">#{config.http_type}://#{config.fqdn}/#login/admin/#{token.name}</a></div>
|
||||
<br>
|
||||
<div>Ez a hivatkozás egy olyan oldalra vezeti Önt, ahol bejelentkezhet.</div>
|
||||
<br>
|
||||
<div>Amennyiben nem szeretne bejelentkezni, kérjük, hagyja figyelmen kívül ezt az üzenetet.</div>
|
||||
<br>
|
||||
<div>Az Ön #{config.product_name} csapata</div>
|
||||
15
app/views/mailer/admin_password_auth/nb.html.erb
Normal file
15
app/views/mailer/admin_password_auth/nb.html.erb
Normal file
@@ -0,0 +1,15 @@
|
||||
Administrasjonspålogging til #{config.product_name}
|
||||
|
||||
<div>Hei #{user.firstname},</div>
|
||||
<br>
|
||||
<div>Vi mottok en henvendelse om administrasjonspålogging for din #{config.product_name}-konto <b>#{user.login}</b>.</div>
|
||||
<br>
|
||||
<div>Klikk på linken nedenfor dersom dette stemmer (eller kopier og lim inn URL-en i din nettleser) for å fortsette:</div>
|
||||
<br>
|
||||
<div><a href="#{config.http_type}://#{config.fqdn}/#login/admin/{token.name}">#{config.http_type}://#{config.fqdn}/#login/admin/{token.name}</a></div>
|
||||
<br>
|
||||
<div>Lenken peker til en påloggingsside.</div>
|
||||
<br>
|
||||
<div>Hvis du ikke ønsker å logge inn, kan du ignorere denne beskjeden.</div>
|
||||
<br>
|
||||
<div>Dine #{config.product_name}-administratorer</div>
|
||||
15
app/views/mailer/admin_password_auth/nl.html.erb
Normal file
15
app/views/mailer/admin_password_auth/nl.html.erb
Normal file
@@ -0,0 +1,15 @@
|
||||
Beheer login op #{config.product_name}
|
||||
|
||||
<div>Hallo #{user.firstname},</div>
|
||||
<br>
|
||||
<div>We hebben een verzoek ontvangen voor een beheerderslogin voor je #{config.product_name}-account <b>#{user.login}</b>.</div>
|
||||
<br>
|
||||
<div>Klik op de onderstaande link (of kopieer en plak de URL in de browser) om verder te gaan:</div>
|
||||
<br>
|
||||
<div><a href="#{config.http_type}://#{config.fqdn}/#login/admin/#{token.name}">#{config.http_type}://#{config. fqdn}/#login/admin/#{token.name}</a></div>
|
||||
<br>
|
||||
<div>Deze link brengt je naar een pagina waar je kunt inloggen.</div>
|
||||
<br>
|
||||
<div>Als je niet wilt inloggen, kun je dit bericht negeren.</div>
|
||||
<br>
|
||||
<div>Het #{config.product_name}-team</div>
|
||||
12
app/views/mailer/email_oversized/cs.txt.erb
Normal file
12
app/views/mailer/email_oversized/cs.txt.erb
Normal file
@@ -0,0 +1,12 @@
|
||||
[undeliverable] Zpráva je příliš velká
|
||||
Dobrý den, #{mail.from_display_name},
|
||||
|
||||
Bohužel, váš e-mail s předmětem "#{mail.subject}" se nepodařilo jednomu nebo více příjemcům doručit.
|
||||
|
||||
Vaše zpráva měla velikost #{mail.msg_size} MB, ale přijímáme pouze zprávy do velikosti #{config.postmaster_max_size} MB.
|
||||
|
||||
Zkuste prosím zmenšit velikost zprávy a odešlete ji znovu. Děkujeme za pochopení.
|
||||
|
||||
S pozdravem,
|
||||
|
||||
Správce pošty #{config.fqdn}
|
||||
12
app/views/mailer/email_oversized/hu.txt.erb
Normal file
12
app/views/mailer/email_oversized/hu.txt.erb
Normal file
@@ -0,0 +1,12 @@
|
||||
[undeliverable] Túl nagy üzenet
|
||||
Tisztelt #{mail.from_display_name},
|
||||
|
||||
Sajnos a "#{mail.subject}" című levelét nem sikerült kézbesíteni egy vagy több címzettnek.
|
||||
|
||||
Az Ön üzenete #{mail.msg_size} MB, de mi csak #{config.postmaster_max_size_max_size} MB méretű üzeneteket fogadunk el.
|
||||
|
||||
Kérjük, csökkentse az üzenet méretét, és próbálja meg újra. Köszönjük megértését.
|
||||
|
||||
Sajnálattal,
|
||||
|
||||
A #{config.fqdn} postmastere
|
||||
12
app/views/mailer/email_oversized/nl.txt.erb
Normal file
12
app/views/mailer/email_oversized/nl.txt.erb
Normal file
@@ -0,0 +1,12 @@
|
||||
[onbestelbaar] Bericht te groot
|
||||
Beste #{mail.from_display_name},
|
||||
|
||||
Helaas kon je e-mail met de titel "#{mail.subject}" niet worden afgeleverd bij een of meer ontvangers.
|
||||
|
||||
Je bericht was #{mail.msg_size} MB, maar we accepteren alleen berichten tot #{config.postmaster_max_size} MB.
|
||||
|
||||
Verklein de berichtgrootte en probeer het opnieuw.
|
||||
|
||||
Bedankt voor je begrip.
|
||||
|
||||
Postmaster van #{config.fqdn}
|
||||
@@ -1,11 +1,10 @@
|
||||
Změna hesla pro přístup na web #{config.product_name}
|
||||
Změna hesla pro přístup do aplikace #{config.product_name}
|
||||
|
||||
<p>Dobrý den #{user.firstname},</p>
|
||||
<p>Dobrý den, #{user.firstname},</p>
|
||||
<br>
|
||||
<p>Heslo pro Váš účet registrovaný na webu #{config.product_name} pro uživatelské jméno <b>#{user.login}</b> bylo právě změněno.</p>
|
||||
<p>Heslo pro Váš účet registrovaný v aplikaci #{config.product_name} pro uživatelské jméno <b>#{user.login}</b> bylo právě změněno.</p>
|
||||
<br>
|
||||
<p>Nic o této aktivitě nevíte? Pokud ano, kontaktujte Vašeho administrátora systému.</p>
|
||||
<p>Pokud si této aktivity nejste vědomi, kontaktujte ihned správce Vašeho systému podpory.</p>
|
||||
<br>
|
||||
<p>S pozdravem,</p>
|
||||
<br>
|
||||
<p>Tým webu #{config.product_name}</p>
|
||||
<p>S pozdravem,<br>
|
||||
Tým aplikace #{config.product_name}</p>
|
||||
|
||||
9
app/views/mailer/password_change/hu.html.erb
Normal file
9
app/views/mailer/password_change/hu.html.erb
Normal file
@@ -0,0 +1,9 @@
|
||||
Az Ön #{config.product_name} jelszava megváltozott.
|
||||
|
||||
<p>Üdvözöljük #{user.firstname},</p>
|
||||
<br>
|
||||
<p>Az Ön #{config.product_name} fiókjának <b>#{user.login}</b> jelszava nemrég megváltozott.</p>
|
||||
<br>
|
||||
<p>Nem ismert Önnek ez a tevékenység? Amennyiben nem, lépjen kapcsolatba a rendszergazdájával.</p>
|
||||
<br>
|
||||
<p>Az Ön #{config.product_name} csapata</p>
|
||||
9
app/views/mailer/password_change/nl.html.erb
Normal file
9
app/views/mailer/password_change/nl.html.erb
Normal file
@@ -0,0 +1,9 @@
|
||||
Je #{config.product_name} wachtwoord is gewijzigd
|
||||
|
||||
<p>Hallo #{user.firstname},</p>
|
||||
<br>
|
||||
<p>Het wachtwoord voor je #{config.product_name}-account <b>#{user.login}</b> is onlangs gewijzigd.</p>
|
||||
<br>
|
||||
<p>Deze activiteit is niet bij je bekend? Neem dan contact op met de systeembeheerder.</p>
|
||||
<br>
|
||||
<p>Het #{config.product_name}-team</p>
|
||||
@@ -1,17 +1,16 @@
|
||||
Resetování Vašeho hesla na webu #{config.product_name}
|
||||
Resetování Vašeho hesla v aplikaci #{config.product_name}
|
||||
|
||||
<div>Dobrý den #{user.firstname},</div>
|
||||
<div>Dobrý den, #{user.firstname},</div>
|
||||
<br>
|
||||
<div>Obdrželi jsme požadavek na změnu vašeho hesla na webu #{config.product_name} u účtu <b>#{user.login}</b>.</div>
|
||||
<div>Obdrželi jsme požadavek na změnu Vašeho hesla v aplikaci #{config.product_name} u účtu <b>#{user.login}</b>.</div>
|
||||
<br>
|
||||
<div>Pokud opravdu chcete resetovat heslo, klikněte na odkaz níže (nebo zkopírujte a vložte URL odkazu do Vašeho prohlížeče):</div>
|
||||
<br>
|
||||
<div><a href="#{config.http_type}://#{config.fqdn}/#password_reset_verify/#{token.name}">#{config.http_type}://#{config.fqdn}/#password_reset_verify/#{token.name}</a></div>
|
||||
<br>
|
||||
<div>Tento oddaz Vás přesměruje na stránku kde můžete změnit své heslo.</div>
|
||||
<div>Tento odkaz Vás přesměruje na stránku, kde si nastavíte své nové heslo.</div>
|
||||
<br>
|
||||
<div>Pokud nechcete změnit Vaše heslo, tuto zprávu ignorujte (nevyužívejte výše zmíněného odkazu) a Vaše heslo nebude změněno.</div>
|
||||
<div>Pokud heslo měnit nechcete, tuto zprávu ignorujte (nevyužívejte výše zmíněného odkazu) a Vaše heslo nebude změněno.</div>
|
||||
<br>
|
||||
<div>S pozdravem,</div>
|
||||
<br>
|
||||
<div>Team webu #{config.product_name}</div>
|
||||
<div>S pozdravem,<br>
|
||||
Tým aplikace #{config.product_name}</div>
|
||||
|
||||
15
app/views/mailer/password_reset/hu.html.erb
Normal file
15
app/views/mailer/password_reset/hu.html.erb
Normal file
@@ -0,0 +1,15 @@
|
||||
Állítsa vissza #{config.product_name} jelszavát
|
||||
|
||||
<div>Üdvözöljük #{user.firstname},</div>
|
||||
<br>
|
||||
<div>Kérést kaptunk a #{config.product_name} fiókja jelszavának visszaállítására. <b>#{user.login}</b>.</div>
|
||||
<br>
|
||||
<div>Amennyiben vissza szeretné állítani jelszavát, kattintson az alábbi hivatkozásra (vagy másolja be az URL címet a böngészőjébe):</div>
|
||||
<br>
|
||||
<div><a href="#{config.http_type}://#{config.fqdn}/#password_reset_verify/#{token.name}">#{config.http_type}://#{config.fqdn}/#password_reset_verify/#{token.name}</a></div>
|
||||
<br>
|
||||
<div>Ez a hivatkozás egy olyan oldalra vezeti Önt, ahol megváltoztathatja jelszavát.</div>
|
||||
<br>
|
||||
<div>Amennyiben nem szeretné visszaállítani jelszavát, kérjük, hagyja figyelmen kívül ezt az üzenetet. A jelszavát nem fogjuk visszaállítani.</div>
|
||||
<br>
|
||||
<div>Az Ön #{config.product_name} csapata</div>
|
||||
15
app/views/mailer/password_reset/nl.html.erb
Normal file
15
app/views/mailer/password_reset/nl.html.erb
Normal file
@@ -0,0 +1,15 @@
|
||||
Reset je #{config.product_name} wachtwoord
|
||||
|
||||
<div>Hallo #{user.firstname},</div>
|
||||
<br>
|
||||
<div>We hebben een verzoek ontvangen om het wachtwoord voor je #{config.product_name}-account <b>#{user.login}</b> opnieuw in te stellen.</div>
|
||||
<br>
|
||||
<div>Als je het wachtwoord opnieuw wilt instellen klikt je op de onderstaande link (of kopieert en plakt de URL in de browser):</div>
|
||||
<br>
|
||||
<div><a href="#{config.http_type}://#{config.fqdn}/#password_reset_verify/#{token.name}">#{config.http_type}://#{config.fqdn} /#password_reset_verify/#{token.name}</a></div>
|
||||
<br>
|
||||
<div>Deze link brengt je naar een pagina waar je het wachtwoord kunt wijzigen.</div>
|
||||
<br>
|
||||
<div>Als je het wachtwoord niet opnieuw wilt instellen, kun je dit bericht negeren. Je wachtwoord wordt niet gereset.</div>
|
||||
<br>
|
||||
<div>Het #{config.product_name}-team</div>
|
||||
@@ -1,11 +1,10 @@
|
||||
Potvrzení pro váš účet na web #{config.product_name}, #{user.firstname} #{user.lastname}
|
||||
Potvrzení pro Váš účet v aplikaci #{config.product_name}, #{user.firstname} #{user.lastname}
|
||||
|
||||
<div>Dobrý den,</div>
|
||||
<div>Dobrý den, #{user.firstname},</div>
|
||||
<br>
|
||||
<div>pro potvrzení Vaší emailové adresy u účtu na webu #{config.product_name} klikněte na odkaz níže.</div>
|
||||
<div>pro potvrzení Vaší emailové adresy u účtu v aplikaci #{config.product_name} klikněte na odkaz níže.</div>
|
||||
<br>
|
||||
<div><a href="#{config.http_type}://#{config.fqdn}/#email_verify/#{token.name}">#{config.http_type}://#{config.fqdn}/#email_verify/#{token.name}</a></div>
|
||||
<br>
|
||||
<div>S pozdravem,</div>
|
||||
<br>
|
||||
<div>Team webu #{config.product_name}</div>
|
||||
<div>S pozdravem,<br>
|
||||
Tým aplikace #{config.product_name}</div>
|
||||
|
||||
9
app/views/mailer/signup/hu.html.erb
Normal file
9
app/views/mailer/signup/hu.html.erb
Normal file
@@ -0,0 +1,9 @@
|
||||
Erősítse meg a #{config.product_name} fiókját, #{user.firstname} #{user.lastname}
|
||||
|
||||
<div>Üdvözöljük #{user.firstname},</div>
|
||||
<br>
|
||||
<div>Erősítse meg e-mail címét, hogy elkészüljön a #{config.product_name} fiókja. Ez könnyű, csak kattintson az alábbi linkre.</div>
|
||||
<br>
|
||||
<div><a href="#{config.http_type}://#{config.fqdn}/#email_verify/#{token.name}">#{config.http_type}://#{config.fqdn}/#email_verify/#{token.name}</a></div>
|
||||
<br>
|
||||
<div>Az Ön #{config.product_name} csapata</div>
|
||||
9
app/views/mailer/signup/nl.html.erb
Normal file
9
app/views/mailer/signup/nl.html.erb
Normal file
@@ -0,0 +1,9 @@
|
||||
Bevestig je #{config.product_name} account, #{user.firstname} #{user.lastname}
|
||||
|
||||
<div>Hallo #{user.firstname},</div>
|
||||
<br>
|
||||
<div>Bevestig je e-mailadres om je #{config.product_name}-account te voltooien. Het is eenvoudig, klik gewoon op de onderstaande link.</div>
|
||||
<br>
|
||||
<div><a href="#{config.http_type}://#{config.fqdn}/#email_verify/#{token.name}">#{config.http_type}://#{config.fqdn} /#email_verify/#{token.name}</a></div>
|
||||
<br>
|
||||
<div>Het #{config.product_name}-team</div>
|
||||
16
app/views/mailer/signup_taken_reset/cs.html.erb
Normal file
16
app/views/mailer/signup_taken_reset/cs.html.erb
Normal file
@@ -0,0 +1,16 @@
|
||||
Obnovení hesla pro aplikaci #{config.product_name}
|
||||
|
||||
<div>Dobrý den, #{user.firstname},</div>
|
||||
<br>
|
||||
<div>Vy nebo někdo jiný se pokusil zaregistrovat se s touto e-mailovou adresou. Tento e-mail je ale již registrován.</div>
|
||||
<br>
|
||||
<div>Pokud si přejete obnovit své heslo, klikněte na odkaz níže (nebo zkopírujte a vložte odkaz do Vašeho prohlížeče):</div>
|
||||
<br>
|
||||
<div><a href="#{config.http_type}://#{config.fqdn}/#password_reset_verify/#{token.name}">#{config.http_type}://#{config.fqdn}/#password_reset_verify/#{token.name}</a></div>
|
||||
<br>
|
||||
<div>Tento odkaz vede na stránku, kde si budete moci nastavit nové heslo.</div>
|
||||
<br>
|
||||
<div>Pokud si heslo změnit nepřejete, ignorujte prosím tuto zprávu. Vaše heslo nebude obnoveno.</div>
|
||||
<br>
|
||||
<div>S pozdravem,<br>
|
||||
Tým aplikace #{config.product_name}</div>
|
||||
15
app/views/mailer/signup_taken_reset/hu.html.erb
Normal file
15
app/views/mailer/signup_taken_reset/hu.html.erb
Normal file
@@ -0,0 +1,15 @@
|
||||
Állítsa vissza a #{config.product_name} jelszavát
|
||||
|
||||
<div>Üdvözöljük #{user.firstname},</div>
|
||||
<br>
|
||||
<div>Ön vagy valaki más megpróbált regisztrálni ezzel az e-mail címmel. Ez az e-mail azonban már használatban van.</div>
|
||||
<br>
|
||||
<div>Amennyiben vissza szeretné állítani jelszavát, kattintson az alábbi hivatkozásra (vagy másolja be az URL címet a böngészőjébe):</div>
|
||||
<br>
|
||||
<div><a href="#{config.http_type}://#{config.fqdn}/#password_reset_verify/#{token.name}">#{config.http_type}://#{config.fqdn}/#password_reset_verify/#{token.name}</a></div>
|
||||
<br>
|
||||
<div>Ez a hivatkozás egy olyan oldalra vezeti Önt, ahol megváltoztathatja jelszavát.</div>
|
||||
<br>
|
||||
<div>Amennyiben nem szeretné visszaállítani a jelszavát, kérjük, hagyja figyelmen kívül ezt az üzenetet. A jelszavát nem fogjuk visszaállítani.</div>
|
||||
<br>
|
||||
<div>Az Ön #{config.product_name} csapata</div>
|
||||
15
app/views/mailer/signup_taken_reset/nl.html.erb
Normal file
15
app/views/mailer/signup_taken_reset/nl.html.erb
Normal file
@@ -0,0 +1,15 @@
|
||||
Reset je #{config.product_name} wachtwoord
|
||||
|
||||
<div>Hallo #{user.firstname},</div>
|
||||
<br>
|
||||
<div>Iemand heeft geprobeerd zich aan te melden met dit e-mailadres. Dit e-mailadres wordt echter al gebruikt.</div>
|
||||
<br>
|
||||
<div>Als je het wachtwoord opnieuw wilt instellen, klik je op de onderstaande link (of kopieert en plakt de URL in de browser):</div>
|
||||
<br>
|
||||
<div><a href="#{config.http_type}://#{config.fqdn}/#password_reset_verify/#{token.name}">#{config.http_type}://#{config.fqdn} /#password_reset_verify/#{token.name}</a></div>
|
||||
<br>
|
||||
<div>Deze link brengt je naar een pagina waar je het wachtwoord kunt wijzigen.</div>
|
||||
<br>
|
||||
<div>Als je het wachtwoord niet opnieuw wilt instellen, kun je dit bericht negeren. Je wachtwoord wordt niet gereset.</div>
|
||||
<br>
|
||||
<div>Het #{config.product_name}-team</div>
|
||||
@@ -1,9 +1,9 @@
|
||||
Testovací Ticket!
|
||||
Zkušební ticket!
|
||||
|
||||
<div>Ahoj,</div>
|
||||
<div>Dobrý den, #{agent.firstname},</div>
|
||||
<br>
|
||||
<div>Toto je <b>testovací ticket</b>. Jsem zákazník a potřebuji s něčím pomoct! :)</div>
|
||||
<div>Toto je <b>zkušební ticket</b>. Jsem zákazník a potřebuji od Vás pomoc! :)</div>
|
||||
<br>
|
||||
<div>#{customer.fullname}</div>
|
||||
<br>
|
||||
<div>The Zammad Project</div>
|
||||
<div>S pozdravem,<br>Tým aplikace #{config.product_name}</div>
|
||||
|
||||
9
app/views/mailer/test_ticket/hu.html.erb
Normal file
9
app/views/mailer/test_ticket/hu.html.erb
Normal file
@@ -0,0 +1,9 @@
|
||||
Teszt Jegy!
|
||||
|
||||
<div>Tisztelt #{agent.firstname},</div>
|
||||
<br>
|
||||
<div>Ez egy <b>teszt jegy</b>. Én egy ügyfél vagyok, és egy kis segítségre lenne szükségem! :)</div>
|
||||
<br>
|
||||
<div>#{customer.fullname}</div>
|
||||
<br>
|
||||
<div>Az Ön #{config.product_name} csapata</div>
|
||||
9
app/views/mailer/test_ticket/nl.html.erb
Normal file
9
app/views/mailer/test_ticket/nl.html.erb
Normal file
@@ -0,0 +1,9 @@
|
||||
Test Ticket!
|
||||
|
||||
<div>Beste #{agent.firstname},</div>
|
||||
<br>
|
||||
<div>Dit is een <b>testticket</b>. Ik ben een klant en heb hulp nodig! :)</div>
|
||||
<br>
|
||||
<div>#{customer.fullname}</div>
|
||||
<br>
|
||||
<div>Het #{config.product_name}-team</div>
|
||||
@@ -5,14 +5,14 @@ Nový ticket (#{ticket.title})
|
||||
<div>byl vytvořen nový ticket (#{ticket.title}) uživatelem "<b>#{current_user.longname}</b>".</div>
|
||||
<br>
|
||||
<div>
|
||||
#{t('Group')}: #{ticket.group.name}<br>
|
||||
#{t('Owner')}: #{ticket.owner.fullname}<br>
|
||||
#{t('State')}: #{t(ticket.state.name)}<br>
|
||||
Skupina: #{ticket.group.name}<br>
|
||||
Vlastník: #{ticket.owner.fullname}<br>
|
||||
Stav: #{t(ticket.state.name)}<br>
|
||||
</div>
|
||||
<br>
|
||||
<% if @objects[:article] %>
|
||||
<div>
|
||||
#{t('Information')}:
|
||||
Informace:
|
||||
<blockquote type="cite">
|
||||
#{article.body_as_html}
|
||||
</blockquote>
|
||||
@@ -20,5 +20,4 @@ Nový ticket (#{ticket.title})
|
||||
<% end %>
|
||||
<br>
|
||||
<div>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}" target="zammad_app">#{t('View this in Zammad')}</a>
|
||||
</div>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}" target="zammad_app">Zobrazit v aplikaci #{config.product_name}</a></div>
|
||||
|
||||
24
app/views/mailer/ticket_create/hu.html.erb
Normal file
24
app/views/mailer/ticket_create/hu.html.erb
Normal file
@@ -0,0 +1,24 @@
|
||||
Új jegy (#{ticket.title})
|
||||
|
||||
<div>Üdvözöljük #{recipient.firstname},</div>
|
||||
<br>
|
||||
<div>Az új jegyet (#{ticket.title}) "<b>#{current_user.longname}</b>" létrehozta.</div>
|
||||
<br>
|
||||
<div>
|
||||
Csoport: #{ticket.group.name}<br>
|
||||
Tulajdonos: #{ticket.owner.fullname}<br>
|
||||
Állapot: #{t(ticket.state.name)}<br>
|
||||
</div>
|
||||
<br>
|
||||
<% if @objects[:article] %>
|
||||
<div>
|
||||
Információ:
|
||||
<blockquote type="cite">
|
||||
#{article.body_as_html}
|
||||
</blockquote>
|
||||
</div>
|
||||
<% end %>
|
||||
<br>
|
||||
<div>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}" target="zammad_app">Tekintse meg itt: #{config.product_name}</a>
|
||||
</div>
|
||||
24
app/views/mailer/ticket_create/nl.html.erb
Normal file
24
app/views/mailer/ticket_create/nl.html.erb
Normal file
@@ -0,0 +1,24 @@
|
||||
Nieuw ticket (#{ticket.title})
|
||||
|
||||
<div>Hallo #{recipient.firstname},</div>
|
||||
<br>
|
||||
<div>Het nieuwe ticket (#{ticket.title}) is aangemaakt door "<b>#{current_user.longname}</b>".</div>
|
||||
<br>
|
||||
<div>
|
||||
Groep: #{ticket.group.name}<br>
|
||||
Behandelaar: #{ticket.owner.fullname}<br>
|
||||
Status: #{ticket.state.name}<br>
|
||||
</div>
|
||||
<br>
|
||||
<% if @objects[:article] %>
|
||||
<div>
|
||||
Informatie:
|
||||
<blockquote type="cite">
|
||||
#{article.body_as_html}
|
||||
</blockquote>
|
||||
</div>
|
||||
<% end %>
|
||||
<br>
|
||||
<div>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}" target="zammad_app">Bekijk dit in #{config.product_name}</a>
|
||||
</div>
|
||||
@@ -1,12 +1,12 @@
|
||||
Vyeskaloval ticket (#{ticket.title})
|
||||
Eskalovaný ticket (#{ticket.title})
|
||||
|
||||
<div>Dobrý den,</div>
|
||||
<div>Dobrý den, #{recipient.firstname},</div>
|
||||
<br>
|
||||
<div>ticket (#{ticket.title}) od "<b>#{ticket.customer.longname}</b>" eskaloval "#{ticket.escalation_at}"!</div>
|
||||
<div>ticket (#{ticket.title}) zákazníka "<b>#{ticket.customer.longname}</b>" eskaloval "#{ticket.escalation_at}"!</div>
|
||||
<br>
|
||||
<% if @objects[:article] %>
|
||||
<div>
|
||||
#{t('Information')}:
|
||||
Informace:
|
||||
<blockquote type="cite">
|
||||
#{article.body_as_html}
|
||||
</blockquote>
|
||||
@@ -14,5 +14,5 @@ Vyeskaloval ticket (#{ticket.title})
|
||||
<% end %>
|
||||
<br>
|
||||
<div>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}" target="zammad_app">#{t('View this in Zammad')}</a>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}" target="zammad_app">Zobrazit v aplikaci #{config.product_name}</a>
|
||||
</div>
|
||||
|
||||
18
app/views/mailer/ticket_escalation/hu.html.erb
Normal file
18
app/views/mailer/ticket_escalation/hu.html.erb
Normal file
@@ -0,0 +1,18 @@
|
||||
Eszkalálódott jegy (#{ticket.title})
|
||||
|
||||
<div>Üdvözöljük #{recipient.firstname},</div>
|
||||
<br>
|
||||
<div>A "<b>#{ticket.customer.longname}</b>" ügyféltől származó jegy (#{ticket.title}) "#{ticket.escalation_at}" óta eszkalálódott!</div>
|
||||
<br>
|
||||
<% if @objects[:article] %>
|
||||
<div>
|
||||
Információ:
|
||||
<blockquote type="cite">
|
||||
#{article.body_as_html}
|
||||
</blockquote>
|
||||
</div>
|
||||
<% end %>
|
||||
<br>
|
||||
<div>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}" target="zammad_app">Tekintse meg itt: #{config.product_name}</a>
|
||||
</div>
|
||||
18
app/views/mailer/ticket_escalation/nl.html.erb
Normal file
18
app/views/mailer/ticket_escalation/nl.html.erb
Normal file
@@ -0,0 +1,18 @@
|
||||
Geëscaleerd ticket (#{ticket.title})
|
||||
|
||||
<div>Hallo #{recipient.firstname},</div>
|
||||
<br>
|
||||
<div>Het ticket (#{ticket.title}) van "<b>#{ticket.customer.longname}</b>" is geëscaleerd sinds "#{ticket.escalation_at}"!</div>
|
||||
<br>
|
||||
<% if @objects[:article] %>
|
||||
<div>
|
||||
Informatie:
|
||||
<blockquote type="cite">
|
||||
#{article.body_as_html}
|
||||
</blockquote>
|
||||
</div>
|
||||
<% end %>
|
||||
<br>
|
||||
<div>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}" target="zammad_app">Bekijk dit in #{config.product_name}</a>
|
||||
</div>
|
||||
@@ -1,12 +1,12 @@
|
||||
Bude eskalovat ticket (#{ticket.title})
|
||||
Ticket (#{ticket.title}) bude eskalován
|
||||
|
||||
<div>Dobrý den,</div>
|
||||
<div>Dobrý den, #{recipient.firstname},</div>
|
||||
<br>
|
||||
<div>ticket (#{ticket.title}) od "<b>#{ticket.customer.longname}</b>" bude "#{ticket.escalation_at}" eskalovat!</div>
|
||||
<div>ticket (#{ticket.title}) uživatele "<b>#{ticket.customer.longname}</b>" bude "#{ticket.escalation_at}" eskalovat!</div>
|
||||
<br>
|
||||
<% if @objects[:article] %>
|
||||
<div>
|
||||
#{t('Information')}:
|
||||
Informace:
|
||||
<blockquote type="cite">
|
||||
#{article.body_as_html}
|
||||
</blockquote>
|
||||
@@ -14,5 +14,5 @@ Bude eskalovat ticket (#{ticket.title})
|
||||
<% end %>
|
||||
<br>
|
||||
<div>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}" target="zammad_app">#{t('View this in Zammad')}</a>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}" target="zammad_app">Zobrazit v aplikaci #{config.product_name}</a>
|
||||
</div>
|
||||
|
||||
18
app/views/mailer/ticket_escalation_warning/hu.html.erb
Normal file
18
app/views/mailer/ticket_escalation_warning/hu.html.erb
Normal file
@@ -0,0 +1,18 @@
|
||||
A jegy eszkalálódik (#{ticket.title})
|
||||
|
||||
<div>Üdvözöljük #{recipient.firstname},</div>
|
||||
<br>
|
||||
<div>A "<b>#{ticket.customer.longname}</b>" ügyféltől származó jegy (#{ticket.title}) eszkalálódni fog a következő időpontban: "#{ticket.escalation_at}"!</div>
|
||||
<br>
|
||||
<% if @objects[:article] %>
|
||||
<div>
|
||||
Információ:
|
||||
<blockquote type="cite">
|
||||
#{article.body_as_html}
|
||||
</blockquote>
|
||||
</div>
|
||||
<% end %>
|
||||
<br>
|
||||
<div>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}" target="zammad_app" >Tekintse meg itt: #{config.product_name}</a>
|
||||
</div>
|
||||
18
app/views/mailer/ticket_escalation_warning/nl.html.erb
Normal file
18
app/views/mailer/ticket_escalation_warning/nl.html.erb
Normal file
@@ -0,0 +1,18 @@
|
||||
Ticket zal escaleren (#{ticket.title})
|
||||
|
||||
<div>Hallo #{recipient.firstname},</div>
|
||||
<br>
|
||||
<div>Het ticket (#{ticket.title}) van "<b>#{ticket.customer.longname}</b>" zal escaleren op "#{ticket.escalation_at}"!</div>
|
||||
<br>
|
||||
<% if @objects[:article] %>
|
||||
<div>
|
||||
Informatie:
|
||||
<blockquote type="cite">
|
||||
#{article.body_as_html}
|
||||
</blockquote>
|
||||
</div>
|
||||
<% end %>
|
||||
<br>
|
||||
<div>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}" target="zammad_app">Bekijk dit in #{config.product_name}</a>
|
||||
</div>
|
||||
@@ -1,12 +1,12 @@
|
||||
Dosažena upomínka pro ticket (#{ticket.title})
|
||||
Dosažena upomínka ticketu (#{ticket.title})
|
||||
|
||||
<div>Dobrý den,</div>
|
||||
<div>Dobrý den, #{recipient.firstname},</div>
|
||||
<br>
|
||||
<div>ticket (#{ticket.title}) vytvořený zákazníkem "<b>#{ticket.customer.longname}</b>" vyžaduje vaši pozornost a to protože bylo dosaženo doby pro upomínku.</div>
|
||||
<div>ticket (#{ticket.title}) vytvořený zákazníkem "<b>#{ticket.customer.longname}</b>" vyžaduje Vaši pozornost, neboť byl dosažen čas pro upomínku.</div>
|
||||
<br>
|
||||
<% if @objects[:article] %>
|
||||
<div>
|
||||
#{t('Information')}:
|
||||
Informace:
|
||||
<blockquote type="cite">
|
||||
#{article.body_as_html}
|
||||
</blockquote>
|
||||
@@ -14,5 +14,5 @@ Dosažena upomínka pro ticket (#{ticket.title})
|
||||
<% end %>
|
||||
<br>
|
||||
<div>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}" target="zammad_app">#{t('View this in Zammad')}</a>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}" target="zammad_app">Otevřít v aplikaci #{config.product_name}</a>
|
||||
</div>
|
||||
|
||||
18
app/views/mailer/ticket_reminder_reached/nl.html.erb
Normal file
18
app/views/mailer/ticket_reminder_reached/nl.html.erb
Normal file
@@ -0,0 +1,18 @@
|
||||
Ticket herinnering bereikt (#{ticket.title})
|
||||
|
||||
<div>Hallo #{recipient.firstname},</div>
|
||||
<br>
|
||||
<div>Een ticket heeft aandacht nodig: herinnering bereikt voor (#{ticket.title}) met klant "<b>#{ticket.customer.longname}</b>".</div>
|
||||
<br>
|
||||
<% if @objects[:article] %>
|
||||
<div>
|
||||
Informatie:
|
||||
<blockquote type="cite">
|
||||
#{article.body_as_html}
|
||||
</blockquote>
|
||||
</div>
|
||||
<% end %>
|
||||
<br>
|
||||
<div>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}" target="zammad_app">Bekijk dit in #{config.product_name}</a>
|
||||
</div>
|
||||
@@ -1,6 +1,6 @@
|
||||
Aktualizován ticket (#{ticket.title})
|
||||
|
||||
<div>Dobrý den,</div>
|
||||
<div>Dobrý den, #{recipient.firstname},</div>
|
||||
<br>
|
||||
<div>
|
||||
Ticket (#{ticket.title}) byl aktualizován uživatelem "<b>#{current_user.longname}</b>".
|
||||
@@ -8,7 +8,7 @@ Ticket (#{ticket.title}) byl aktualizován uživatelem "<b>#{current_user.longna
|
||||
<br>
|
||||
<% if @objects[:changes].present? %>
|
||||
<div>
|
||||
#{t('Changes')}:<br>
|
||||
Změny:
|
||||
<% @objects[:changes].each do |key, value| %>
|
||||
<%= t key %>: <%= h value[0] %> -> <%= h value[1] %><br>
|
||||
<% end %>
|
||||
@@ -17,7 +17,7 @@ Ticket (#{ticket.title}) byl aktualizován uživatelem "<b>#{current_user.longna
|
||||
<br>
|
||||
<% if @objects[:article] %>
|
||||
<div>
|
||||
#{t('Information')}:
|
||||
Informace:
|
||||
<blockquote type="cite">
|
||||
#{article.body_as_html}
|
||||
</blockquote>
|
||||
@@ -25,5 +25,5 @@ Ticket (#{ticket.title}) byl aktualizován uživatelem "<b>#{current_user.longna
|
||||
<% end %>
|
||||
<br>
|
||||
<div>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}<% if @objects[:article] %>/#{article.id}<% end %>" target="zammad_app">#{t('View this in Zammad')}</a>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}<% if @objects[:article] %>/#{article.id}<% end %>" target="zammad_app">Zobrazit v aplikaci #{config.product_name}</a>
|
||||
</div>
|
||||
|
||||
29
app/views/mailer/ticket_update/hu.html.erb
Normal file
29
app/views/mailer/ticket_update/hu.html.erb
Normal file
@@ -0,0 +1,29 @@
|
||||
Frissített jegy (#{ticket.title})
|
||||
|
||||
<div>Üdvözöljük #{recipient.firstname},</div>
|
||||
<br>
|
||||
<div>
|
||||
A jegyet (#{ticket.title}) frissítette: "<b>#{current_user.longname}</b>".
|
||||
</div>
|
||||
<br>
|
||||
<% if @objects[:changes].present? %>
|
||||
<div>
|
||||
Változások:<br>
|
||||
<% @objects[:changes].each do |key, value| %>
|
||||
<%= t key %>: <%= h value[0] %> -> <%= h value[1] %><br>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<br>
|
||||
<% if @objects[:article] %>
|
||||
<div>
|
||||
Információ:
|
||||
<blockquote type="cite">
|
||||
#{article.body_as_html}
|
||||
</blockquote>
|
||||
</div>
|
||||
<% end %>
|
||||
<br>
|
||||
<div>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}<% if @objects[:article] %>/#{article.id}<% end %>" target="zammad_app">Tekintse meg ebben: #{config.product_name}</a>
|
||||
</div>
|
||||
29
app/views/mailer/ticket_update/nl.html.erb
Normal file
29
app/views/mailer/ticket_update/nl.html.erb
Normal file
@@ -0,0 +1,29 @@
|
||||
Bijgewerkt ticket (#{ticket.title})
|
||||
|
||||
<div>Hallo #{recipient.firstname},</div>
|
||||
<br>
|
||||
<div>
|
||||
Ticket (#{ticket.title}) is bijgewerkt door "<b>#{current_user.longname}</b>".
|
||||
</div>
|
||||
<br>
|
||||
<% if @objects[:changes].present? %>
|
||||
<div>
|
||||
Wijzigingen:<br>
|
||||
<% @objects[:changes].each do |key, value| %>
|
||||
<%= t key %>: <%= h value[0] %> -> <%= h value[1] %><br>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<br>
|
||||
<% if @objects[:article] %>
|
||||
<div>
|
||||
Informatie:
|
||||
<blockquote type="citeer">
|
||||
#{article.body_as_html}
|
||||
</blockquote>
|
||||
</div>
|
||||
<% end %>
|
||||
<br>
|
||||
<div>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}<% if @objects[:article] %>/#{article.id} <% end %>" target="zammad_app">Bekijk dit in #{config.product_name}</a>
|
||||
</div>
|
||||
11
app/views/mailer/ticket_update_merged_into/cs.html.erb
Normal file
11
app/views/mailer/ticket_update_merged_into/cs.html.erb
Normal file
@@ -0,0 +1,11 @@
|
||||
Ticket (#{ticket.title}) byl sloučen do jiného ticketu
|
||||
|
||||
<div>Dobrý den, #{recipient.firstname},</div>
|
||||
<br>
|
||||
<div>
|
||||
Ticket (#{ticket.title}) byl sloučen do jiného ticketu uživatelem "<b>#{current_user.longname}</b>".
|
||||
</div>
|
||||
<br>
|
||||
<div>
|
||||
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}" target="zammad_app">View this in #{config.product_name}</a>
|
||||
</div>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user