1
0
mirror of https://github.com/chatopera/cosin.git synced 2025-08-01 16:38:02 +08:00

Merge codes to 8.0.1

Signed-off-by: Hai Liang Wang <hai@chatopera.com>
This commit is contained in:
Hai Liang Wang 2023-07-22 05:56:04 +08:00
commit 1438379573
1049 changed files with 28646 additions and 111400 deletions

42
.circleci/config.yml Normal file
View File

@ -0,0 +1,42 @@
# Use the latest 2.1 version of CircleCI pipeline process engine.
# See: https://circleci.com/docs/configuration-reference
version: 2.1
# Define a job to be invoked later in a workflow.
# See: https://circleci.com/docs/configuration-reference/#jobs
jobs:
# Below is the definition of your job to build and test your app, you can rename and customize it as you want.
package-build-push:
# These next lines define a Docker executor: https://circleci.com/docs/executor-types/
# You can specify an image from Dockerhub or use one of our Convenience Images from CircleCI's Developer Hub.
# Be sure to update the Docker image tag below to openjdk version of your application.
# A list of available CircleCI Docker Convenience Images are available here: https://circleci.com/developer/images/image/cimg/openjdk
docker:
- image: cimg/openjdk:17.0.7
# Add steps to the job
# See: https://circleci.com/docs/configuration-reference/#steps
steps:
# Checkout the code as the first step.
- checkout
- setup_remote_docker
- run:
name: Login DockerHub
command: |
echo "$DOCKERHUB_USERPASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin
- run:
name: Build Contact Center Docker Image
command: cd $CIRCLE_WORKING_DIRECTORY/contact-center && ./admin/build.sh
- run:
name: Push Contact Center Docker Image to DockerHub
command: cd $CIRCLE_WORKING_DIRECTORY/contact-center && ./admin/push.sh
# Invoke jobs via workflows
# See: https://circleci.com/docs/configuration-reference/#workflows
workflows:
dockerize: # This is the name of the workflow, feel free to change it to better match your workflow.
# Inside the workflow, you define the jobs you want to run.
jobs:
- package-build-push:
filters:
branches:
only: develop

18
.github/CODEOWNERS vendored Normal file
View File

@ -0,0 +1,18 @@
# https://github.com/cskefu/cskefu/issues/758
# defaults
* @cskefu/reviewers
# Order is important; the last matching pattern takes the most
# precedence. When someone opens a pull request that only
# modifies JS files, only @js-owner and not the global
# owner(s) will be requested for a review.
*.js @lecjy
*.ts @lecjy
*.pug @lecjy
*.java @lecjy
*.sql @lecjy
pom.xml @lecjy
docs/* @SAMZONG
README* @SAMZONG

2
.gitignore vendored
View File

@ -22,4 +22,4 @@ build.gradle
nohup.out
docker-compose.dev.yml
docker-compose.custom.yml
private
private/

View File

@ -1,4 +1,15 @@
以下为概述,各版本发布详情,请访问[春松客服专栏博客](https://chatopera.blog.csdn.net/)。
各版本发布更新情况描述。
# 8.0.0
- 更新春松客服应用的开源许可证,使用[春松许可证, v1.0](https://www.cskefu.com/2023/06/25/chunsong-public-license-1-0)
- 更新 MySQL 数据库表结构,大量优化 Table 定义,去掉冗余字段,大幅度提升性能
- 使用 Java 17 API & SDK利用 JDK 新功能,大幅度提升性能
- 从 Springboot 1.5.x 升级到 Springboot 3.x 版本,大幅度提升性能
- 去掉了对中间件服务 Elasticsearch 的依赖,大幅度提升性能
- 去掉了冗余的第三方代码,提升编译性能,减少潜在风险
- 修补若干安全漏洞,如 [#735](https://github.com/cskefu/cskefu/issues/735), [#435](https://github.com/cskefu/cskefu/issues/435), [#177](https://github.com/cskefu/cskefu/issues/177)
- Fixed [#476](https://github.com/cskefu/cskefu/issues/476) every SQL execution slowly on first run
# 7.0.1

208
LICENSE
View File

@ -1,201 +1,13 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
Copyright 2023 Beijing Huaxia Chunsong Technology Co., Ltd. <https://www.chatopera.com>
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
Licensed under the Chunsong Public License, Version 1.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
1. Definitions.
https://docs.cskefu.com/licenses/v1.html
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2018-2022 北京华夏春松科技有限公司
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,21 +1,21 @@
<div align=right>
[主页](https://www.cskefu.com/) | [开源许可协议](https://www.cskefu.com/2022/06/24/cskefu-opensource-license/) | [邮件列表](https://lists.cskefu.com/cgi-bin/mailman/listinfo/dev) | [路线图](https://chatopera.github.io/cskefu.roadmap/)
[主页](https://www.cskefu.com/) | [开源许可协议](https://docs.cskefu.com/licenses/v1.html) | [工单列表](https://github.com/cskefu/cskefu/issues) | [路线图](https://github.com/orgs/cskefu/projects/1)
</div>
# 春松客服
[![GitHub Stargazers](https://img.shields.io/github/stars/chatopera/cskefu.svg?style=social&label=Star&maxAge=2592000)](https://github.com/cskefu/cskefu/stargazers) [![GitHub Forks](https://img.shields.io/github/forks/chatopera/cskefu.svg?style=social&label=Fork&maxAge=2592000)](https://github.com/cskefu/cskefu/network/members) [![License](https://img.shields.io/github/license/chatopera/cskefu.svg)](https://www.cskefu.com/2022/06/24/cskefu-opensource-license/ "开源许可协议") [![GitHub Issues](https://img.shields.io/github/issues/chatopera/cskefu.svg)](https://github.com/cskefu/cskefu/issues) [![GitHub Issues Closed](https://img.shields.io/github/issues-closed/chatopera/cskefu.svg)](https://github.com/cskefu/cskefu/issues?q=is%3Aissue+is%3Aclosed) [![docker](https://img.shields.io/docker/pulls/chatopera/contact-center.svg "Docker Pulls")](https://hub.docker.com/r/chatopera/contact-center/) <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![GitHub Stargazers](https://img.shields.io/github/stars/chatopera/cskefu.svg?style=social&label=Star&maxAge=2592000)](https://github.com/cskefu/cskefu/stargazers) [![GitHub Forks](https://img.shields.io/github/forks/chatopera/cskefu.svg?style=social&label=Fork&maxAge=2592000)](https://github.com/cskefu/cskefu/network/members) [![License](https://cdndownload2.chatopera.com/cskefu/licenses/chunsong1.0.svg)](https://www.cskefu.com/licenses/v1.html "开源许可协议") [![GitHub Issues](https://img.shields.io/github/issues/chatopera/cskefu.svg)](https://github.com/cskefu/cskefu/issues) [![GitHub Issues Closed](https://img.shields.io/github/issues-closed/chatopera/cskefu.svg)](https://github.com/cskefu/cskefu/issues?q=is%3Aissue+is%3Aclosed) [![docker](https://img.shields.io/docker/pulls/chatopera/contact-center.svg "Docker Pulls")](https://hub.docker.com/r/chatopera/contact-center/) <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-33-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
[https://www.cskefu.com](https://www.cskefu.com/)
| 版本 | 文档中心 | Git 分支 |
| --- | --- | --- |
| v8.x | [v8](https://docs.cskefu.com/docs/) | [GitHub](https://github.com/cskefu/cskefu/tree/develop) \| [Gitee](https://gitee.com/cskefu/cskefu/tree/develop/) |
| v7.x | [v7](https://docs.cskefu.com/docs/v7/) | [GitHub](https://github.com/cskefu/cskefu/tree/master) \| [Gitee](https://gitee.com/cskefu/cskefu/tree/master/) |
| 版本 | 文档中心 | Git 分支 | 状态 |
| --- | --- | --- | --- |
| v8.x | [v8](https://docs.cskefu.com/docs/) | [GitHub](https://github.com/cskefu/cskefu/tree/develop) \| [Gitee](https://gitee.com/cskefu/cskefu/tree/develop/) | Active, 维护中 |
| v7.x | [v7](https://docs.cskefu.com/docs/v7/) | [GitHub](https://github.com/cskefu/cskefu/tree/v7) \| [Gitee](https://gitee.com/cskefu/cskefu/tree/v7/) | Sunset, 维护终止 |
:hearts: 春松客服的愿景:
@ -29,7 +29,7 @@
春松客服宣言视频: [Bilibili](https://www.bilibili.com/video/BV1hu411o76r/) | [YouTube](https://youtu.be/ILf3BWpq4Ns)
<!-- TODO 新版本介绍:[自然选择开源客服系统!春松客服 v8 版本发布 | Chatopera]() -->
新版本介绍:[观看春松客服 v8 新版本发布会 @ 2023-07-01](https://www.cskefu.com/2023/07/03/community-conf/)
## 媒体报道
@ -233,7 +233,7 @@
在春松客服开源社区,我们建立关系、发现认同、合作共赢!
- 了解春松客服采用的开源许可协议,参考[文档](https://www.cskefu.com/2022/06/24/cskefu-opensource-license/)
- 了解春松客服采用的开源许可协议,参考[文档](https://www.cskefu.com/2023/06/25/chunsong-public-license-1-0/)
- 了解春松客服的开发计划,参考[文档](https://chatopera.github.io/cskefu.roadmap/)
- 加入开源社区运营,成为社区合伙人,参考[文档](https://mp.weixin.qq.com/s/TLE87YX4k097iOXnV4WVSw)
- 加入春松客服开源社区,参考[文档](https://www.cskefu.com/join-us/)
@ -293,8 +293,8 @@
## 开源许可协议
Copyright (2018-2023) <a href="https://www.chatopera.com/" target="_blank">北京华夏春松科技有限公司</a>
Copyright 2023 <a href="https://www.chatopera.com/" target="_blank">Beijing Huaxia Chunsong Technology Co., Ltd.</a>
[Apache License Version 2.0](https://www.cskefu.com/2022/06/24/cskefu-opensource-license/)
[Chunsong Public License, version 1.0](https://docs.cskefu.com/licenses/v1.html)
![image](./public/assets/screenshot-20220323-163051.jpg)

View File

@ -1,6 +1,5 @@
FROM chatopera/java:11
FROM chatopera/java:17
MAINTAINER Hai Liang Wang <hain@chatopera.com>
# base image is built with config/base/build.sh
ARG DEBIAN_FRONTEND=noninteractive
ARG VCS_REF

View File

@ -1,7 +1,7 @@
# 春松客服:智能客服系统
# Chatopera Contact Center
前三代呼叫中心均是以电话为主要的服务渠道。在 2000 年伴随着互联网以及移动通信的发展与普及将电子邮件、互联网、手机短信等渠道接入呼叫中心成为第四代呼叫中心的标志。第四代呼叫中心也称为多媒体呼叫中心或联络中心Contact Center。它相对传统呼叫中心来说接入渠道丰富同时引入了多渠道接入与多渠道统一排队等概念。
## 文档
<https://docs.cskefu.com>
<https://docs.chatopera.com/>

View File

@ -15,10 +15,6 @@ imagename=cskefu/contact-center
[ -z "${BASH_SOURCE[0]}" -o "${BASH_SOURCE[0]}" = "$0" ] || return
# build
cd $appHome
if [ -d ../private ]; then
registryPrefix=dockerhub.qingcloud.com/
fi
TIMESTAMP=`date "+%Y%m%d.%H%M%S"`
PACKAGE_VERSION=`git rev-parse --short HEAD`
APPLICATION_CUSTOMER_ENTITY=${APPLICATION_CUSTOMER_ENTITY:-"OpenSource Community"}

View File

@ -10,4 +10,10 @@ baseDir=$(cd `dirname "$0"`;pwd)
# main
[ -z "${BASH_SOURCE[0]}" -o "${BASH_SOURCE[0]}" = "$0" ] || return
cd $baseDir/../app
mvn clean compile
mvn -DskipTests clean compile
# take too long time with dev002 for uploading artifact, skip this operation
# $baseDir/deploy.app.sh
if [ ! $? -eq 0 ]; then
exit 1
fi

View File

@ -0,0 +1,30 @@
#! /bin/bash
###########################################
# Create standalone SQL file to setup db
###########################################
# constants
baseDir=$(cd `dirname "$0"`;pwd)
cwdDir=$PWD
export PYTHONUNBUFFERED=1
export PATH=/opt/miniconda3/envs/venv-py3/bin:$PATH
export TS=$(date +%Y%m%d%H%M%S)
export DATE=`date "+%Y%m%d"`
export DATE_WITH_TIME=`date "+%Y%m%d-%H%M%S"` #add %3N as we want millisecond too
# functions
# main
[ -z "${BASH_SOURCE[0]}" -o "${BASH_SOURCE[0]}" = "$0" ] || return
cd $baseDir/..
if [ ! -e tmp ]; then
mkdir tmp
fi
cat config/sql/001.mysql-create-db.sql > tmp/db-setup.sql
echo "" >> tmp/db-setup.sql
cat config/sql/002.mysql-create-schemas.sql >> tmp/db-setup.sql
echo "Setup Script created in" `pwd`/tmp/db-setup.sql

View File

@ -17,9 +17,5 @@ imagename=cskefu/contact-center
cd $appHome
PACKAGE_VERSION=`git rev-parse --short HEAD`
if [ -d ../private ]; then
registryPrefix=dockerhub.qingcloud.com/
fi
docker push $registryPrefix$imagename:$PACKAGE_VERSION
docker push $registryPrefix$imagename:develop

View File

@ -1,9 +1,11 @@
# dev profile
src/main/resources/application-dev.properties
# ignore app views within plugins
# ignore plugins: app views, classes
src/main/resources/templates/apps/callout
src/main/resources/templates/apps/callcenter
src/main/java/com/cskefu/cc/plugins/botplt
# ignore logs
logs/
data/

View File

@ -1,15 +1,25 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.cskefu.cc</groupId>
<artifactId>contact-center</artifactId>
<packaging>war</packaging>
<name>cc-core</name>
<description>春松客服:上线开源客服系统</description>
<description>春松客服:开源客服系统</description>
<licenses>
<license>
<name>Chunsong Public License, version 1.0</name>
<url>https://docs.cskefu.com/licenses/v1.html</url>
<comments>
Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
</comments>
</license>
</licenses>
<parent>
<groupId>com.cskefu.cc</groupId>
<artifactId>cc-root</artifactId>
<version>7.0.0-SNAPSHOT</version>
<version>8.0.0-SNAPSHOT</version>
<!-- for Chatopera Nexus reference if file is available with latest version -->
<!-- <relativePath/> -->
<!-- for local reference if file is available with latest version -->
@ -18,21 +28,6 @@
<build>
<finalName>contact-center</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
</plugin>
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
@ -72,28 +67,6 @@
<injectAllReactorProjects>true</injectAllReactorProjects>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
</configuration>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
<version>1.2.8.RELEASE</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
@ -110,7 +83,29 @@
</resource>
</webResources>
</configuration>
<version>2.1.1</version>
<version>3.3.2</version>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
<version>1.2.8.RELEASE</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
</plugin>
</plugins>
<defaultGoal>compile</defaultGoal>
@ -132,7 +127,7 @@
<developer>
<id>hain</id>
<name>Hai Liang Wang</name>
<email>h@cskefu.com</email>
<email>hai@chatopera.com</email>
<url>https://github.com/hailiang-wang</url>
<organization>Chatopera Inc.</organization>
<organizationUrl>https://www.chatopera.com</organizationUrl>

View File

@ -1,50 +1,48 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc;
import com.chatopera.cc.BlessingAndUnblessing;
import com.cskefu.cc.basic.Constants;
import com.cskefu.cc.basic.MainContext;
import com.cskefu.cc.config.AppCtxRefreshEventListener;
import com.cskefu.cc.util.SystemEnvHelper;
import com.cskefu.cc.util.mobile.MobileNumberUtils;
import org.apache.commons.lang.StringUtils;
import jakarta.servlet.MultipartConfigElement;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jms.JmsPoolConnectionFactoryFactory;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.web.servlet.ErrorPage;
import org.springframework.boot.web.server.ConfigurableWebServerFactory;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.http.HttpStatus;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.util.unit.DataSize;
import javax.servlet.MultipartConfigElement;
import java.io.IOException;
@SpringBootApplication
@EnableJpaRepositories("com.cskefu.cc.persistence.repository")
@EnableElasticsearchRepositories("com.cskefu.cc.persistence.es")
@EnableTransactionManagement
public class Application {
@ -54,10 +52,10 @@ public class Application {
private String uploaddir;
@Value("${spring.servlet.multipart.max-file-size}")
private String multipartMaxUpload;
private Long multipartMaxUpload;
@Value("${spring.servlet.multipart.max-request-size}")
private String multipartMaxRequest;
private Long multipartMaxRequest;
/**
* 加载模块
@ -67,7 +65,6 @@ public class Application {
if (StringUtils.equalsIgnoreCase(SystemEnvHelper.parseFromApplicationProps("cskefu.modules.contacts"), "true")) {
MainContext.enableModule(Constants.CSKEFU_MODULE_CONTACTS);
}
// 会话监控模块 Customer Chats Audit
if (StringUtils.equalsIgnoreCase(SystemEnvHelper.parseFromApplicationProps("cskefu.modules.cca"), "true")) {
MainContext.enableModule(Constants.CSKEFU_MODULE_CCA);
@ -84,21 +81,14 @@ public class Application {
}
}
/**
* 开源许可协议
*/
protected static void license(){
System.out.println(">> 春松客服采用开源许可证Apache License 2.0");
System.out.println(">> 详细介绍https://www.cskefu.com/cskefu-opensource-license");
System.out.println(">> CSKeFu is released under Apache License 2.0");
System.out.println(">> Get details about CSKeFu License with https://www.cskefu.com/cskefu-opensource-license");
}
/**
* Init local resources
*/
protected static void serve(final String[] args) {
try {
// Tune druid params, https://github.com/cskefu/cskefu/issues/835
System.setProperty("druid.mysql.usePingMethod", "false");
MobileNumberUtils.init();
/************************
* 该APP中加载多个配置文件
@ -107,8 +97,6 @@ public class Application {
SpringApplication app = new SpringApplicationBuilder(Application.class)
.properties("spring.config.name:application,git")
.build();
Application.license();
BlessingAndUnblessing.print();
app.setBannerMode(Banner.Mode.CONSOLE);
app.setAddCommandLineProperties(false);
app.addListeners(new AppCtxRefreshEventListener());
@ -120,27 +108,34 @@ public class Application {
}
}
// TODO lecjy
@Bean
public MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory factory = new MultipartConfigFactory();
factory.setMaxFileSize(multipartMaxUpload); //KB,MB
factory.setMaxRequestSize(multipartMaxRequest);
factory.setMaxFileSize(DataSize.ofMegabytes(multipartMaxUpload)); //KB,MB
factory.setMaxRequestSize(DataSize.ofMegabytes(multipartMaxRequest));
factory.setLocation(uploaddir);
return factory.createMultipartConfig();
}
// TODO lecjy
@Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
return new EmbeddedServletContainerCustomizer() {
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
ErrorPage error = new ErrorPage("/error.html");
container.addErrorPages(error);
}
public WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer() {
return factory -> {
// 定义404错误页
HttpStatus notFound = HttpStatus.NOT_FOUND;
// 定义404错误页
ErrorPage errorPage = new ErrorPage(notFound, "/error.html");
// 追加错误页替换springboot默认的错误页
factory.addErrorPages(errorPage);
};
}
public static void main(String[] args) {
Application.serve(args);
try {
Application.serve(args);
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -1,28 +0,0 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cskefu.cc;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
public class ServletInitializer extends SpringBootServletInitializer{
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}

View File

@ -1,17 +1,15 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.acd;
@ -63,26 +61,26 @@ public class ACDAgentDispatcher implements IACDDispatcher {
* 1将该坐席状态置为"非就绪"
* 2) 将该坐席的访客重新分配给其它坐席
*
* @param ctx agentno和orgi为必填
* @param ctx agentno为必填
* @return 有没有成功将所有其服务的访客都分配出去
*/
@Override
public void dequeue(final ACDComposeContext ctx) {
// 先将该客服切换到非就绪状态
final AgentStatus agentStatus = cache.findOneAgentStatusByAgentnoAndOrig(ctx.getAgentno(), ctx.getOrgi());
final AgentStatus agentStatus = cache.findOneAgentStatusByAgentno(ctx.getAgentno());
if (agentStatus != null) {
agentStatus.setBusy(false);
agentStatus.setUpdatetime(new Date());
agentStatus.setStatus(MainContext.AgentStatusEnum.NOTREADY.toString());
agentStatusRes.save(agentStatus);
cache.putAgentStatusByOrgi(agentStatus, ctx.getOrgi());
cache.putAgentStatus(agentStatus);
}
// 然后将该坐席的访客分配给其它坐席
// 获得该租户在线的客服的多少
// TODO 对于agentUser的技能组过滤在下面再逐个考虑
// 该信息同样也包括当前用户
List<AgentUser> agentUsers = cache.findInservAgentUsersByAgentnoAndOrgi(ctx.getAgentno(), ctx.getOrgi());
List<AgentUser> agentUsers = cache.findInservAgentUsersByAgentno(ctx.getAgentno());
int sz = agentUsers.size();
for (final AgentUser x : agentUsers) {
try {
@ -96,7 +94,7 @@ public class ACDAgentDispatcher implements IACDDispatcher {
// 因为重新分配该访客将其从撤离的坐席中服务集合中删除
// 此处类似于 Transfer
redisCommand.removeSetVal(
RedisKey.getInServAgentUsersByAgentnoAndOrgi(ctx.getAgentno(), ctx.getOrgi()), x.getUserid());
RedisKey.getInServAgentUsersByAgentno(ctx.getAgentno()), x.getUserid());
sz--;
} catch (Exception e) {
logger.warn("[dequeue] throw error:", e);

View File

@ -1,17 +1,15 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.acd;
@ -33,10 +31,11 @@ import com.cskefu.cc.socketio.client.NettyClients;
import com.cskefu.cc.socketio.message.Message;
import com.cskefu.cc.util.HashMapUtils;
import com.cskefu.cc.util.SerializeUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import java.util.Date;
@ -61,6 +60,7 @@ public class ACDAgentService {
private ACDPolicyService acdPolicyService;
@Autowired
@Lazy
private PeerSyncIM peerSyncIM;
@Autowired
@ -79,7 +79,7 @@ public class ACDAgentService {
private AgentStatusRepository agentStatusRes;
@Autowired
private OnlineUserRepository onlineUserRes;
private PassportWebIMUserRepository onlineUserRes;
@Autowired
private UserRepository userRes;
@ -94,7 +94,7 @@ public class ACDAgentService {
* @param ctx
*/
public void notifyAgentUserProcessResult(final ACDComposeContext ctx) {
Objects.requireNonNull(ctx,"ctx can not be null");
Objects.requireNonNull(ctx, "ctx can not be null");
if (StringUtils.isBlank(ctx.getMessage())) {
logger.info("[onConnect] can not find available agent for user {}", ctx.getOnlineUserId());
return;
@ -132,7 +132,7 @@ public class ACDAgentService {
}
MainContext.getPeerSyncIM().send(MainContext.ReceiverType.VISITOR,
MainContext.ChannelType.toValue(ctx.getChannel()),
MainContext.ChannelType.toValue(ctx.getChannelType()),
ctx.getAppid(),
MainContext.MessageType.NEW, ctx.getOnlineUserId(), outMessage, true);
@ -144,30 +144,26 @@ public class ACDAgentService {
*
* @param agentno
* @param agentUser
* @param orgi
* @return
* @throws Exception
*/
public AgentService assignVisitorAsInvite(
public void assignVisitorAsInvite(
final String agentno,
final AgentUser agentUser,
final String orgi
final AgentUser agentUser
) throws Exception {
final AgentStatus agentStatus = cache.findOneAgentStatusByAgentnoAndOrig(agentno, orgi);
return pickupAgentUserInQueue(agentUser, agentStatus);
final AgentStatus agentStatus = cache.findOneAgentStatusByAgentno(agentno);
pickupAgentUserInQueue(agentUser, agentStatus);
}
/**
* 为坐席批量分配用户
*
* @param agentno
* @param orgi
*/
public void assignVisitors(String agentno, String orgi) {
logger.info("[assignVisitors] agentno {}, orgi {}", agentno, orgi);
public void assignVisitors(String agentno) {
logger.info("[assignVisitors] agentno {}", agentno);
// 获得目标坐席的状态
AgentStatus agentStatus = SerializeUtil.deserialize(
redisCommand.getHashKV(RedisKey.getAgentStatusReadyHashKey(orgi), agentno));
redisCommand.getHashKV(RedisKey.getAgentStatusReadyHashKey(), agentno));
if (agentStatus == null) {
logger.warn("[assignVisitors] can not find AgentStatus for agentno {}", agentno);
@ -185,12 +181,12 @@ public class ACDAgentService {
}
// 获得所有待服务访客的列表
final Map<String, AgentUser> pendingAgentUsers = cache.getAgentUsersInQueByOrgi(orgi);
final Map<String, AgentUser> pendingAgentUsers = cache.getAgentUsersInQue();
// 本次批量分配访客数目
Map<String, Integer> assigned = new HashMap<>();
int currentAssigned = cache.getInservAgentUsersSizeByAgentnoAndOrgi(
agentStatus.getAgentno(), agentStatus.getOrgi());
int currentAssigned = cache.getInservAgentUsersSizeByAgentno(
agentStatus.getAgentno());
logger.info(
"[assignVisitors] agentno {}, name {}, current assigned {}, batch size in queue {}",
@ -229,7 +225,7 @@ public class ACDAgentService {
}
// 坐席未达到最大咨询访客数量并且单次批量分配小于坐席就绪时分配最大访客数量(initMaxuser)
final SessionConfig sessionConfig = acdPolicyService.initSessionConfig(agentUser.getSkill(), orgi);
final SessionConfig sessionConfig = acdPolicyService.initSessionConfig(agentUser.getSkill());
if ((ACDServiceRouter.getAcdPolicyService().getAgentUsersBySkill(agentStatus, agentUser.getSkill()) < sessionConfig.getMaxuser()) && (assigned.getOrDefault(agentUser.getSkill(), 0) < sessionConfig.getInitmaxuser())) {
assigned.merge(agentUser.getSkill(), 1, Integer::sum);
pickupAgentUserInQueue(agentUser, agentStatus);
@ -242,7 +238,7 @@ public class ACDAgentService {
break;
}
}
agentStatusProxy.broadcastAgentsStatus(orgi, "agent", "success", agentno);
agentStatusProxy.broadcastAgentsStatus("agent", "success", agentno);
}
/**
@ -254,19 +250,18 @@ public class ACDAgentService {
*/
public AgentService pickupAgentUserInQueue(final AgentUser agentUser, final AgentStatus agentStatus) {
// 从排队队列移除
cache.deleteAgentUserInqueByAgentUserIdAndOrgi(agentUser.getUserid(), agentUser.getOrgi());
cache.deleteAgentUserInqueByAgentUserId(agentUser.getUserid());
AgentService agentService = null;
// 下面开始处理其加入到服务中的队列
try {
agentService = resolveAgentService(
agentStatus, agentUser, agentUser.getOrgi(), false);
agentStatus, agentUser, false);
// 处理完成得到 agentService
Message outMessage = new Message();
outMessage.setMessage(acdMessageHelper.getSuccessMessage(
agentService,
agentUser.getChannel(),
agentUser.getOrgi()));
agentUser.getChanneltype()));
outMessage.setMessageType(MainContext.MediaType.TEXT.toString());
outMessage.setCalltype(MainContext.CallType.IN.toString());
outMessage.setCreatetime(MainUtils.dateFormate.format(new Date()));
@ -278,7 +273,7 @@ public class ACDAgentService {
// 向访客推送消息
peerSyncIM.send(
MainContext.ReceiverType.VISITOR,
MainContext.ChannelType.toValue(agentUser.getChannel()), agentUser.getAppid(),
MainContext.ChannelType.toValue(agentUser.getChanneltype()), agentUser.getAppid(),
MainContext.MessageType.STATUS, agentUser.getUserid(), outMessage, true
);
@ -288,7 +283,7 @@ public class ACDAgentService {
MainContext.MessageType.NEW, agentUser.getAgentno(), outMessage, true);
// 通知更新在线数据
agentStatusProxy.broadcastAgentsStatus(agentUser.getOrgi(), "agent", "pickup", agentStatus.getAgentno());
agentStatusProxy.broadcastAgentsStatus("agent", "pickup", agentStatus.getAgentno());
}
} catch (Exception ex) {
logger.warn("[assignVisitors] fail to process service", ex);
@ -300,10 +295,9 @@ public class ACDAgentService {
* 访客服务结束
*
* @param agentUser
* @param orgi
* @throws Exception
*/
public void finishAgentService(final AgentUser agentUser, final String orgi) {
public void finishAgentService(final AgentUser agentUser) {
if (agentUser != null) {
/**
* 设置AgentUser
@ -312,7 +306,7 @@ public class ACDAgentService {
AgentStatus agentStatus = null;
if (StringUtils.equals(MainContext.AgentUserStatusEnum.INSERVICE.toString(), agentUser.getStatus()) &&
agentUser.getAgentno() != null) {
agentStatus = cache.findOneAgentStatusByAgentnoAndOrig(agentUser.getAgentno(), orgi);
agentStatus = cache.findOneAgentStatusByAgentno(agentUser.getAgentno());
}
// 设置新AgentUser的状态
@ -324,18 +318,18 @@ public class ACDAgentService {
// 从缓存中删除agentUser缓存
agentUserRes.save(agentUser);
final SessionConfig sessionConfig = acdPolicyService.initSessionConfig(agentUser.getSkill(), orgi);
final SessionConfig sessionConfig = acdPolicyService.initSessionConfig(agentUser.getSkill());
/**
* 坐席服务
*/
AgentService service = null;
if (StringUtils.isNotBlank(agentUser.getAgentserviceid())) {
service = agentServiceRes.findByIdAndOrgi(agentUser.getAgentserviceid(), agentUser.getOrgi());
service = agentServiceRes.findById(agentUser.getAgentserviceid()).orElse(null);
} else if (agentStatus != null) {
// 该访客没有和坐席对话因此没有 AgentService
// 当做留言处理创建一个新的 AgentService
service = resolveAgentService(agentStatus, agentUser, orgi, true);
service = resolveAgentService(agentStatus, agentUser, true);
}
if (service != null) {
@ -345,8 +339,7 @@ public class ACDAgentService {
service.setSessiontimes(System.currentTimeMillis() - service.getServicetime().getTime());
}
final AgentUserTask agentUserTask = agentUserTaskRes.findOne(
agentUser.getId());
final AgentUserTask agentUserTask = agentUserTaskRes.findById(agentUser.getId()).orElse(null);
if (agentUserTask != null) {
service.setAgentreplyinterval(agentUserTask.getAgentreplyinterval());
service.setAgentreplytime(agentUserTask.getAgentreplytime());
@ -378,7 +371,7 @@ public class ACDAgentService {
*/
if (agentStatus != null) {
agentStatus.setUsers(
cache.getInservAgentUsersSizeByAgentnoAndOrgi(agentStatus.getAgentno(), agentStatus.getOrgi()));
cache.getInservAgentUsersSizeByAgentno(agentStatus.getAgentno()));
agentStatusRes.save(agentStatus);
}
@ -387,12 +380,12 @@ public class ACDAgentService {
/**
* 发送到访客端的通知
*/
switch (MainContext.ChannelType.toValue(agentUser.getChannel())) {
switch (MainContext.ChannelType.toValue(agentUser.getChanneltype())) {
case WEBIM:
// WebIM 发送对话结束事件
// 向访客发送消息
outMessage.setAgentStatus(agentStatus);
outMessage.setMessage(acdMessageHelper.getServiceFinishMessage(agentUser.getChannel(), agentUser.getSkill(), orgi));
outMessage.setMessage(acdMessageHelper.getServiceFinishMessage(agentUser.getChanneltype(), agentUser.getSkill()));
outMessage.setMessageType(MainContext.AgentUserStatusEnum.END.toString());
outMessage.setCalltype(MainContext.CallType.IN.toString());
outMessage.setCreatetime(MainUtils.dateFormate.format(new Date()));
@ -401,7 +394,7 @@ public class ACDAgentService {
// 向访客发送消息
peerSyncIM.send(
MainContext.ReceiverType.VISITOR,
MainContext.ChannelType.toValue(agentUser.getChannel()), agentUser.getAppid(),
MainContext.ChannelType.toValue(agentUser.getChanneltype()), agentUser.getAppid(),
MainContext.MessageType.STATUS, agentUser.getUserid(), outMessage, true
);
@ -423,7 +416,7 @@ public class ACDAgentService {
break;
case MESSENGER:
outMessage.setAgentStatus(agentStatus);
outMessage.setMessage(acdMessageHelper.getServiceFinishMessage(agentUser.getChannel(), agentUser.getSkill(), orgi));
outMessage.setMessage(acdMessageHelper.getServiceFinishMessage(agentUser.getChanneltype(), agentUser.getSkill()));
outMessage.setMessageType(MainContext.AgentUserStatusEnum.END.toString());
outMessage.setCalltype(MainContext.CallType.IN.toString());
outMessage.setCreatetime(MainUtils.dateFormate.format(new Date()));
@ -432,7 +425,7 @@ public class ACDAgentService {
// 向访客发送消息
peerSyncIM.send(
MainContext.ReceiverType.VISITOR,
MainContext.ChannelType.toValue(agentUser.getChannel()), agentUser.getAppid(),
MainContext.ChannelType.toValue(agentUser.getChanneltype()), agentUser.getAppid(),
MainContext.MessageType.STATUS, agentUser.getUserid(), outMessage, true
);
@ -448,30 +441,30 @@ public class ACDAgentService {
default:
logger.info(
"[finishAgentService] ignore notify agent service end for channel {}, agent user id {}",
agentUser.getChannel(), agentUser.getId());
agentUser.getChanneltype(), agentUser.getId());
}
// 更新访客的状态为可以接收邀请
final OnlineUser onlineUser = onlineUserRes.findOneByUseridAndOrgi(
agentUser.getUserid(), agentUser.getOrgi());
if (onlineUser != null) {
onlineUser.setInvitestatus(MainContext.OnlineUserInviteStatus.DEFAULT.toString());
onlineUserRes.save(onlineUser);
final PassportWebIMUser passportWebIMUser = onlineUserRes.findOneByUserid(
agentUser.getUserid());
if (passportWebIMUser != null) {
passportWebIMUser.setInvitestatus(MainContext.OnlineUserInviteStatus.DEFAULT.toString());
onlineUserRes.save(passportWebIMUser);
logger.info(
"[finishAgentService] onlineUser id {}, status {}, invite status {}", onlineUser.getId(),
onlineUser.getStatus(), onlineUser.getInvitestatus());
"[finishAgentService] onlineUser id {}, status {}, invite status {}", passportWebIMUser.getId(),
passportWebIMUser.getStatus(), passportWebIMUser.getInvitestatus());
}
// 当前访客服务已经结束为坐席寻找新访客
if (agentStatus != null) {
if ((ACDServiceRouter.getAcdPolicyService().getAgentUsersBySkill(agentStatus, agentUser.getSkill()) - 1) < sessionConfig.getMaxuser()) {
assignVisitors(agentStatus.getAgentno(), orgi);
assignVisitors(agentStatus.getAgentno());
}
}
agentStatusProxy.broadcastAgentsStatus(
orgi, "end", "success", agentUser != null ? agentUser.getId() : null);
"end", "success", agentUser != null ? agentUser.getId() : null);
} else {
logger.info("[finishAgentService] orgi {}, invalid agent user, should not be null", orgi);
logger.info("[finishAgentService] invalid agent user, should not be null");
}
}
@ -481,11 +474,10 @@ public class ACDAgentService {
* 包括数据库记录及缓存信息
*
* @param agentUser
* @param orgi
* @return
*/
public void finishAgentUser(final AgentUser agentUser, final String orgi) throws CSKefuException {
logger.info("[finishAgentUser] userId {}, orgi {}", agentUser.getUserid(), orgi);
public void finishAgentUser(final AgentUser agentUser) throws CSKefuException {
logger.info("[finishAgentUser] userId {}", agentUser.getUserid());
if (agentUser == null || agentUser.getId() == null) {
throw new CSKefuException("Invalid agentUser info");
@ -496,7 +488,7 @@ public class ACDAgentService {
* 未结束聊天先结束对话然后删除记录
*/
// 删除缓存
finishAgentService(agentUser, orgi);
finishAgentService(agentUser);
}
// 删除数据库里的AgentUser记录
@ -511,36 +503,32 @@ public class ACDAgentService {
*
* @param agentStatus 坐席状态
* @param agentUser 坐席访客会话
* @param orgi 租户ID
* @param finished 结束服务
* @return
*/
public AgentService resolveAgentService(
AgentStatus agentStatus,
final AgentUser agentUser,
final String orgi,
final boolean finished) {
AgentService agentService = new AgentService();
if (StringUtils.isNotBlank(agentUser.getAgentserviceid())) {
AgentService existAgentService = agentServiceRes.findByIdAndOrgi(agentUser.getAgentserviceid(), orgi);
AgentService existAgentService = agentServiceRes.findById(agentUser.getAgentserviceid()).orElse(null);
if (existAgentService != null) {
agentService = existAgentService;
} else {
agentService.setId(agentUser.getAgentserviceid());
}
}
agentService.setOrgi(orgi);
final Date now = new Date();
// 批量复制属性
MainUtils.copyProperties(agentUser, agentService);
agentService.setChannel(agentUser.getChannel());
agentService.setChanneltype(agentUser.getChanneltype());
agentService.setSessionid(agentUser.getSessionid());
// 此处为何设置loginDate为现在
agentUser.setLogindate(now);
OnlineUser onlineUser = onlineUserRes.findOneByUseridAndOrgi(agentUser.getUserid(), orgi);
PassportWebIMUser passportWebIMUser = onlineUserRes.findOneByUserid(agentUser.getUserid());
if (finished == true) {
// 服务结束
@ -553,9 +541,9 @@ public class ACDAgentService {
agentService.setLeavemsgstatus(MainContext.LeaveMsgStatus.NOTPROCESS.toString()); //未处理的留言
}
if (onlineUser != null) {
if (passportWebIMUser != null) {
// 更新OnlineUser对象变更为默认状态可以接受邀请
onlineUser.setInvitestatus(MainContext.OnlineUserInviteStatus.DEFAULT.toString());
passportWebIMUser.setInvitestatus(MainContext.OnlineUserInviteStatus.DEFAULT.toString());
}
} else if (agentStatus != null) {
agentService.setAgent(agentStatus.getAgentno());
@ -592,7 +580,7 @@ public class ACDAgentService {
agentService.setOwner(agentUser.getOwner());
agentService.setTimes(0);
final User agent = userRes.findOne(agentService.getAgentno());
final User agent = userRes.findById(agentService.getAgentno()).orElse(null);
agentUser.setAgentname(agent.getUname());
agentUser.setAgentno(agentService.getAgentno());
@ -619,11 +607,11 @@ public class ACDAgentService {
agentService.setWaittingtime((int) (System.currentTimeMillis() - agentUser.getCreatetime().getTime()));
agentUser.setWaittingtime(agentService.getWaittingtime());
}
if (onlineUser != null) {
agentService.setOsname(onlineUser.getOpersystem());
agentService.setBrowser(onlineUser.getBrowser());
if (passportWebIMUser != null) {
agentService.setOsname(passportWebIMUser.getOpersystem());
agentService.setBrowser(passportWebIMUser.getBrowser());
// 记录onlineUser的id
agentService.setDataid(onlineUser.getId());
agentService.setDataid(passportWebIMUser.getId());
}
agentService.setLogindate(agentUser.getCreatetime());
@ -645,14 +633,14 @@ public class ACDAgentService {
/**
* 更新OnlineUser对象变更为服务中不可邀请
*/
if (onlineUser != null && !finished) {
onlineUser.setInvitestatus(MainContext.OnlineUserInviteStatus.INSERV.toString());
onlineUserRes.save(onlineUser);
if (passportWebIMUser != null && !finished) {
passportWebIMUser.setInvitestatus(MainContext.OnlineUserInviteStatus.INSERV.toString());
onlineUserRes.save(passportWebIMUser);
}
// 更新坐席服务人数坐席更新时间到缓存
if (agentStatus != null) {
agentUserProxy.updateAgentStatus(agentStatus, orgi);
agentUserProxy.updateAgentStatus(agentStatus);
}
return agentService;
}

View File

@ -1,17 +1,15 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.acd;
@ -20,7 +18,7 @@ import com.cskefu.cc.basic.MainContext;
import com.cskefu.cc.model.AgentService;
import com.cskefu.cc.model.AgentUser;
import com.cskefu.cc.persistence.repository.AgentServiceRepository;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -39,15 +37,14 @@ public class ACDChatbotService {
* 为访客分配机器人客服 ACD策略此处 AgentStatus 是建议 坐席 如果启用了 历史服务坐席 优先策略 则会默认检查历史坐席是否空闲如果空闲则分配如果不空闲 分配当前建议的坐席
*
* @param agentUser
* @param orgi
* @return
* @throws Exception
*/
public AgentService processChatbotService(final String botName, final AgentUser agentUser, final String orgi) {
public AgentService processChatbotService(final String botName, final AgentUser agentUser) {
AgentService agentService = new AgentService(); //放入缓存的对象
Date now = new Date();
if (StringUtils.isNotBlank(agentUser.getAgentserviceid())) {
agentService = agentServiceRes.findByIdAndOrgi(agentUser.getAgentserviceid(), orgi);
agentService = agentServiceRes.findById(agentUser.getAgentserviceid()).orElse(null);
agentService.setEndtime(now);
if (agentService.getServicetime() != null) {
agentService.setSessiontimes(System.currentTimeMillis() - agentService.getServicetime().getTime());
@ -56,12 +53,11 @@ public class ACDChatbotService {
} else {
agentService.setServicetime(now);
agentService.setLogindate(now);
agentService.setOrgi(orgi);
agentService.setOwner(agentUser.getContextid());
agentService.setSessionid(agentUser.getSessionid());
agentService.setRegion(agentUser.getRegion());
agentService.setUsername(agentUser.getUsername());
agentService.setChannel(agentUser.getChannel());
agentService.setChanneltype(agentUser.getChanneltype());
if (botName != null) {
agentService.setAgentusername(botName);
}

View File

@ -1,22 +1,19 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.acd;
import com.cskefu.cc.basic.Constants;
import com.cskefu.cc.basic.MainContext;
import com.cskefu.cc.basic.MainUtils;
import com.cskefu.cc.cache.Cache;
@ -25,7 +22,7 @@ import com.cskefu.cc.persistence.repository.*;
import com.cskefu.cc.proxy.OrganProxy;
import com.cskefu.cc.util.HashMapUtils;
import com.cskefu.cc.util.WebIMReport;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -50,13 +47,13 @@ public class ACDPolicyService {
private SessionConfigRepository sessionConfigRes;
@Autowired
private OnlineUserRepository onlineUserRes;
private PassportWebIMUserRepository onlineUserRes;
@Autowired
private AgentUserRepository agentUserRes;
@Autowired
private SNSAccountRepository snsAccountRes;
private ChannelRepository snsAccountRes;
@Autowired
private OrganProxy organProxy;
@ -69,10 +66,10 @@ public class ACDPolicyService {
@SuppressWarnings("unchecked")
public List<SessionConfig> initSessionConfigList() {
List<SessionConfig> sessionConfigList;
if ((sessionConfigList = cache.findOneSessionConfigListByOrgi(Constants.SYSTEM_ORGI)) == null) {
if ((sessionConfigList = cache.findOneSessionConfigList()) == null) {
sessionConfigList = sessionConfigRes.findAll();
if (sessionConfigList != null && sessionConfigList.size() > 0) {
cache.putSessionConfigListByOrgi(sessionConfigList, Constants.SYSTEM_ORGI);
cache.putSessionConfigList(sessionConfigList);
}
}
return sessionConfigList;
@ -81,17 +78,16 @@ public class ACDPolicyService {
/**
* 载入坐席 ACD策略配置
*
* @param orgi
* @return
*/
public SessionConfig initSessionConfig(String organid, final String orgi) {
public SessionConfig initSessionConfig(String organid) {
SessionConfig sessionConfig;
if ((sessionConfig = cache.findOneSessionConfigByOrgi(organid, orgi)) == null) {
sessionConfig = sessionConfigRes.findByOrgiAndSkill(orgi, organid);
if ((sessionConfig = cache.findOneSessionConfig(organid)) == null) {
sessionConfig = sessionConfigRes.findBySkill(organid);
if (sessionConfig == null) {
sessionConfig = new SessionConfig();
} else {
cache.putSessionConfigByOrgi(sessionConfig, organid, orgi);
cache.putSessionConfig(sessionConfig, organid);
}
}
@ -136,19 +132,17 @@ public class ACDPolicyService {
* 优先级: 1. 指定坐席;2. 指定技能组; 3. 租户所有的坐席
*
* @param agentUser
* @param orgi
* @return
*/
public List<AgentStatus> filterOutAvailableAgentStatus(
final AgentUser agentUser,
final String orgi,
final SessionConfig sessionConfig) {
logger.info(
"[filterOutAvailableAgentStatus] pre-conditions: agentUser.agentno {}, orgi {}, skill {}, onlineUser {}",
agentUser.getAgentno(), orgi, agentUser.getSkill(), agentUser.getUserid()
"[filterOutAvailableAgentStatus] pre-conditions: agentUser.agentno {}, skill {}, onlineUser {}",
agentUser.getAgentno(), agentUser.getSkill(), agentUser.getUserid()
);
List<AgentStatus> agentStatuses = new ArrayList<>();
Map<String, AgentStatus> map = cache.findAllReadyAgentStatusByOrgi(orgi);
Map<String, AgentStatus> map = cache.findAllReadyAgentStatus();
// DEBUG
if (map.size() > 0) {
@ -168,7 +162,7 @@ public class ACDPolicyService {
}
if (agentUser != null && StringUtils.isNotBlank(agentUser.getAgentno())) {
User user = userRes.findById(agentUser.getAgentno());
User user = userRes.findById(agentUser.getAgentno()).orElse(null);
if (user != null && !user.isSuperadmin()) {
// 用户不为空并且不是超级管理员
// 指定坐席
@ -236,9 +230,8 @@ public class ACDPolicyService {
*
* TODO 指定技能组无用户停止分配
*/
SNSAccount snsAccount = snsAccountRes.findBySnsidAndOrgi(agentUser.getAppid(), orgi);
Map<String, Organ> allOrgan = organProxy.findAllOrganByParentIdAndOrgi(snsAccount.getOrgan(), orgi);
Channel channel = snsAccountRes.findBySnsid(agentUser.getAppid()).get();
Map<String, Organ> allOrgan = organProxy.findAllOrganByParentId(channel.getOrgan());
// allOrgan.keySet().retainAll
// 对于该租户的所有客服
@ -313,7 +306,6 @@ public class ACDPolicyService {
public AgentStatus filterOutAgentStatusWithPolicies(
final SessionConfig sessionConfig,
final List<AgentStatus> agentStatuses,
final String orgi,
final String onlineUserId,
final boolean isInvite) {
AgentStatus agentStatus = null;
@ -341,7 +333,7 @@ public class ACDPolicyService {
logger.info("[filterOutAgentStatusWithPolicies] check agent against chat history.");
// 启用了历史坐席优先 查找 历史服务坐席
List<WebIMReport> webIMaggs = MainUtils.getWebIMDataAgg(
onlineUserRes.findBySkillAndOrgiForDistinctAgent(sessionConfig.getSkill(), orgi, onlineUserId));
onlineUserRes.findBySkillForDistinctAgent(sessionConfig.getSkill(), onlineUserId));
for (WebIMReport report : webIMaggs) {
for (final AgentStatus o : agentStatuses) {
if (StringUtils.equals(
@ -399,7 +391,7 @@ public class ACDPolicyService {
}
public int getAgentUsersBySkill(AgentStatus agentStatus, String skill) {
return agentUserRes.countByAgentnoAndStatusAndOrgiAndSkill(agentStatus.getAgentno(), MainContext.AgentUserStatusEnum.INSERVICE.toString(), agentStatus.getOrgi(), skill);
return agentUserRes.countByAgentnoAndStatusAndSkill(agentStatus.getAgentno(), MainContext.AgentUserStatusEnum.INSERVICE.toString(), skill);
}
}

View File

@ -1,24 +1,22 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.acd;
import com.cskefu.cc.cache.Cache;
import com.cskefu.cc.model.AgentUser;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -35,9 +33,9 @@ public class ACDQueueService {
private Cache cache;
@SuppressWarnings("unchecked")
public int getQueueIndex(String agent, String orgi, String skill) {
public int getQueueIndex(String agent, String skill) {
int queneUsers = 0;
Map<String, AgentUser> map = cache.getAgentUsersInQueByOrgi(orgi);
Map<String, AgentUser> map = cache.getAgentUsersInQue();
for (final Map.Entry<String, AgentUser> entry : map.entrySet()) {
if (StringUtils.isNotBlank(skill)) {

View File

@ -1,17 +1,15 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.acd;

View File

@ -1,17 +1,15 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.acd;
@ -25,7 +23,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import jakarta.annotation.PostConstruct;
/**
* 处置访客分配

View File

@ -1,17 +1,15 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.acd;
@ -26,7 +24,7 @@ import com.cskefu.cc.persistence.repository.AgentServiceRepository;
import com.cskefu.cc.persistence.repository.AgentUserRepository;
import com.cskefu.cc.persistence.repository.WorkMonitorRepository;
import com.cskefu.cc.proxy.OrganProxy;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -58,28 +56,26 @@ public class ACDWorkMonitor {
/**
* 获得 当前服务状态
*
* @param orgi
* @return
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public AgentReport getAgentReport(String orgi) {
return getAgentReport(null, orgi);
public AgentReport getAgentReport() {
return getAgentReport(null);
}
/**
* 获得一个技能组的坐席状态
*
* @param organ
* @param orgi
* @return
*/
public AgentReport getAgentReport(String organ, String orgi) {
public AgentReport getAgentReport(String organ) {
/**
* 统计当前在线的坐席数量
*/
AgentReport report = new AgentReport();
Map<String, AgentStatus> readys = cache.getAgentStatusReadyByOrig(orgi);
Map<String, AgentStatus> readys = cache.getAgentStatusReady();
int readyNum = 0;
int busyNum = 0;
@ -104,7 +100,6 @@ public class ACDWorkMonitor {
}
report.setAgents(readyNum);
report.setBusy(busyNum);
report.setOrgi(orgi);
/**
* 统计当前服务中的用户数量
@ -113,20 +108,20 @@ public class ACDWorkMonitor {
if (organ != null) {
Organ currentOrgan = new Organ();
currentOrgan.setId(organ);
Map<String, Organ> organs = organProxy.findAllOrganByParentAndOrgi(currentOrgan, orgi);
Map<String, Organ> organs = organProxy.findAllOrganByParent(currentOrgan);
report.setUsers(agentServiceRes.countByOrgiAndStatusAndAgentskillIn(orgi, MainContext.AgentUserStatusEnum.INSERVICE.toString(), organs.keySet()));
report.setInquene(agentUserRes.countByOrgiAndStatusAndSkillIn(orgi, MainContext.AgentUserStatusEnum.INQUENE.toString(), organs.keySet()));
report.setUsers(agentServiceRes.countByStatusAndAgentskillIn(MainContext.AgentUserStatusEnum.INSERVICE.toString(), organs.keySet()));
report.setInquene(agentUserRes.countByStatusAndSkillIn(MainContext.AgentUserStatusEnum.INQUENE.toString(), organs.keySet()));
} else {
// 服务中
report.setUsers(cache.getInservAgentUsersSizeByOrgi(orgi));
report.setUsers(cache.getInservAgentUsersSize());
// 等待中
report.setInquene(cache.getInqueAgentUsersSizeByOrgi(orgi));
report.setInquene(cache.getInqueAgentUsersSize());
}
// DEBUG
logger.info(
"[getAgentReport] orgi {}, organ {}, agents {}, busy {}, users {}, inqueue {}", orgi, organ,
"[getAgentReport] organ {}, agents {}, busy {}, users {}, inqueue {}", organ,
report.getAgents(), report.getBusy(), report.getUsers(), report.getInquene()
);
return report;
@ -138,7 +133,6 @@ public class ACDWorkMonitor {
* @param status 工作状态也就是上一个状态
* @param current 下一个工作状态
* @param worktype 类型 语音OR 文本
* @param orgi
* @param lasttime
*/
public void recordAgentStatus(
@ -150,7 +144,6 @@ public class ACDWorkMonitor {
String status,
String current,
String worktype,
String orgi,
Date lasttime
) {
WorkMonitor workMonitor = new WorkMonitor();
@ -169,17 +162,16 @@ public class ACDWorkMonitor {
workMonitor.setBusy(true);
}
if (status.equals(MainContext.AgentStatusEnum.READY.toString())) {
int count = workMonitorRes.countByAgentAndDatestrAndStatusAndOrgi(
int count = workMonitorRes.countByAgentAndDatestrAndStatus(
agent, MainUtils.simpleDateFormat.format(new Date()),
MainContext.AgentStatusEnum.READY.toString(), orgi
MainContext.AgentStatusEnum.READY.toString()
);
if (count == 0) {
workMonitor.setFirsttime(true);
}
}
if (current.equals(MainContext.AgentStatusEnum.NOTREADY.toString())) {
List<WorkMonitor> workMonitorList = workMonitorRes.findByOrgiAndAgentAndDatestrAndFirsttime(
orgi, agent, MainUtils.simpleDateFormat.format(new Date()), true);
List<WorkMonitor> workMonitorList = workMonitorRes.findByAgentAndDatestrAndFirsttime(agent, MainUtils.simpleDateFormat.format(new Date()), true);
if (workMonitorList.size() > 0) {
WorkMonitor firstWorkMonitor = workMonitorList.get(0);
if (firstWorkMonitor.getFirsttimes() == 0) {
@ -193,7 +185,6 @@ public class ACDWorkMonitor {
workMonitor.setDatestr(MainUtils.simpleDateFormat.format(new Date()));
workMonitor.setName(agent);
workMonitor.setOrgi(orgi);
workMonitor.setUserid(userid);
workMonitorRes.save(workMonitor);

View File

@ -1,17 +1,15 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.acd.basic;
@ -23,12 +21,11 @@ import com.cskefu.cc.util.IP;
public class ACDComposeContext extends Message {
// 技能组及渠道
private String orgi;
private String organid;
private Organ organ;
private String appid;
private String channel;
private SNSAccount snsAccount;
private String channeltype;
private Channel channel;
private String sessionid;
// 策略
@ -55,7 +52,7 @@ public class ACDComposeContext extends Message {
// 访客
private String onlineUserId;
private OnlineUser onlineUser;
private PassportWebIMUser passportWebIMUser;
private String onlineUserNickname;
private String onlineUserHeadimgUrl;
@ -94,22 +91,22 @@ public class ACDComposeContext extends Message {
this.appid = appid;
}
public String getChannel() {
public String getChannelType() {
return channeltype;
}
public void setChannelType(String channelType) {
this.channeltype = channelType;
}
public Channel getSnsAccount() {
return channel;
}
public void setChannel(String channel) {
public void setSnsAccount(Channel channel) {
this.channel = channel;
}
public SNSAccount getSnsAccount() {
return snsAccount;
}
public void setSnsAccount(SNSAccount snsAccount) {
this.snsAccount = snsAccount;
}
public SessionConfig getSessionConfig() {
return sessionConfig;
}
@ -190,12 +187,12 @@ public class ACDComposeContext extends Message {
this.agentUser = agentUser;
}
public OnlineUser getOnlineUser() {
return onlineUser;
public PassportWebIMUser getOnlineUser() {
return passportWebIMUser;
}
public void setOnlineUser(OnlineUser onlineUser) {
this.onlineUser = onlineUser;
public void setOnlineUser(PassportWebIMUser passportWebIMUser) {
this.passportWebIMUser = passportWebIMUser;
}
public AgentService getAgentService() {
@ -286,14 +283,6 @@ public class ACDComposeContext extends Message {
this.ownerid = ownerid;
}
public String getOrgi() {
return orgi;
}
public void setOrgi(String orgi) {
this.orgi = orgi;
}
public String getOnlineUserHeadimgUrl() {
return onlineUserHeadimgUrl;
}

View File

@ -1,17 +1,15 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.acd.basic;
@ -23,7 +21,7 @@ import com.cskefu.cc.model.AgentUser;
import com.cskefu.cc.model.SessionConfig;
import com.cskefu.cc.util.IP;
import com.cskefu.cc.util.IPTools;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -50,8 +48,7 @@ public class ACDMessageHelper {
ctx.setOnlineUserId(agentUser.getUserid());
ctx.setOnlineUserNickname(agentUser.getNickname());
ctx.setOrganid(agentUser.getSkill());
ctx.setOrgi(agentUser.getOrgi());
ctx.setChannel(agentUser.getChannel());
ctx.setChannelType(agentUser.getChanneltype());
ctx.setAgentno(agentUser.getAgentno());
ctx.setBrowser(agentUser.getBrowser());
ctx.setOsname(agentUser.getOsname());
@ -78,15 +75,14 @@ public class ACDMessageHelper {
*
* @param agentService
* @param channel
* @param orgi
* @return
*/
public String getSuccessMessage(AgentService agentService, String channel, String orgi) {
public String getSuccessMessage(AgentService agentService, String channel) {
String queneTip = "<span id='agentno'>" + agentService.getAgentusername() + "</span>";
if (!MainContext.ChannelType.WEBIM.toString().equals(channel)) {
queneTip = agentService.getAgentusername();
}
SessionConfig sessionConfig = acdPolicyService.initSessionConfig(agentService.getSkill(), orgi);
SessionConfig sessionConfig = acdPolicyService.initSessionConfig(agentService.getSkill());
String successMsg = "坐席分配成功," + queneTip + "为您服务。";
if (StringUtils.isNotBlank(sessionConfig.getSuccessmsg())) {
successMsg = sessionConfig.getSuccessmsg().replaceAll("\\{agent\\}", queneTip);
@ -98,11 +94,10 @@ public class ACDMessageHelper {
* 通知消息内容和坐席断开
*
* @param channel
* @param orgi
* @return
*/
public String getServiceFinishMessage(String channel, String organid, String orgi) {
SessionConfig sessionConfig = acdPolicyService.initSessionConfig(organid, orgi);
public String getServiceFinishMessage(String channel, String organid) {
SessionConfig sessionConfig = acdPolicyService.initSessionConfig(organid);
String queneTip = "坐席已断开和您的对话";
if (StringUtils.isNotBlank(sessionConfig.getFinessmsg())) {
queneTip = sessionConfig.getFinessmsg();
@ -115,11 +110,10 @@ public class ACDMessageHelper {
* 通知消息内容和坐席断开刷新页面
*
* @param channel
* @param orgi
* @return
*/
public String getServiceOffMessage(String channel, String organid, String orgi) {
SessionConfig sessionConfig = acdPolicyService.initSessionConfig(organid, orgi);
public String getServiceOffMessage(String channel, String organid) {
SessionConfig sessionConfig = acdPolicyService.initSessionConfig(organid);
String queneTip = "坐席已断开和您的对话,刷新页面为您分配新的坐席";
if (StringUtils.isNotBlank(sessionConfig.getFinessmsg())) {
queneTip = sessionConfig.getFinessmsg();
@ -127,7 +121,7 @@ public class ACDMessageHelper {
return queneTip;
}
public String getNoAgentMessage(int queneIndex, String channel, String organid, String orgi) {
public String getNoAgentMessage(int queneIndex, String channel, String organid) {
if (queneIndex < 0) {
queneIndex = 0;
}
@ -135,7 +129,7 @@ public class ACDMessageHelper {
if (!MainContext.ChannelType.WEBIM.toString().equals(channel)) {
queneTip = String.valueOf(queneIndex);
}
SessionConfig sessionConfig = acdPolicyService.initSessionConfig(organid, orgi);
SessionConfig sessionConfig = acdPolicyService.initSessionConfig(organid);
String noAgentTipMsg = "坐席全忙,已进入等待队列,您也可以在其他时间再来咨询。";
if (StringUtils.isNotBlank(sessionConfig.getNoagentmsg())) {
noAgentTipMsg = sessionConfig.getNoagentmsg().replaceAll("\\{num\\}", queneTip);
@ -143,13 +137,13 @@ public class ACDMessageHelper {
return noAgentTipMsg;
}
public String getQueneMessage(int queneIndex, String channel, String organid, String orgi) {
public String getQueneMessage(int queneIndex, String channel, String organid) {
String queneTip = "<span id='queneindex'>" + queneIndex + "</span>";
if (!MainContext.ChannelType.WEBIM.toString().equals(channel)) {
queneTip = String.valueOf(queneIndex);
}
SessionConfig sessionConfig = acdPolicyService.initSessionConfig(organid, orgi);
SessionConfig sessionConfig = acdPolicyService.initSessionConfig(organid);
String agentBusyTipMsg = "正在排队,请稍候,在您之前,还有 " + queneTip + " 位等待用户。";
if (StringUtils.isNotBlank(sessionConfig.getAgentbusymsg())) {
agentBusyTipMsg = sessionConfig.getAgentbusymsg().replaceAll("\\{num\\}", queneTip);
@ -163,7 +157,6 @@ public class ACDMessageHelper {
*
* @param onlineUserId
* @param nickname
* @param orgi
* @param session
* @param appid
* @param ip
@ -185,7 +178,6 @@ public class ACDMessageHelper {
public static ACDComposeContext getWebIMComposeContext(
final String onlineUserId,
final String nickname,
final String orgi,
final String session,
final String appid,
final String ip,
@ -215,8 +207,7 @@ public class ACDMessageHelper {
ctx.setOnlineUserId(onlineUserId);
ctx.setOnlineUserNickname(nickname);
ctx.setOrganid(skill);
ctx.setOrgi(orgi);
ctx.setChannel(channel);
ctx.setChannelType(channel);
ctx.setAgentno(agent);
ctx.setBrowser(browser);
ctx.setOsname(osname);

View File

@ -1,18 +1,16 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.acd.basic;

View File

@ -1,17 +1,15 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.acd.middleware.visitor;
@ -47,18 +45,18 @@ public class ACDVisAllocatorMw implements Middleware<ACDComposeContext> {
* 查询条件当前在线的 坐席并且 未达到最大 服务人数的坐席
*/
final List<AgentStatus> agentStatuses = acdPolicyService.filterOutAvailableAgentStatus(
ctx.getAgentUser(), ctx.getOrgi(), ctx.getSessionConfig());
ctx.getAgentUser(), ctx.getSessionConfig());
/**
* 处理ACD 技能组请求和 坐席请求
*/
AgentStatus agentStatus = acdPolicyService.filterOutAgentStatusWithPolicies(
ctx.getSessionConfig(), agentStatuses, ctx.getOrgi(), ctx.getOnlineUserId(), ctx.isInvite());
ctx.getSessionConfig(), agentStatuses, ctx.getOnlineUserId(), ctx.isInvite());
AgentService agentService = null;
try {
agentService = acdAgentService.resolveAgentService(
agentStatus, ctx.getAgentUser(), ctx.getOrgi(), false);
agentStatus, ctx.getAgentUser(), false);
} catch (Exception ex) {
logger.warn("[allotAgent] exception: ", ex);
}

View File

@ -1,17 +1,15 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.acd.middleware.visitor;
@ -57,7 +55,7 @@ public class ACDVisBindingMw implements Middleware<ACDComposeContext> {
if (StringUtils.isNotBlank(ctx.getOrganid())) {
logger.info("[apply] bind skill {}", ctx.getOrganid());
// 绑定技能组
Organ organ = organRes.findOne(ctx.getOrganid());
Organ organ = organRes.findById(ctx.getOrganid()).orElse(null);
if (organ != null) {
ctx.getAgentUser().setSkill(organ.getId());
ctx.setOrgan(organ);
@ -73,7 +71,7 @@ public class ACDVisBindingMw implements Middleware<ACDComposeContext> {
// 绑定坐席有可能是因为前端展示了技能组和坐席
// 也有可能是坐席发送了邀请该访客接收邀请
ctx.getAgentUser().setAgentno(ctx.getAgentno());
User agent = userRes.findOne(ctx.getAgentno());
User agent = userRes.findById(ctx.getAgentno()).orElse(null);
ctx.setAgent(agent);
ctx.getAgentUser().setAgentname(agent.getUname());
} else {

View File

@ -1,17 +1,15 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.acd.middleware.visitor;
@ -24,13 +22,13 @@ import com.cskefu.cc.cache.Cache;
import com.cskefu.cc.model.AgentUser;
import com.cskefu.cc.model.AgentUserContacts;
import com.cskefu.cc.model.Contacts;
import com.cskefu.cc.persistence.es.ContactsRepository;
import com.cskefu.cc.persistence.repository.ContactsRepository;
import com.cskefu.cc.persistence.repository.AgentUserContactsRepository;
import com.cskefu.cc.proxy.AgentStatusProxy;
import com.cskefu.cc.proxy.AgentUserProxy;
import com.chatopera.compose4j.Functional;
import com.chatopera.compose4j.Middleware;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -77,7 +75,7 @@ public class ACDVisBodyParserMw implements Middleware<ACDComposeContext> {
* NOTE AgentUser代表一次会话记录在上一个会话结束并且由坐席人员点击"清除"会从数据库中删除
* 此处查询到的可能是之前的会话其状态需要验证所以不一定是由TA来服务本次会话
*/
AgentUser agentUser = cache.findOneAgentUserByUserIdAndOrgi(ctx.getOnlineUserId(), ctx.getOrgi()).orElseGet(
AgentUser agentUser = cache.findOneAgentUserByUserId(ctx.getOnlineUserId()).orElseGet(
() -> {
/**
* NOTE 新创建的AgentUser不需要设置Status和Agentno
@ -85,10 +83,9 @@ public class ACDVisBodyParserMw implements Middleware<ACDComposeContext> {
*/
AgentUser p = new AgentUser(
ctx.getOnlineUserId(),
ctx.getChannel(),
ctx.getChannelType(),
ctx.getOnlineUserId(),
ctx.getOnlineUserNickname(),
ctx.getOrgi(),
ctx.getAppid());
logger.info("[apply] create new agent user id {}", p.getId());
return p;
@ -97,7 +94,6 @@ public class ACDVisBodyParserMw implements Middleware<ACDComposeContext> {
logger.info("[apply] resolve agent user id {}", agentUser.getId());
agentUser.setOrgi(ctx.getOrgi());
agentUser.setUsername(resolveAgentUsername(agentUser, ctx.getOnlineUserNickname()));
agentUser.setOsname(ctx.getOsname());
agentUser.setBrowser(ctx.getBrowser());
@ -137,22 +133,19 @@ public class ACDVisBodyParserMw implements Middleware<ACDComposeContext> {
ctx.setMessage(
acdMessageHelper.getSuccessMessage(
ctx.getAgentService(),
ctx.getChannel(),
ctx.getOrgi()));
ctx.getChannelType()));
// TODO 判断 INSERVICE agentService 对应的 agentUser
logger.info(
"[apply] agent service: agentno {}, \n agentuser id {} \n user {} \n channel {} \n status {} \n queue index {}",
ctx.getAgentService().getAgentno(), ctx.getAgentService().getAgentuserid(),
ctx.getAgentService().getUserid(),
ctx.getAgentService().getChannel(),
ctx.getAgentService().getChanneltype(),
ctx.getAgentService().getStatus(),
ctx.getAgentService().getQueneindex());
if (StringUtils.isNotBlank(ctx.getAgentService().getAgentuserid())) {
agentUserProxy.findOne(ctx.getAgentService().getAgentuserid()).ifPresent(p -> {
ctx.setAgentUser(p);
});
agentUserProxy.findOne(ctx.getAgentService().getAgentuserid()).ifPresent(ctx::setAgentUser);
}
// TODO 如果是 INSERVICE 那么 agentService.getAgentuserid 就一定不能为空
@ -168,35 +161,32 @@ public class ACDVisBodyParserMw implements Middleware<ACDComposeContext> {
// }
agentStatusProxy.broadcastAgentsStatus(
ctx.getOrgi(), "user", MainContext.AgentUserStatusEnum.INSERVICE.toString(),
"user", MainContext.AgentUserStatusEnum.INSERVICE.toString(),
ctx.getAgentUser().getId());
break;
case INQUENE:
// 处理结果进入排队队列
ctx.getAgentService().setQueneindex(
acdQueueService.getQueueIndex(
ctx.getAgentUser().getAgentno(), ctx.getOrgi(), ctx.getAgentUser().getSkill()));
ctx.getAgentUser().getAgentno(), ctx.getAgentUser().getSkill()));
if (ctx.getAgentService().getQueneindex() > 0) {
// 当前有坐席要排队
ctx.setMessage(acdMessageHelper.getQueneMessage(
ctx.getAgentService().getQueneindex(),
ctx.getAgentUser().getChannel(),
ctx.getOrganid(),
ctx.getOrgi()));
ctx.getAgentUser().getChanneltype(),
ctx.getOrganid()));
} else {
// TODO 什么是否返回 noAgentMessage, 是否在是 INQUENE getQueneindex == 0
// 当前没有坐席要留言
ctx.setNoagent(true);
ctx.setMessage(acdMessageHelper.getNoAgentMessage(
ctx.getAgentService().getQueneindex(),
ctx.getChannel(),
ctx.getOrganid(),
ctx.getOrgi()));
ctx.getChannelType(),
ctx.getOrganid()));
}
agentStatusProxy.broadcastAgentsStatus(
ctx.getOrgi(), "user", MainContext.AgentUserStatusEnum.INQUENE.toString(),
agentStatusProxy.broadcastAgentsStatus("user", MainContext.AgentUserStatusEnum.INQUENE.toString(),
ctx.getAgentUser().getId());
break;
@ -209,9 +199,8 @@ public class ACDVisBodyParserMw implements Middleware<ACDComposeContext> {
ctx.setNoagent(true);
ctx.setMessage(acdMessageHelper.getNoAgentMessage(
0,
ctx.getChannel(),
ctx.getOrganid(),
ctx.getOrgi()));
ctx.getChannelType(),
ctx.getOrganid()));
}
logger.info(
@ -239,8 +228,8 @@ public class ACDVisBodyParserMw implements Middleware<ACDComposeContext> {
}
// 查找会话联系人关联表
AgentUserContacts agentUserContact = agentUserContactsRes.findOneByUseridAndOrgi(
agentUser.getUserid(), agentUser.getOrgi()).orElse(null);
AgentUserContacts agentUserContact = agentUserContactsRes.findOneByUserid(
agentUser.getUserid()).orElse(null);
if (agentUserContact != null) {
Contacts contact = contactsRes.findOneById(agentUserContact.getContactsid()).orElseGet(null);
if (contact != null) {

View File

@ -1,17 +1,15 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.acd.middleware.visitor;
@ -22,7 +20,7 @@ import com.cskefu.cc.acd.basic.ACDMessageHelper;
import com.cskefu.cc.basic.MainContext;
import com.chatopera.compose4j.Functional;
import com.chatopera.compose4j.Middleware;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -53,14 +51,13 @@ public class ACDVisServiceMw implements Middleware<ACDComposeContext> {
case INQUENE:
logger.info("[apply] agent user is in queue");
int queueIndex = acdQueueService.getQueueIndex(
ctx.getAgentUser().getAgentno(), ctx.getOrgi(),
ctx.getAgentUser().getAgentno(),
ctx.getOrganid());
ctx.setMessage(
acdMessageHelper.getQueneMessage(
queueIndex,
ctx.getChannel(),
ctx.getOrganid(),
ctx.getOrgi()));
ctx.getChannelType(),
ctx.getOrganid()));
break;
case INSERVICE:
// 该访客与坐席正在服务中忽略新的连接

View File

@ -1,17 +1,15 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.acd.middleware.visitor;
@ -46,17 +44,16 @@ public class ACDVisSessionCfgMw implements Middleware<ACDComposeContext> {
@Override
public void apply(final ACDComposeContext ctx, final Functional next) {
SessionConfig sessionConfig = acdPolicyService.initSessionConfig(ctx.getOrganid(),
ctx.getOrgi());
SessionConfig sessionConfig = acdPolicyService.initSessionConfig(ctx.getOrganid());
ctx.setSessionConfig(sessionConfig);
// 查询就绪的坐席如果指定技能组则按照技能组查询
AgentReport report;
if (StringUtils.isNotBlank(ctx.getOrganid())) {
report = acdWorkMonitor.getAgentReport(ctx.getOrganid(), ctx.getOrgi());
report = acdWorkMonitor.getAgentReport(ctx.getOrganid());
} else {
report = acdWorkMonitor.getAgentReport(ctx.getOrgi());
report = acdWorkMonitor.getAgentReport();
}
ctx.setAgentReport(report);
@ -67,7 +64,7 @@ public class ACDVisSessionCfgMw implements Middleware<ACDComposeContext> {
ctx.setMessage(sessionConfig.getNotinwhmsg());
} else if (report.getAgents() == 0) {
// 没有就绪的坐席
if (ctx.getChannel().equals(MainContext.ChannelType.MESSENGER.toString())) {
if (ctx.getChannelType().equals(MainContext.ChannelType.MESSENGER.toString())) {
next.apply();
} else {
logger.info("[apply] find no agents, redirect to leave a message.");

View File

@ -1,17 +1,15 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.activemq;
@ -27,7 +25,7 @@ import com.cskefu.cc.socketio.client.NettyClients;
import com.cskefu.cc.util.SerializeUtil;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -62,15 +60,14 @@ public class AgentAuditSubscription {
try {
final JsonObject json = new JsonParser().parse(msg).getAsJsonObject();
if (json.has("orgi") && json.has("data") &&
if (json.has("data") &&
json.has("agentUserId") &&
json.has("event") && json.has("agentno")) {
// 查找关联的会话监控信息
final AgentUserAudit agentUserAudit = cache.findOneAgentUserAuditByOrgiAndId(
json.get("orgi").getAsString(),
final AgentUserAudit agentUserAudit = cache.findOneAgentUserAuditById(
json.get("agentUserId").getAsString()).orElseGet(() -> {
final AgentUser agentUser = agentUserRes.findOne(json.get("agentUserId").getAsString());
final AgentUser agentUser = agentUserRes.findById(json.get("agentUserId").getAsString()).orElse(null);
if (agentUser != null) {
return agentAuditProxy.updateAgentUserAudits(agentUser);
} else {

View File

@ -1,17 +1,15 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.activemq;

View File

@ -1,12 +1,14 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, All rights reserved.
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, All rights reserved.
* <https://www.chatopera.com>
* This software and related documentation are provided under a license agreement containing
* restrictions on use and disclosure and are protected by intellectual property laws.
* Except as expressly permitted in your license agreement or allowed by law, you may not use,
* copy, reproduce, translate, broadcast, modify, license, transmit, distribute, exhibit, perform,
* publish, or display any part, in any form, or by any means. Reverse engineering, disassembly,
* or decompilation of this software, unless required by law for interoperability, is prohibited.
*/
package com.cskefu.cc.activemq;

View File

@ -1,17 +1,15 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.activemq;
@ -20,7 +18,7 @@ import com.alibaba.fastjson.JSONObject;
import com.cskefu.cc.basic.Constants;
import com.cskefu.cc.cache.Cache;
import com.cskefu.cc.persistence.repository.BlackListRepository;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -52,10 +50,9 @@ public class BlackListEventSubscription {
try {
final JSONObject json = JSON.parseObject(payload);
final String userId = json.getString("userId");
final String orgi = json.getString("orgi");
if (StringUtils.isNotBlank(userId) && StringUtils.isNotBlank(orgi)) {
cache.findOneBlackEntityByUserIdAndOrgi(userId, orgi).ifPresent(blackListRes::delete);
if (StringUtils.isNotBlank(userId)) {
cache.findOneBlackEntityByUserId(userId).ifPresent(blackListRes::delete);
} else {
logger.warn("[onMessage] error: invalid payload");
}

View File

@ -1,26 +1,31 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, All rights reserved.
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, All rights reserved.
* <https://www.chatopera.com>
* This software and related documentation are provided under a license agreement containing
* restrictions on use and disclosure and are protected by intellectual property laws.
* Except as expressly permitted in your license agreement or allowed by law, you may not use,
* copy, reproduce, translate, broadcast, modify, license, transmit, distribute, exhibit, perform,
* publish, or display any part, in any form, or by any means. Reverse engineering, disassembly,
* or decompilation of this software, unless required by law for interoperability, is prohibited.
*/
package com.cskefu.cc.activemq;
import com.alibaba.fastjson.JSONObject;
import jakarta.annotation.PostConstruct;
import org.apache.activemq.ScheduledMessage;
import org.apache.activemq.command.ActiveMQTopic;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.core.MessagePostProcessor;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.Map;
@Component
@ -36,7 +41,6 @@ public class BrokerPublisher {
logger.info("[ActiveMQ Publisher] setup successfully.");
}
/**
* 时延消息
*

View File

@ -1,12 +1,14 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, All rights reserved.
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, All rights reserved.
* <https://www.chatopera.com>
* This software and related documentation are provided under a license agreement containing
* restrictions on use and disclosure and are protected by intellectual property laws.
* Except as expressly permitted in your license agreement or allowed by law, you may not use,
* copy, reproduce, translate, broadcast, modify, license, transmit, distribute, exhibit, perform,
* publish, or display any part, in any form, or by any means. Reverse engineering, disassembly,
* or decompilation of this software, unless required by law for interoperability, is prohibited.
*/
package com.cskefu.cc.activemq;
@ -22,7 +24,7 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import jakarta.annotation.PostConstruct;
/**
* IM OnlineUser

View File

@ -1,12 +1,14 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, All rights reserved.
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, All rights reserved.
* <https://www.chatopera.com>
* This software and related documentation are provided under a license agreement containing
* restrictions on use and disclosure and are protected by intellectual property laws.
* Except as expressly permitted in your license agreement or allowed by law, you may not use,
* copy, reproduce, translate, broadcast, modify, license, transmit, distribute, exhibit, perform,
* publish, or display any part, in any form, or by any means. Reverse engineering, disassembly,
* or decompilation of this software, unless required by law for interoperability, is prohibited.
*/
package com.cskefu.cc.activemq;
@ -27,7 +29,7 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import jakarta.annotation.PostConstruct;
import java.util.Date;
/**
@ -65,10 +67,9 @@ public class SocketioConnEventSubscription {
try {
JsonParser parser = new JsonParser();
JsonObject j = parser.parse(payload).getAsJsonObject();
if (j.has("userId") && j.has("orgi") && j.has("isAdmin")) {
final AgentStatus agentStatus = cache.findOneAgentStatusByAgentnoAndOrig(
j.get("userId").getAsString(),
j.get("orgi").getAsString());
if (j.has("userId") && j.has("isAdmin")) {
final AgentStatus agentStatus = cache.findOneAgentStatusByAgentno(
j.get("userId").getAsString());
if (agentStatus != null && (!agentStatus.isConnected())) {
/**
* 处理该坐席为离线
@ -76,7 +77,6 @@ public class SocketioConnEventSubscription {
// 重分配坐席
ACDComposeContext ctx = new ACDComposeContext();
ctx.setAgentno(agentStatus.getAgentno());
ctx.setOrgi(agentStatus.getOrgi());
acdAgentDispatcher.dequeue(ctx);
if (ctx.isResolved()) {
logger.info("[onMessage] re-allotAgent for user's visitors successfully.");
@ -90,19 +90,19 @@ public class SocketioConnEventSubscription {
agentStatus.setUpdatetime(new Date());
// 设置该坐席状态为离线
cache.deleteAgentStatusByAgentnoAndOrgi(agentStatus.getAgentno(), agentStatus.getOrgi());
cache.deleteAgentStatusByAgentno(agentStatus.getAgentno());
agentStatusRes.save(agentStatus);
// 记录坐席工作日志
acdWorkMonitor.recordAgentStatus(agentStatus.getAgentno(),
agentStatus.getUsername(),
agentStatus.getAgentno(),
j.get("isAdmin").getAsBoolean(),
agentStatus.getAgentno(),
agentStatus.getStatus(),
MainContext.AgentStatusEnum.OFFLINE.toString(),
MainContext.AgentWorkType.MEIDIACHAT.toString(),
agentStatus.getOrgi(), null);
agentStatus.getUsername(),
agentStatus.getAgentno(),
j.get("isAdmin").getAsBoolean(),
agentStatus.getAgentno(),
agentStatus.getStatus(),
MainContext.AgentStatusEnum.OFFLINE.toString(),
MainContext.AgentWorkType.MEIDIACHAT.toString(),
null);
} else if (agentStatus == null) {
// 该坐席已经完成离线设置
logger.info("[onMessage] agent is already offline, skip any further operations");

View File

@ -1,17 +1,15 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.aspect;
@ -39,12 +37,12 @@ public class AgentStatusAspect {
@After("execution(* com.cskefu.cc.persistence.repository.AgentStatusRepository.save(..))")
public void save(final JoinPoint joinPoint) {
final AgentStatus agentStatus = (AgentStatus) joinPoint.getArgs()[0];
cache.putAgentStatusByOrgi(agentStatus, agentStatus.getOrgi());
cache.putAgentStatus(agentStatus);
}
@After("execution(* com.cskefu.cc.persistence.repository.AgentStatusRepository.delete(..))")
public void delete(final JoinPoint joinPoint) {
final AgentStatus agentStatus = (AgentStatus) joinPoint.getArgs()[0];
cache.deleteAgentStatusByAgentnoAndOrgi(agentStatus.getAgentno(), agentStatus.getOrgi());
cache.deleteAgentStatusByAgentno(agentStatus.getAgentno());
}
}

View File

@ -1,17 +1,15 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.aspect;
@ -22,7 +20,7 @@ import com.cskefu.cc.cache.RedisCommand;
import com.cskefu.cc.cache.RedisKey;
import com.cskefu.cc.model.AgentUser;
import com.cskefu.cc.proxy.AgentAuditProxy;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
@ -69,7 +67,7 @@ public class AgentUserAspect {
agentAuditProxy.updateAgentUserAudits(agentUser);
// 同步缓存
cache.putAgentUserByOrgi(agentUser, agentUser.getOrgi());
cache.putAgentUser(agentUser);
}
@After("execution(* com.cskefu.cc.persistence.repository.AgentUserRepository.delete(..))")
@ -78,8 +76,8 @@ public class AgentUserAspect {
logger.info(
"[delete] agentUser id {}, agentno {}, userId {}", agentUser.getId(), agentUser.getAgentno(),
agentUser.getUserid());
cache.deleteAgentUserAuditByOrgiAndId(agentUser.getOrgi(), agentUser.getId());
cache.deleteAgentUserByUserIdAndOrgi(agentUser, agentUser.getOrgi());
cache.deleteAgentUserAuditById(agentUser.getId());
cache.deleteAgentUserByUserId(agentUser);
}
/**
@ -92,18 +90,17 @@ public class AgentUserAspect {
@Around("@annotation(com.cskefu.cc.aspect.AgentUserAspect.LinkAgentUser)")
public Object LinkAgentUser(ProceedingJoinPoint joinPoint) throws Throwable {
final AgentUser updated = (AgentUser) joinPoint.getArgs()[0];
final String orgi = (String) joinPoint.getArgs()[1];
Object proceed = joinPoint.proceed(); // after things are done.
logger.info(
"[linkAgentUser] agentUser: status {}, userId {}, agentno {}, orgi {}", updated.getStatus(),
updated.getUserid(), updated.getAgentno(), orgi);
"[linkAgentUser] agentUser: status {}, userId {}, agentno {}", updated.getStatus(),
updated.getUserid(), updated.getAgentno());
if (StringUtils.equals(updated.getStatus(), MainContext.AgentUserStatusEnum.END.toString())) {
// 从集合中删除
redisCommand.removeSetVal(
RedisKey.getInServAgentUsersByAgentnoAndOrgi(updated.getAgentno(), orgi), updated.getUserid());
RedisKey.getInServAgentUsersByAgentno(updated.getAgentno()), updated.getUserid());
} else if (StringUtils.equals(updated.getStatus(), MainContext.AgentUserStatusEnum.INSERVICE.toString())) {
redisCommand.insertSetVal(
RedisKey.getInServAgentUsersByAgentnoAndOrgi(updated.getAgentno(), orgi), updated.getUserid());
RedisKey.getInServAgentUsersByAgentno(updated.getAgentno()), updated.getUserid());
} else if (StringUtils.equals(updated.getStatus(), MainContext.AgentUserStatusEnum.INQUENE.toString())) {
logger.info("[linkAgentUser] ignored inque agent user, haven't resolve one agent yet.");
} else {

View File

@ -1,17 +1,15 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.aspect;
@ -39,14 +37,14 @@ public class BlackEntityAspect {
@After("execution(* com.cskefu.cc.persistence.repository.BlackListRepository.save(..))")
public void save(final JoinPoint joinPoint) {
final BlackEntity blackEntity = (BlackEntity) joinPoint.getArgs()[0];
logger.info("[save] blackEntity userId {}, orgi {}", blackEntity.getUserid(), blackEntity.getOrgi());
cache.putBlackEntityByOrgi(blackEntity, blackEntity.getOrgi());
logger.info("[save] blackEntity userId {}", blackEntity.getUserid());
cache.putBlackEntity(blackEntity);
}
@After("execution(* com.cskefu.cc.persistence.repository.BlackListRepository.delete(..))")
public void delete(final JoinPoint joinPoint) {
final BlackEntity blackEntity = (BlackEntity) joinPoint.getArgs()[0];
logger.info("[delete] blackEntity userId {}, orgi {}", blackEntity.getUserid(), blackEntity.getOrgi());
cache.deleteBlackEntityByUserIdAndOrgi(blackEntity.getUserid(), blackEntity.getOrgi());
logger.info("[delete] blackEntity userId {}", blackEntity.getUserid());
cache.deleteBlackEntityByUserId(blackEntity.getUserid());
}
}

View File

@ -1,24 +1,22 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.aspect;
import com.cskefu.cc.basic.MainContext;
import com.cskefu.cc.cache.Cache;
import com.cskefu.cc.model.OnlineUser;
import org.apache.commons.lang.StringUtils;
import com.cskefu.cc.model.PassportWebIMUser;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@ -40,19 +38,19 @@ public class OnlineUserAspect {
*
* @param joinPoint
*/
@Before("execution(* com.cskefu.cc.persistence.repository.OnlineUserRepository.save(..))")
@Before("execution(* com.cskefu.cc.persistence.repository.PassportWebIMUserRepository.save(..))")
public void save(final JoinPoint joinPoint) {
final OnlineUser onlineUser = (OnlineUser) joinPoint.getArgs()[0];
final PassportWebIMUser passportWebIMUser = (PassportWebIMUser) joinPoint.getArgs()[0];
// logger.info(
// "[save] put onlineUser id {}, status {}, invite status {}", onlineUser.getId(), onlineUser.getStatus(),
// onlineUser.getInvitestatus());
if (StringUtils.isNotBlank(onlineUser.getStatus())) {
switch (MainContext.OnlineUserStatusEnum.toValue(onlineUser.getStatus())) {
if (StringUtils.isNotBlank(passportWebIMUser.getStatus())) {
switch (MainContext.OnlineUserStatusEnum.toValue(passportWebIMUser.getStatus())) {
case OFFLINE:
cache.deleteOnlineUserByIdAndOrgi(onlineUser.getId(), onlineUser.getOrgi());
cache.deleteOnlineUserById(passportWebIMUser.getId());
break;
default:
cache.putOnlineUserByOrgi(onlineUser, onlineUser.getOrgi());
cache.putOnlineUser(passportWebIMUser);
}
}
}

View File

@ -1,22 +1,19 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.aspect;
import com.cskefu.cc.model.ESBean;
import com.cskefu.cc.persistence.hibernate.BaseService;
import com.cskefu.cc.util.CskefuList;
import org.aspectj.lang.ProceedingJoinPoint;
@ -89,11 +86,7 @@ public class SyncDatabaseAspect {
if (data instanceof List) {
dbDataRes.deleteAll((List<Object>) data);
} else {
if (data instanceof ESBean) {
dbDataRes.delete(data);
} else {
dbDataRes.delete(data);
}
dbDataRes.delete(data);
}
}
}

View File

@ -1,17 +1,15 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.basic;
@ -29,7 +27,6 @@ public class Constants {
/**
* 系统配置
*/
public static final String SYSTEM_ORGI = "cskefu";
public static final String USER_SESSION_NAME = "user";
public static final String ORGAN_SESSION_NAME = "organ";
public static final String GUEST_USER = "guest";
@ -208,11 +205,16 @@ public class Constants {
/**
* 聊天机器人
*/
public static final HashSet<String> CHATBOT_VALID_LANGS = new HashSet<String>(Arrays.asList("zh_CN", "en_US"));
public static final HashSet<String> CHATBOT_VALID_LANGS = new HashSet<>(Arrays.asList("zh_CN", "en_US"));
public static final String CHATBOT_CHATBOT_FIRST = "机器人客服优先";
public static final String CHATBOT_HUMAN_FIRST = "人工客服优先";
public static final String CHATBOT_CHATBOT_ONLY = "仅机器人客服";
public static final HashSet<String> CHATBOT_VALID_WORKMODELS = new HashSet<String>(Arrays.asList(CHATBOT_CHATBOT_FIRST, CHATBOT_HUMAN_FIRST, CHATBOT_CHATBOT_ONLY));
public static final HashSet<String> CHATBOT_VALID_WORKMODELS = new HashSet<>(Arrays.asList(CHATBOT_CHATBOT_FIRST, CHATBOT_HUMAN_FIRST, CHATBOT_CHATBOT_ONLY));
/**
* AUTH
*/
public static final String AUTH_TOKEN_TYPE_BEARER = "Bearer";
public static final String AUTH_TOKEN_TYPE_BASIC = "Basic";
}

View File

@ -1,24 +1,20 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.basic;
import com.cskefu.cc.basic.resource.ActivityResource;
import com.cskefu.cc.basic.resource.BatchResource;
import com.cskefu.cc.cache.Cache;
import com.cskefu.cc.cache.RedisCommand;
import com.cskefu.cc.peer.PeerSyncIM;
@ -26,11 +22,10 @@ import com.cskefu.cc.util.DateConverter;
import com.cskefu.cc.util.SystemEnvHelper;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import java.util.HashMap;
import java.util.HashSet;
@ -43,14 +38,12 @@ public class MainContext {
private static boolean imServerRunning = false; // IM服务状态
private static Set<String> modules = new HashSet<String>();
private static final Set<String> modules = new HashSet<>();
public static Map<String, Class<?>> csKeFuResourceMap = new HashMap<String, Class<?>>();
public static final Map<String, Class<?>> csKeFuResourceMap = new HashMap<>();
private static ApplicationContext applicationContext;
private static ElasticsearchTemplate templet;
private static RedisCommand redisCommand;
private static Cache cache;
@ -59,8 +52,6 @@ public class MainContext {
static {
ConvertUtils.register(new DateConverter(), java.util.Date.class);
csKeFuResourceMap.put(TaskType.ACTIVE.toString(), ActivityResource.class);
csKeFuResourceMap.put(TaskType.BATCH.toString(), BatchResource.class);
}
public enum AskSectionType {
@ -339,8 +330,8 @@ public class MainContext {
CALLIN_DIST("呼入挂断", 8),
CALLIN_FAIL("呼入失败", 9);
private String name;
private int index;
private final String name;
private final int index;
CallWireEventType(final String name, final int index) {
this.name = name;
@ -663,8 +654,8 @@ public class MainContext {
OFFLINE("离线", 6),
SERVICES("服务", 7);
private String name;
private int index;
private final String name;
private final int index;
AgentStatusEnum(final String name, final int index) {
this.name = name;
@ -947,14 +938,6 @@ public class MainContext {
return applicationContext;
}
public static ElasticsearchTemplate getTemplet() {
return templet;
}
public static void setTemplet(ElasticsearchTemplate templet) {
MainContext.templet = templet;
}
/**
* 系统级的加密密码 从CA获取
*

View File

@ -1,18 +1,16 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.basic;
@ -25,7 +23,6 @@ import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.cskefu.cc.model.*;
import com.cskefu.cc.persistence.repository.*;
import com.cskefu.cc.util.WebIMReport;
import com.cskefu.cc.util.*;
import com.cskefu.cc.util.asr.AsrResult;
import com.cskefu.cc.util.mail.MailSender;
@ -42,13 +39,14 @@ import de.neuland.pug4j.parser.node.Node;
import de.neuland.pug4j.template.PugTemplate;
import de.neuland.pug4j.template.ReaderTemplateLoader;
import io.netty.handler.codec.http.HttpHeaders;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.ConversionException;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.jasypt.util.text.BasicTextEncryptor;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
@ -62,8 +60,6 @@ import org.springframework.beans.FatalBeanException;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.beans.BeanInfo;
import java.beans.Introspector;
@ -83,13 +79,13 @@ import java.util.regex.Pattern;
public class MainUtils {
private final static Logger logger = LoggerFactory.getLogger(MainUtils.class);
private static MD5 md5 = new MD5();
private static final MD5 md5 = new MD5();
public static SimpleDateFormat dateFormate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static final SimpleDateFormat dateFormate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
public static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
public static SimpleDateFormat timeRangeDateFormat = new SimpleDateFormat("HH:mm");
public static final SimpleDateFormat timeRangeDateFormat = new SimpleDateFormat("HH:mm");
/**
* 当前时间+已过随机生成的 长整形数字
@ -214,7 +210,7 @@ public class MainUtils {
* @return
*/
public static Map<String, Object> getRequestParam(HttpServletRequest request) {
Map<String, Object> values = new HashMap<String, Object>();
Map<String, Object> values = new HashMap<>();
Enumeration<String> enums = request.getParameterNames();
while (enums.hasMoreElements()) {
String param = enums.nextElement();
@ -232,7 +228,7 @@ public class MainUtils {
StringBuffer strb = new StringBuffer();
while (names.hasMoreElements()) {
String name = names.nextElement();
if (name.indexOf("password") < 0) { //不记录 任何包含 password 的参数内容
if (!name.contains("password")) { //不记录 任何包含 password 的参数内容
if (strb.length() > 0) {
strb.append(",");
}
@ -348,15 +344,15 @@ public class MainUtils {
//=================OS=======================
if (userAgent.toLowerCase().indexOf("windows") >= 0) {
if (userAgent.toLowerCase().contains("windows")) {
os = "windows";
} else if (userAgent.toLowerCase().indexOf("mac") >= 0) {
} else if (userAgent.toLowerCase().contains("mac")) {
os = "mac";
} else if (userAgent.toLowerCase().indexOf("x11") >= 0) {
} else if (userAgent.toLowerCase().contains("x11")) {
os = "unix";
} else if (userAgent.toLowerCase().indexOf("android") >= 0) {
} else if (userAgent.toLowerCase().contains("android")) {
os = "android";
} else if (userAgent.toLowerCase().indexOf("iphone") >= 0) {
} else if (userAgent.toLowerCase().contains("iphone")) {
os = "iphone";
} else {
os = "UnKnown";
@ -364,8 +360,8 @@ public class MainUtils {
//===============Browser===========================
if (user.contains("qqbrowser")) {
browser = "QQBrowser";
} else if (user.contains("msie") || user.indexOf("rv:11") > -1) {
if (user.indexOf("rv:11") >= 0) {
} else if (user.contains("msie") || user.contains("rv:11")) {
if (user.contains("rv:11")) {
browser = "IE11";
} else {
String substring = userAgent.substring(userAgent.indexOf("MSIE")).split(";")[0];
@ -388,13 +384,11 @@ public class MainUtils {
}
} else if (user.contains("chrome")) {
browser = "Chrome";
} else if ((user.indexOf("mozilla/7.0") > -1) || (user.indexOf("netscape6") != -1) || (user.indexOf(
"mozilla/4.7") != -1) || (user.indexOf("mozilla/4.78") != -1) || (user.indexOf(
"mozilla/4.08") != -1) || (user.indexOf("mozilla/3") != -1)) {
} else if ((user.contains("mozilla/7.0")) || (user.contains("netscape6")) || (user.contains("mozilla/4.7")) || (user.contains("mozilla/4.78")) || (user.contains("mozilla/4.08")) || (user.contains("mozilla/3"))) {
//browser=(userAgent.substring(userAgent.indexOf("MSIE")).split(" ")[0]).replace("/", "-");
browser = "Netscape-?";
} else if ((user.indexOf("mozilla") > -1)) {
} else if ((user.contains("mozilla"))) {
//browser=(userAgent.substring(userAgent.indexOf("MSIE")).split(" ")[0]).replace("/", "-");
if (browserDetails.indexOf(" ") > 0) {
browser = browserDetails.substring(0, browserDetails.indexOf(" "));
@ -445,8 +439,8 @@ public class MainUtils {
WebIMReport report = new WebIMReport();
if (values != null && values.size() > 0) {
for (int i = 0; i < values.size(); i++) {
Object[] value = (Object[]) values.get(i);
for (Object o : values) {
Object[] value = (Object[]) o;
if (value.length >= 2) {
String invitestatus = (String) value[0];
if (MainContext.OnlineUserInviteStatus.DEFAULT.toString().equals(
@ -470,10 +464,10 @@ public class MainUtils {
* @return
*/
public static List<WebIMReport> getWebIMInviteAgg(List<Object> values) {
List<WebIMReport> webIMReportList = new ArrayList<WebIMReport>();
List<WebIMReport> webIMReportList = new ArrayList<>();
if (values != null && values.size() > 0) {
for (int i = 0; i < values.size(); i++) {
Object[] value = (Object[]) values.get(i);
for (Object o : values) {
Object[] value = (Object[]) o;
WebIMReport report = new WebIMReport();
if (value.length == 3) {
report.setData((String) value[0]);
@ -493,10 +487,10 @@ public class MainUtils {
* @return
*/
public static List<WebIMReport> getWebIMDataAgg(List<Object> values) {
List<WebIMReport> webIMReportList = new ArrayList<WebIMReport>();
List<WebIMReport> webIMReportList = new ArrayList<>();
if (values != null && values.size() > 0) {
for (int i = 0; i < values.size(); i++) {
Object[] value = (Object[]) values.get(i);
for (Object o : values) {
Object[] value = (Object[]) o;
WebIMReport report = new WebIMReport();
if (value.length == 2) {
if (value[0] == null || value[0].toString().equalsIgnoreCase("null") || StringUtils.isBlank(value[0].toString())) {
@ -522,8 +516,8 @@ public class MainUtils {
WebIMReport report = new WebIMReport();
if (values != null && values.size() > 0) {
for (int i = 0; i < values.size(); i++) {
Object[] value = (Object[]) values.get(i);
for (Object o : values) {
Object[] value = (Object[]) o;
if (value.length >= 2) {
String invitestatus = (String) value[0];
if (MainContext.OnlineUserInviteStatus.DEFAULT.toString().equals(
@ -549,8 +543,8 @@ public class MainUtils {
public static WeiXinReport getWeiXinReportResult(List<Object> values) {
WeiXinReport report = new WeiXinReport();
if (values != null && values.size() > 0) {
for (int i = 0; i < values.size(); i++) {
Object[] value = (Object[]) values.get(i);
for (Object o : values) {
Object[] value = (Object[]) o;
if (value.length >= 2) {
String event = (String) value[0];
if (MainContext.WeiXinEventType.SUB.toString().equals(event)) {
@ -569,7 +563,7 @@ public class MainUtils {
if (obj == null) {
return null;
}
Map<String, Object> map = new HashMap<String, Object>();
Map<String, Object> map = new HashMap<>();
try {
BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
@ -600,31 +594,26 @@ public class MainUtils {
}
public static void populate(Object bean, Map<Object, Object> properties) throws IllegalAccessException, InvocationTargetException {
ConvertUtils.register(new Converter() {
@SuppressWarnings("rawtypes")
@Override
public Object convert(Class arg0, Object arg1) {
if (arg1 == null) {
return null;
}
if (arg1 instanceof Date) {
return arg1;
} else if (!(arg1 instanceof String)) {
throw new ConversionException("只支持字符串转换 !");
}
String str = (String) arg1;
if (str.trim().equals("")) {
return null;
}
ConvertUtils.register((arg0, arg1) -> {
if (arg1 == null) {
return null;
}
if (arg1 instanceof Date) {
return arg1;
} else if (!(arg1 instanceof String)) {
throw new ConversionException("只支持字符串转换 !");
}
String str = (String) arg1;
if (str.trim().equals("")) {
return null;
}
SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
return sd.parse(str);
} catch (Exception e) {
throw new RuntimeException(e);
}
SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
return sd.parse(str);
} catch (Exception e) {
throw new RuntimeException(e);
}
}, java.util.Date.class);
@ -648,6 +637,12 @@ public class MainUtils {
public static Object toObject(byte[] data) throws Exception {
ByteArrayInputStream input = new ByteArrayInputStream(data);
ObjectInputStream objectInput = new ObjectInputStream(input);
// https://github.com/cskefu/cskefu/issues/177
// https://www.davidvlijmincx.com/posts/creating_context_specific_deserialization_filters/
ObjectInputFilter filter = ObjectInputFilter.Config.createFilter("java.util.List;com.cskefu.cc.model;!*");
objectInput.setObjectInputFilter(filter);
return objectInput.readObject();
}
@ -715,7 +710,7 @@ public class MainUtils {
Elements pngs = document.select("img[src]");
for (Element element : pngs) {
String imgUrl = element.attr("src");
if (imgUrl.indexOf("/res/image") >= 0) {
if (imgUrl.contains("/res/image")) {
element.attr("class", "ukefu-media-image");
}
}
@ -752,24 +747,21 @@ public class MainUtils {
return workintTime;
}
public static File processImage(final File destFile, final File imageFile) throws IOException {
public static void processImage(final File destFile, final File imageFile) throws IOException {
if (imageFile != null && imageFile.exists()) {
Thumbnails.of(imageFile).imageType(BufferedImage.TYPE_INT_ARGB).width(460).keepAspectRatio(true).toFile(destFile);
}
return destFile;
}
public static File scaleImage(final File destFile, final File imageFile, float quality) throws IOException {
public static void scaleImage(final File destFile, final File imageFile, float quality) throws IOException {
if (imageFile != null && imageFile.exists()) {
Thumbnails.of(imageFile).scale(1f).outputQuality(quality).toFile(destFile);
}
return destFile;
}
public static String processEmoti(String message) {
Pattern pattern = Pattern.compile("\\[([\\d]*?)\\]");
SystemConfig systemConfig = MainContext.getCache().findOneSystemByIdAndOrgi(
"systemConfig", Constants.SYSTEM_ORGI);
SystemConfig systemConfig = MainContext.getCache().findOneSystemById("systemConfig");
Matcher matcher = pattern.matcher(message);
StringBuffer strb = new StringBuffer();
@ -819,12 +811,12 @@ public class MainUtils {
return ip;
}
public static boolean secConfirm(SecretRepository secRes, String orgi, String confirm) {
public static boolean secConfirm(SecretRepository secRes, String confirm) {
/**
* 先调用 IMServer
*/
boolean execute = false;
List<Secret> secretConfig = secRes.findByOrgi(orgi);
List<Secret> secretConfig = secRes.findAll();
if (StringUtils.isNotBlank(confirm)) {
if (secretConfig != null && secretConfig.size() > 0) {
Secret secret = secretConfig.get(0);
@ -844,11 +836,13 @@ public class MainUtils {
* @return
*/
public static SystemConfig getSystemConfig() {
SystemConfig systemConfig = MainContext.getCache().findOneSystemByIdAndOrgi(
"systemConfig", Constants.SYSTEM_ORGI);
SystemConfig systemConfig = MainContext.getCache().findOneSystemById("systemConfig");
if (systemConfig == null) {
SystemConfigRepository systemConfigRes = MainContext.getContext().getBean(SystemConfigRepository.class);
systemConfig = systemConfigRes.findByOrgi(Constants.SYSTEM_ORGI);
List<SystemConfig> systemConfigs = systemConfigRes.findAll();
if (systemConfigs.size() > 0) {
systemConfig = systemConfigs.get(0);
}
}
return systemConfig;
}
@ -861,8 +855,7 @@ public class MainUtils {
public static void initSystemSecField(TablePropertiesRepository tpRes) {
if (tpRes != null) {
List<TableProperties> tpList = tpRes.findBySecfield(true);
MainContext.getCache().putSystemListByIdAndOrgi(
Constants.CSKEFU_SYSTEM_SECFIELD, Constants.SYSTEM_ORGI, tpList);
MainContext.getCache().putSystemListById(Constants.CSKEFU_SYSTEM_SECFIELD, tpList);
}
}
@ -872,10 +865,10 @@ public class MainUtils {
* @return
*/
public static void initSystemArea() {
MainContext.getCache().deleteSystembyIdAndOrgi(Constants.CSKEFU_SYSTEM_AREA, Constants.SYSTEM_ORGI);
MainContext.getCache().deleteSystembyId(Constants.CSKEFU_SYSTEM_AREA);
AreaTypeRepository areaTypeRes = MainContext.getContext().getBean(AreaTypeRepository.class);
MainContext.getCache().putSystemListByIdAndOrgi(
Constants.CSKEFU_SYSTEM_AREA, Constants.SYSTEM_ORGI, areaTypeRes.findAll());
MainContext.getCache().putSystemListById(
Constants.CSKEFU_SYSTEM_AREA, areaTypeRes.findAll());
}
/**
@ -883,19 +876,19 @@ public class MainUtils {
*
* @return
*/
public static void initAdv(String orgi, String skill) {
MainContext.getCache().deleteSystembyIdAndOrgi(Constants.CSKEFU_SYSTEM_ADV + "_" + skill, orgi);
public static void initAdv(String skill) {
MainContext.getCache().deleteSystembyId(Constants.CSKEFU_SYSTEM_ADV + "_" + skill);
AdTypeRepository adRes = MainContext.getContext().getBean(AdTypeRepository.class);
MainContext.getCache().putSystemListByIdAndOrgi(
Constants.CSKEFU_SYSTEM_ADV + "_" + skill, orgi, adRes.findByOrgiAndSkill(orgi, skill));
MainContext.getCache().putSystemListById(
Constants.CSKEFU_SYSTEM_ADV + "_" + skill, adRes.findBySkill(skill));
}
public static Template getTemplate(String id) {
Template templet = null;
if ((templet = MainContext.getCache().findOneSystemByIdAndOrgi(id, Constants.SYSTEM_ORGI)) == null) {
if ((templet = MainContext.getCache().findOneSystemById(id)) == null) {
TemplateRepository templateRes = MainContext.getContext().getBean(TemplateRepository.class);
templet = templateRes.findByIdAndOrgi(id, Constants.SYSTEM_ORGI);
MainContext.getCache().putSystemByIdAndOrgi(id, Constants.SYSTEM_ORGI, templet);
templet = templateRes.findById(id).orElse(null);
MainContext.getCache().putSystemById(id, templet);
}
return templet;
}
@ -905,18 +898,17 @@ public class MainUtils {
*
* @param adpos
* @param skill
* @param orgi
* @return
*/
public static List<AdType> getPointAdvs(String adpos, String skill, String orgi) {
List<AdType> adTypeList = new ArrayList<AdType>();
List<AdType> cacheAdTypeList = MainContext.getCache().findOneSystemListByIdAndOrgi(
Constants.CSKEFU_SYSTEM_ADV + "_" + skill, orgi);
public static List<AdType> getPointAdvs(String adpos, String skill) {
List<AdType> adTypeList = new ArrayList<>();
List<AdType> cacheAdTypeList = MainContext.getCache().findOneSystemListById(
Constants.CSKEFU_SYSTEM_ADV + "_" + skill);
if (cacheAdTypeList == null) {
AdTypeRepository adRes = MainContext.getContext().getBean(AdTypeRepository.class);
cacheAdTypeList = adRes.findByOrgiAndSkill(orgi, skill);
MainContext.getCache().putSystemListByIdAndOrgi(
Constants.CSKEFU_SYSTEM_ADV + "_" + skill, orgi, cacheAdTypeList);
cacheAdTypeList = adRes.findBySkill(skill);
MainContext.getCache().putSystemListById(
Constants.CSKEFU_SYSTEM_ADV + "_" + skill, cacheAdTypeList);
}
List<SysDic> sysDicList = Dict.getInstance().getDic(Constants.CSKEFU_SYSTEM_ADPOS_DIC);
SysDic sysDic = null;
@ -945,12 +937,12 @@ public class MainUtils {
* @return
*/
@SuppressWarnings("unchecked")
public static AdType getPointAdv(String adpos, String skill, String orgi) {
List<AdType> ads = getPointAdvs(adpos, skill, orgi);
public static AdType getPointAdv(String adpos, String skill) {
List<AdType> ads = getPointAdvs(adpos, skill);
return weitht(ads);
}
private static Random random = new Random();
private static final Random random = new Random();
/**
* 按照权重获取广告内容
@ -1034,7 +1026,7 @@ public class MainUtils {
SystemConfig config = MainUtils.getSystemConfig();
if (config != null && config.isEnablemail() && config.getEmailid() != null) {
SystemMessage systemMessage = MainContext.getContext().getBean(
SystemMessageRepository.class).findByIdAndOrgi(config.getEmailid(), config.getOrgi());
SystemMessageRepository.class).findById(config.getEmailid()).orElse(null);
MailSender sender = new MailSender(
systemMessage.getSmtpserver(), systemMessage.getMailfrom(), systemMessage.getSmtpuser(),
decryption(systemMessage.getSmtppassword()), systemMessage.getSeclev(), systemMessage.getSslport());
@ -1111,7 +1103,7 @@ public class MainUtils {
* @return
*/
public static Object getDaysParam(String text) {
Map<String, Object> context = new HashMap<String, Object>();
Map<String, Object> context = new HashMap<>();
context.put("T", processDays());
context.put("t", processDays());
context.put("M", processMonth());
@ -1238,7 +1230,7 @@ public class MainUtils {
SystemConfig config = MainUtils.getSystemConfig();
if (config != null) {
SystemMessage systemMessage = MainContext.getContext().getBean(
SystemMessageRepository.class).findByIdAndOrgi(id, config.getOrgi());
SystemMessageRepository.class).findById(id).orElse(null);
if (systemMessage == null) {
return false;
}
@ -1302,12 +1294,11 @@ public class MainUtils {
* @param userid
* @param client
* @param session
* @param orgi
* @param ipaddr
* @param hostname
* @return
*/
public static WorkSession createWorkSession(String userid, String client, String session, String orgi, String ipaddr, String hostname, String admin, boolean first) {
public static WorkSession createWorkSession(String userid, String client, String session, String ipaddr, String hostname, String admin, boolean first) {
WorkSession workSession = new WorkSession();
workSession.setCreatetime(new Date());
workSession.setBegintime(new Date());
@ -1325,7 +1316,6 @@ public class MainUtils {
workSession.setUserid(userid);
workSession.setClientid(client);
workSession.setSessionid(session);
workSession.setOrgi(orgi);
workSession.setDatestr(MainUtils.simpleDateFormat.format(new Date()));

View File

@ -1,22 +1,20 @@
/*
* Copyright (C) 2022 Chatopera Inc, All rights reserved.
* <https://www.chatopera.com>
* This software and related documentation are provided under a license agreement containing
* restrictions on use and disclosure and are protected by intellectual property laws.
* Except as expressly permitted in your license agreement or allowed by law, you may not use,
* copy, reproduce, translate, broadcast, modify, license, transmit, distribute, exhibit, perform,
* publish, or display any part, in any form, or by any means. Reverse engineering, disassembly,
* or decompilation of this software, unless required by law for interoperability, is prohibited.
/**
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright Jun. 2023 Chatopera Inc. <https://www.chatopera.com>. All rights reserved.
*/
package com.cskefu.cc.basic;
import javax.annotation.PreDestroy;
import com.chatopera.cc.BlessingAndUnblessing;
import jakarta.annotation.PreDestroy;
public class TerminateBean {
@PreDestroy
public void onDestroy() throws Exception {
BlessingAndUnblessing.print();
}
@PreDestroy
public void onDestroy() throws Exception {
}
}

View File

@ -1,18 +1,16 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.basic;

View File

@ -1,17 +1,15 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.basic.auth;

View File

@ -0,0 +1,32 @@
/**
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright Jun. 2023 Chatopera Inc. <https://www.chatopera.com>. All rights reserved.
*/
package com.cskefu.cc.basic.auth;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class BasicTokenMgr {
final static Logger logger = LoggerFactory.getLogger(BasicTokenMgr.class);
/**
* Generate basic token with username and password
*
* @param username
* @param password
* @return
*/
public String generate(final String username, final String password) {
return null;
}
}

View File

@ -1,24 +1,23 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.basic.auth;
import com.cskefu.cc.basic.Constants;
import com.cskefu.cc.cache.RedisKey;
import com.cskefu.cc.model.User;
import com.cskefu.cc.util.SerializeUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -26,16 +25,16 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import jakarta.annotation.PostConstruct;
import java.util.concurrent.TimeUnit;
/**
* 认证和授权的API Token管理
*/
@Component
public class AuthToken {
public class BearerTokenMgr {
private final static Logger logger = LoggerFactory.getLogger(AuthToken.class);
private final static Logger logger = LoggerFactory.getLogger(BearerTokenMgr.class);
@Value("${server.session-timeout}")
private int timeout;
@ -50,6 +49,19 @@ public class AuthToken {
redisValOps = authRedisTemplate.opsForValue();
}
/**
* Remove token with Bearer prefix
*
* @param token
* @return
*/
private String trimToken(final String token) {
if (token.startsWith(Constants.AUTH_TOKEN_TYPE_BEARER)) {
return StringUtils.substring(token, 7);
}
return token;
}
/**
* 设置一个KEY的过期时间
*
@ -60,9 +72,8 @@ public class AuthToken {
authRedisTemplate.expire(key, seconds, TimeUnit.SECONDS);
}
private String authKey(final String auth) {
return RedisKey.getLoginUserKey(auth);
private String resolveTokenKey(final String token) {
return RedisKey.getApiTokenBearerKeyWithValue(trimToken(token));
}
/**********************************
@ -71,13 +82,13 @@ public class AuthToken {
**********************************/
/**
* @param auth 授权的KEY
* @param loginUser 已经登录的用户
* @param token 授权的KEY
* @param user 已经登录的用户
*/
public void putUserByAuth(final String auth, final User loginUser) {
if (StringUtils.isNotBlank(auth) && loginUser != null) {
String serialized = SerializeUtil.serialize(loginUser);
final String key = authKey(auth);
public void update(final String token, final User user) {
if (StringUtils.isNotBlank(token) && user != null) {
String serialized = SerializeUtil.serialize(user);
final String key = resolveTokenKey(token);
redisValOps.set(key, serialized);
expire(key, timeout);
} else {
@ -89,21 +100,21 @@ public class AuthToken {
/**
* 判断一个Auth是否是有效的
*
* @param auth
* @param token
* @return
*/
public boolean existUserByAuth(final String auth) {
return authRedisTemplate.hasKey(authKey(auth));
public boolean existToken(final String token) {
return authRedisTemplate.hasKey(resolveTokenKey(token));
}
/**
* 根据租户ID和认证Auth获得一个登录用户
*
* @param auth
* @param token
* @return
*/
public User findUserByAuth(final String auth) {
String serialized = redisValOps.get(authKey(auth));
public User retrieve(final String token) {
String serialized = redisValOps.get(resolveTokenKey(token));
if (StringUtils.isNotBlank(serialized)) {
return (User) SerializeUtil.deserialize(serialized);
}
@ -113,9 +124,9 @@ public class AuthToken {
/**
* 登出已经登录的系统用户
*
* @param auth
* @param token
*/
public void deleteUserByAuth(final String auth) {
authRedisTemplate.delete(authKey(auth));
public void delete(final String token) {
authRedisTemplate.delete(resolveTokenKey(token));
}
}

View File

@ -1,3 +1,13 @@
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cskefu.cc.basic.plugins;
import java.util.HashMap;

View File

@ -1,17 +1,15 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.basic.plugins;

View File

@ -1,22 +1,20 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.basic.plugins;
import com.cskefu.cc.basic.MainContext;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
@ -42,12 +40,11 @@ public class PluginRegistry {
* 添加插件
*
* @param plugin
* @return
*/
public boolean addPlugin(final IPluginConfigurer plugin) {
public void addPlugin(final IPluginConfigurer plugin) {
for (final IPluginConfigurer x : plugins) {
if (StringUtils.equalsIgnoreCase(x.getPluginId(), plugin.getPluginId())) {
return false;
return;
}
}
@ -56,7 +53,6 @@ public class PluginRegistry {
}
plugins.add(plugin);
return true;
}
/**

View File

@ -1,380 +0,0 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cskefu.cc.basic.resource;
import com.cskefu.cc.basic.Constants;
import com.cskefu.cc.basic.MainContext;
import com.cskefu.cc.basic.MainUtils;
import com.cskefu.cc.model.*;
import com.cskefu.cc.persistence.impl.BatchDataProcess;
import com.cskefu.cc.persistence.impl.ESDataExchangeImpl;
import com.cskefu.cc.persistence.repository.*;
import com.cskefu.cc.util.es.SearchTools;
import com.cskefu.cc.util.es.UKDataBean;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.PageImpl;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class ActivityResource extends Resource{
private JobDetail jobDetail ;
private FormFilterRepository formFilterRes ;
private FormFilterItemRepository formFilterItemRes ;
private PageImpl<UKDataBean> dataList ;
private MetadataTable metadataTable ;
private FormFilter formFilter = null ;
private List<CallAgent> callAgentList ;
private CallAgent current ;
private UKefuCallOutTask task ;
private UKefuCallOutFilter filter ;
private UKefuCallOutTaskRepository callOutTaskRes ;
private UKefuCallOutFilterRepository callOutFilterRes ;
private JobDetailRepository batchRes;
private MetadataRepository metadataRes ;
private JobDetail batch ;
private AtomicInteger assignorganInt = new AtomicInteger() /***分配到坐席***/, assignInt = new AtomicInteger() /***分配到部门***/ , assignAiInt = new AtomicInteger() /***分配到AI***/ ,atomInt = new AtomicInteger() ;
private BatchDataProcess batchDataProcess ;
public ActivityResource(JobDetail jobDetail) {
this.jobDetail = jobDetail ;
this.formFilterRes = MainContext.getContext().getBean(FormFilterRepository.class) ;
this.formFilterItemRes = MainContext.getContext().getBean(FormFilterItemRepository.class) ;
this.callOutTaskRes = MainContext.getContext().getBean(UKefuCallOutTaskRepository.class);
this.callOutFilterRes = MainContext.getContext().getBean(UKefuCallOutFilterRepository.class);
this.batchRes = MainContext.getContext().getBean(JobDetailRepository.class);
this.metadataRes = MainContext.getContext().getBean(MetadataRepository.class);
this.batchDataProcess = new BatchDataProcess(null , MainContext.getContext().getBean(ESDataExchangeImpl.class)) ;
}
@Override
public void begin() throws Exception {
if(!StringUtils.isBlank(jobDetail.getFilterid())) {
formFilter = formFilterRes.findByIdAndOrgi(jobDetail.getFilterid(), this.jobDetail.getOrgi()) ;
List<FormFilterItem> formFilterList = formFilterItemRes.findByOrgiAndFormfilterid(this.jobDetail.getOrgi(), jobDetail.getFilterid()) ;
if(formFilter!=null && !StringUtils.isBlank(formFilter.getFiltertype())) {
if(formFilter.getFiltertype().equals(MainContext.FormFilterType.BATCH.toString())) {
batch = batchRes.findByIdAndOrgi(formFilter.getBatid(), this.jobDetail.getOrgi()) ;
if(batch!=null && !StringUtils.isBlank(batch.getActid())) {
metadataTable = metadataRes.findByTablename(batch.getActid()) ;
}
}else { //业务表
if(!StringUtils.isBlank(formFilter.getTableid())) {
metadataTable = metadataRes.findById(formFilter.getTableid()) ;
}
}
}
if(metadataTable!=null) {
/**
* 只加载 未分配的有效名单数据
*/
if(isRecovery()) {
//回收数据 , 需要传入回收的目标 包括 批次ID任务ID筛选ID活动ID
dataList = SearchTools.recoversearch(this.jobDetail.getOrgi(), this.jobDetail.getExectype(), this.jobDetail.getExectarget() , metadataTable ,(int) Math.ceil(this.jobDetail.getStartindex()/50000), 50000) ;
}else {
dataList = SearchTools.dissearch(this.jobDetail.getOrgi(), formFilter, formFilterList , metadataTable ,(int) Math.ceil(this.jobDetail.getStartindex()/50000), 50000) ;
}
}
this.callAgentList = MainContext.getContext().getBean(CallAgentRepository.class).findByActidAndOrgi(this.jobDetail.getId() , this.jobDetail.getOrgi()) ;
/**
* 生成 活动任务 然后完成分配 , 同时还需要生成 筛选表单的筛选记录 在后台管理界面上可以看到
*/
if(this.callAgentList!=null && this.callAgentList.size() > 0) {
this.current = this.callAgentList.remove(0) ;
}
this.jobDetail.setExecnum(this.jobDetail.getExecnum() + 1);
if(this.isRecovery() && !StringUtils.isBlank(this.jobDetail.getExectype()) && (this.jobDetail.getExectype().equals("filterid") || this.jobDetail.getExectype().equals("filterskill") || this.jobDetail.getExectype().equals("taskskill") || this.jobDetail.getExectype().equals("taskid"))) {
if(this.jobDetail.getExectype().equals("filterid") || this.jobDetail.getExectype().equals("filterskill")) {
this.filter = this.callOutFilterRes.findByIdAndOrgi(this.jobDetail.getExectarget(), this.jobDetail.getOrgi()) ;
}else if(this.jobDetail.getExectype().equals("taskid") || this.jobDetail.getExectype().equals("taskskill") ) {
this.task = this.callOutTaskRes.findByIdAndOrgi(this.jobDetail.getExectarget(), this.jobDetail.getOrgi()) ;
}
}else {
task = new UKefuCallOutTask() ;
task.setName(this.jobDetail.getName() + "_" + MainUtils.dateFormate.format(new Date()));
task.setBatid(formFilter.getBatid());
task.setOrgi(this.jobDetail.getOrgi());
if(this.isRecovery()) {
task.setExectype(MainContext.ActivityExecType.RECOVERY.toString());
}else {
task.setExectype(MainContext.ActivityExecType.DEFAULT.toString());
}
task.setFilterid(formFilter.getId());
task.setActid(this.jobDetail.getId());
task.setExecnum(this.jobDetail.getExecnum());
task.setOrgan(this.jobDetail.getOrgan());
task.setCreatetime(new Date());
if(this.dataList!=null) {
task.setNamenum((int) this.dataList.getTotalElements());
task.setNotassigned((int) this.dataList.getTotalElements());
}
this.callOutTaskRes.save(task) ;
filter = new UKefuCallOutFilter() ;
formFilter.setExecnum(formFilter.getExecnum() + 1);
MainUtils.copyProperties(task, filter);
filter.setName(this.formFilter.getName() + "_" + MainUtils.dateFormate.format(new Date()));
filter.setExecnum(formFilter.getExecnum());
this.callOutFilterRes.save(filter) ;
}
}
}
@Override
public void end(boolean clear) throws Exception {
if(this.atomInt.intValue() > 0) {
this.batchDataProcess.end();
}
//doNothing
/**
* FormFilter的执行信息更新执行次数
*/
if(formFilterRes!=null && this.formFilter != null) {
this.formFilter.setFilternum(this.formFilter.getFilternum()+1);
formFilterRes.save(this.formFilter) ;
}
/**
* 批次的信息更新批次剩余未分配的名单总数 已分配的名单总数
*/
if(this.batchRes!=null && this.batch != null) {
if(this.isRecovery()) {
batch.setAssigned(batch.getAssigned() - this.atomInt.intValue());
}else {
batch.setAssigned(batch.getAssigned() + this.atomInt.intValue());
}
batch.setNotassigned(batch.getNamenum() - batch.getAssigned());
this.batchRes.save(batch) ;
}
if(this.task!=null) {
if(this.isRecovery()) {
if(!StringUtils.isBlank(this.jobDetail.getExecto())) {
this.task.setReorgannum(this.atomInt.intValue());
}else {
this.task.setRenum(this.atomInt.intValue());
}
}else {
this.task.setAssigned(this.assignInt.intValue());
this.task.setAssignedorgan(this.assignorganInt.intValue());
this.task.setAssignedai(this.assignAiInt.intValue());
this.task.setNotassigned(this.task.getNamenum() - this.assignInt.intValue() - this.assignorganInt.intValue() - this.assignAiInt.intValue());
}
this.callOutTaskRes.save(this.task) ;
}
if(this.filter!=null) {
if(this.isRecovery()) {
if(!StringUtils.isBlank(this.jobDetail.getExecto())) {
this.filter.setReorgannum(this.atomInt.intValue());
}else {
this.filter.setRenum(this.atomInt.intValue());
}
}else {
this.filter.setAssigned(this.assignInt.intValue());
this.filter.setAssignedorgan(this.assignorganInt.intValue());
this.filter.setAssignedai(this.assignAiInt.intValue());
this.filter.setNotassigned(this.task.getNamenum() - this.assignInt.intValue() - this.assignorganInt.intValue() - this.assignAiInt.intValue());
}
this.callOutFilterRes.save(this.filter) ;
}
/**
* 更新任务状态记录生成的任务信息
*/
this.jobDetail.setExecmd(null);
this.jobDetail.setExectype(null);
this.jobDetail.setExectarget(null);
this.jobDetail.setExecto(null);
}
@Override
public JobDetail getJob() {
return this.jobDetail;
}
@Override
public void process(OutputTextFormat meta, JobDetail job) throws Exception {
/**
* 执行分配
*/
if(this.isRecovery()) {
if(!StringUtils.isBlank(this.jobDetail.getExecto())) {
meta.getDataBean().getValues().put(Constants.CSKEFU_SYSTEM_DIS_AGENT, null) ;
meta.getDataBean().getValues().put(Constants.CSKEFU_SYSTEM_DIS_AI, null) ;
// meta.getDataBean().getValues().put(Constants.CSKEFU_SYSTEM_DIS_ORGAN, this.jobDetail.getExecto()) ;
meta.getDataBean().getValues().put(Constants.CSKEFU_SYSTEM_DIS_TIME, System.currentTimeMillis()) ;
meta.getDataBean().getValues().put("status", MainContext.NamesDisStatusType.DISORGAN.toString()) ;
}else {
meta.getDataBean().getValues().put(Constants.CSKEFU_SYSTEM_DIS_AI, null) ;
meta.getDataBean().getValues().put(Constants.CSKEFU_SYSTEM_DIS_AGENT, null) ;
meta.getDataBean().getValues().put(Constants.CSKEFU_SYSTEM_DIS_ORGAN, null) ;
meta.getDataBean().getValues().put(Constants.CSKEFU_SYSTEM_DIS_TIME, null) ;
meta.getDataBean().getValues().put("status", MainContext.NamesDisStatusType.NOT.toString()) ;
}
}else {
if(this.current!=null && meta!=null && meta.getDataBean()!=null) {
this.current.getDisnames().incrementAndGet() ;
/**
*
*/
meta.getDataBean().getValues().put(Constants.CSKEFU_SYSTEM_DIS_TIME, System.currentTimeMillis()) ;
meta.getDataBean().getValues().put("actid", this.jobDetail.getId()) ;
meta.getDataBean().getValues().put("metaid", this.metadataTable.getTablename()) ;
meta.getDataBean().getValues().put("batid", this.formFilter.getBatid()) ;
meta.getDataBean().getValues().put("taskid", this.task.getId()) ;
meta.getDataBean().getValues().put("filterid", this.formFilter.getId()) ;
meta.getDataBean().getValues().put("calloutfilid", this.filter.getId()) ;
meta.getDataBean().getValues().put("taskid", this.task.getId()) ;
if(!StringUtils.isBlank(this.jobDetail.getUserid())){
meta.getDataBean().getValues().put("assuser", this.jobDetail.getUserid()) ;
}else{
meta.getDataBean().getValues().put("assuser", this.jobDetail.getCreater()) ;
}
/**
* 任务ID
*/
if("agent".equals(this.current.getDistype())) {
meta.getDataBean().getValues().put("status", MainContext.NamesDisStatusType.DISAGENT.toString()) ;
meta.getDataBean().getValues().put(Constants.CSKEFU_SYSTEM_DIS_AGENT, this.current.getDistarget()) ;
meta.getDataBean().getValues().put(Constants.CSKEFU_SYSTEM_DIS_ORGAN, this.current.getOrgan()) ;
this.assignInt.incrementAndGet() ;
}else if("skill".equals(this.current.getDistype())) {
meta.getDataBean().getValues().put("status", MainContext.NamesDisStatusType.DISORGAN.toString()) ;
meta.getDataBean().getValues().put(Constants.CSKEFU_SYSTEM_DIS_ORGAN, this.current.getDistarget()) ;
this.assignorganInt.incrementAndGet() ;
}else if("ai".equals(this.current.getDistype())) {
meta.getDataBean().getValues().put("status", MainContext.NamesDisStatusType.DISAI.toString()) ;
meta.getDataBean().getValues().put(Constants.CSKEFU_SYSTEM_DIS_AI, this.current.getDistarget()) ;
meta.getDataBean().getValues().put(Constants.CSKEFU_SYSTEM_DIS_ORGAN, this.current.getOrgan()) ;
this.assignAiInt.incrementAndGet() ;
}
}
}
meta.getDataBean().getValues().put("updatetime", System.currentTimeMillis()) ;
/**
* 更新记录是否同时保存分配信息以便于查看分配历史
*/
batchDataProcess.process(meta.getDataBean());
}
@Override
public OutputTextFormat next() throws Exception {
OutputTextFormat outputTextFormat = null;
if(this.dataList!=null && this.current!=null) {
synchronized (this.dataList) {
if(atomInt.intValue() < this.dataList.getContent().size()) {
if(this.isRecovery()) {
UKDataBean dataBean = this.dataList.getContent().get(atomInt.intValue()) ;
outputTextFormat = new OutputTextFormat(this.jobDetail);
if(this.formFilter!=null) {
outputTextFormat.setTitle(this.formFilter.getName());
}
outputTextFormat.setDataBean(dataBean);
atomInt.incrementAndGet() ;
}else if(this.dataList!=null) {
if(this.current.getDisnames().intValue() >= this.current.getDisnum() ) {
if(this.callAgentList.size() > 0) {
this.current = this.callAgentList.remove(0) ;
}else {
this.current = null ;
}
}
if(this.current != null) {
UKDataBean dataBean = this.dataList.getContent().get(atomInt.intValue()) ;
outputTextFormat = new OutputTextFormat(this.jobDetail);
if(this.formFilter!=null) {
outputTextFormat.setTitle(this.formFilter.getName());
}
outputTextFormat.setDataBean(dataBean);
atomInt.incrementAndGet() ;
/**
* 修改为平均分配的方式 每个坐席或者部门评价分配
*/
this.callAgentList.add(this.current) ;
if(this.callAgentList.size() > 0) {
this.current = this.callAgentList.remove(0) ;
}
}
}
}
}
}
return outputTextFormat;
}
@Override
public boolean isAvailable() {
return true;
}
@Override
public OutputTextFormat getText(OutputTextFormat object) throws Exception {
return object;
}
@Override
public void rmResource() {
/**
* 啥也不做
*/
}
@Override
public void updateTask() throws Exception {
/**
* 更新任务状态记录生成的任务信息
*/
this.jobDetail.setExecmd(null);
this.jobDetail.setExectype(null);
this.jobDetail.setExectarget(null);
this.jobDetail.setExecto(null);
}
private boolean isRecovery() {
return StringUtils.isNotBlank(this.jobDetail.getExecmd()) && this.jobDetail.getExecmd().equals("recovery") ;
}
}

View File

@ -1,146 +0,0 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cskefu.cc.basic.resource;
import com.cskefu.cc.basic.MainContext;
import com.cskefu.cc.basic.MainUtils;
import com.cskefu.cc.model.JobDetail;
import com.cskefu.cc.model.MetadataTable;
import com.cskefu.cc.persistence.impl.BatchDataProcess;
import com.cskefu.cc.persistence.impl.ESDataExchangeImpl;
import com.cskefu.cc.persistence.repository.MetadataRepository;
import com.cskefu.cc.persistence.repository.ReporterRepository;
import com.cskefu.cc.util.dsdata.DSData;
import com.cskefu.cc.util.dsdata.DSDataEvent;
import com.cskefu.cc.util.dsdata.ExcelImportProecess;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
public class BatchResource extends Resource{
private JobDetail jobDetail ;
private MetadataTable metadataTable ;
private ESDataExchangeImpl esDataExchange = null ;
private MetadataRepository metadataRes ;
private ReporterRepository reporterRes ;
public BatchResource(JobDetail jobDetail) {
this.jobDetail = jobDetail ;
this.metadataRes = MainContext.getContext().getBean(MetadataRepository.class);
this.reporterRes = MainContext.getContext().getBean(ReporterRepository.class);
this.esDataExchange = MainContext.getContext().getBean(ESDataExchangeImpl.class);
}
@Override
public void begin() throws Exception {
if(!StringUtils.isBlank(jobDetail.getActid())) {
metadataTable = metadataRes.findByTablename(jobDetail.getActid()) ;
}
DSDataEvent event = new DSDataEvent();
String path = MainContext.getContext().getEnvironment().getProperty("web.upload-path") ;
File tempFile = null ;
if(metadataTable!=null && !StringUtils.isBlank(this.jobDetail.getBatchtype()) && this.jobDetail.getBatchtype().equals("plan")) {
if(!StringUtils.isBlank(this.jobDetail.getImptype())) {
if(this.jobDetail.getImptype().equals("local")) {
tempFile = new File(MainUtils.getTemplet(this.jobDetail.getImpurl(), new HashMap<String,Object>()));
}else if(this.jobDetail.getImptype().equals("remote")){
FileUtils.copyURLToFile(new URL(MainUtils.getTemplet(this.jobDetail.getImpurl(), new HashMap<String,Object>())), tempFile = File.createTempFile("UKeFu-CallOut-Temp", ".xls"));
}
}
if(tempFile.exists()) {
String fileName = "callout/batch/"+ MainUtils.getUUID() + tempFile.getName().substring(tempFile.getName().lastIndexOf(".")) ;
File excelFile = new File(path , fileName) ;
if(!excelFile.getParentFile().exists()){
excelFile.getParentFile().mkdirs() ;
}
event.setTablename(metadataTable.getTablename());
event.setDSData(new DSData(null ,excelFile , tempFile.getName(), null));
event.setOrgi(this.jobDetail.getOrgi());
event.getValues().put("creater", this.jobDetail.getCreater()) ;
FileUtils.copyFile(tempFile, new File(path , fileName));
event.getDSData().setTask(metadataTable);
event.getDSData().setProcess(new BatchDataProcess(metadataTable, esDataExchange));
event.setOrgi(this.jobDetail.getOrgi());
event.setBatid(this.jobDetail.getId());
event.getDSData().setJobDetail(this.jobDetail);
event.getDSData().getReport().setOrgi(this.jobDetail.getOrgi());
event.getDSData().getReport().setDataid(this.jobDetail.getId());
event.getDSData().getReport().setTitle(this.jobDetail.getName() + "_" + MainUtils.dateFormate.format(new Date()));
}else {
event.getDSData().getReport().setError(true);
if(tempFile!=null) {
event.getDSData().getReport().setErrormsg(tempFile.getAbsolutePath() + " Not Exist!");
}
}
reporterRes.save(event.getDSData().getReport()) ;
new ExcelImportProecess(event).process() ; //启动导入任务
}
}
@Override
public void end(boolean clear) throws Exception {
}
@Override
public JobDetail getJob() {
return this.jobDetail;
}
@Override
public void process(OutputTextFormat meta, JobDetail job) throws Exception {
}
@Override
public OutputTextFormat next() throws Exception {
return null ;
}
@Override
public boolean isAvailable() {
return true;
}
@Override
public OutputTextFormat getText(OutputTextFormat object) throws Exception {
return object;
}
@Override
public void rmResource() {
/**
* 啥也不做
*/
}
@Override
public void updateTask() throws Exception {
}
}

View File

@ -1,18 +1,16 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.basic.resource;
@ -27,7 +25,7 @@ public class OutputTextFormat {
private String title ;
private String parent ;
private Map<String , Object> data = new HashMap<String , Object>();
private Map<String , Object> data = new HashMap<>();
private JobDetail job ;
private UKDataBean dataBean ;

View File

@ -1,18 +1,16 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.basic.resource;
@ -20,7 +18,8 @@ import com.cskefu.cc.basic.MainContext;
import com.cskefu.cc.model.JobDetail;
import java.lang.reflect.InvocationTargetException;
import java.util.logging.Logger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author jaddy0302 Rivulet Resource.java 2010-3-6
@ -28,7 +27,7 @@ import java.util.logging.Logger;
*/
public abstract class Resource {
public static Logger log = Logger.getLogger(Resource.class.getName()) ;
public static Logger log = LoggerFactory.getLogger(Resource.class.getName()) ;
public abstract void begin() throws Exception;
@ -107,7 +106,7 @@ public abstract class Resource {
*/
public boolean val(String inputFile , String acceptDocType){
String file = inputFile!=null ? inputFile.toLowerCase() :null ;
return file!=null && acceptDocType!=null && ((acceptDocType.indexOf(file.substring(file.lastIndexOf(".")+1))>=0||acceptDocType.indexOf("all")>=0)) ;
return file!=null && acceptDocType!=null && ((acceptDocType.contains(file.substring(file.lastIndexOf(".") + 1)) || acceptDocType.contains("all"))) ;
}
}

View File

@ -1,17 +1,15 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.cache;
@ -20,14 +18,14 @@ import com.cskefu.cc.basic.MainContext;
import com.cskefu.cc.exception.CSKefuCacheException;
import com.cskefu.cc.model.*;
import com.cskefu.cc.persistence.repository.AgentUserRepository;
import com.cskefu.cc.persistence.repository.OnlineUserRepository;
import com.cskefu.cc.persistence.repository.PassportWebIMUserRepository;
import com.cskefu.cc.util.SerializeUtil;
import com.cskefu.cc.util.freeswitch.model.CallCenterAgent;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.apache.commons.lang3.StringUtils;
import java.io.Serializable;
import java.util.*;
@ -38,7 +36,7 @@ public class Cache {
final static private Logger logger = LoggerFactory.getLogger(Cache.class);
@Autowired
private OnlineUserRepository onlineUserRes;
private PassportWebIMUserRepository onlineUserRes;
@Autowired
private AgentUserRepository agentUserRes;
@ -49,37 +47,35 @@ public class Cache {
/**
* 获得就绪的坐席列表
*
* @param orgi 租户
* @return
*/
public Map<String, AgentStatus> getAgentStatusReadyByOrig(final String orgi) {
Map<String, String> agentStatuses = redisCommand.getHash(RedisKey.getAgentStatusReadyHashKey(orgi));
public Map<String, AgentStatus> getAgentStatusReady() {
Map<String, String> agentStatuses = redisCommand.getHash(RedisKey.getAgentStatusReadyHashKey());
return convertFromStringToAgentStatus(agentStatuses);
}
/**
* 通过访客ID和ORGI获得访客坐席关联关系
* 通过访客ID获得访客坐席关联关系
*
* @param userId
* @param orgi
* @return
*/
public Optional<AgentUser> findOneAgentUserByUserIdAndOrgi(final String userId, final String orgi) {
if (redisCommand.hasHashKV(RedisKey.getAgentUserInQueHashKey(orgi), userId)) {
public Optional<AgentUser> findOneAgentUserByUserId(final String userId) {
if (redisCommand.hasHashKV(RedisKey.getAgentUserInQueHashKey(), userId)) {
// 排队等待中
return Optional.ofNullable((AgentUser) SerializeUtil.deserialize(
redisCommand.getHashKV(RedisKey.getAgentUserInQueHashKey(orgi), userId)));
} else if (redisCommand.hasHashKV(RedisKey.getAgentUserInServHashKey(orgi), userId)) {
redisCommand.getHashKV(RedisKey.getAgentUserInQueHashKey(), userId)));
} else if (redisCommand.hasHashKV(RedisKey.getAgentUserInServHashKey(), userId)) {
// 服务中
return Optional.ofNullable((AgentUser) SerializeUtil.deserialize(
redisCommand.getHashKV(RedisKey.getAgentUserInServHashKey(orgi), userId)));
} else if (redisCommand.hasHashKV(RedisKey.getAgentUserEndHashKey(orgi), userId)) {
redisCommand.getHashKV(RedisKey.getAgentUserInServHashKey(), userId)));
} else if (redisCommand.hasHashKV(RedisKey.getAgentUserEndHashKey(), userId)) {
// 已经结束
return Optional.ofNullable((AgentUser) SerializeUtil.deserialize(
redisCommand.getHashKV(RedisKey.getAgentUserEndHashKey(orgi), userId)));
redisCommand.getHashKV(RedisKey.getAgentUserEndHashKey(), userId)));
} else {
// 缓存中没有找到继续到数据库查找
return agentUserRes.findOneByUseridAndOrgi(userId, orgi);
return agentUserRes.findOneByUserid(userId);
}
}
@ -87,11 +83,10 @@ public class Cache {
/**
* 返回排队中的客服列表
*
* @param orgi
* @return
*/
public Map<String, AgentUser> getAgentUsersInQueByOrgi(final String orgi) {
Map<String, String> agentUsers = redisCommand.getHash(RedisKey.getAgentUserInQueHashKey(orgi));
public Map<String, AgentUser> getAgentUsersInQue() {
Map<String, String> agentUsers = redisCommand.getHash(RedisKey.getAgentUserInQueHashKey());
Map<String, AgentUser> map = new HashMap<>();
for (final Map.Entry<String, String> entry : agentUsers.entrySet()) {
final AgentUser obj = SerializeUtil.deserialize(entry.getValue());
@ -105,10 +100,9 @@ public class Cache {
* TODO 将访客对应的客服的服务列表变更
*
* @param userid
* @param orgi
*/
public void deleteAgentUserInservByAgentUserIdAndOrgi(final String userid, final String orgi) {
redisCommand.delHashKV(RedisKey.getAgentUserInServHashKey(orgi), userid);
public void deleteAgentUserInservByAgentUserId(final String userid) {
redisCommand.delHashKV(RedisKey.getAgentUserInServHashKey(), userid);
}
@ -116,21 +110,19 @@ public class Cache {
* 将访客ID从排队队列中删除
*
* @param userid
* @param orgi
*/
public void deleteAgentUserInqueByAgentUserIdAndOrgi(final String userid, final String orgi) {
redisCommand.delHashKV(RedisKey.getAgentUserInQueHashKey(orgi), userid);
public void deleteAgentUserInqueByAgentUserId(final String userid) {
redisCommand.delHashKV(RedisKey.getAgentUserInQueHashKey(), userid);
}
/**
* 获得一个坐席的状态
*
* @param agentno 坐席ID
* @param orgi 租户ID
* @return
*/
public AgentStatus findOneAgentStatusByAgentnoAndOrig(final String agentno, final String orgi) {
String status = getAgentStatusStatus(agentno, orgi);
public AgentStatus findOneAgentStatusByAgentno(final String agentno) {
String status = getAgentStatusStatus(agentno);
logger.debug("[findOneAgentStatusByAgentnoAndOrig] agentno {}, status {}", agentno, status);
// 缓存中没有该坐席状态该坐席目前是离线的
@ -138,7 +130,7 @@ public class Cache {
return null;
}
String val = redisCommand.getHashKV(RedisKey.getAgentStatusHashKeyByStatusStr(orgi, status), agentno);
String val = redisCommand.getHashKV(RedisKey.getAgentStatusHashKeyByStatusStr(status), agentno);
AgentStatus result = SerializeUtil.deserialize(val);
logger.debug("[findOneAgentStatusByAgentnoAndOrig] result: username {}", result.getUsername());
return result;
@ -148,16 +140,15 @@ public class Cache {
* 更新坐席状态
*
* @param agentStatus
* @param orgi
*/
public void putAgentStatusByOrgi(AgentStatus agentStatus, String orgi) {
String pre = getAgentStatusStatus(agentStatus.getAgentno(), orgi); // 坐席前状态
public void putAgentStatus(AgentStatus agentStatus) {
String pre = getAgentStatusStatus(agentStatus.getAgentno()); // 坐席前状态
if (StringUtils.equals(pre, MainContext.AgentStatusEnum.OFFLINE.toString())) {
// 之前不存在新建缓存
if ((!StringUtils.equals(agentStatus.getStatus(), MainContext.AgentStatusEnum.OFFLINE.toString()))) {
redisCommand.setHashKV(
RedisKey.getAgentStatusHashKeyByStatusStr(orgi, agentStatus.getStatus()),
RedisKey.getAgentStatusHashKeyByStatusStr(agentStatus.getStatus()),
agentStatus.getAgentno(), SerializeUtil.serialize(agentStatus));
}
return;
@ -165,15 +156,15 @@ public class Cache {
// 之前存在与将要更新的状态一致
if (StringUtils.equals(pre, agentStatus.getStatus())) {
redisCommand.setHashKV(
RedisKey.getAgentStatusHashKeyByStatusStr(orgi, pre), agentStatus.getAgentno(),
RedisKey.getAgentStatusHashKeyByStatusStr(pre), agentStatus.getAgentno(),
SerializeUtil.serialize(agentStatus));
return;
} else {
// 之前存在而且与新状态不一致
redisCommand.delHashKV(RedisKey.getAgentStatusHashKeyByStatusStr(orgi, pre), agentStatus.getAgentno());
redisCommand.delHashKV(RedisKey.getAgentStatusHashKeyByStatusStr(pre), agentStatus.getAgentno());
if (!StringUtils.equals(agentStatus.getStatus(), MainContext.AgentStatusEnum.OFFLINE.toString())) {
redisCommand.setHashKV(
RedisKey.getAgentStatusHashKeyByStatusStr(orgi, agentStatus.getStatus()),
RedisKey.getAgentStatusHashKeyByStatusStr(agentStatus.getStatus()),
agentStatus.getAgentno(), SerializeUtil.serialize(agentStatus));
}
}
@ -183,12 +174,11 @@ public class Cache {
/**
* 获得一个租户的就绪坐席状态
*
* @param orgi
* @return
*/
public Map<String, AgentStatus> findAllReadyAgentStatusByOrgi(final String orgi) {
public Map<String, AgentStatus> findAllReadyAgentStatus() {
List<String> keys = new ArrayList<>();
keys.add(RedisKey.getAgentStatusReadyHashKey(orgi));
keys.add(RedisKey.getAgentStatusReadyHashKey());
Map<String, String> map = redisCommand.getAllMembersInMultiHash(keys);
return convertFromStringToAgentStatus(map);
@ -197,14 +187,13 @@ public class Cache {
/**
* 获得一个租户的所有坐席状态
*
* @param orgi
* @return
*/
public Map<String, AgentStatus> findAllAgentStatusByOrgi(final String orgi) {
public Map<String, AgentStatus> findAllAgentStatus() {
List<String> keys = new ArrayList<>();
// TODO 增加支持更多状态
keys.add(RedisKey.getAgentStatusReadyHashKey(orgi));
keys.add(RedisKey.getAgentStatusNotReadyHashKey(orgi));
keys.add(RedisKey.getAgentStatusReadyHashKey());
keys.add(RedisKey.getAgentStatusNotReadyHashKey());
Map<String, String> map = redisCommand.getAllMembersInMultiHash(keys);
return convertFromStringToAgentStatus(map);
@ -215,7 +204,7 @@ public class Cache {
* Inline方法
*/
private static Map<String, AgentStatus> convertFromStringToAgentStatus(final Map<String, String> map) {
Map<String, AgentStatus> result = new HashMap<String, AgentStatus>();
Map<String, AgentStatus> result = new HashMap<>();
for (Map.Entry<String, String> entry : map.entrySet()) {
AgentStatus obj = SerializeUtil.deserialize(entry.getValue());
result.put(entry.getKey(), obj);
@ -228,12 +217,11 @@ public class Cache {
* Delete Agent Status
*
* @param agentno
* @param orgi
*/
public void deleteAgentStatusByAgentnoAndOrgi(final String agentno, final String orgi) {
String status = getAgentStatusStatus(agentno, orgi);
public void deleteAgentStatusByAgentno(final String agentno) {
String status = getAgentStatusStatus(agentno);
if (!StringUtils.equals(MainContext.AgentStatusEnum.OFFLINE.toString(), status)) {
redisCommand.delHashKV(RedisKey.getAgentStatusHashKeyByStatusStr(orgi, status), agentno);
redisCommand.delHashKV(RedisKey.getAgentStatusHashKeyByStatusStr(status), agentno);
}
}
@ -242,14 +230,13 @@ public class Cache {
* 只返回大类状态
*
* @param agentno
* @param orgi
* @return
*/
private String getAgentStatusStatus(final String agentno, final String orgi) {
private String getAgentStatusStatus(final String agentno) {
// 首先判断这个坐席的状态是READY还是BUSY再去更新
if (redisCommand.hasHashKV(RedisKey.getAgentStatusReadyHashKey(orgi), agentno)) {
if (redisCommand.hasHashKV(RedisKey.getAgentStatusReadyHashKey(), agentno)) {
return MainContext.AgentStatusEnum.READY.toString();
} else if (redisCommand.hasHashKV(RedisKey.getAgentStatusNotReadyHashKey(orgi), agentno)) {
} else if (redisCommand.hasHashKV(RedisKey.getAgentStatusNotReadyHashKey(), agentno)) {
return MainContext.AgentStatusEnum.NOTREADY.toString();
} else {
return MainContext.AgentStatusEnum.OFFLINE.toString();
@ -261,12 +248,11 @@ public class Cache {
* 获得技能组的坐席状态
*
* @param skill
* @param orgi
* @return
*/
public List<AgentStatus> getAgentStatusBySkillAndOrgi(final String skill, final String orgi) {
Map<String, AgentStatus> map = findAllAgentStatusByOrgi(orgi);
List<AgentStatus> agentList = new ArrayList<AgentStatus>();
public List<AgentStatus> getAgentStatusBySkill(final String skill) {
Map<String, AgentStatus> map = findAllAgentStatus();
List<AgentStatus> agentList = new ArrayList<>();
for (Map.Entry<String, AgentStatus> entry : map.entrySet()) {
if (StringUtils.isNotBlank(skill)) {
@ -285,11 +271,10 @@ public class Cache {
/**
* 获得指定租户的就绪的坐席个数
*
* @param orgi
* @return
*/
public int getAgentStatusReadySizeByOrgi(final String orgi) {
return Math.toIntExact(redisCommand.getHashSize(RedisKey.getAgentStatusReadyHashKey(orgi)));
public int getAgentStatusReadySize() {
return Math.toIntExact(redisCommand.getHashSize(RedisKey.getAgentStatusReadyHashKey()));
}
@ -305,32 +290,31 @@ public class Cache {
* 但是之前那个关联坐席的信息需要删除要另行维护
*
* @param agentUser 最新的agentUser的状态
* @param orgi
*/
@AgentUserAspect.LinkAgentUser
public void putAgentUserByOrgi(AgentUser agentUser, String orgi) {
if (redisCommand.hasHashKV(RedisKey.getAgentUserInServHashKey(orgi), agentUser.getUserid())) {
public void putAgentUser(AgentUser agentUser) {
if (redisCommand.hasHashKV(RedisKey.getAgentUserInServHashKey(), agentUser.getUserid())) {
// 服务中
if (!StringUtils.equals(
agentUser.getStatus(),
MainContext.AgentUserStatusEnum.INSERVICE.toString())) {
// 删除旧记录
redisCommand.delHashKV(RedisKey.getAgentUserInServHashKey(orgi), agentUser.getUserid());
redisCommand.delHashKV(RedisKey.getAgentUserInServHashKey(), agentUser.getUserid());
}
} else if (redisCommand.hasHashKV(RedisKey.getAgentUserInQueHashKey(orgi), agentUser.getUserid())) {
} else if (redisCommand.hasHashKV(RedisKey.getAgentUserInQueHashKey(), agentUser.getUserid())) {
// 等待服务
if (!StringUtils.equals(
agentUser.getStatus(),
MainContext.AgentUserStatusEnum.INQUENE.toString())) {
// 删除旧记录
redisCommand.delHashKV(RedisKey.getAgentUserInQueHashKey(orgi), agentUser.getUserid());
redisCommand.delHashKV(RedisKey.getAgentUserInQueHashKey(), agentUser.getUserid());
}
}
// 更新新记录忽略状态为END的agentUser已结束的服务不加入缓存
if (!StringUtils.equals(agentUser.getStatus(), MainContext.AgentUserStatusEnum.END.toString())) {
redisCommand.setHashKV(
RedisKey.getAgentUserHashKeyByStatusStr(orgi, agentUser.getStatus()), agentUser.getUserid(),
RedisKey.getAgentUserHashKeyByStatusStr(agentUser.getStatus()), agentUser.getUserid(),
SerializeUtil.serialize(agentUser));
}
}
@ -340,13 +324,12 @@ public class Cache {
* 获得一个客服服务中的访客列表
*
* @param agentno
* @param orgi
* @return
*/
public List<AgentUser> findInservAgentUsersByAgentnoAndOrgi(final String agentno, final String orgi) {
logger.info("[findInservAgentUsersByAgentnoAndOrgi] agentno {}, orgi {}", agentno, orgi);
public List<AgentUser> findInservAgentUsersByAgentno(final String agentno) {
logger.info("[findInservAgentUsersByAgentno] agentno {}", agentno);
List<AgentUser> result = new ArrayList<>();
List<String> ids = redisCommand.getSet(RedisKey.getInServAgentUsersByAgentnoAndOrgi(agentno, orgi));
List<String> ids = redisCommand.getSet(RedisKey.getInServAgentUsersByAgentno(agentno));
if (ids.size() == 0) { // no inserv agentUser
return result;
} else {
@ -360,48 +343,44 @@ public class Cache {
* 获得一个坐席服务中的访客数量
*
* @param agentno
* @param orgi
* @return
*/
public int getInservAgentUsersSizeByAgentnoAndOrgi(final String agentno, final String orgi) {
return Math.toIntExact(redisCommand.getSetSize(RedisKey.getInServAgentUsersByAgentnoAndOrgi(agentno, orgi)));
public int getInservAgentUsersSizeByAgentno(final String agentno) {
return Math.toIntExact(redisCommand.getSetSize(RedisKey.getInServAgentUsersByAgentno(agentno)));
}
/**
* 获得服务中的访客的数量
*
* @param orgi
* @return
*/
public int getInservAgentUsersSizeByOrgi(final String orgi) {
return redisCommand.getHashSize(RedisKey.getAgentUserInServHashKey(orgi));
public int getInservAgentUsersSize() {
return redisCommand.getHashSize(RedisKey.getAgentUserInServHashKey());
}
/**
* 获得等待中的访客的数量
*
* @param orgi
* @return
*/
public int getInqueAgentUsersSizeByOrgi(final String orgi) {
return redisCommand.getHashSize(RedisKey.getAgentUserInQueHashKey(orgi));
public int getInqueAgentUsersSize() {
return redisCommand.getHashSize(RedisKey.getAgentUserInQueHashKey());
}
/**
* Delete agentUser
*
* @param agentUser
* @param orgi
*/
@AgentUserAspect.LinkAgentUser
public void deleteAgentUserByUserIdAndOrgi(final AgentUser agentUser, String orgi) {
if (redisCommand.hasHashKV(RedisKey.getAgentUserInQueHashKey(orgi), agentUser.getUserid())) {
public void deleteAgentUserByUserId(final AgentUser agentUser) {
if (redisCommand.hasHashKV(RedisKey.getAgentUserInQueHashKey(), agentUser.getUserid())) {
// 排队等待中
redisCommand.delHashKV(RedisKey.getAgentUserInQueHashKey(orgi), agentUser.getUserid());
} else if (redisCommand.hasHashKV(RedisKey.getAgentUserInServHashKey(orgi), agentUser.getUserid())) {
redisCommand.delHashKV(RedisKey.getAgentUserInServHashKey(orgi), agentUser.getUserid());
} else if (redisCommand.hasHashKV(RedisKey.getAgentUserEndHashKey(orgi), agentUser.getUserid())) {
redisCommand.delHashKV(RedisKey.getAgentUserEndHashKey(orgi), agentUser.getUserid());
redisCommand.delHashKV(RedisKey.getAgentUserInQueHashKey(), agentUser.getUserid());
} else if (redisCommand.hasHashKV(RedisKey.getAgentUserInServHashKey(), agentUser.getUserid())) {
redisCommand.delHashKV(RedisKey.getAgentUserInServHashKey(), agentUser.getUserid());
} else if (redisCommand.hasHashKV(RedisKey.getAgentUserEndHashKey(), agentUser.getUserid())) {
redisCommand.delHashKV(RedisKey.getAgentUserEndHashKey(), agentUser.getUserid());
} else {
// TODO 考虑是否有其他状态保存
}
@ -410,14 +389,14 @@ public class Cache {
/***************************
* CousultInvite 相关
***************************/
public void putConsultInviteByOrgi(final String orgi, final CousultInvite cousultInvite) {
public void putConsultInvite(final CousultInvite cousultInvite) {
redisCommand.setHashKV(
RedisKey.getConsultInvitesByOrgi(orgi), cousultInvite.getSnsaccountid(),
RedisKey.getConsultInvites(), cousultInvite.getSnsaccountid(),
SerializeUtil.serialize(cousultInvite));
}
public CousultInvite findOneConsultInviteBySnsidAndOrgi(final String snsid, final String orgi) {
String serialized = redisCommand.getHashKV(RedisKey.getConsultInvitesByOrgi(orgi), snsid);
public CousultInvite findOneConsultInviteBySnsid(final String snsid) {
String serialized = redisCommand.getHashKV(RedisKey.getConsultInvites(), snsid);
if (StringUtils.isBlank(serialized)) {
return null;
} else {
@ -425,8 +404,8 @@ public class Cache {
}
}
public void deleteConsultInviteBySnsidAndOrgi(final String snsid, final String orgi) {
redisCommand.delHashKV(RedisKey.getConsultInvitesByOrgi(orgi), snsid);
public void deleteConsultInviteBySnsid(final String snsid) {
redisCommand.delHashKV(RedisKey.getConsultInvites(), snsid);
}
@ -437,34 +416,32 @@ public class Cache {
/**
* 更新 onlineUser
*
* @param onlineUser
* @param orgi
* @param passportWebIMUser
*/
public void putOnlineUserByOrgi(final OnlineUser onlineUser, final String orgi) {
public void putOnlineUser(final PassportWebIMUser passportWebIMUser) {
// 此处onlineUser的id onlineUser userId相同
redisCommand.setHashKV(
RedisKey.getOnlineUserHashKey(orgi), onlineUser.getId(), SerializeUtil.serialize(onlineUser));
RedisKey.getOnlineUserHashKey(), passportWebIMUser.getId(), SerializeUtil.serialize(passportWebIMUser));
}
/**
* 获得 onlineUser
*
* @param id
* @param orgi
* @return
*/
public OnlineUser findOneOnlineUserByUserIdAndOrgi(final String id, final String orgi) {
String serialized = redisCommand.getHashKV(RedisKey.getOnlineUserHashKey(orgi), id);
public PassportWebIMUser findOneOnlineUserByUserId(final String id) {
String serialized = redisCommand.getHashKV(RedisKey.getOnlineUserHashKey(), id);
if (StringUtils.isBlank(serialized)) {
// query with MySQL
return onlineUserRes.findOneByUseridAndOrgi(id, orgi);
return onlineUserRes.findOneByUserid(id);
} else {
return convertFromStringToOnlineUser(serialized);
}
}
private static OnlineUser convertFromStringToOnlineUser(final String serialized) {
OnlineUser obj = SerializeUtil.deserialize(serialized);
private static PassportWebIMUser convertFromStringToOnlineUser(final String serialized) {
PassportWebIMUser obj = SerializeUtil.deserialize(serialized);
return obj;
}
@ -472,19 +449,16 @@ public class Cache {
* 删除 onlineUser
*
* @param id
* @param orgi
*/
public void deleteOnlineUserByIdAndOrgi(final String id, final String orgi) {
redisCommand.delHashKV(RedisKey.getOnlineUserHashKey(orgi), id);
public void deleteOnlineUserById(final String id) {
redisCommand.delHashKV(RedisKey.getOnlineUserHashKey(), id);
}
/**
* 根据租户ID获得在线访客的列表大小
*
* @param orgi
*/
public int getOnlineUserSizeByOrgi(final String orgi) {
return redisCommand.getHashSize(RedisKey.getOnlineUserHashKey(orgi));
public int getOnlineUserSize() {
return redisCommand.getHashSize(RedisKey.getOnlineUserHashKey());
}
@ -493,16 +467,15 @@ public class Cache {
*
* @param userid
* @param agentno
* @param orgi
*/
public void deleteOnlineUserIdFromAgentStatusByUseridAndAgentnoAndOrgi(final String userid, final String agentno, final String orgi) {
redisCommand.removeSetVal(RedisKey.getInServAgentUsersByAgentnoAndOrgi(agentno, orgi), userid);
public void deleteOnlineUserIdFromAgentStatusByUseridAndAgentno(final String userid, final String agentno) {
redisCommand.removeSetVal(RedisKey.getInServAgentUsersByAgentno(agentno), userid);
}
private Map<String, OnlineUser> convertFromStringToOnlineUsers(final Map<String, String> map) {
Map<String, OnlineUser> result = new HashMap<>();
private Map<String, PassportWebIMUser> convertFromStringToOnlineUsers(final Map<String, String> map) {
Map<String, PassportWebIMUser> result = new HashMap<>();
for (Map.Entry<String, String> entry : map.entrySet()) {
OnlineUser x = SerializeUtil.deserialize(entry.getValue());
PassportWebIMUser x = SerializeUtil.deserialize(entry.getValue());
result.put(entry.getKey(), x);
}
return result;
@ -517,22 +490,20 @@ public class Cache {
* 更新CallCenterAgent
*
* @param id
* @param orgi
* @param agent
*/
public void putCallCenterAgentByIdAndOrgi(final String id, final String orgi, final CallCenterAgent agent) {
redisCommand.setHashKV(RedisKey.getCallCenterAgentHashKeyByOrgi(orgi), id, SerializeUtil.serialize(agent));
public void putCallCenterAgentById(final String id, final CallCenterAgent agent) {
redisCommand.setHashKV(RedisKey.getCallCenterAgentHashKey(), id, SerializeUtil.serialize(agent));
}
/**
* 根据ID和租户ID获得CallCenterAgent
*
* @param id
* @param orgi
* @return
*/
public CallCenterAgent findOneCallCenterAgentByIdAndOrgi(final String id, final String orgi) {
String serialized = redisCommand.getHashKV(RedisKey.getCallCenterAgentHashKeyByOrgi(orgi), id);
public CallCenterAgent findOneCallCenterAgentById(final String id) {
String serialized = redisCommand.getHashKV(RedisKey.getCallCenterAgentHashKey(), id);
if (StringUtils.isNotBlank(serialized)) {
return (CallCenterAgent) SerializeUtil.deserialize(serialized);
} else {
@ -544,21 +515,19 @@ public class Cache {
* 删除CallCenterAgent
*
* @param id
* @param orgi
*/
public void deleteCallCenterAgentByIdAndOrgi(final String id, final String orgi) {
redisCommand.delHashKV(RedisKey.getCallCenterAgentHashKeyByOrgi(orgi), id);
public void deleteCallCenterAgentById(final String id) {
redisCommand.delHashKV(RedisKey.getCallCenterAgentHashKey(), id);
}
/**
* 根据租户ID获得所有的CallCenterAgent
*
* @param orgi
* @return
*/
public Map<String, CallCenterAgent> findAllCallCenterAgentsByOrgi(final String orgi) {
Map<String, String> map = redisCommand.getHash(RedisKey.getCallCenterAgentHashKeyByOrgi(orgi));
public Map<String, CallCenterAgent> findAllCallCenterAgents() {
Map<String, String> map = redisCommand.getHash(RedisKey.getCallCenterAgentHashKey());
Map<String, CallCenterAgent> result = new HashMap<>();
for (Map.Entry<String, String> entry : map.entrySet()) {
@ -572,14 +541,14 @@ public class Cache {
* 访客黑名单
*/
// 将访客放在租户的黑名单中
public void putBlackEntityByOrgi(final BlackEntity blackEntity, final String orgi) {
public void putBlackEntity(final BlackEntity blackEntity) {
redisCommand.setHashKV(
RedisKey.getBlackEntityKeyByOrgi(orgi), blackEntity.getUserid(), SerializeUtil.serialize(blackEntity));
RedisKey.getBlackEntityKey(), blackEntity.getUserid(), SerializeUtil.serialize(blackEntity));
}
// 通过指定的访客和租户查找黑名单
public Optional<BlackEntity> findOneBlackEntityByUserIdAndOrgi(final String userid, final String orgi) {
String ser = redisCommand.getHashKV(RedisKey.getBlackEntityKeyByOrgi(orgi), userid);
public Optional<BlackEntity> findOneBlackEntityByUserId(final String userid) {
String ser = redisCommand.getHashKV(RedisKey.getBlackEntityKey(), userid);
if (StringUtils.isBlank(ser)) {
return Optional.empty();
}
@ -588,20 +557,20 @@ public class Cache {
}
// 将一个访客从黑名单中移除
public void deleteBlackEntityByUserIdAndOrgi(final String userid, final String orgi) {
redisCommand.delHashKV(RedisKey.getBlackEntityKeyByOrgi(orgi), userid);
public void deleteBlackEntityByUserId(final String userid) {
redisCommand.delHashKV(RedisKey.getBlackEntityKey(), userid);
}
// 指定的访客是否在租户的黑名单中
public boolean existBlackEntityByUserIdAndOrgi(final String userid, final String orgi) {
return redisCommand.hasHashKV(RedisKey.getBlackEntityKeyByOrgi(orgi), userid);
public boolean existBlackEntityByUserId(final String userid) {
return redisCommand.hasHashKV(RedisKey.getBlackEntityKey(), userid);
}
// 根据租户ID获得所有访客的黑名单
public Map<String, BlackEntity> findAllBlackEntityByOrgi(final String orgi) {
public Map<String, BlackEntity> findAllBlackEntity() {
Map<String, BlackEntity> result = new HashMap<>();
for (Map.Entry<String, String> entry : redisCommand.getHash(
RedisKey.getBlackEntityKeyByOrgi(orgi)).entrySet()) {
RedisKey.getBlackEntityKey()).entrySet()) {
result.put(entry.getKey(), SerializeUtil.deserialize(entry.getValue()));
}
return result;
@ -611,12 +580,12 @@ public class Cache {
/*****************************
* Job 相关
*****************************/
public void putJobByIdAndOrgi(final String jobId, final String orgi, final JobDetail job) {
redisCommand.setHashKV(RedisKey.getJobHashKeyByOrgi(orgi), jobId, SerializeUtil.serialize(job));
public void putJobById(final String jobId, final JobDetail job) {
redisCommand.setHashKV(RedisKey.getJobHashKey(), jobId, SerializeUtil.serialize(job));
}
public JobDetail findOneJobByIdAndOrgi(final String jobId, final String orgi) {
String serialized = redisCommand.getHashKV(RedisKey.getJobHashKeyByOrgi(orgi), jobId);
public JobDetail findOneJobById(final String jobId) {
String serialized = redisCommand.getHashKV(RedisKey.getJobHashKey(), jobId);
if (StringUtils.isNotBlank(serialized)) {
return (JobDetail) SerializeUtil.deserialize(serialized);
@ -624,35 +593,35 @@ public class Cache {
return null;
}
public boolean existJobByIdAndOrgi(final String jobId, final String orgi) {
return redisCommand.hasHashKV(RedisKey.getJobHashKeyByOrgi(orgi), jobId);
public boolean existJobById(final String jobId) {
return redisCommand.hasHashKV(RedisKey.getJobHashKey(), jobId);
}
public void deleteJobByJobIdAndOrgi(final String jobId, final String orgi) {
redisCommand.delHashKV(RedisKey.getJobHashKeyByOrgi(orgi), jobId);
public void deleteJobByJobId(final String jobId) {
redisCommand.delHashKV(RedisKey.getJobHashKey(), jobId);
}
/**
* 系统词典相关
*/
// 存储根词典
public void putSysDicByOrgi(final String id, final String orgi, final SysDic sysDic) {
redisCommand.setHashKV(RedisKey.getSysDicHashKeyByOrgi(orgi), id, SerializeUtil.serialize(sysDic));
public void putSysDic(final String id, final SysDic sysDic) {
redisCommand.setHashKV(RedisKey.getSysDicHashKey(), id, SerializeUtil.serialize(sysDic));
}
// 将指定租户的系统词典清空
public void eraseSysDicByOrgi(final String orgi) {
redisCommand.delete(RedisKey.getSysDicHashKeyByOrgi(orgi));
public void eraseSysDic() {
redisCommand.delete(RedisKey.getSysDicHashKey());
}
// 存储词典子项
public void putSysDicByOrgi(final String code, final String orgi, final List<SysDic> sysDics) {
redisCommand.setHashKV(RedisKey.getSysDicHashKeyByOrgi(orgi), code, SerializeUtil.serialize(sysDics));
public void putSysDic(final String code, final List<SysDic> sysDics) {
redisCommand.setHashKV(RedisKey.getSysDicHashKey(), code, SerializeUtil.serialize(sysDics));
}
// 获得词典的子项列表
public List<SysDic> getSysDicItemsByCodeAndOrgi(final String code, final String orgi) {
String serialized = redisCommand.getHashKV(RedisKey.getSysDicHashKeyByOrgi(orgi), code);
public List<SysDic> getSysDicItemsByCode(final String code) {
String serialized = redisCommand.getHashKV(RedisKey.getSysDicHashKey(), code);
if (serialized != null) {
return (List<SysDic>) SerializeUtil.deserialize(serialized);
}
@ -660,8 +629,8 @@ public class Cache {
}
// 获得词典子项
public SysDic findOneSysDicByCodeAndOrgi(final String code, final String orgi) {
String serialized = redisCommand.getHashKV(RedisKey.getSysDicHashKeyByOrgi(orgi), code);
public SysDic findOneSysDicByCode(final String code) {
String serialized = redisCommand.getHashKV(RedisKey.getSysDicHashKey(), code);
if (StringUtils.isBlank(serialized)) {
return null;
@ -671,8 +640,8 @@ public class Cache {
}
// 获得词典
public SysDic findOneSysDicByIdAndOrgi(final String id, final String orgi) {
String serialized = redisCommand.getHashKV(RedisKey.getSysDicHashKeyByOrgi(orgi), id);
public SysDic findOneSysDicById(final String id) {
String serialized = redisCommand.getHashKV(RedisKey.getSysDicHashKey(), id);
if (StringUtils.isBlank(serialized)) {
return null;
@ -682,63 +651,63 @@ public class Cache {
}
// 批量存储
public void putSysDicByOrgi(List<SysDic> vals, final String orgi) {
public void putSysDic(List<SysDic> vals) {
Map<String, String> map = new HashMap<>();
for (final SysDic dic : vals) {
map.put(dic.getId(), SerializeUtil.serialize(dic));
}
redisCommand.hmset(RedisKey.getSysDicHashKeyByOrgi(orgi), map);
redisCommand.hmset(RedisKey.getSysDicHashKey(), map);
}
public void deleteSysDicByIdAndOrgi(final String id, final String orgi) {
redisCommand.delHashKV(RedisKey.getSysDicHashKeyByOrgi(orgi), id);
public void deleteSysDicById(final String id) {
redisCommand.delHashKV(RedisKey.getSysDicHashKey(), id);
}
public boolean existSysDicByIdAndOrgi(final String id, final String orgi) {
return redisCommand.hasHashKV(RedisKey.getSysDicHashKeyByOrgi(orgi), id);
public boolean existSysDicById(final String id) {
return redisCommand.hasHashKV(RedisKey.getSysDicHashKey(), id);
}
/**
* System 相关
*/
public <T extends Serializable> void putSystemByIdAndOrgi(final String id, final String orgi, final T obj) {
redisCommand.setHashKV(RedisKey.getSystemHashKeyByOrgi(orgi), id, SerializeUtil.serialize(obj));
public <T extends Serializable> void putSystemById(final String id, final T obj) {
redisCommand.setHashKV(RedisKey.getSystemHashKey(), id, SerializeUtil.serialize(obj));
}
public <T extends Serializable> void putSystemListByIdAndOrgi(final String id, final String orgi, final List<T> obj) {
redisCommand.setHashKV(RedisKey.getSystemHashKeyByOrgi(orgi), id, SerializeUtil.serialize(obj));
public <T extends Serializable> void putSystemListById(final String id, final List<T> obj) {
redisCommand.setHashKV(RedisKey.getSystemHashKey(), id, SerializeUtil.serialize(obj));
}
public <TK, TV extends Serializable> void putSystemMapByIdAndOrgi(final String id, final String orgi, final Map<TK, TV> obj) {
redisCommand.setHashKV(RedisKey.getSystemHashKeyByOrgi(orgi), id, SerializeUtil.serialize(obj));
public <TK, TV extends Serializable> void putSystemMapById(final String id, final Map<TK, TV> obj) {
redisCommand.setHashKV(RedisKey.getSystemHashKey(), id, SerializeUtil.serialize(obj));
}
public boolean existSystemByIdAndOrgi(final String id, final String orgi) {
return redisCommand.hasHashKV(RedisKey.getSystemHashKeyByOrgi(orgi), id);
public boolean existSystemById(final String id) {
return redisCommand.hasHashKV(RedisKey.getSystemHashKey(), id);
}
public void deleteSystembyIdAndOrgi(final String id, final String orgi) {
redisCommand.delHashKV(RedisKey.getSystemHashKeyByOrgi(orgi), id);
public void deleteSystembyId(final String id) {
redisCommand.delHashKV(RedisKey.getSystemHashKey(), id);
}
public <T extends Serializable> T findOneSystemByIdAndOrgi(final String id, final String orgi) {
String serialized = redisCommand.getHashKV(RedisKey.getSystemHashKeyByOrgi(orgi), id);
public <T extends Serializable> T findOneSystemById(final String id) {
String serialized = redisCommand.getHashKV(RedisKey.getSystemHashKey(), id);
if (StringUtils.isNotBlank(serialized)) {
return (T) SerializeUtil.deserialize(serialized);
}
return null;
}
public <T extends Serializable> List<T> findOneSystemListByIdAndOrgi(final String id, final String orgi) {
String serialized = redisCommand.getHashKV(RedisKey.getSystemHashKeyByOrgi(orgi), id);
public <T extends Serializable> List<T> findOneSystemListById(final String id) {
String serialized = redisCommand.getHashKV(RedisKey.getSystemHashKey(), id);
if (StringUtils.isNotBlank(serialized)) {
return (List<T>) SerializeUtil.deserialize(serialized);
}
return null;
}
public <TK, TV extends Serializable> Map<TK, TV> findOneSystemMapByIdAndOrgi(final String id, final String orgi) {
String serialized = redisCommand.getHashKV(RedisKey.getSystemHashKeyByOrgi(orgi), id);
public <TK, TV extends Serializable> Map<TK, TV> findOneSystemMapById(final String id) {
String serialized = redisCommand.getHashKV(RedisKey.getSystemHashKey(), id);
if (StringUtils.isNotBlank(serialized)) {
return (Map<TK, TV>) SerializeUtil.deserialize(serialized);
}
@ -746,40 +715,40 @@ public class Cache {
}
// 获得系统cache的列表大小
public int getSystemSizeByOrgi(final String orgi) {
return redisCommand.getHashSize(RedisKey.getSystemHashKeyByOrgi(orgi));
public int getSystemSize() {
return redisCommand.getHashSize(RedisKey.getSystemHashKey());
}
/**************************
* Session Config 相关
**************************/
public void putSessionConfigByOrgi(final SessionConfig sessionConfig, String organid, final String orgi) {
redisCommand.put(RedisKey.getSessionConfig(organid, orgi), SerializeUtil.serialize(sessionConfig));
public void putSessionConfig(final SessionConfig sessionConfig, String organid) {
redisCommand.put(RedisKey.getSessionConfig(organid), SerializeUtil.serialize(sessionConfig));
}
public SessionConfig findOneSessionConfigByOrgi(String organid, final String orgi) {
String serialized = redisCommand.get(RedisKey.getSessionConfig(organid, orgi));
public SessionConfig findOneSessionConfig(String organid) {
String serialized = redisCommand.get(RedisKey.getSessionConfig(organid));
if (StringUtils.isNotBlank(serialized)) {
return (SessionConfig) SerializeUtil.deserialize(serialized);
}
return null;
}
public void deleteSessionConfigByOrgi(String organid, final String orgi) {
redisCommand.delete(RedisKey.getSessionConfig(organid, orgi));
public void deleteSessionConfig(String organid) {
redisCommand.delete(RedisKey.getSessionConfig(organid));
}
public boolean existSessionConfigByOrgi(String organid, final String orgi) {
return redisCommand.exists(RedisKey.getSessionConfig(organid, orgi));
public boolean existSessionConfig(String organid) {
return redisCommand.exists(RedisKey.getSessionConfig(organid));
}
public void putSessionConfigListByOrgi(final List<SessionConfig> lis, final String orgi) {
redisCommand.put(RedisKey.getSessionConfigList(orgi), SerializeUtil.serialize(lis));
public void putSessionConfigList(final List<SessionConfig> lis) {
redisCommand.put(RedisKey.getSessionConfigList(), SerializeUtil.serialize(lis));
}
public List<SessionConfig> findOneSessionConfigListByOrgi(final String orgi) {
String serialized = redisCommand.get(RedisKey.getSessionConfigList(orgi));
public List<SessionConfig> findOneSessionConfigList() {
String serialized = redisCommand.get(RedisKey.getSessionConfigList());
if (StringUtils.isNotBlank(serialized)) {
return (List<SessionConfig>) SerializeUtil.deserialize(serialized);
}
@ -787,40 +756,40 @@ public class Cache {
return null;
}
public void deleteSessionConfigListByOrgi(final String orgi) {
redisCommand.delete(RedisKey.getSessionConfigList(orgi));
public void deleteSessionConfigList() {
redisCommand.delete(RedisKey.getSessionConfigList());
}
public boolean existSessionConfigListByOrgi(final String orgi) {
return redisCommand.exists(RedisKey.getSessionConfigList(orgi));
public boolean existSessionConfigList() {
return redisCommand.exists(RedisKey.getSessionConfigList());
}
/******************************************
* Customer Chats Audit 相关
******************************************/
public void putAgentUserAuditByOrgi(final String orgi, final AgentUserAudit audit) throws CSKefuCacheException {
public void putAgentUserAudit(final AgentUserAudit audit) throws CSKefuCacheException {
if (StringUtils.isBlank(audit.getAgentUserId())) {
throw new CSKefuCacheException("agentUserId is required.");
}
redisCommand.setHashKV(
RedisKey.getCustomerChatsAuditKeyByOrgi(orgi), audit.getAgentUserId(), SerializeUtil.serialize(audit));
RedisKey.getCustomerChatsAuditKey(), audit.getAgentUserId(), SerializeUtil.serialize(audit));
}
public void deleteAgentUserAuditByOrgiAndId(final String orgi, final String agentUserId) {
redisCommand.delHashKV(RedisKey.getCustomerChatsAuditKeyByOrgi(orgi), agentUserId);
public void deleteAgentUserAuditById(final String agentUserId) {
redisCommand.delHashKV(RedisKey.getCustomerChatsAuditKey(), agentUserId);
}
public Optional<AgentUserAudit> findOneAgentUserAuditByOrgiAndId(final String orgi, final String agentUserId) {
logger.info("[findOneAgentUserAuditByOrgiAndId] orgi {}, agentUserId {}", orgi, agentUserId);
String serialized = redisCommand.getHashKV(RedisKey.getCustomerChatsAuditKeyByOrgi(orgi), agentUserId);
public Optional<AgentUserAudit> findOneAgentUserAuditById(final String agentUserId) {
logger.info("[findOneAgentUserAuditById] agentUserId {}", agentUserId);
String serialized = redisCommand.getHashKV(RedisKey.getCustomerChatsAuditKey(), agentUserId);
if (StringUtils.isBlank(serialized)) {
return Optional.empty();
}
return Optional.ofNullable((AgentUserAudit) SerializeUtil.deserialize(serialized));
}
public boolean existAgentUserAuditByOrgiAndId(final String orgi, final String agentUserId) {
return redisCommand.hasHashKV(RedisKey.getCustomerChatsAuditKeyByOrgi(orgi), agentUserId);
public boolean existAgentUserAuditById(final String agentUserId) {
return redisCommand.hasHashKV(RedisKey.getCustomerChatsAuditKey(), agentUserId);
}
@ -833,22 +802,21 @@ public class Cache {
*
* @param agentno
* @param sessionId
* @param orgi
*/
public void putUserSessionByAgentnoAndSessionIdAndOrgi(final String agentno, final String sessionId, final String orgi) {
redisCommand.setHashKV(RedisKey.getUserSessionKeyByOrgi(orgi), agentno, sessionId);
public void putUserSessionByAgentnoAndSessionId(final String agentno, final String sessionId) {
redisCommand.setHashKV(RedisKey.getUserSessionKey(), agentno, sessionId);
}
public boolean existUserSessionByAgentnoAndOrgi(final String agentno, final String orgi) {
return redisCommand.hasHashKV(RedisKey.getUserSessionKeyByOrgi(orgi), agentno);
public boolean existUserSessionByAgentno(final String agentno) {
return redisCommand.hasHashKV(RedisKey.getUserSessionKey(), agentno);
}
public String findOneSessionIdByAgentnoAndOrgi(final String agentno, final String orgi) {
return redisCommand.getHashKV(RedisKey.getUserSessionKeyByOrgi(orgi), agentno);
public String findOneSessionIdByAgentno(final String agentno) {
return redisCommand.getHashKV(RedisKey.getUserSessionKey(), agentno);
}
public void deleteUserSessionByAgentnoAndOrgi(final String agentno, final String orgi) {
redisCommand.delHashKV(RedisKey.getUserSessionKeyByOrgi(orgi), agentno);
public void deleteUserSessionByAgentno(final String agentno) {
redisCommand.delHashKV(RedisKey.getUserSessionKey(), agentno);
}
}

View File

@ -1,17 +1,15 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.cache;
@ -22,7 +20,7 @@ import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.annotation.PostConstruct;
import jakarta.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.TimeUnit;
@ -62,12 +60,10 @@ public class RedisCommand {
*
* @param key
* @param serialized
* @return
*/
public boolean put(final String key, final String serialized) {
public void put(final String key, final String serialized) {
boolean result = true;
redisValOps.set(key, serialized);
return result;
}
public String get(final String key) {
@ -270,15 +266,12 @@ public class RedisCommand {
*
* @param key
* @param map 对应多个键值
* @return true 成功 false 失败
*/
public boolean hmset(final String key, final Map<String, String> map) {
public void hmset(final String key, final Map<String, String> map) {
try {
redisHashOps.putAll(key, map);
return true;
} catch (Exception e) {
logger.error("hmset bad things happen", e);
return false;
}
}

View File

@ -1,17 +1,15 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.cache;
@ -32,13 +30,11 @@ public class RedisKey {
/**
* 获得坐席列表指定字符串状态的KEY
*
* @param orgi 租户ID
* @return
*/
public static String getAgentStatusHashKeyByStatusStr(final String orgi, final String status) {
public static String getAgentStatusHashKeyByStatusStr(final String status) {
StringBuffer sb = new StringBuffer();
sb.append(orgi);
sb.append(":agent:status:");
sb.append("agent:status:");
sb.append(status);
return sb.toString();
}
@ -46,21 +42,19 @@ public class RedisKey {
/**
* 就绪的客服列表KEY
*
* @param orgi 租户ID
* @return
*/
public static String getAgentStatusReadyHashKey(final String orgi) {
return getAgentStatusHashKeyByStatusStr(orgi, MainContext.AgentStatusEnum.READY.toString());
public static String getAgentStatusReadyHashKey() {
return getAgentStatusHashKeyByStatusStr(MainContext.AgentStatusEnum.READY.toString());
}
/**
* 未就绪的坐席
*
* @param orgi
* @return
*/
public static String getAgentStatusNotReadyHashKey(final String orgi) {
return getAgentStatusHashKeyByStatusStr(orgi, MainContext.AgentStatusEnum.NOTREADY.toString());
public static String getAgentStatusNotReadyHashKey() {
return getAgentStatusHashKeyByStatusStr(MainContext.AgentStatusEnum.NOTREADY.toString());
}
@ -69,14 +63,12 @@ public class RedisKey {
/**
* 获得坐席访客关联列表指定字符串状态的KEY
*
* @param orgi
* @param status
* @return
*/
public static String getAgentUserHashKeyByStatusStr(final String orgi, final String status) {
public static String getAgentUserHashKeyByStatusStr(final String status) {
StringBuffer sb = new StringBuffer();
sb.append(orgi);
sb.append(":agent:user:");
sb.append("agent:user:");
sb.append(status);
return sb.toString();
}
@ -84,40 +76,36 @@ public class RedisKey {
/**
* 排队中的访客KEY
*
* @param orgi
* @return
*/
public static String getAgentUserInQueHashKey(final String orgi) {
return getAgentUserHashKeyByStatusStr(orgi, MainContext.AgentUserStatusEnum.INQUENE.toString());
public static String getAgentUserInQueHashKey() {
return getAgentUserHashKeyByStatusStr(MainContext.AgentUserStatusEnum.INQUENE.toString());
}
/**
* 服务中的访客
*
* @param orgi
* @return
*/
public static String getAgentUserInServHashKey(final String orgi) {
return getAgentUserHashKeyByStatusStr(orgi, MainContext.AgentUserStatusEnum.INSERVICE.toString());
public static String getAgentUserInServHashKey() {
return getAgentUserHashKeyByStatusStr(MainContext.AgentUserStatusEnum.INSERVICE.toString());
}
/**
* 结束服务的访客
*
* @param orgi
* @return
*/
public static String getAgentUserEndHashKey(final String orgi) {
return getAgentUserHashKeyByStatusStr(orgi, MainContext.AgentUserStatusEnum.END.toString());
public static String getAgentUserEndHashKey() {
return getAgentUserHashKeyByStatusStr(MainContext.AgentUserStatusEnum.END.toString());
}
/**
* 获得一个坐席的服务中的访客列表KEY
*/
public static String getInServAgentUsersByAgentnoAndOrgi(final String agentno, final String orgi) {
public static String getInServAgentUsersByAgentno(final String agentno) {
StringBuffer sb = new StringBuffer();
sb.append(orgi);
sb.append(":agent:");
sb.append("agent:");
sb.append(agentno);
sb.append(":inserv");
return sb.toString();
@ -129,13 +117,11 @@ public class RedisKey {
/**
* 存储AgentUser监控信息的存储Hash的KEY
*
* @param orgi
* @return
*/
public static String getCustomerChatsAuditKeyByOrgi(final String orgi) {
public static String getCustomerChatsAuditKey() {
StringBuffer sb = new StringBuffer();
sb.append(orgi);
sb.append(":audit:customerchats");
sb.append("audit:customerchats");
return sb.toString();
}
@ -145,13 +131,11 @@ public class RedisKey {
/**
* 获得在线访客列表
*
* @param orgi
* @return
*/
public static String getOnlineUserHashKey(final String orgi) {
public static String getOnlineUserHashKey() {
StringBuffer sb = new StringBuffer();
sb.append(orgi);
sb.append(":visitor:online");
sb.append("visitor:online");
return sb.toString();
}
@ -162,65 +146,56 @@ public class RedisKey {
* 包括管理员坐席等访客不在该列
* 在该列表中的用户代表在线的系统用户通过浏览器或API访问了系统
*
* @param orgi
* @return
*/
public static String getLoginUserKey(final String auth) {
public static String getApiTokenBearerKeyWithValue(final String token) {
StringBuffer sb = new StringBuffer();
sb.append("token:");
sb.append(auth);
sb.append("api:token:bearer:");
sb.append(token);
return sb.toString();
}
/**
* CallCenter Agent 相关
*
* @param orgi
* @return
*/
public static String getCallCenterAgentHashKeyByOrgi(final String orgi) {
public static String getCallCenterAgentHashKey() {
StringBuffer sb = new StringBuffer();
sb.append(orgi);
sb.append(":callcenter:agent");
sb.append("callcenter:agent");
return sb.toString();
}
/**
* Job 相关
*
* @param orgi
* @return
*/
public static String getJobHashKeyByOrgi(final String orgi) {
public static String getJobHashKey() {
StringBuffer sb = new StringBuffer();
sb.append(orgi);
sb.append(":job");
sb.append("job");
return sb.toString();
}
/**
* System 相关
*
* @param orgi
* @return
*/
public static String getSystemHashKeyByOrgi(final String orgi) {
public static String getSystemHashKey() {
StringBuffer sb = new StringBuffer();
sb.append(orgi);
sb.append(":system");
sb.append("system");
return sb.toString();
}
/**
* 系统词典
*
* @param orgi
* @return
*/
public static String getSysDicHashKeyByOrgi(final String orgi) {
public static String getSysDicHashKey() {
StringBuffer sb = new StringBuffer();
sb.append(orgi);
sb.append(":sysdic");
sb.append("sysdic");
return sb.toString();
}
@ -228,20 +203,16 @@ public class RedisKey {
/**
* 坐席会话配置相关
*
* @param orgi
* @return
*/
public static String getSessionConfigList(final String orgi) {
public static String getSessionConfigList() {
StringBuffer sb = new StringBuffer();
sb.append(orgi);
sb.append(":session:config:list");
sb.append("session:config:list");
return sb.toString();
}
public static String getSessionConfig(String organid, final String orgi) {
public static String getSessionConfig(String organid) {
StringBuffer sb = new StringBuffer();
sb.append(orgi);
sb.append(":");
sb.append(organid);
sb.append(":session:config");
return sb.toString();
@ -250,10 +221,9 @@ public class RedisKey {
/**
* SocketIO连接相关
*/
public static String getWebIMAgentSocketIOByAgentnoAndOrgi(final String agentno, final String orgi) {
public static String getWebIMAgentSocketIOByAgentno(final String agentno) {
StringBuffer sb = new StringBuffer();
sb.append(orgi);
sb.append(":agent:socketio:");
sb.append("agent:socketio:");
sb.append(agentno);
return sb.toString();
}
@ -261,30 +231,27 @@ public class RedisKey {
/**
* CousultInvite 相关
*/
public static String getConsultInvitesByOrgi(final String orgi) {
public static String getConsultInvites() {
StringBuffer sb = new StringBuffer();
sb.append(orgi);
sb.append(":consultinvite");
sb.append("consultinvite");
return sb.toString();
}
/**
* 和访客黑名单相关
*/
public static String getBlackEntityKeyByOrgi(final String orgi) {
public static String getBlackEntityKey() {
StringBuffer sb = new StringBuffer();
sb.append(orgi);
sb.append(":visitor:blacklist");
sb.append("visitor:blacklist");
return sb.toString();
}
/**
* 系统登录用户的会话Session信息
*/
public static String getUserSessionKeyByOrgi(final String orgi) {
public static String getUserSessionKey() {
StringBuffer sb = new StringBuffer();
sb.append(orgi);
sb.append(":user:session");
sb.append("user:session");
return sb.toString();
}

View File

@ -1,23 +1,24 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, All rights reserved.
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, All rights reserved.
* <https://www.chatopera.com>
* This software and related documentation are provided under a license agreement containing
* restrictions on use and disclosure and are protected by intellectual property laws.
* Except as expressly permitted in your license agreement or allowed by law, you may not use,
* copy, reproduce, translate, broadcast, modify, license, transmit, distribute, exhibit, perform,
* publish, or display any part, in any form, or by any means. Reverse engineering, disassembly,
* or decompilation of this software, unless required by law for interoperability, is prohibited.
*/
package com.cskefu.cc.config;
import jakarta.jms.ConnectionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerContainerFactory;
import javax.jms.ConnectionFactory;
@EnableJms
@Configuration
public class ActiveMQConfigure {

View File

@ -1,39 +1,40 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.config;
import com.cskefu.cc.basic.MainContext;
import com.cskefu.cc.basic.auth.AuthToken;
import org.apache.commons.lang.StringUtils;
import com.cskefu.cc.basic.auth.BearerTokenMgr;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.security.web.util.matcher.RequestMatcher;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import static com.cskefu.cc.basic.Constants.AUTH_TOKEN_TYPE_BASIC;
import static com.cskefu.cc.basic.Constants.AUTH_TOKEN_TYPE_BEARER;
public class ApiRequestMatchingFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(ApiRequestMatchingFilter.class);
private RequestMatcher[] ignoredRequests;
private static AuthToken authToken;
private final RequestMatcher[] ignoredRequests;
private static BearerTokenMgr bearerTokenMgr;
public ApiRequestMatchingFilter(RequestMatcher... matcher) {
@ -46,7 +47,7 @@ public class ApiRequestMatchingFilter implements Filter {
String method = request.getMethod();
if (!StringUtils.isBlank(method) && method.equalsIgnoreCase("options")) {
if (StringUtils.isNotBlank(method) && method.equalsIgnoreCase("options")) {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
response.setHeader("Access-Control-Max-Age", "3600");
@ -65,11 +66,40 @@ public class ApiRequestMatchingFilter implements Filter {
if (StringUtils.isBlank(authorization)) {
authorization = request.getParameter("authorization");
}
if (StringUtils.isNotBlank(authorization) &&
getAuthToken().existUserByAuth(authorization)) {
chain.doFilter(req, resp);
if (StringUtils.isNotBlank(authorization)) {
// set the default value for backward compatibility as bear token bare metal
String authorizationTrimed = authorization;
String authorizationTokenType = AUTH_TOKEN_TYPE_BEARER;
if (authorization.startsWith(String.format("%s ", AUTH_TOKEN_TYPE_BEARER))) {
authorizationTrimed = StringUtils.substring(authorization, 7);
authorizationTokenType = AUTH_TOKEN_TYPE_BEARER;
} else if (authorization.startsWith(String.format("%s ", AUTH_TOKEN_TYPE_BASIC))) {
authorizationTrimed = StringUtils.substring(authorization, 6);
authorizationTokenType = AUTH_TOKEN_TYPE_BASIC;
}
if (StringUtils.isNotBlank(authorizationTrimed)) {
switch (authorizationTokenType) {
case AUTH_TOKEN_TYPE_BEARER:
if (getBearerTokenMgr().existToken(authorizationTrimed)) {
chain.doFilter(req, resp);
} else {
response.sendRedirect("/auth/error");
}
break;
case AUTH_TOKEN_TYPE_BASIC:
// TODO
response.sendRedirect("/auth/error");
break;
default:
response.sendRedirect("/auth/error");
}
} else {
response.sendRedirect("/auth/error");
}
} else {
response.sendRedirect("/tokens/error");
response.sendRedirect("/auth/error");
}
} else {
chain.doFilter(req, resp);
@ -87,11 +117,11 @@ public class ApiRequestMatchingFilter implements Filter {
}
private static AuthToken getAuthToken() {
if (authToken == null) {
authToken = MainContext.getContext().getBean(AuthToken.class);
private static BearerTokenMgr getBearerTokenMgr() {
if (bearerTokenMgr == null) {
bearerTokenMgr = MainContext.getContext().getBean(BearerTokenMgr.class);
}
return authToken;
return bearerTokenMgr;
}
}

View File

@ -1,18 +1,16 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.config;
@ -25,10 +23,7 @@ import com.cskefu.cc.cache.Cache;
import com.cskefu.cc.model.BlackEntity;
import com.cskefu.cc.model.SysDic;
import com.cskefu.cc.model.SystemConfig;
import com.cskefu.cc.persistence.repository.BlackListRepository;
import com.cskefu.cc.persistence.repository.SysDicRepository;
import com.cskefu.cc.persistence.repository.SystemConfigRepository;
import com.cskefu.cc.persistence.repository.TablePropertiesRepository;
import com.cskefu.cc.persistence.repository.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -41,6 +36,85 @@ public class AppCtxRefreshEventListener implements ApplicationListener<ContextRe
private static final Logger logger = LoggerFactory.getLogger(AppCtxRefreshEventListener.class);
private void setupSysdicCacheAndExtras(final ContextRefreshedEvent event, final String cacheSetupStrategy, final Cache cache, final SysDicRepository sysDicRes, final BlackListRepository blackListRes) {
if (!StringUtils.equalsIgnoreCase(cacheSetupStrategy, Constants.cache_setup_strategy_skip)) {
/**************************
* 加载系统到缓存
* 加载系统词典大约只需要5s左右
**************************/
// 首先将之前缓存清空此处使用系统的默认租户信息
cache.eraseSysDic();
List<SysDic> sysDicList = sysDicRes.findAll();
Map<String, List<SysDic>> rootDictItems = new HashMap<>(); // 关联根词典及其子项
Map<String, SysDic> rootDics = new HashMap<>();
Set<String> parents = new HashSet<>();
// 获得所有根词典
for (final SysDic dic : sysDicList) {
if (StringUtils.equals(dic.getParentid(), "0")) {
parents.add(dic.getId());
rootDics.put(dic.getId(), dic);
}
}
// 向根词典中添加子项
for (final SysDic dic : sysDicList) {
if ((!StringUtils.equals(dic.getParentid(), "0")) &&
parents.contains(dic.getDicid())) {
// 不是根词典并且包含在一个根词典内
if (!rootDictItems.containsKey(dic.getDicid())) {
rootDictItems.put(dic.getDicid(), new ArrayList<>());
}
rootDictItems.get(dic.getDicid()).add(dic);
}
}
// 更新缓存
// TODO 集群时注意!!!
// 此处为长时间的操作如果在一个集群中会操作共享内容非常不可靠
// 所以当前代码不支持集群需要解决启动上的这个问题
// 存储根词典 TODO 此处只考虑了系统默认租户
cache.putSysDic(new ArrayList<>(rootDics.values()));
for (final Map.Entry<String, List<SysDic>> entry : rootDictItems.entrySet()) {
SysDic rootDic = rootDics.get(entry.getKey());
// 打印根词典信息
logger.debug("[onApplicationEvent] root dict: {}, code {}, name {}, item size {}", entry.getKey(), rootDics.get(entry.getKey()).getCode(), rootDics.get(entry.getKey()).getName(), entry.getValue().size());
// 存储子项列表
cache.putSysDic(rootDic.getCode(), entry.getValue());
// 存储子项成员
cache.putSysDic(entry.getValue());
}
List<BlackEntity> blackList = blackListRes.findAll();
for (final BlackEntity black : blackList) {
if (StringUtils.isNotBlank(black.getUserid())) {
if (black.getEndtime() == null || black.getEndtime().after(new Date())) {
cache.putSystemById(black.getUserid(), black);
}
}
}
/**
* 加载系统全局配置
*/
SystemConfigRepository systemConfigRes = event.getApplicationContext().getBean(SystemConfigRepository.class);
List<SystemConfig> configs = systemConfigRes.findAll();
SystemConfig config = configs.size() > 0 ? configs.get(0) : null;
if (config != null) {
cache.putSystemById("systemConfig", config);
}
logger.warn("[StartedEventListener] setup Sysdicts in Redis done, strategy {}", cacheSetupStrategy);
} else {
logger.warn("[onApplicationEvent] skip initialize sysdicts.");
}
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if (MainContext.getContext() == null) {
@ -51,80 +125,7 @@ public class AppCtxRefreshEventListener implements ApplicationListener<ContextRe
Cache cache = event.getApplicationContext().getBean(Cache.class);
String cacheSetupStrategy = event.getApplicationContext().getEnvironment().getProperty("cache.setup.strategy");
if (!StringUtils.equalsIgnoreCase(cacheSetupStrategy, Constants.cache_setup_strategy_skip)) {
/**************************
* 加载系统到缓存
* 加载系统词典大约只需要5s左右
**************************/
// 首先将之前缓存清空此处使用系统的默认租户信息
cache.eraseSysDicByOrgi(Constants.SYSTEM_ORGI);
List<SysDic> sysDicList = sysDicRes.findAll();
Map<String, List<SysDic>> rootDictItems = new HashMap<>(); // 关联根词典及其子项
Map<String, SysDic> rootDics = new HashMap<>();
Set<String> parents = new HashSet<>();
// 获得所有根词典
for (final SysDic dic : sysDicList) {
if (StringUtils.equals(dic.getParentid(), "0")) {
parents.add(dic.getId());
rootDics.put(dic.getId(), dic);
}
}
// 向根词典中添加子项
for (final SysDic dic : sysDicList) {
if ((!StringUtils.equals(dic.getParentid(), "0")) &&
parents.contains(dic.getDicid())) {
// 不是根词典并且包含在一个根词典内
if (!rootDictItems.containsKey(dic.getDicid())) {
rootDictItems.put(dic.getDicid(), new ArrayList<SysDic>());
}
rootDictItems.get(dic.getDicid()).add(dic);
}
}
// 更新缓存
// TODO 集群时注意!!!
// 此处为长时间的操作如果在一个集群中会操作共享内容非常不可靠
// 所以当前代码不支持集群需要解决启动上的这个问题
// 存储根词典 TODO 此处只考虑了系统默认租户
cache.putSysDicByOrgi(new ArrayList<>(rootDics.values()), Constants.SYSTEM_ORGI);
for (final Map.Entry<String, List<SysDic>> entry : rootDictItems.entrySet()) {
SysDic rootDic = rootDics.get(entry.getKey());
// 打印根词典信息
logger.debug("[onApplicationEvent] root dict: {}, code {}, name {}, item size {}", entry.getKey(), rootDics.get(entry.getKey()).getCode(), rootDics.get(entry.getKey()).getName(), entry.getValue().size());
// 存储子项列表
cache.putSysDicByOrgi(rootDic.getCode(), Constants.SYSTEM_ORGI, entry.getValue());
// 存储子项成员
cache.putSysDicByOrgi(entry.getValue(), Constants.SYSTEM_ORGI);
}
List<BlackEntity> blackList = blackListRes.findByOrgi(Constants.SYSTEM_ORGI);
for (final BlackEntity black : blackList) {
if (StringUtils.isNotBlank(black.getUserid())) {
if (black.getEndtime() == null || black.getEndtime().after(new Date())) {
cache.putSystemByIdAndOrgi(black.getUserid(), black.getOrgi(), black);
}
}
}
/**
* 加载系统全局配置
*/
SystemConfigRepository systemConfigRes = event.getApplicationContext().getBean(SystemConfigRepository.class);
SystemConfig config = systemConfigRes.findByOrgi(Constants.SYSTEM_ORGI);
if (config != null) {
cache.putSystemByIdAndOrgi("systemConfig", Constants.SYSTEM_ORGI, config);
}
logger.info("[StartedEventListener] setup Sysdicts in Redis done, strategy {}", cacheSetupStrategy);
} else {
logger.info("[onApplicationEvent] skip initialize sysdicts.");
}
setupSysdicCacheAndExtras(event, cacheSetupStrategy, cache, sysDicRes, blackListRes);
MainUtils.initSystemArea();
@ -140,5 +141,13 @@ public class AppCtxRefreshEventListener implements ApplicationListener<ContextRe
} else {
logger.info("[onApplicationEvent] bypass, initialization has been done already.");
}
// Fix SQL init lazy load delay
if (MainContext.getContext() != null) {
UserRepository userRes = MainContext.getContext().getBean(UserRepository.class);
userRes.findByUsername("admin").ifPresent((p) -> {
logger.warn("[onApplicationEvent] inited JPA sql.");
});
}
}
}

View File

@ -1,50 +1,48 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.config;
import com.cskefu.cc.basic.MainContext;
import com.cskefu.cc.model.Favorites;
import com.cskefu.cc.model.WorkOrders;
import com.cskefu.cc.proxy.UserProxy;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.data.elasticsearch.ElasticsearchException;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.stereotype.Component;
@Component
public class ApplicationStartupListener implements ApplicationListener<ContextRefreshedEvent> {
@Autowired ElasticsearchTemplate elasticSearchTemplate;
public class ApplicationStartupListener implements ApplicationListener<ApplicationReadyEvent> {
final private static Logger logger = LoggerFactory.getLogger(ApplicationStartupListener.class);
@Value("${extras.auth.super-admin.pass}")
private String superAdminPass;
@Autowired
private UserProxy userProxy;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if (!elasticSearchTemplate.indexExists(WorkOrders.class)) {
elasticSearchTemplate.createIndex(WorkOrders.class);
public void onApplicationEvent(final ApplicationReadyEvent event) {
if (StringUtils.isNotBlank(superAdminPass)) {
logger.warn("Reset Superadmin Password by ENV variable EXTRAS_AUTH_SUPER_ADMIN_PASS=********");
if (!userProxy.resetAccountPasswordByUsername("admin", superAdminPass)) {
logger.error("Reset Superadmin Password failure. Check 1) admin user do exist in DB with username admin.");
}
}
if (!elasticSearchTemplate.indexExists(Favorites.class)) {
elasticSearchTemplate.createIndex(Favorites.class);
}
try {
elasticSearchTemplate.getMapping(WorkOrders.class);
} catch (ElasticsearchException e) {
elasticSearchTemplate.putMapping(Favorites.class);
elasticSearchTemplate.putMapping(WorkOrders.class);
}
MainContext.setTemplet(elasticSearchTemplate);
return;
}
}

View File

@ -1,18 +1,16 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.config;

View File

@ -1,34 +1,35 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.config;
import com.cskefu.cc.interceptor.*;
import com.cskefu.cc.util.SystemEnvHelper;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.config.annotation.*;
@Configuration
public class CSKeFuWebAppConfigurer
extends WebMvcConfigurerAdapter {
public class CSKeFuWebAppConfigurer implements WebMvcConfigurer {
private final static Logger logger = LoggerFactory.getLogger(CSKeFuWebAppConfigurer.class);
private final static String ENABLE_LOG_REQUEST = SystemEnvHelper.parseFromApplicationProps("extras.log.request");
/**
* https://www.baeldung.com/spring-cors
*
* @param registry
*/
@Override
@ -37,6 +38,17 @@ public class CSKeFuWebAppConfigurer
registry.addMapping("/**").allowedOrigins("*");
}
@Override
@SuppressWarnings("deprecation")
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(Boolean.TRUE);
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 多个拦截器组成一个拦截器链
@ -45,8 +57,14 @@ public class CSKeFuWebAppConfigurer
registry.addInterceptor(new UserExperiencePlanInterceptorHandler()).addPathPatterns("/**").excludePathPatterns("/im/**", "/res/image*", "/res/file*", "/cs/**", "/messenger/webhook/*");
registry.addInterceptor(new UserInterceptorHandler()).addPathPatterns("/**").excludePathPatterns("/login.html", "/im/**", "/res/image*", "/res/file*", "/cs/**", "/messenger/webhook/*");
registry.addInterceptor(new CrossInterceptorHandler()).addPathPatterns("/**");
registry.addInterceptor(new LogIntercreptorHandler()).addPathPatterns("/**");
if (StringUtils.equalsIgnoreCase(ENABLE_LOG_REQUEST, "on")) {
logger.warn("Logging request into DB as in ENV: ENABLE_LOG_REQUEST=on");
registry.addInterceptor(new RequestLogIntercreptorHandler()).addPathPatterns("/**");
} else {
logger.info("Disable Logging request into DB.");
}
registry.addInterceptor(new ViewsInterceptorHandler()).addPathPatterns("/**");
super.addInterceptors(registry);
}
}

View File

@ -1,18 +1,16 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.config;
@ -21,13 +19,13 @@ import com.cskefu.cc.model.User;
import org.apache.catalina.connector.ClientAbortException;
import org.springframework.security.web.util.matcher.RequestMatcher;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
public class DelegateRequestMatchingFilter implements Filter {
private RequestMatcher[] ignoredRequests;
private final RequestMatcher[] ignoredRequests;
public DelegateRequestMatchingFilter(RequestMatcher... matcher) {
this.ignoredRequests = matcher;

View File

@ -1,102 +0,0 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cskefu.cc.config;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DatabaseDriver;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
@Configuration
@ConditionalOnClass(com.alibaba.druid.pool.DruidDataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.alibaba.druid.pool.DruidDataSource", matchIfMissing = true)
public class DruidConfiguration {
@SuppressWarnings("unchecked")
protected <T> T createDataSource(DataSourceProperties properties,
Class<? extends DataSource> type) {
return (T) properties.initializeDataSourceBuilder().type(type).build();
}
/**
* @see org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration.Tomcat 仿写的你可以去了解
* @param properties 读入的配置
* @return DruidDataSource
*/
@Bean
@ConfigurationProperties("spring.datasource.druid")
public com.alibaba.druid.pool.DruidDataSource dataSource(DataSourceProperties properties) {
com.alibaba.druid.pool.DruidDataSource dataSource = createDataSource(properties, com.alibaba.druid.pool.DruidDataSource.class);
DatabaseDriver databaseDriver = DatabaseDriver.fromJdbcUrl(properties.determineUrl());
String validationQuery = databaseDriver.getValidationQuery();
if (validationQuery != null) {
dataSource.setTestOnBorrow(true);
dataSource.setValidationQuery(validationQuery);
}
return dataSource;
}
/**
* 注册一个StatViewServlet
* @return
*/
@Bean
public ServletRegistrationBean DruidStatViewServle2(){
//org.springframework.boot.context.embedded.ServletRegistrationBean提供类的进行注册.
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(),"/druid/*");
//添加初始化参数initParams
//白名单
// servletRegistrationBean.addInitParameter("allow","127.0.0.1");
//IP黑名单 (存在共同时deny优先于allow) : 如果满足deny的话提示:Sorry, you are not permitted to view this page.
// servletRegistrationBean.addInitParameter("deny","192.168.1.73");
//登录查看信息的账号密码.
servletRegistrationBean.addInitParameter("loginUsername","admin");
servletRegistrationBean.addInitParameter("loginPassword","123456");
//是否能够重置数据.
servletRegistrationBean.addInitParameter("resetEnable","false");
return servletRegistrationBean;
}
/**
* 注册一个filterRegistrationBean
* @return
*/
@Bean
public FilterRegistrationBean druidStatFilter2(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
//添加过滤规则.
filterRegistrationBean.addUrlPatterns("/*");
//添加不需要忽略的格式信息.
filterRegistrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid2/*");
return filterRegistrationBean;
}
}

View File

@ -1,18 +1,16 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.config;
@ -28,8 +26,8 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
*/
@Configuration
public class ExecutorConfig {
private static int CORE_POOL_SIZE = 7;
private static int MAX_POOL_SIZE = 100;
private static final int CORE_POOL_SIZE = 7;
private static final int MAX_POOL_SIZE = 100;
/**
* 作业平台使用的线程池

View File

@ -1,39 +1,32 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.config;
import com.cskefu.cc.basic.MainUtils;
import com.cskefu.cc.exception.InstantMessagingExceptionListener;
import com.corundumstudio.socketio.AuthorizationListener;
import com.corundumstudio.socketio.Configuration;
import com.corundumstudio.socketio.HandshakeData;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.annotation.SpringAnnotationScanner;
import com.cskefu.cc.exception.InstantMessagingExceptionListener;
import jakarta.annotation.PreDestroy;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.web.server.Ssl;
import org.springframework.context.annotation.Bean;
import javax.annotation.PreDestroy;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.NoSuchAlgorithmException;
import java.util.Properties;
@org.springframework.context.annotation.Configuration
public class MessagingServerConfigure {
@ -46,9 +39,6 @@ public class MessagingServerConfigure {
@Value("${cs.im.server.ssl.port}")
private Integer sslPort;
@Value("${web.upload-path}")
private String path;
@Value("${uk.im.server.threads}")
private String threads;
@ -63,15 +53,18 @@ public class MessagingServerConfigure {
}
}
@Autowired
private ServerProperties serverProperties;
@Bean
public SocketIOServer socketIOServer() throws NoSuchAlgorithmException, IOException {
public SocketIOServer socketIOServer() {
Configuration config = new Configuration();
//解决对此重启服务时netty端口被占用问题
com.corundumstudio.socketio.SocketConfig tmpConfig = new com.corundumstudio.socketio.SocketConfig();
tmpConfig.setReuseAddress(true);
config.setSocketConfig(tmpConfig);
// config.setHostname("localhost");
// config.setHostname(host);
config.setPort(port);
// config.getSocketConfig().setReuseAddress(true);
@ -79,38 +72,28 @@ public class MessagingServerConfigure {
// config.setOrigin("*");
config.setExceptionListener(new InstantMessagingExceptionListener());
File sslFile = new File(path, "ssl/https.properties");
if (sslFile.exists()) {
Properties sslProperties = new Properties();
try (FileInputStream in = new FileInputStream(sslFile)) {
sslProperties.load(in);
}
if (StringUtils.isNotBlank(sslProperties.getProperty("key-store")) && StringUtils.isNotBlank(
sslProperties.getProperty("key-store-password"))) {
config.setKeyStorePassword(MainUtils.decryption(sslProperties.getProperty("key-store-password")));
InputStream stream = new FileInputStream(
new File(path, "ssl/" + sslProperties.getProperty("key-store")));
config.setKeyStore(stream);
}
}
// config.setSSLProtocol("https");
int workThreads = StringUtils.isNotBlank(threads) && threads.matches("[\\d]{1,6}") ? Integer.parseInt(
threads) : 100;
int workThreads = StringUtils.isNotBlank(threads) && threads.matches("[\\d]{1,6}") ? Integer.parseInt(threads) : 100;
config.setWorkerThreads(workThreads);
// config.setStoreFactory(new HazelcastStoreFactory());
config.setAuthorizationListener(new AuthorizationListener() {
public boolean isAuthorized(HandshakeData data) {
return true;
}
});
config.setAuthorizationListener(data -> true);
config.getSocketConfig().setReuseAddress(true);
config.getSocketConfig().setSoLinger(0);
config.getSocketConfig().setTcpNoDelay(true);
config.getSocketConfig().setTcpKeepAlive(true);
// ServerProperties serverProperties = applicationContext.getBean(ServerProperties.class);
Ssl ssl = serverProperties.getSsl();
if (ssl != null) {
String keyStore = ssl.getKeyStore();
String keyStorePassword = ssl.getKeyStorePassword();
if (StringUtils.isNotEmpty(keyStore) && StringUtils.isNotEmpty(keyStorePassword)) {
InputStream keyStoreStream = this.getClass().getResourceAsStream("/" + keyStore.trim().split(":")[1]);
config.setKeyStore(keyStoreStream);
config.setKeyStorePassword(keyStorePassword);
}
}
return server = new SocketIOServer(config);
}
@ -123,4 +106,4 @@ public class MessagingServerConfigure {
public void destory() {
server.stop();
}
}
}

View File

@ -1,17 +1,15 @@
/*
* Copyright (C) 2020 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.config;
@ -30,7 +28,6 @@ public class PugConfig {
@Value("${spring.pug4j.template-loader-path}")
private String templatePath;
@Bean
public SpringTemplateLoader templateLoader() {
SpringTemplateLoader templateLoader = new SpringTemplateLoader();

View File

@ -1,3 +1,13 @@
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cskefu.cc.config;
import de.neuland.pug4j.spring.view.PugView;
@ -10,7 +20,7 @@ public class PugCskefuViewResolver extends PugViewResolver {
AbstractUrlBasedView view = super.buildView(viewName);
if (viewName.startsWith("/resource/css")) {
PugView pugView = (PugView) view;
pugView.setContentType("text/css ; charset=UTF-8");
pugView.setContentType("text/css; charset=UTF-8");
}
return view;
}

View File

@ -1,24 +1,21 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import java.util.concurrent.Executors;
@ -26,13 +23,10 @@ import java.util.concurrent.Executors;
@Configuration
public class RedisConfigure {
@Autowired
JedisConnectionFactory jedisConnectionFactory;
@Bean
RedisMessageListenerContainer redisContainer() {
RedisMessageListenerContainer redisContainer(RedisConnectionFactory redisConnectionFactory) {
final RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(jedisConnectionFactory);
container.setConnectionFactory(redisConnectionFactory);
container.setTaskExecutor(Executors.newFixedThreadPool(100));
return container;
}

View File

@ -1,12 +1,13 @@
/*
* Copyright (C) 2022 Chatopera Inc, All rights reserved.
* <https://www.chatopera.com>
* This software and related documentation are provided under a license agreement containing
* restrictions on use and disclosure and are protected by intellectual property laws.
* Except as expressly permitted in your license agreement or allowed by law, you may not use,
* copy, reproduce, translate, broadcast, modify, license, transmit, distribute, exhibit, perform,
* publish, or display any part, in any form, or by any means. Reverse engineering, disassembly,
* or decompilation of this software, unless required by law for interoperability, is prohibited.
/**
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright Jun. 2023 Chatopera Inc. <https://www.chatopera.com>. All rights reserved.
*/
package com.cskefu.cc.config;

View File

@ -1,22 +1,20 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.config;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.convert.converter.Converter;
import java.text.SimpleDateFormat;

View File

@ -1,18 +1,16 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.config;
@ -24,7 +22,7 @@ import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.multipart.support.StandardServletMultipartResolver;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import javax.annotation.PostConstruct;
import jakarta.annotation.PostConstruct;
@Configuration
public class WebConfigBeans {

View File

@ -1,26 +1,32 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.config;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@ -28,29 +34,26 @@ import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.WebUtils;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
public class WebSecurityConfig {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterAfter(tokenInfoTokenFilterSecurityInterceptor() , BasicAuthenticationFilter.class)
.antMatcher("*/*").authorizeRequests()
.anyRequest().permitAll()
.and().addFilterAfter(csrfHeaderFilter(), BasicAuthenticationFilter.class)
.addFilterAfter(apiTokenFilterSecurityInterceptor(), BasicAuthenticationFilter.class);
}
@Bean
public Filter tokenInfoTokenFilterSecurityInterceptor() throws Exception
{
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.addFilterAfter(tokenInfoTokenFilterSecurityInterceptor(), BasicAuthenticationFilter.class)
.authorizeHttpRequests(authorize -> authorize.requestMatchers("/**").permitAll())
.csrf().disable().headers().frameOptions().sameOrigin()
// .addFilterAfter(csrfHeaderFilter(), BasicAuthenticationFilter.class) // TODO lecjy
.and().addFilterAfter(apiTokenFilterSecurityInterceptor(), BasicAuthenticationFilter.class);
http.headers().contentTypeOptions().disable();
return http.build();
}
@Bean
public Filter tokenInfoTokenFilterSecurityInterceptor() throws Exception {
RequestMatcher autconfig = new AntPathRequestMatcher("/autoconfig/**");
RequestMatcher configprops = new AntPathRequestMatcher("/configprops/**");
RequestMatcher beans = new AntPathRequestMatcher("/beans/**");
@ -67,15 +70,14 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
// RequestMatcher health = new AntPathRequestMatcher("/health/**");
// RequestMatcher metrics = new AntPathRequestMatcher("/metrics/**");
// return new DelegateRequestMatchingFilter(autconfig , configprops , beans , dump , env , health , info , mappings , metrics , trace, druid);
return new DelegateRequestMatchingFilter(autconfig , configprops , beans , dump , env , mappings , trace, druid);
return new DelegateRequestMatchingFilter(autconfig, configprops, beans, dump, env, mappings, trace, druid);
}
@Bean
public Filter apiTokenFilterSecurityInterceptor() throws Exception
{
public Filter apiTokenFilterSecurityInterceptor() throws Exception {
return new ApiRequestMatchingFilter(new AntPathRequestMatcher("/api/**"));
}
private Filter csrfHeaderFilter() {
return new OncePerRequestFilter() {

View File

@ -1,27 +1,26 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.config;
import org.apache.catalina.connector.Connector;
import org.apache.coyote.ProtocolHandler;
import org.apache.coyote.http11.Http11NioProtocol;
import org.apache.tomcat.util.http.Rfc6265CookieProcessor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -41,21 +40,26 @@ public class WebServerContainerConfigure {
private String path;
@Bean
public EmbeddedServletContainerFactory createEmbeddedServletContainerFactory() throws IOException, NoSuchAlgorithmException {
TomcatEmbeddedServletContainerFactory tomcatFactory = new TomcatEmbeddedServletContainerFactory();
public TomcatServletWebServerFactory createEmbeddedServletContainerFactory() throws IOException, NoSuchAlgorithmException {
TomcatServletWebServerFactory tomcatFactory = new TomcatServletWebServerFactory();
tomcatFactory.addConnectorCustomizers(new CSKeFuTomcatConnectorCustomizer(maxthread, maxconnections));
// Enable cookie value with space
// https://stackoverflow.com/questions/38687210/error-with-cookie-value-when-adding-a-new-spring-session
// TODO lecjy
tomcatFactory.addContextCustomizers(context -> context.setCookieProcessor(new Rfc6265CookieProcessor()));
return tomcatFactory;
}
class CSKeFuTomcatConnectorCustomizer implements TomcatConnectorCustomizer {
private Integer maxthread;
private Integer maxconnection;
private final Integer maxthread;
private final Integer maxconnection;
CSKeFuTomcatConnectorCustomizer(Integer maxthread, Integer maxconnection) {
this.maxthread = maxthread;
this.maxconnection = maxconnection;
}
@Override
public void customize(Connector connector) {
Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
//设置最大连接数

View File

@ -1,23 +1,21 @@
/*
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-2022 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.config;
import com.cskefu.cc.basic.auth.AuthRedisTemplate;
import com.cskefu.cc.cache.RedisKey;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -25,10 +23,12 @@ import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.session.data.redis.RedisFlushMode;
import org.springframework.session.data.redis.RedisOperationsSessionRepository;
import org.springframework.session.FlushMode;
import org.springframework.session.data.redis.RedisSessionRepository;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import java.time.Duration;
/**
* maxInactiveIntervalInSeconds: 设置 Session 失效时间
@ -39,22 +39,21 @@ import org.springframework.session.data.redis.config.annotation.web.http.EnableR
*/
@Configuration
@EnableRedisHttpSession()
public class WebServerSessionConfigure {
/**
* spring在多长时间后强制使redis中的session失效,默认是1800.(单位/)
*/
@Value("${server.session-timeout}")
private int maxInactiveIntervalInSeconds;
private long maxInactiveIntervalInSeconds;
@Value("${spring.redis.host}")
@Value("${spring.data.redis.host}")
private String host;
@Value("${spring.redis.port}")
@Value("${spring.data.redis.port}")
private int port;
@Value("${spring.redis.password}")
@Value("${spring.data.redis.password}")
private String pass;
@Value("${spring.redis.session.db}")
@ -63,21 +62,22 @@ public class WebServerSessionConfigure {
@Value("${spring.redis.token.db}")
private int tokenDb;
@Value("${spring.redis.timeout}")
@Value("${spring.data.redis.timeout}")
private int timeout;
@Primary
@Bean
public RedisOperationsSessionRepository sessionRepository(RedisTemplate<Object, Object> sessionRedisTemplate) {
RedisOperationsSessionRepository sessionRepository = new RedisOperationsSessionRepository(sessionRedisTemplate);
sessionRepository.setDefaultMaxInactiveInterval(maxInactiveIntervalInSeconds);
sessionRepository.setRedisFlushMode(RedisFlushMode.IMMEDIATE);
// TODO lecjy
public RedisSessionRepository sessionRepository(RedisTemplate<String, Object> sessionRedisTemplate) {
RedisSessionRepository sessionRepository = new RedisSessionRepository(sessionRedisTemplate);
sessionRepository.setDefaultMaxInactiveInterval(Duration.ofSeconds(maxInactiveIntervalInSeconds));
sessionRepository.setFlushMode(FlushMode.IMMEDIATE);
sessionRepository.setRedisKeyNamespace(RedisKey.CACHE_SESSIONS);
return sessionRepository;
}
@Bean
public RedisTemplate<Object, Object> sessionRedisTemplate() {
public RedisTemplate<String, Object> sessionRedisTemplate() {
JedisConnectionFactory factory = new JedisConnectionFactory();
factory.setHostName(host);
factory.setPort(port);
@ -87,7 +87,7 @@ public class WebServerSessionConfigure {
}
factory.setTimeout(timeout);
factory.afterPropertiesSet();
RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setConnectionFactory(factory);

View File

@ -1,18 +1,16 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.controller;
@ -22,6 +20,7 @@ import com.cskefu.cc.basic.MainContext;
import com.cskefu.cc.basic.MainUtils;
import com.cskefu.cc.cache.Cache;
import com.cskefu.cc.model.Organ;
import com.cskefu.cc.model.PbxHost;
import com.cskefu.cc.model.User;
import com.cskefu.cc.persistence.repository.ExtensionRepository;
import com.cskefu.cc.persistence.repository.OrganRepository;
@ -37,8 +36,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.List;
@ -96,10 +95,10 @@ public class ApplicationController extends Handler {
view.addObject(
"skills",
organProxy.findAllOrganByParentAndOrgi(currentOrgan, super.getOrgi(request)).keySet().stream().collect(Collectors.joining(","))
organProxy.findAllOrganByParent(currentOrgan).keySet().stream().collect(Collectors.joining(","))
);
view.addObject("agentStatusReport", acdWorkMonitor.getAgentReport(currentOrgan != null ? currentOrgan.getId() : null, logined.getOrgi()));
view.addObject("agentStatusReport", acdWorkMonitor.getAgentReport(currentOrgan != null ? currentOrgan.getId() : null));
view.addObject("istenantshare", false);
view.addObject("timeDifference", timezone.getRawOffset());
view.addObject("organList", organs);
@ -112,24 +111,23 @@ public class ApplicationController extends Handler {
view.addObject("appCustomerEntity", appCustomerEntity);
// 在线坐席状态信息
view.addObject("agentStatus", cache.findOneAgentStatusByAgentnoAndOrig(logined.getId(), logined.getOrgi()));
view.addObject("agentStatus", cache.findOneAgentStatusByAgentno(logined.getId()));
// 呼叫中心信息
if (MainContext.hasModule(Constants.CSKEFU_MODULE_CALLCENTER) && logined.isCallcenter()) {
extensionRes.findByAgentnoAndOrgi(logined.getId(), logined.getOrgi()).ifPresent(ext -> {
pbxHostRes.findById(ext.getHostid()).ifPresent(pbx -> {
Map<String, Object> webrtcData = new HashMap<>();
webrtcData.put("callCenterWebrtcIP", pbx.getWebrtcaddress());
webrtcData.put("callCenterWebRtcPort", pbx.getWebrtcport());
webrtcData.put("callCenterExtensionNum", ext.getExtension());
try {
webrtcData.put("callCenterExtensionPassword", MainUtils.decryption(ext.getPassword()));
} catch (NoSuchAlgorithmException e) {
logger.error("[admin]", e);
webrtcData.put("callCenterError", "Invalid data for callcenter agent.");
}
view.addObject("webrtc", webrtcData);
});
extensionRes.findByAgentno(logined.getId()).ifPresent(ext -> {
PbxHost one = pbxHostRes.findById(ext.getHostid()).orElse(null);
Map<String, Object> webrtcData = new HashMap<>();
webrtcData.put("callCenterWebrtcIP", one.getWebrtcaddress());
webrtcData.put("callCenterWebRtcPort", one.getWebrtcport());
webrtcData.put("callCenterExtensionNum", ext.getExtension());
try {
webrtcData.put("callCenterExtensionPassword", MainUtils.decryption(ext.getPassword()));
} catch (NoSuchAlgorithmException e) {
logger.error("[admin]", e);
webrtcData.put("callCenterError", "Invalid data for callcenter agent.");
}
view.addObject("webrtc", webrtcData);
});
}
@ -145,7 +143,7 @@ public class ApplicationController extends Handler {
@ResponseBody
public String setOrgan(HttpServletRequest request, @Valid String organ) {
if (StringUtils.isNotBlank(organ)) {
Organ currentOrgan = organRepository.findByIdAndOrgi(organ, super.getOrgi(request));
Organ currentOrgan = organRepository.findById(organ).orElse(null);
if (currentOrgan != null) {
request.getSession(true).setAttribute(Constants.ORGAN_SESSION_NAME, currentOrgan);
}
@ -158,7 +156,7 @@ public class ApplicationController extends Handler {
public ModelAndView lazyAgentStatus(HttpServletRequest request) {
ModelAndView view = request(super.createView("/public/agentstatustext"));
Organ currentOrgan = super.getOrgan(request);
view.addObject("agentStatusReport", acdWorkMonitor.getAgentReport(currentOrgan != null ? currentOrgan.getId() : null, super.getOrgi(request)));
view.addObject("agentStatusReport", acdWorkMonitor.getAgentReport(currentOrgan != null ? currentOrgan.getId() : null));
return view;
}

View File

@ -1,25 +1,23 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.controller;
import com.cskefu.cc.basic.Constants;
import com.cskefu.cc.basic.MainUtils;
import com.cskefu.cc.basic.Viewport;
import com.cskefu.cc.basic.auth.AuthToken;
import com.cskefu.cc.basic.auth.BearerTokenMgr;
import com.cskefu.cc.cache.Cache;
import com.cskefu.cc.controller.api.QueryParams;
import com.cskefu.cc.exception.CSKefuException;
@ -29,29 +27,26 @@ import com.cskefu.cc.model.User;
import com.cskefu.cc.persistence.blob.JpaBlobHelper;
import com.cskefu.cc.persistence.repository.StreamingFileRepository;
import com.cskefu.cc.proxy.OrganProxy;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.index.query.QueryStringQueryBuilder.Operator;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.text.ParseException;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static com.cskefu.cc.basic.Constants.AUTH_TOKEN_TYPE_BASIC;
import static com.cskefu.cc.basic.Constants.AUTH_TOKEN_TYPE_BEARER;
@Controller
@SessionAttributes
@ -68,7 +63,7 @@ public class Handler {
private Cache cache;
@Autowired
private AuthToken authToken;
private BearerTokenMgr bearerTokenMgr;
@Autowired
private OrganProxy organProxy;
@ -92,14 +87,26 @@ public class Handler {
}
}
}
// trim token
if (StringUtils.isNotBlank(authorization)) {
user = authToken.findUserByAuth(authorization);
String authorizationTrimed = authorization;
if (authorization.startsWith(String.format("%s ", AUTH_TOKEN_TYPE_BEARER))) {
authorizationTrimed = StringUtils.substring(authorization, 7);
if (StringUtils.isNotBlank(authorizationTrimed)) {
user = bearerTokenMgr.retrieve(authorizationTrimed);
}
} else if (authorization.startsWith(String.format("%s ", AUTH_TOKEN_TYPE_BASIC))) {
authorizationTrimed = StringUtils.substring(authorization, 6);
// TODO https://gitlab.chatopera.com/chatopera/chatopera.bot/issues/1292
// get user with basic token mgr
}
}
if (user == null) {
user = new User();
user.setId(MainUtils.getContextID(request.getSession().getId()));
user.setUsername(Constants.GUEST_USER + "_" + MainUtils.genIDByKey(user.getId()));
user.setOrgi(Constants.SYSTEM_ORGI);
user.setSessionid(user.getId());
}
} else {
@ -132,15 +139,36 @@ public class Handler {
}
}
/**
* 获得该用户的组织机构及附属组织机构的数组
*
* @param user
* @return
*/
public List<String> getMyAffiliatesFlat(final User user) {
ArrayList<String> organIds = new ArrayList<>(user.getAffiliates());
return organIds;
}
/**
* 获得当前用户导航的组织机构和附属组织机构的信息
*
* @param user
* @return
*/
public List<String> getMyCurrentAffiliatesFlat(final User user) {
ArrayList<String> organIds = new ArrayList<>(user.getCurrOrganAffiliates());
return organIds;
}
/**
* 构建ElasticSearch基于部门查询的Filter
*
* @param request
* @param boolQueryBuilder
* @return
* @throws CSKefuException
*/
public boolean esOrganFilter(final HttpServletRequest request, final BoolQueryBuilder boolQueryBuilder)
public boolean preCheckPermissions(final HttpServletRequest request)
throws CSKefuException {
// 组合部门条件
User u = getUser(request);
@ -160,156 +188,6 @@ public class Handler {
return true;
}
/**
* @param queryBuilder
* @param request
*/
public BoolQueryBuilder search(BoolQueryBuilder queryBuilder, ModelMap map, HttpServletRequest request) {
queryBuilder.must(termQuery("orgi", this.getOrgi(request)));
// 搜索框
if (StringUtils.isNotBlank(request.getParameter("q"))) {
String q = request.getParameter("q");
q = q.replaceAll("(OR|AND|NOT|:|\\(|\\))", "");
if (StringUtils.isNotBlank(q)) {
queryBuilder.must(
QueryBuilders.boolQuery().must(new QueryStringQueryBuilder(q).defaultOperator(Operator.AND)));
map.put("q", q);
}
}
// 筛选表单
if (StringUtils.isNotBlank(request.getParameter("filterid"))) {
queryBuilder.must(termQuery("filterid", request.getParameter("filterid")));
map.put("filterid", request.getParameter("filterid"));
}
// 批次
if (StringUtils.isNotBlank(request.getParameter("batid"))) {
queryBuilder.must(termQuery("batid", request.getParameter("batid")));
map.put("batid", request.getParameter("batid"));
}
// 活动
if (StringUtils.isNotBlank(request.getParameter("actid"))) {
queryBuilder.must(termQuery("actid", request.getParameter("actid")));
map.put("actid", request.getParameter("actid"));
}
// 业务状态
if (StringUtils.isNotBlank(request.getParameter("workstatus"))) {
queryBuilder.must(termQuery("workstatus", request.getParameter("workstatus")));
map.put("workstatus", request.getParameter("workstatus"));
}
// 拨打状态
if (StringUtils.isNotBlank(request.getParameter("callstatus"))) {
queryBuilder.must(termQuery("callstatus", request.getParameter("callstatus")));
map.put("callstatus", request.getParameter("callstatus"));
}
// 预约状态
if (StringUtils.isNotBlank(request.getParameter("apstatus"))) {
queryBuilder.must(termQuery("apstatus", request.getParameter("apstatus")));
map.put("apstatus", request.getParameter("apstatus"));
}
RangeQueryBuilder rangeQuery = null;
// 拨打时间区间查询
if (StringUtils.isNotBlank(request.getParameter("callbegin")) || StringUtils.isNotBlank(
request.getParameter("callend"))) {
if (StringUtils.isNotBlank(request.getParameter("callbegin"))) {
try {
rangeQuery = QueryBuilders.rangeQuery("calltime").from(
MainUtils.dateFormate.parse(request.getParameter("callbegin")).getTime());
} catch (ParseException e) {
e.printStackTrace();
}
}
if (StringUtils.isNotBlank(request.getParameter("callend"))) {
try {
if (rangeQuery == null) {
rangeQuery = QueryBuilders.rangeQuery("calltime").to(
MainUtils.dateFormate.parse(request.getParameter("callend")).getTime());
} else {
rangeQuery.to(MainUtils.dateFormate.parse(request.getParameter("callend")).getTime());
}
} catch (ParseException e) {
e.printStackTrace();
}
}
map.put("callbegin", request.getParameter("callbegin"));
map.put("callend", request.getParameter("callend"));
}
// 预约时间区间查询
if (StringUtils.isNotBlank(request.getParameter("apbegin")) || StringUtils.isNotBlank(
request.getParameter("apend"))) {
if (StringUtils.isNotBlank(request.getParameter("apbegin"))) {
try {
rangeQuery = QueryBuilders.rangeQuery("aptime").from(
MainUtils.dateFormate.parse(request.getParameter("apbegin")).getTime());
} catch (ParseException e) {
e.printStackTrace();
}
}
if (StringUtils.isNotBlank(request.getParameter("apend"))) {
try {
if (rangeQuery == null) {
rangeQuery = QueryBuilders.rangeQuery("aptime").to(
MainUtils.dateFormate.parse(request.getParameter("apend")).getTime());
} else {
rangeQuery.to(MainUtils.dateFormate.parse(request.getParameter("apend")).getTime());
}
} catch (ParseException e) {
e.printStackTrace();
}
}
map.put("apbegin", request.getParameter("apbegin"));
map.put("apend", request.getParameter("apend"));
}
if (rangeQuery != null) {
queryBuilder.must(rangeQuery);
}
// 外呼任务id
if (StringUtils.isNotBlank(request.getParameter("taskid"))) {
queryBuilder.must(termQuery("taskid", request.getParameter("taskid")));
map.put("taskid", request.getParameter("taskid"));
}
// 坐席
if (StringUtils.isNotBlank(request.getParameter("owneruser"))) {
queryBuilder.must(termQuery("owneruser", request.getParameter("owneruser")));
map.put("owneruser", request.getParameter("owneruser"));
}
// 部门
if (StringUtils.isNotBlank(request.getParameter("ownerdept"))) {
queryBuilder.must(termQuery("ownerdept", request.getParameter("ownerdept")));
map.put("ownerdept", request.getParameter("ownerdept"));
}
// 分配状态
if (StringUtils.isNotBlank(request.getParameter("status"))) {
queryBuilder.must(termQuery("status", request.getParameter("status")));
map.put("status", request.getParameter("status"));
}
return queryBuilder;
}
/**
* 创建或从HTTP会话中查找到访客的User对象该对象不在数据库中属于临时会话
* 这个User很可能是打开一个WebIM访客聊天控件随机生成用户名之后和Contact关联
@ -332,8 +210,7 @@ public class Handler {
if (StringUtils.isNotBlank(nickname)) {
user.setUsername(nickname);
} else {
Map<String, String> sessionMessage = cache.findOneSystemMapByIdAndOrgi(
request.getSession().getId(), Constants.SYSTEM_ORGI);
Map<String, String> sessionMessage = cache.findOneSystemMapById(request.getSession().getId());
if (sessionMessage != null) {
String struname = sessionMessage.get("username");
String strcname = sessionMessage.get("company_name");
@ -362,8 +239,7 @@ public class Handler {
if (StringUtils.isNotBlank(nickname)) {
user.setUsername(nickname);
} else {
Map<String, String> sessionMessage = cache.findOneSystemMapByIdAndOrgi(
sessionid, Constants.SYSTEM_ORGI);
Map<String, String> sessionMessage = cache.findOneSystemMapById(sessionid);
if (sessionMessage != null) {
String struname = sessionMessage.get("username");
String strcname = sessionMessage.get("company_name");
@ -476,15 +352,6 @@ public class Handler {
return pagesize;
}
public String getOrgi() {
return Constants.SYSTEM_ORGI;
}
// FIXME: 保存此处是为了兼容之前到代码宜去掉
public String getOrgi(HttpServletRequest request) {
return getOrgi();
}
public long getStarttime() {
return starttime;
}
@ -511,6 +378,30 @@ public class Handler {
return fileid;
}
/**
* 使用Blob保存文件
*
* @param dataStr Data URL 图片数据
* @return id
* @throws IOException
*/
public String saveImageFileWithDataURL(String dataStr) throws IOException {
String[] cell = dataStr.split(";");
String mime = cell[0].substring(5);
String base64Str = cell[1].substring(7);
byte[] buf = Base64.decodeBase64(base64Str);
StreamingFile sf = new StreamingFile();
final String fileid = MainUtils.getUUID();
sf.setId(fileid);
sf.setMime(mime);
sf.setData(jpaBlobHelper.createBlob(new ByteArrayInputStream(buf),
buf.length));
sf.setName(fileid);
streamingFileRes.save(sf);
return fileid;
}
public String getSchema(HttpServletRequest request) {
String schema = request.getScheme();
String headerProto = request.getHeader("X-Forwarded-Proto");

View File

@ -1,18 +1,16 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.controller;
@ -20,7 +18,7 @@ import com.cskefu.cc.acd.ACDWorkMonitor;
import com.cskefu.cc.basic.Constants;
import com.cskefu.cc.basic.MainContext;
import com.cskefu.cc.basic.MainUtils;
import com.cskefu.cc.basic.auth.AuthToken;
import com.cskefu.cc.basic.auth.BearerTokenMgr;
import com.cskefu.cc.model.AgentStatus;
import com.cskefu.cc.model.Organ;
import com.cskefu.cc.model.SystemConfig;
@ -30,9 +28,10 @@ import com.cskefu.cc.persistence.repository.UserRepository;
import com.cskefu.cc.persistence.repository.UserRoleRepository;
import com.cskefu.cc.proxy.AgentProxy;
import com.cskefu.cc.proxy.AgentSessionProxy;
import com.cskefu.cc.proxy.OrganProxy;
import com.cskefu.cc.proxy.UserProxy;
import com.cskefu.cc.util.Menu;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.jasypt.exceptions.EncryptionOperationNotPossibleException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -45,10 +44,10 @@ import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
@ -69,7 +68,7 @@ public class LoginController extends Handler {
private UserRoleRepository userRoleRes;
@Autowired
private AuthToken authToken;
private BearerTokenMgr bearerTokenMgr;
@Autowired
private AgentProxy agentProxy;
@ -119,7 +118,7 @@ public class LoginController extends Handler {
@RequestMapping(value = "/login", method = RequestMethod.GET)
@Menu(type = "apps", subtype = "user", access = true)
public ModelAndView login(HttpServletRequest request, HttpServletResponse response,
@RequestHeader(value = "referer", required = false) String referer, @Valid String msg) {
@RequestHeader(value = "referer", required = false) String referer, @Valid String msg) {
ModelAndView view = new ModelAndView("redirect:/");
if (request.getSession(true).getAttribute(Constants.USER_SESSION_NAME) == null) {
view = new ModelAndView("/login");
@ -139,7 +138,7 @@ public class LoginController extends Handler {
try {
flagid = MainUtils.decryption(cookie.getValue());
if (StringUtils.isNotBlank(flagid)) {
User user = userRepository.findById(flagid);
User user = userRepository.findById(flagid).orElse(null);
if (user != null) {
view = this.processLogin(request, user, referer);
}
@ -160,9 +159,9 @@ public class LoginController extends Handler {
view.addObject("msg", msg);
}
SystemConfig systemConfig = MainUtils.getSystemConfig();
if (systemConfig != null && systemConfig.isEnableregorgi()) {
view.addObject("show", true);
}
// is Enable reg tenant
// view.addObject("show", false);
if (systemConfig != null) {
view.addObject("systemConfig", systemConfig);
}
@ -213,11 +212,11 @@ public class LoginController extends Handler {
}
// add authorization code for rest api
final String orgi = loginUser.getOrgi();
String auth = MainUtils.getUUID();
authToken.putUserByAuth(auth, loginUser);
String uuid = MainUtils.getUUID();
String token = String.format("%s %s", Constants.AUTH_TOKEN_TYPE_BEARER, uuid);
bearerTokenMgr.update(token, loginUser);
userRepository.save(loginUser); // 更新登录状态到数据库
response.addCookie((new Cookie("authorization", auth)));
response.addCookie((new Cookie("authorization", uuid)));
// 该登录用户是坐席并且具有坐席对话的角色
if ((loginUser.isAgent() &&
@ -229,8 +228,8 @@ public class LoginController extends Handler {
* 登录成功设置该坐席为就绪状态默认
****************************************/
// https://gitlab.chatopera.com/chatopera/cosinee.w4l/issues/306
final AgentStatus agentStatus = agentProxy.resolveAgentStatusByAgentnoAndOrgi(
loginUser.getId(), orgi, loginUser.getSkills());
final AgentStatus agentStatus = agentProxy.resolveAgentStatusByAgentno(
loginUser.getId(), loginUser.getSkills());
agentStatus.setBusy(false);
agentProxy.ready(loginUser, agentStatus, false);
@ -243,7 +242,7 @@ public class LoginController extends Handler {
MainContext.AgentStatusEnum.OFFLINE.toString(),
MainContext.AgentStatusEnum.READY.toString(),
MainContext.AgentWorkType.MEIDIACHAT.toString(),
orgi, null);
null);
} catch (Exception e) {
logger.error("[login] set agent status", e);
@ -262,9 +261,9 @@ public class LoginController extends Handler {
}
}
SystemConfig systemConfig = MainUtils.getSystemConfig();
if (systemConfig != null && systemConfig.isEnableregorgi()) {
view.addObject("show", true);
}
// is Enable reg tenant
// view.addObject("show", false);
if (systemConfig != null) {
view.addObject("systemConfig", systemConfig);
}
@ -287,7 +286,7 @@ public class LoginController extends Handler {
loginUser.setLogin(true);
// 更新redis session信息用以支持sso
agentSessionProxy.updateUserSession(
loginUser.getId(), MainUtils.getContextID(request.getSession().getId()), loginUser.getOrgi());
loginUser.getId(), MainUtils.getContextID(request.getSession().getId()));
loginUser.setSessionid(MainUtils.getContextID(request.getSession().getId()));
if (StringUtils.isNotBlank(referer)) {
@ -302,17 +301,19 @@ public class LoginController extends Handler {
&& !loginUser.isAdmin()) {
view = new ModelAndView("redirect:/apps/tenant/index");
}
List<UserRole> userRoleList = userRoleRes.findByOrgiAndUser(loginUser.getOrgi(), loginUser);
List<UserRole> userRoleList = userRoleRes.findByUser(loginUser);
if (userRoleList != null && userRoleList.size() > 0) {
for (UserRole userRole : userRoleList) {
loginUser.getRoleList().add(userRole.getRole());
}
}
// 获取用户部门以及下级部门
// 获取用户所在部门及附属部门的信息
userProxy.attachOrgansPropertiesForUser(loginUser);
Organ currentOrgan = super.getOrgan(request);
userProxy.attachCurrentOrgansPropertiesForUser(loginUser, currentOrgan);
// 添加角色信息
userProxy.attachRolesMap(loginUser, currentOrgan);
@ -338,7 +339,7 @@ public class LoginController extends Handler {
*/
@RequestMapping("/logout")
public String logout(HttpServletRequest request, HttpServletResponse response,
@RequestParam(value = "code", required = false) String code) throws UnsupportedEncodingException {
@RequestParam(value = "code", required = false) String code) throws UnsupportedEncodingException {
final User user = super.getUser(request);
request.getSession().removeAttribute(Constants.USER_SESSION_NAME);
request.getSession().invalidate();
@ -388,7 +389,6 @@ public class LoginController extends Handler {
if (StringUtils.isNotBlank(user.getPassword())) {
user.setPassword(MainUtils.md5(user.getPassword()));
}
user.setOrgi(super.getOrgi());
userRepository.save(user);
}
ModelAndView view = this.processLogin(request, user, "");
@ -414,4 +414,4 @@ public class LoginController extends Handler {
}
return msg;
}
}
}

View File

@ -1,18 +1,16 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.controller.admin;
@ -23,20 +21,20 @@ import com.cskefu.cc.basic.MainUtils;
import com.cskefu.cc.cache.Cache;
import com.cskefu.cc.controller.Handler;
import com.cskefu.cc.model.User;
import com.cskefu.cc.persistence.repository.OnlineUserRepository;
import com.cskefu.cc.persistence.repository.PassportWebIMUserRepository;
import com.cskefu.cc.persistence.repository.UserEventRepository;
import com.cskefu.cc.persistence.repository.UserRepository;
import com.cskefu.cc.proxy.OnlineUserProxy;
import com.cskefu.cc.socketio.client.NettyClients;
import com.cskefu.cc.util.Menu;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
@ -50,7 +48,7 @@ public class AdminController extends Handler {
private UserRepository userRes;
@Autowired
private OnlineUserRepository onlineUserRes;
private PassportWebIMUserRepository onlineUserRes;
@Autowired
private UserEventRepository userEventRes;
@ -62,46 +60,45 @@ public class AdminController extends Handler {
public ModelAndView index(ModelMap map, HttpServletRequest request) {
ModelAndView view = request(super.createView("redirect:/"));
User user = super.getUser(request);
view.addObject("agentStatusReport", acdWorkMonitor.getAgentReport(user.getOrgi()));
view.addObject("agentStatus", cache.findOneAgentStatusByAgentnoAndOrig(user.getId(), user.getOrgi()));
view.addObject("agentStatusReport", acdWorkMonitor.getAgentReport());
view.addObject("agentStatus", cache.findOneAgentStatusByAgentno(user.getId()));
return view;
}
private void aggValues(ModelMap map, HttpServletRequest request) {
String orgi = super.getOrgi(request);
map.put("onlineUserCache", cache.getOnlineUserSizeByOrgi(orgi));
map.put("onlineUserCache", cache.getOnlineUserSize());
map.put("onlineUserClients", OnlineUserProxy.webIMClients.size());
map.put("chatClients", NettyClients.getInstance().size());
map.put("systemCaches", cache.getSystemSizeByOrgi(Constants.SYSTEM_ORGI));
map.put("systemCaches", cache.getSystemSize());
map.put("agentReport", acdWorkMonitor.getAgentReport(orgi));
map.put("webIMReport", MainUtils.getWebIMReport(userEventRes.findByOrgiAndCreatetimeRange(super.getOrgi(request), MainUtils.getStartTime(), MainUtils.getEndTime())));
map.put("agentReport", acdWorkMonitor.getAgentReport());
map.put("webIMReport", MainUtils.getWebIMReport(userEventRes.findByCreatetimeRange(MainUtils.getStartTime(), MainUtils.getEndTime())));
map.put("agents", getAgent(request).size());
map.put("webIMInvite", MainUtils.getWebIMInviteStatus(onlineUserRes.findByOrgiAndStatus(super.getOrgi(request), MainContext.OnlineUserStatusEnum.ONLINE.toString())));
map.put("webIMInvite", MainUtils.getWebIMInviteStatus(onlineUserRes.findByStatus(MainContext.OnlineUserStatusEnum.ONLINE.toString())));
map.put("inviteResult", MainUtils.getWebIMInviteResult(onlineUserRes.findByOrgiAndAgentnoAndCreatetimeRange(super.getOrgi(request), super.getUser(request).getId(), MainUtils.getStartTime(), MainUtils.getEndTime())));
map.put("inviteResult", MainUtils.getWebIMInviteResult(onlineUserRes.findByAgentnoAndCreatetimeRange(super.getUser(request).getId(), MainUtils.getStartTime(), MainUtils.getEndTime())));
map.put("agentUserCount", onlineUserRes.countByAgentForAgentUser(super.getOrgi(request), MainContext.AgentUserStatusEnum.INSERVICE.toString(), super.getUser(request).getId(), MainUtils.getStartTime(), MainUtils.getEndTime()));
map.put("agentUserCount", onlineUserRes.countByAgentForAgentUser(MainContext.AgentUserStatusEnum.INSERVICE.toString(), super.getUser(request).getId(), MainUtils.getStartTime(), MainUtils.getEndTime()));
map.put("agentServicesCount", onlineUserRes.countByAgentForAgentUser(super.getOrgi(request), MainContext.AgentUserStatusEnum.END.toString(), super.getUser(request).getId(), MainUtils.getStartTime(), MainUtils.getEndTime()));
map.put("agentServicesCount", onlineUserRes.countByAgentForAgentUser(MainContext.AgentUserStatusEnum.END.toString(), super.getUser(request).getId(), MainUtils.getStartTime(), MainUtils.getEndTime()));
map.put("agentServicesAvg", onlineUserRes.countByAgentForAvagTime(super.getOrgi(request), MainContext.AgentUserStatusEnum.END.toString(), super.getUser(request).getId(), MainUtils.getStartTime(), MainUtils.getEndTime()));
map.put("agentServicesAvg", onlineUserRes.countByAgentForAvagTime(MainContext.AgentUserStatusEnum.END.toString(), super.getUser(request).getId(), MainUtils.getStartTime(), MainUtils.getEndTime()));
map.put("webInviteReport", MainUtils.getWebIMInviteAgg(onlineUserRes.findByOrgiAndCreatetimeRange(super.getOrgi(request), MainContext.ChannelType.WEBIM.toString(), MainUtils.getLast30Day(), MainUtils.getEndTime())));
map.put("webInviteReport", MainUtils.getWebIMInviteAgg(onlineUserRes.findByCreatetimeRange(MainContext.ChannelType.WEBIM.toString(), MainUtils.getLast30Day(), MainUtils.getEndTime())));
map.put("agentConsultReport", MainUtils.getWebIMDataAgg(onlineUserRes.findByOrgiAndCreatetimeRangeForAgent(super.getOrgi(request), MainUtils.getLast30Day(), MainUtils.getEndTime())));
map.put("agentConsultReport", MainUtils.getWebIMDataAgg(onlineUserRes.findByCreatetimeRangeForAgent(MainUtils.getLast30Day(), MainUtils.getEndTime())));
map.put("clentConsultReport", MainUtils.getWebIMDataAgg(onlineUserRes.findByOrgiAndCreatetimeRangeForClient(super.getOrgi(request), MainUtils.getLast30Day(), MainUtils.getEndTime(), MainContext.ChannelType.WEBIM.toString())));
map.put("clentConsultReport", MainUtils.getWebIMDataAgg(onlineUserRes.findByCreatetimeRangeForClient(MainUtils.getLast30Day(), MainUtils.getEndTime(), MainContext.ChannelType.WEBIM.toString())));
map.put("browserConsultReport", MainUtils.getWebIMDataAgg(onlineUserRes.findByOrgiAndCreatetimeRangeForBrowser(super.getOrgi(request), MainUtils.getLast30Day(), MainUtils.getEndTime(), MainContext.ChannelType.WEBIM.toString())));
map.put("browserConsultReport", MainUtils.getWebIMDataAgg(onlineUserRes.findByCreatetimeRangeForBrowser(MainUtils.getLast30Day(), MainUtils.getEndTime(), MainContext.ChannelType.WEBIM.toString())));
}
private List<User> getAgent(HttpServletRequest request) {
//获取当前产品or租户坐席数
List<User> userList = userRes.findByOrgiAndAgentAndDatastatus(super.getOrgi(request), true, false);
return userList.isEmpty() ? new ArrayList<User>() : userList;
List<User> userList = userRes.findByAgentAndDatastatus(true, false);
return userList.isEmpty() ? new ArrayList<>() : userList;
}
@RequestMapping("/admin/content")
@ -118,7 +115,7 @@ public class AdminController extends Handler {
}
@RequestMapping("/admin/auth/infoacq")
@Menu(type = "admin", subtype = "infoacq", access = false, admin = true)
@Menu(type = "admin", subtype = "infoacq", admin = true)
public ModelAndView infoacq(ModelMap map, HttpServletRequest request) {
String inacq = (String) request.getSession().getAttribute(Constants.CSKEFU_SYSTEM_INFOACQ);
if (StringUtils.isNotBlank(inacq)) {

View File

@ -1,18 +1,16 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.controller.admin;
@ -25,7 +23,7 @@ import com.cskefu.cc.proxy.OrganProxy;
import com.cskefu.cc.proxy.UserProxy;
import com.cskefu.cc.util.Menu;
import com.cskefu.cc.util.json.GsonTools;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -34,8 +32,8 @@ import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import java.util.*;
/**
@ -81,14 +79,14 @@ public class OrganController extends Handler {
private Collection<Organ> getOwnOragans(HttpServletRequest request) {
Organ currentOrgan = super.getOrgan(request);
return organProxy.findAllOrganByParentAndOrgi(currentOrgan, super.getOrgi()).values();
return organProxy.findAllOrganByParent(currentOrgan).values();
}
@RequestMapping("/index")
@Menu(type = "admin", subtype = "organ")
public ModelAndView index(ModelMap map, HttpServletRequest request, @Valid String organ, @Valid String msg) {
Organ currentOrgan = super.getOrgan(request);
List<Organ> organList = organRepository.findByOrgi(super.getOrgi());
List<Organ> organList = organRepository.findAll();
map.addAttribute("organList", getOwnOragans(request));
if (organList.size() > 0) {
Organ organData = null;
@ -104,22 +102,19 @@ public class OrganController extends Handler {
}
if (organData != null) {
map.addAttribute(
"userList", userProxy.findByOrganAndOrgiAndDatastatus(
"userList", userProxy.findByOrganAndDatastatus(
organData.getId(),
super.getOrgi(),
false));
// 处理附属组织
final Map<String, Organ> affiliates = organProxy.findAllOrganByParentAndOrgi(organData,
super.getOrgi());
final Map<String, Organ> affiliates = organProxy.findAllOrganByParent(organData);
List<User> affiliateUsers = new ArrayList<>();
for (final Map.Entry<String, Organ> o : affiliates.entrySet()) {
if (StringUtils.equals(o.getKey(), organData.getId()))
continue;
List<User> ousers = userProxy.findByOrganAndOrgiAndDatastatus(
List<User> ousers = userProxy.findByOrganAndDatastatus(
o.getKey(),
super.getOrgi(),
false);
if (ousers != null && ousers.size() > 0) {
for (User u : ousers) {
@ -135,8 +130,8 @@ public class OrganController extends Handler {
}
}
map.addAttribute("currentOrgan", currentOrgan);
map.addAttribute("areaList", areaRepository.findByOrgi(super.getOrgi()));
map.addAttribute("roleList", roleRepository.findByOrgi(super.getOrgi()));
map.addAttribute("areaList", areaRepository.findAll());
map.addAttribute("roleList", roleRepository.findAll());
map.put("msg", msg);
return request(super.createView("/admin/organ/index"));
}
@ -144,12 +139,12 @@ public class OrganController extends Handler {
@RequestMapping("/add")
@Menu(type = "admin", subtype = "organ")
public ModelAndView add(ModelMap map, HttpServletRequest request, @Valid String parent, @Valid String area) {
map.addAttribute("areaList", areaRepository.findByOrgi(super.getOrgi()));
map.addAttribute("areaList", areaRepository.findAll());
if (!StringUtils.isBlank(parent)) {
map.addAttribute("organ", organRepository.findByIdAndOrgi(parent, super.getOrgi()));
map.addAttribute("organ", organRepository.findById(parent).orElse(null));
}
if (!StringUtils.isBlank(area)) {
map.addAttribute("area", areaRepository.findByIdAndOrgi(area, super.getOrgi()));
map.addAttribute("area", areaRepository.findById(area).orElse(null));
}
map.addAttribute("organList", getOwnOragans(request));
@ -160,13 +155,12 @@ public class OrganController extends Handler {
@RequestMapping("/save")
@Menu(type = "admin", subtype = "organ")
public ModelAndView save(HttpServletRequest request, @Valid Organ organ) {
Organ tempOrgan = organRepository.findByNameAndOrgi(organ.getName(), super.getOrgi(request));
Organ tempOrgan = organRepository.findByName(organ.getName());
String msg = "admin_organ_new_success";
String firstId = null;
if (tempOrgan != null) {
msg = "admin_organ_update_name_not"; // 分类名字重复
} else {
organ.setOrgi(super.getOrgi());
firstId = organ.getId();
organRepository.save(organ);
@ -186,12 +180,11 @@ public class OrganController extends Handler {
@RequestMapping("/seluser")
@Menu(type = "admin", subtype = "seluser", admin = true)
public ModelAndView seluser(ModelMap map, HttpServletRequest request, @Valid String organ) {
Map<String, Organ> organs = organProxy.findAllOrganByParentAndOrgi(super.getOrgan(request),
super.getOrgi(request));
Map<String, Organ> organs = organProxy.findAllOrganByParent(super.getOrgan(request));
map.addAttribute("userList", userProxy.findUserInOrgans(organs.keySet()));
Organ organData = organRepository.findByIdAndOrgi(organ, super.getOrgi());
Organ organData = organRepository.findById(organ).orElse(null);
map.addAttribute("userOrganList", userProxy
.findByOrganAndOrgiAndDatastatus(organ, super.getOrgi(), false));
.findByOrganAndDatastatus(organ, false));
map.addAttribute("organ", organData);
return request(super.createView("/admin/organ/seluser"));
}
@ -214,9 +207,9 @@ public class OrganController extends Handler {
final User loginUser = super.getUser(request);
if (users != null && users.length > 0) {
List<String> chosen = new ArrayList<String>(Arrays.asList(users));
Organ organData = organRepository.findByIdAndOrgi(organ, super.getOrgi());
List<User> organUserList = userRepository.findAll(chosen);
List<String> chosen = new ArrayList<>(Arrays.asList(users));
Organ organData = organRepository.findById(organ).orElse(null);
List<User> organUserList = userRepository.findAllById(chosen);
for (final User user : organUserList) {
OrganUser ou = organUserRes.findByUseridAndOrgan(user.getId(), organ);
@ -248,19 +241,18 @@ public class OrganController extends Handler {
/**
* 以下更新技能组状态
*/
AgentStatus agentStatus = cache.findOneAgentStatusByAgentnoAndOrig(
user.getId(), super.getOrgi());
AgentStatus agentStatus = cache.findOneAgentStatusByAgentno(user.getId());
// TODO 因为一个用户可以包含在多个技能组中所以skill应该对应
// 一个List列表此处需要重构Skill为列表
if (agentStatus != null) {
userProxy.attachOrgansPropertiesForUser(user);
agentStatus.setSkills(user.getSkills());
cache.putAgentStatusByOrgi(agentStatus, super.getOrgi());
cache.putAgentStatus(agentStatus);
}
}
}
userRepository.save(organUserList);
userRepository.saveAll(organUserList);
}
return request(super.createView("redirect:/admin/organ/index.html?organ=" + organ));
@ -290,8 +282,8 @@ public class OrganController extends Handler {
public ModelAndView edit(ModelMap map, HttpServletRequest request, @Valid String id) {
ModelAndView view = request(super.createView("/admin/organ/edit"));
Organ currentOrgan = super.getOrgan(request);
map.addAttribute("areaList", areaRepository.findByOrgi(super.getOrgi()));
view.addObject("organData", organRepository.findByIdAndOrgi(id, super.getOrgi()));
map.addAttribute("areaList", areaRepository.findAll());
view.addObject("organData", organRepository.findById(id).orElse(null));
view.addObject("isRootOrgan", id.equals(currentOrgan.getId()));
map.addAttribute("organList", getOwnOragans(request));
return view;
@ -300,7 +292,7 @@ public class OrganController extends Handler {
@RequestMapping("/update")
@Menu(type = "admin", subtype = "organ")
public ModelAndView update(HttpServletRequest request, @Valid Organ organ) {
String msg = organProxy.updateOrgan(organ, super.getOrgi(request), super.getUser(request));
String msg = organProxy.updateOrgan(organ, super.getUser(request));
return request(super.createView(
"redirect:/admin/organ/index.html?msg=" + msg + "&organ=" + organ.getId()));
}
@ -316,14 +308,14 @@ public class OrganController extends Handler {
}
map.addAttribute("cacheList", Dict.getInstance().getDic(Constants.CSKEFU_SYSTEM_AREA_DIC));
map.addAttribute("organData", organRepository.findByIdAndOrgi(id, super.getOrgi()));
map.addAttribute("organData", organRepository.findById(id).orElse(null));
return request(super.createView("/admin/organ/area"));
}
@RequestMapping("/area/update")
@Menu(type = "admin", subtype = "organ")
public ModelAndView areaupdate(HttpServletRequest request, @Valid Organ organ) {
Organ tempOrgan = organRepository.findByIdAndOrgi(organ.getId(), super.getOrgi());
Organ tempOrgan = organRepository.findById(organ.getId()).orElse(null);
String msg = "admin_organ_update_success";
if (tempOrgan != null) {
tempOrgan.setArea(organ.getArea());
@ -340,8 +332,8 @@ public class OrganController extends Handler {
public ModelAndView delete(HttpServletRequest request, @Valid Organ organ) {
String msg = "admin_organ_delete";
Organ organSelf = organRepository.findByIdAndOrgi(organ.getId(), super.getOrgi());
List<Organ> organParentAre = organRepository.findByOrgiAndParent(organSelf.getOrgi(), organSelf.getId());
Organ organSelf = organRepository.findById(organ.getId()).orElse(null);
List<Organ> organParentAre = organRepository.findByParent(organSelf.getId());
if (organ != null && organParentAre != null && organParentAre.size() > 0) {
msg = "admin_oran_not_delete";
} else if (organ != null) {
@ -359,9 +351,9 @@ public class OrganController extends Handler {
@RequestMapping("/auth/save")
@Menu(type = "admin", subtype = "role")
public ModelAndView authsave(HttpServletRequest request, @Valid String id, @Valid String menus) {
Organ organData = organRepository.findByIdAndOrgi(id, super.getOrgi());
List<OrganRole> organRoleList = organRoleRes.findByOrgiAndOrgan(super.getOrgi(), organData);
organRoleRes.delete(organRoleList);
Organ organData = organRepository.findById(id).orElse(null);
List<OrganRole> organRoleList = organRoleRes.findByOrgan(organData);
organRoleRes.deleteAll(organRoleList);
if (!StringUtils.isBlank(menus)) {
String[] menusarray = menus.split(",");
for (String menu : menusarray) {
@ -373,7 +365,6 @@ public class OrganController extends Handler {
organRole.setOrgan(organData);
organRole.setCreater(super.getUser(request).getId());
organRole.setOrgi(super.getOrgi(request));
organRole.setCreatetime(new Date());
organRoleRes.save(organRole);
}

View File

@ -1,18 +1,16 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.controller.admin;
@ -27,7 +25,7 @@ import com.cskefu.cc.proxy.OrganProxy;
import com.cskefu.cc.proxy.UserProxy;
import com.cskefu.cc.util.Menu;
import com.cskefu.cc.util.json.GsonTools;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -38,8 +36,8 @@ import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
@ -74,7 +72,7 @@ public class RoleController extends Handler {
public ModelAndView index(ModelMap map, HttpServletRequest request, @Valid String role, @Valid String msg) {
Organ currentOrgan = super.getOrgan(request);
List<Role> roleList = roleRepository.findByOrgi(super.getOrgi());
List<Role> roleList = roleRepository.findAll();
map.addAttribute("roleList", roleList);
map.addAttribute("msg", msg);
map.addAttribute("currentOrgan", currentOrgan);
@ -91,16 +89,15 @@ public class RoleController extends Handler {
map.addAttribute("roleData", roleData = roleList.get(0));
}
if (roleData != null) {
Map<String, Organ> organs = organProxy.findAllOrganByParentAndOrgi(currentOrgan,
super.getOrgi(request));
Map<String, Organ> organs = organProxy.findAllOrganByParent(currentOrgan);
// List<String> userIds = userProxy.findUserIdsInOrgans(organs.keySet());
// Page<UserRole> userRoleList =
// userRoleRes.findByOrganAndRole(currentOrgan.getId(), roleData,
// new PageRequest(super.getP(request), super.getPs(request)));
// PageRequest.of(super.getP(request), super.getPs(request)));
Page<UserRole> userRoleList = userRoleRes.findByOrganInAndRole(organs.keySet(), roleData,
new PageRequest(super.getP(request), super.getPs(request)));
PageRequest.of(super.getP(request), super.getPs(request)));
if (userRoleList.getContent().size() > 0) {
for (UserRole ur : userRoleList.getContent()) {
@ -130,12 +127,11 @@ public class RoleController extends Handler {
@Menu(type = "admin", subtype = "role")
public ModelAndView save(HttpServletRequest request, @Valid Role role) {
Organ currentOrgan = super.getOrgan(request);
Role tempRole = roleRepository.findByNameAndOrgi(role.getName(), super.getOrgi());
Role tempRole = roleRepository.findByName(role.getName());
String msg = "admin_role_save_success";
if (tempRole != null) {
msg = "admin_role_save_exist";
} else {
role.setOrgi(super.getOrgi());
role.setCreater(super.getUser(request).getId());
role.setCreatetime(new Date());
role.setUpdatetime(new Date());
@ -150,8 +146,8 @@ public class RoleController extends Handler {
public ModelAndView seluser(ModelMap map, HttpServletRequest request, @Valid String role) {
Organ currentOrgan = super.getOrgan(request);
map.addAttribute("userList", userProxy.findUserInOrgans(Arrays.asList(currentOrgan.getId())));
Role roleData = roleRepository.findByIdAndOrgi(role, super.getOrgi());
map.addAttribute("userRoleList", userRoleRes.findByOrgiAndRole(super.getOrgi(), roleData));
Role roleData = roleRepository.findById(role).orElse(null);
map.addAttribute("userRoleList", userRoleRes.findByRole(roleData));
map.addAttribute("role", roleData);
return request(super.createView("/admin/role/seluser"));
}
@ -160,8 +156,8 @@ public class RoleController extends Handler {
@Menu(type = "admin", subtype = "saveuser", admin = true)
public ModelAndView saveuser(HttpServletRequest request, @Valid String[] users, @Valid String role) {
Organ currentOrgan = super.getOrgan(request);
Role roleData = roleRepository.findByIdAndOrgi(role, super.getOrgi());
List<UserRole> userRoleList = userRoleRes.findByOrganAndRole(super.getOrgi(), roleData);
Role roleData = roleRepository.findById(role).orElse(null);
List<UserRole> userRoleList = userRoleRes.findByRole(roleData);
if (users != null && users.length > 0) {
for (String user : users) {
boolean exist = false;
@ -175,7 +171,6 @@ public class RoleController extends Handler {
UserRole userRole = new UserRole();
userRole.setUser(new User(user));
userRole.setRole(new Role(role));
userRole.setOrgi(super.getOrgi());
userRole.setCreater(super.getUser(request).getId());
userRole.setOrgan(currentOrgan.getId());
userRoleRes.save(userRole);
@ -189,7 +184,7 @@ public class RoleController extends Handler {
@Menu(type = "admin", subtype = "role")
public ModelAndView userroledelete(HttpServletRequest request, @Valid String id, @Valid String role) {
if (role != null) {
userRoleRes.delete(id);
userRoleRes.deleteById(id);
}
return request(super.createView("redirect:/admin/role/index.html?role=" + role));
}
@ -198,18 +193,18 @@ public class RoleController extends Handler {
@Menu(type = "admin", subtype = "role")
public ModelAndView edit(ModelMap map, HttpServletRequest request, @Valid String id) {
ModelAndView view = request(super.createView("/admin/role/edit"));
view.addObject("roleData", roleRepository.findByIdAndOrgi(id, super.getOrgi()));
view.addObject("roleData", roleRepository.findById(id).orElse(null));
return view;
}
@RequestMapping("/update")
@Menu(type = "admin", subtype = "role")
public ModelAndView update(HttpServletRequest request, @Valid Role role) {
Role tempRoleExist = roleRepository.findByNameAndOrgi(role.getName(), super.getOrgi());
Role tempRoleExist = roleRepository.findByName(role.getName());
String msg = "";
if (tempRoleExist == null) {
msg = "admin_role_update_success";
Role tempRole = roleRepository.findByIdAndOrgi(role.getId(), super.getOrgi());
Role tempRole = roleRepository.findById(role.getId()).orElse(null);
tempRole.setName(role.getName());
tempRole.setUpdatetime(new Date());
roleRepository.save(tempRole);
@ -224,7 +219,7 @@ public class RoleController extends Handler {
public ModelAndView delete(HttpServletRequest request, @Valid Role role) {
String msg = "admin_role_delete";
if (role != null) {
userRoleRes.delete(userRoleRes.findByOrgiAndRole(super.getOrgi(), role));
userRoleRes.deleteAll(userRoleRes.findByRole(role));
roleRepository.delete(role);
} else {
msg = "admin_role_not_exist";
@ -241,9 +236,9 @@ public class RoleController extends Handler {
map.addAttribute("resourceList", sysDicRes.findByDicid(sysDic.getId()));
}
map.addAttribute("sysDic", sysDic);
Role role = roleRepository.findByIdAndOrgi(id, super.getOrgi());
Role role = roleRepository.findById(id).orElse(null);
map.addAttribute("role", role);
map.addAttribute("roleAuthList", roleAuthRes.findByRoleidAndOrgi(role.getId(), super.getOrgi()));
map.addAttribute("roleAuthList", roleAuthRes.findByRoleid(role.getId()));
return request(super.createView("/admin/role/auth"));
}
@ -252,8 +247,8 @@ public class RoleController extends Handler {
public ModelAndView authsave(HttpServletRequest request, @Valid String id, @Valid String menus) {
// logger.info("[authsave] id {}, menus {}", id, menus);
List<RoleAuth> roleAuthList = roleAuthRes.findByRoleidAndOrgi(id, super.getOrgi());
roleAuthRes.delete(roleAuthList);
List<RoleAuth> roleAuthList = roleAuthRes.findByRoleid(id);
roleAuthRes.deleteAll(roleAuthList);
if (StringUtils.isNotBlank(menus)) {
String[] menuarray = menus.split(",");
@ -270,7 +265,6 @@ public class RoleController extends Handler {
logger.debug("[authsave] get sysdict {}, code {}, name {}, parent {}", sysDic.getId(),
sysDic.getCode(), sysDic.getName(), sysDic.getParentid());
roleAuth.setCreater(super.getUser(request).getId());
roleAuth.setOrgi(super.getOrgi());
roleAuth.setCreatetime(new Date());
roleAuth.setName(sysDic.getName());
roleAuth.setDicvalue(sysDic.getCode());

View File

@ -1,18 +1,16 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.controller.admin;
@ -21,17 +19,13 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import com.cskefu.cc.basic.Constants;
import com.cskefu.cc.basic.MainContext;
import com.cskefu.cc.controller.Handler;
import com.cskefu.cc.model.Organ;
import com.cskefu.cc.model.OrganUser;
import com.cskefu.cc.model.Role;
import com.cskefu.cc.model.User;
import com.cskefu.cc.model.UserRole;
import com.cskefu.cc.model.*;
import com.cskefu.cc.persistence.repository.ExtensionRepository;
import com.cskefu.cc.persistence.repository.OrganUserRepository;
import com.cskefu.cc.persistence.repository.PbxHostRepository;
@ -89,7 +83,7 @@ public class UsersController extends Handler {
/**
* 只返回根用户只属于该部门的非下级部门的用户
*
*
* @param map
* @param request
* @return
@ -103,7 +97,7 @@ public class UsersController extends Handler {
organs.add(currentOrgan.getId());
map.addAttribute("currentOrgan", currentOrgan);
map.addAttribute("userList", userProxy.findUserInOrgans(organs, new PageRequest(
map.addAttribute("userList", userProxy.findUserInOrgans(organs, PageRequest.of(
super.getP(request),
super.getPs(request),
Sort.Direction.ASC,
@ -117,8 +111,8 @@ public class UsersController extends Handler {
public ModelAndView add(ModelMap map, HttpServletRequest request) {
ModelAndView view = request(super.createView("/admin/user/add"));
Organ currentOrgan = super.getOrgan(request);
Map<String, Organ> organs = organProxy.findAllOrganByParentAndOrgi(currentOrgan, super.getOrgi(request));
List<Role> sysRoles = roleRes.findByOrgi(super.getOrgi(request));
Map<String, Organ> organs = organProxy.findAllOrganByParent(currentOrgan);
List<Role> sysRoles = roleRes.findAll();
map.addAttribute("currentOrgan", currentOrgan);
map.addAttribute("organList", organs.values());
map.addAttribute("sysRoles", sysRoles);
@ -130,17 +124,16 @@ public class UsersController extends Handler {
@Menu(type = "admin", subtype = "user")
public ModelAndView edit(ModelMap map, HttpServletRequest request, @Valid String id) {
ModelAndView view = request(super.createView("/admin/user/edit"));
User user = userRepository.findById(id);
User user = userRepository.findById(id).orElse(null);
if (user != null && MainContext.hasModule(Constants.CSKEFU_MODULE_CALLCENTER)) {
// 加载呼叫中心信息
extensionRes.findByAgentnoAndOrgi(user.getId(), user.getOrgi()).ifPresent(p -> {
extensionRes.findByAgentno(user.getId()).ifPresent(p -> {
user.setExtensionId(p.getId());
user.setExtension(p);
pbxHostRes.findById(p.getHostid()).ifPresent(b -> {
user.setPbxhostId(b.getId());
user.setPbxHost(b);
});
PbxHost one = pbxHostRes.findById(p.getHostid()).orElse(null);
user.setPbxhostId(one.getId());
user.setPbxHost(one);
});
}
view.addObject("userData", user);
@ -152,21 +145,21 @@ public class UsersController extends Handler {
public ModelAndView delete(HttpServletRequest request, @Valid User user) {
String msg = "admin_user_delete";
if (user != null) {
User dbUser = userRepository.getOne(user.getId());
User dbUser = userRepository.findById(user.getId()).orElse(null);
if (dbUser.isSuperadmin()) {
msg = "admin_user_abandoned";
} else {
// 删除用户的时候同时删除用户对应的权限数据
List<UserRole> userRole = userRoleRes.findByOrgiAndUser(super.getOrgi(), user);
userRoleRes.delete(userRole);
List<UserRole> userRole = userRoleRes.findByUser(user);
userRoleRes.deleteAll(userRole);
// 删除用户对应的组织机构关系
List<OrganUser> organUsers = organUserRes.findByUserid(user.getId());
organUserRes.delete(organUsers);
organUserRes.deleteAll(organUsers);
userRepository.delete(dbUser);
AgentSessionProxy agentSessionProxy = MainContext.getContext().getBean(AgentSessionProxy.class);
agentSessionProxy.deleteUserSession(dbUser.getId(), dbUser.getOrgi());
agentSessionProxy.deleteUserSession(dbUser.getId());
}
} else {
msg = "admin_user_not_exist";

View File

@ -1,205 +1,200 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cskefu.cc.controller.admin.channel;
import com.cskefu.cc.basic.MainContext;
import com.cskefu.cc.basic.MainUtils;
import com.cskefu.cc.cache.Cache;
import com.cskefu.cc.controller.Handler;
import com.cskefu.cc.model.*;
import com.cskefu.cc.persistence.repository.ConsultInviteRepository;
import com.cskefu.cc.persistence.repository.OrganRepository;
import com.cskefu.cc.persistence.repository.SNSAccountRepository;
import com.cskefu.cc.persistence.repository.SecretRepository;
import com.cskefu.cc.proxy.OrganProxy;
import com.cskefu.cc.util.Base62;
import com.cskefu.cc.util.Menu;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
*
*/
@Controller
@RequestMapping("/admin/im")
public class SNSAccountIMController extends Handler {
@Autowired
private SNSAccountRepository snsAccountRes;
@Autowired
private ConsultInviteRepository invite;
@Autowired
private SecretRepository secRes;
@Autowired
private OrganProxy organProxy;
@Autowired
private OrganRepository organRes;
@Autowired
private Cache cache;
@RequestMapping("/index")
@Menu(type = "admin", subtype = "im", access = false, admin = true)
public ModelAndView index(ModelMap map, HttpServletRequest request, @Valid String execute, @RequestParam(name = "status", required = false) String status) {
Map<String, Organ> organs = organProxy.findAllOrganByParentAndOrgi(super.getOrgan(request), super.getOrgi(request));
map.addAttribute("snsAccountList", snsAccountRes.findBySnstypeAndOrgiAndOrgan(MainContext.ChannelType.WEBIM.toString(), super.getOrgi(request), organs.keySet(), new PageRequest(super.getP(request), super.getPs(request))));
map.addAttribute("status", status);
List<Secret> secretConfig = secRes.findByOrgi(super.getOrgi(request));
if (secretConfig != null && secretConfig.size() > 0) {
map.addAttribute("secret", secretConfig.get(0));
}
if (StringUtils.isNotBlank(execute) && execute.equals("false")) {
map.addAttribute("execute", execute);
}
return request(super.createView("/admin/channel/im/index"));
}
@RequestMapping("/add")
@Menu(type = "admin", subtype = "send", access = false, admin = true)
public ModelAndView add(ModelMap map, HttpServletRequest request) {
Organ currentOrgan = super.getOrgan(request);
map.put("organ", currentOrgan);
return request(super.createView("/admin/channel/im/add"));
}
@RequestMapping("/save")
@Menu(type = "admin", subtype = "weixin")
public ModelAndView save(HttpServletRequest request,
@Valid SNSAccount snsAccount) throws NoSuchAlgorithmException {
Organ currentOrgan = super.getOrgan(request);
String status = "new_webim_fail";
if (StringUtils.isNotBlank(snsAccount.getBaseURL())) {
snsAccount.setSnsid(Base62.encode(snsAccount.getBaseURL()).toLowerCase());
int count = snsAccountRes.countBySnsidAndOrgi(snsAccount.getSnsid(), super.getOrgi(request));
if (count == 0) {
status = "new_webim_success";
snsAccount.setOrgi(super.getOrgi(request));
snsAccount.setSnstype(MainContext.ChannelType.WEBIM.toString());
snsAccount.setCreatetime(new Date());
User curr = super.getUser(request);
snsAccount.setCreater(curr.getId());
snsAccount.setOrgan(currentOrgan.getId());
snsAccountRes.save(snsAccount);
/**
* 同时创建CousultInvite 记录
*/
CousultInvite coultInvite = invite.findBySnsaccountidAndOrgi(snsAccount.getSnsid(), super.getOrgi(request));
if (coultInvite == null) {
coultInvite = new CousultInvite();
coultInvite.setSnsaccountid(snsAccount.getSnsid());
coultInvite.setCreate_time(new Date());
coultInvite.setOrgi(super.getOrgi(request));
coultInvite.setName(snsAccount.getName());
coultInvite.setOwner(snsAccount.getCreater());
coultInvite.setSkill(false); // 不启动技能组
coultInvite.setConsult_skill_fixed(false); // 不绑定唯一技能组
coultInvite.setAi(false);
coultInvite.setAifirst(false);
invite.save(coultInvite);
}
}
}
return request(super.createView("redirect:/admin/im/index.html?status=" + status));
}
@RequestMapping("/delete")
@Menu(type = "weixin", subtype = "delete")
public ModelAndView delete(ModelMap map, HttpServletRequest request, @Valid String id, @Valid String confirm) {
boolean execute;
if (execute = MainUtils.secConfirm(secRes, super.getOrgi(request), confirm)) {
SNSAccount snsAccount = snsAccountRes.findByIdAndOrgi(id, super.getOrgi(request));
if (snsAccountRes != null) {
// 删除网站渠道记录
snsAccountRes.delete(snsAccount);
/**
* 删除网站渠道客服配置
*/
CousultInvite coultInvite = invite.findBySnsaccountidAndOrgi(snsAccount.getSnsid(), super.getOrgi(request));
if (coultInvite != null) {
invite.delete(coultInvite);
}
// 删除缓存
cache.deleteConsultInviteBySnsidAndOrgi(snsAccount.getSnsid(), super.getOrgi(request));
}
}
return request(super.createView("redirect:/admin/im/index.html?execute=" + execute));
}
@RequestMapping("/edit")
@Menu(type = "admin", subtype = "send", access = false, admin = true)
public ModelAndView edit(ModelMap map, HttpServletRequest request, @Valid String id) {
SNSAccount snsAccount = snsAccountRes.findByIdAndOrgi(id, super.getOrgi(request));
Organ organ = organRes.findOne(snsAccount.getOrgan());
map.put("organ", organ);
map.addAttribute("snsAccount", snsAccount);
return request(super.createView("/admin/channel/im/edit"));
}
@RequestMapping("/update")
@Menu(type = "admin", subtype = "send", access = false, admin = true)
public ModelAndView update(HttpServletRequest request, @Valid SNSAccount snsAccount) throws NoSuchAlgorithmException {
SNSAccount oldSnsAccount = snsAccountRes.findByIdAndOrgi(snsAccount.getId(), super.getOrgi(request));
if (oldSnsAccount != null) {
oldSnsAccount.setName(snsAccount.getName());
oldSnsAccount.setBaseURL(snsAccount.getBaseURL());
oldSnsAccount.setUpdatetime(new Date());
/**
* SNSID如果有变更需要同时变更 CoultInvite 表的 记录
*/
if (StringUtils.isNotBlank(oldSnsAccount.getSnsid())) {
CousultInvite coultInvite = invite.findBySnsaccountidAndOrgi(oldSnsAccount.getSnsid(), super.getOrgi(request));
if (coultInvite == null) {
/**
* 同时创建CousultInvite 记录
*/
coultInvite = new CousultInvite();
coultInvite.setSnsaccountid(oldSnsAccount.getSnsid());
coultInvite.setCreate_time(new Date());
coultInvite.setOrgi(super.getOrgi(request));
coultInvite.setName(snsAccount.getName());
invite.save(coultInvite);
}
}
oldSnsAccount.setSnstype(MainContext.ChannelType.WEBIM.toString());
snsAccountRes.save(oldSnsAccount);
}
return request(super.createView("redirect:/admin/im/index.html"));
}
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.controller.admin.channel;
import com.cskefu.cc.basic.MainContext;
import com.cskefu.cc.basic.MainUtils;
import com.cskefu.cc.cache.Cache;
import com.cskefu.cc.controller.Handler;
import com.cskefu.cc.model.*;
import com.cskefu.cc.persistence.repository.ConsultInviteRepository;
import com.cskefu.cc.persistence.repository.OrganRepository;
import com.cskefu.cc.persistence.repository.ChannelRepository;
import com.cskefu.cc.persistence.repository.SecretRepository;
import com.cskefu.cc.proxy.OrganProxy;
import com.cskefu.cc.util.Base62;
import com.cskefu.cc.util.Menu;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
*
*/
@Controller
@RequestMapping("/admin/im")
public class ChannelController extends Handler {
@Autowired
private ChannelRepository snsAccountRes;
@Autowired
private ConsultInviteRepository invite;
@Autowired
private SecretRepository secRes;
@Autowired
private OrganProxy organProxy;
@Autowired
private OrganRepository organRes;
@Autowired
private Cache cache;
@RequestMapping("/index")
@Menu(type = "admin", subtype = "im", admin = true)
public ModelAndView index(ModelMap map, HttpServletRequest request, @Valid String execute, @RequestParam(name = "status", required = false) String status) {
Map<String, Organ> organs = organProxy.findAllOrganByParent(super.getOrgan(request));
map.addAttribute("snsAccountList", snsAccountRes.findByTypeAndOrgan(MainContext.ChannelType.WEBIM.toString(), organs.keySet(), PageRequest.of(super.getP(request), super.getPs(request))));
map.addAttribute("status", status);
List<Secret> secretConfig = secRes.findAll();
if (secretConfig != null && secretConfig.size() > 0) {
map.addAttribute("secret", secretConfig.get(0));
}
if (StringUtils.isNotBlank(execute) && execute.equals("false")) {
map.addAttribute("execute", execute);
}
return request(super.createView("/admin/channel/im/index"));
}
@RequestMapping("/add")
@Menu(type = "admin", subtype = "send", admin = true)
public ModelAndView add(ModelMap map, HttpServletRequest request) {
Organ currentOrgan = super.getOrgan(request);
map.put("organ", currentOrgan);
return request(super.createView("/admin/channel/im/add"));
}
@RequestMapping("/save")
@Menu(type = "admin", subtype = "weixin")
public ModelAndView save(HttpServletRequest request,
@Valid Channel channel) throws NoSuchAlgorithmException {
Organ currentOrgan = super.getOrgan(request);
String status = "new_webim_fail";
if (StringUtils.isNotBlank(channel.getBaseURL())) {
channel.setSnsid(Base62.encode(channel.getBaseURL()).toLowerCase());
int count = snsAccountRes.countBySnsid(channel.getSnsid());
if (count == 0) {
status = "new_webim_success";
channel.setType(MainContext.ChannelType.WEBIM.toString());
channel.setCreatetime(new Date());
User curr = super.getUser(request);
channel.setCreater(curr.getId());
channel.setOrgan(currentOrgan.getId());
snsAccountRes.save(channel);
/**
* 同时创建CousultInvite 记录
*/
CousultInvite coultInvite = invite.findBySnsaccountid(channel.getSnsid());
if (coultInvite == null) {
coultInvite = new CousultInvite();
coultInvite.setSnsaccountid(channel.getSnsid());
coultInvite.setCreate_time(new Date());
coultInvite.setName(channel.getName());
coultInvite.setOwner(channel.getCreater());
coultInvite.setSkill(false); // 不启动技能组
coultInvite.setConsult_skill_fixed(false); // 不绑定唯一技能组
coultInvite.setAi(false);
coultInvite.setAifirst(false);
invite.save(coultInvite);
}
}
}
return request(super.createView("redirect:/admin/im/index.html?status=" + status));
}
@RequestMapping("/delete")
@Menu(type = "weixin", subtype = "delete")
public ModelAndView delete(ModelMap map, HttpServletRequest request, @Valid String id, @Valid String confirm) {
boolean execute;
if (execute = MainUtils.secConfirm(secRes, confirm)) {
Channel channel = snsAccountRes.findById(id).orElse(null);
if (snsAccountRes != null) {
// 删除网站渠道记录
snsAccountRes.delete(channel);
/**
* 删除网站渠道客服配置
*/
CousultInvite coultInvite = invite.findBySnsaccountid(channel.getSnsid());
if (coultInvite != null) {
invite.delete(coultInvite);
}
// 删除缓存
cache.deleteConsultInviteBySnsid(channel.getSnsid());
}
}
return request(super.createView("redirect:/admin/im/index.html?execute=" + execute));
}
@RequestMapping("/edit")
@Menu(type = "admin", subtype = "send", admin = true)
public ModelAndView edit(ModelMap map, HttpServletRequest request, @Valid String id) {
Channel channel = snsAccountRes.findById(id).orElse(null);
Organ organ = organRes.findById(channel.getOrgan()).orElse(null);
map.put("organ", organ);
map.addAttribute("channel", channel);
return request(super.createView("/admin/channel/im/edit"));
}
@RequestMapping("/update")
@Menu(type = "admin", subtype = "send", admin = true)
public ModelAndView update(HttpServletRequest request, @Valid Channel channel) throws NoSuchAlgorithmException {
Channel oldChannel = snsAccountRes.findById(channel.getId()).orElse(null);
if (oldChannel != null) {
oldChannel.setName(channel.getName());
oldChannel.setBaseURL(channel.getBaseURL());
oldChannel.setUpdatetime(new Date());
/**
* SNSID如果有变更需要同时变更 CoultInvite 表的 记录
*/
if (StringUtils.isNotBlank(oldChannel.getSnsid())) {
CousultInvite coultInvite = invite.findBySnsaccountid(oldChannel.getSnsid());
if (coultInvite == null) {
/**
* 同时创建CousultInvite 记录
*/
coultInvite = new CousultInvite();
coultInvite.setSnsaccountid(oldChannel.getSnsid());
coultInvite.setCreate_time(new Date());
coultInvite.setName(channel.getName());
invite.save(coultInvite);
}
}
oldChannel.setType(MainContext.ChannelType.WEBIM.toString());
snsAccountRes.save(oldChannel);
}
return request(super.createView("redirect:/admin/im/index.html"));
}
}

View File

@ -1,18 +1,16 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.controller.admin.channel;
@ -20,11 +18,12 @@ import com.cskefu.cc.cache.Cache;
import com.cskefu.cc.controller.Handler;
import com.cskefu.cc.model.CousultInvite;
import com.cskefu.cc.model.Organ;
import com.cskefu.cc.model.Channel;
import com.cskefu.cc.model.User;
import com.cskefu.cc.persistence.repository.*;
import com.cskefu.cc.proxy.OnlineUserProxy;
import com.cskefu.cc.util.Menu;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -36,11 +35,12 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@Controller
@RequestMapping("/admin/webim")
@ -63,7 +63,7 @@ public class WebIMController extends Handler {
private String path;
@Autowired
private SNSAccountRepository snsAccountRes;
private ChannelRepository snsAccountRes;
@Autowired
private Cache cache;
@ -71,15 +71,17 @@ public class WebIMController extends Handler {
@RequestMapping("/index")
@Menu(type = "app", subtype = "app", admin = true)
public ModelAndView index(ModelMap map, HttpServletRequest request, @Valid String snsid) {
CousultInvite coultInvite = OnlineUserProxy.consult(snsid, super.getOrgi(request));
logger.info("[index] snsaccount Id {}, Ai {}, Aifirst {}, Ainame {}, Aisuccess {}, Aiid {}", coultInvite.getSnsaccountid(), coultInvite.isAi(), coultInvite.isAifirst(), coultInvite.getAiname(), coultInvite.getAisuccesstip(), coultInvite.getAiid());
CousultInvite coultInvite = OnlineUserProxy.consult(snsid);
if (coultInvite != null) {
logger.info("[index] snsaccount Id {}, Ai {}, Aifirst {}, Ainame {}, Aisuccess {}, Aiid {}", coultInvite.getSnsaccountid(), coultInvite.isAi(), coultInvite.isAifirst(), coultInvite.getAiname(), coultInvite.getAisuccesstip(), coultInvite.getAiid());
map.addAttribute("inviteData", coultInvite);
map.addAttribute("skillGroups", getSkillGroups(request));
map.addAttribute("agentList", getUsers(request));
map.addAttribute("port", request.getServerPort());
map.addAttribute("snsAccount", snsAccountRes.findBySnsidAndOrgi(snsid, super.getOrgi(request)));
Optional<Channel> snsAccountOpt = snsAccountRes.findBySnsid(snsid);
snsAccountOpt.ifPresent(snsAccount -> map.addAttribute("channel", snsAccount));
}
return request(super.createView("/admin/webim/index"));
}
@ -101,20 +103,19 @@ public class WebIMController extends Handler {
logger.info("[save] snsaccount Id {}, Ai {}, Aifirst {}, Ainame {}, Aisuccess {}, Aiid {}", inviteData.getSnsaccountid(), inviteData.isAi(), inviteData.isAifirst(), inviteData.getAiname(), inviteData.getAisuccesstip(), inviteData.getAiid());
if (StringUtils.isNotBlank(inviteData.getSnsaccountid())) {
CousultInvite tempData = inviteRes.findBySnsaccountidAndOrgi(inviteData.getSnsaccountid(), super.getOrgi(request));
CousultInvite tempData = inviteRes.findBySnsaccountid(inviteData.getSnsaccountid());
if (tempData != null) {
tempData.setConsult_vsitorbtn_model(inviteData.getConsult_vsitorbtn_model());
tempData.setConsult_vsitorbtn_color(inviteData.getConsult_vsitorbtn_color());
tempData.setConsult_vsitorbtn_position(inviteData.getConsult_vsitorbtn_position());
tempData.setConsult_vsitorbtn_content(inviteData.getConsult_vsitorbtn_content());
tempData.setConsult_vsitorbtn_display(inviteData.getConsult_vsitorbtn_display());
tempData.setConsult_vsitorbtn_delay(inviteData.getConsult_vsitorbtn_delay());
tempData.setConsult_dialog_color(inviteData.getConsult_dialog_color());
inviteData = tempData;
}
} else {
inviteData.setSnsaccountid(super.getUser(request).getId());
}
inviteData.setOrgi(super.getOrgi(request));
// 网页品牌标识
if (webimlogo != null && webimlogo.getOriginalFilename().lastIndexOf(".") > 0) {
inviteData.setConsult_dialog_logo(super.saveImageFileWithMultipart(webimlogo));
@ -125,32 +126,31 @@ public class WebIMController extends Handler {
inviteData.setConsult_dialog_headimg(super.saveImageFileWithMultipart(agentheadimg));
}
inviteRes.save(inviteData);
cache.putConsultInviteByOrgi(inviteData.getOrgi(), inviteData);
cache.putConsultInvite(inviteData);
return request(super.createView("redirect:/admin/webim/index.html?snsid=" + inviteData.getSnsaccountid()));
}
@RequestMapping("/profile")
@Menu(type = "app", subtype = "profile", admin = true)
public ModelAndView profile(ModelMap map, HttpServletRequest request, @Valid String snsid) {
CousultInvite coultInvite = OnlineUserProxy.consult(snsid, super.getOrgi(request));
logger.info("[profile] snsaccount Id {}, Ai {}, Aifirst {}, Ainame {}, Aisuccess {}, Aiid {}", coultInvite.getSnsaccountid(), coultInvite.isAi(), coultInvite.isAifirst(), coultInvite.getAiname(), coultInvite.getAisuccesstip(), coultInvite.getAiid());
CousultInvite coultInvite = OnlineUserProxy.consult(snsid);
if (coultInvite != null) {
logger.info("[profile] snsaccount Id {}, Ai {}, Aifirst {}, Ainame {}, Aisuccess {}, Aiid {}", coultInvite.getSnsaccountid(), coultInvite.isAi(), coultInvite.isAifirst(), coultInvite.getAiname(), coultInvite.getAisuccesstip(), coultInvite.getAiid());
map.addAttribute("inviteData", coultInvite);
map.addAttribute("skillGroups", getSkillGroups(request));
}
map.addAttribute("import", request.getServerPort());
map.addAttribute("snsAccount", snsAccountRes.findBySnsidAndOrgi(snsid, super.getOrgi(request)));
Optional<Channel> snsAccountOpt = snsAccountRes.findBySnsid(snsid);
snsAccountOpt.ifPresent(snsAccount -> map.addAttribute("channel", snsAccount));
map.put("serviceAiList", serviceAiRes.findByOrgi(super.getOrgi(request)));
map.put("serviceAiList", serviceAiRes.findAll());
return request(super.createView("/admin/webim/profile"));
}
@RequestMapping("/profile/save")
@Menu(type = "admin", subtype = "profile", admin = true)
public ModelAndView saveprofile(HttpServletRequest request, @Valid CousultInvite inviteData, @RequestParam(value = "dialogad", required = false) MultipartFile dialogad) throws IOException {
final String orgi = super.getOrgi(request);
CousultInvite tempInviteData;
logger.info("[profile/save] snsaccount Id {}, Ai {}, Aifirst {}, Ainame {}, Aisuccess {}, Aiid {}, traceUser {}",
inviteData.getSnsaccountid(),
@ -163,7 +163,7 @@ public class WebIMController extends Handler {
if (inviteData != null && StringUtils.isNotBlank(inviteData.getId())) {
// 从Cache及DB加载consult
tempInviteData = OnlineUserProxy.consult(inviteData.getSnsaccountid(), orgi);
tempInviteData = OnlineUserProxy.consult(inviteData.getSnsaccountid());
if (tempInviteData != null) {
tempInviteData.setDialog_name(inviteData.getDialog_name());
@ -227,21 +227,22 @@ public class WebIMController extends Handler {
inviteRes.save(inviteData);
}
cache.putConsultInviteByOrgi(orgi, inviteData);
cache.putConsultInvite(inviteData);
return request(super.createView("redirect:/admin/webim/profile.html?snsid=" + inviteData.getSnsaccountid()));
}
@RequestMapping("/invote")
@Menu(type = "app", subtype = "invote", admin = true)
public ModelAndView invote(ModelMap map, HttpServletRequest request, @Valid String snsid) {
CousultInvite coultInvite = OnlineUserProxy.consult(snsid, super.getOrgi(request));
logger.info("[invote] snsaccount Id {}, Ai {}, Aifirst {}, Ainame {}, Aisuccess {}, Aiid {}", coultInvite.getSnsaccountid(), coultInvite.isAi(), coultInvite.isAifirst(), coultInvite.getAiname(), coultInvite.getAisuccesstip(), coultInvite.getAiid());
CousultInvite coultInvite = OnlineUserProxy.consult(snsid);
if (coultInvite != null) {
logger.info("[invote] snsaccount Id {}, Ai {}, Aifirst {}, Ainame {}, Aisuccess {}, Aiid {}", coultInvite.getSnsaccountid(), coultInvite.isAi(), coultInvite.isAifirst(), coultInvite.getAiname(), coultInvite.getAisuccesstip(), coultInvite.getAiid());
map.addAttribute("inviteData", coultInvite);
}
map.addAttribute("import", request.getServerPort());
map.addAttribute("snsAccount", snsAccountRes.findBySnsidAndOrgi(snsid, super.getOrgi(request)));
Optional<Channel> snsAccountOpt = snsAccountRes.findBySnsid(snsid);
snsAccountOpt.ifPresent(snsAccount -> map.addAttribute("channel", snsAccount));
return request(super.createView("/admin/webim/invote"));
}
@ -252,7 +253,7 @@ public class WebIMController extends Handler {
logger.info("[invote/save] snsaccount Id {}, Ai {}, Aifirst {}, Ainame {}, Aisuccess {}, Aiid {}", inviteData.getSnsaccountid(), inviteData.isAi(), inviteData.isAifirst(), inviteData.getAiname(), inviteData.getAisuccesstip(), inviteData.getAiid());
if (inviteData != null && StringUtils.isNotBlank(inviteData.getId())) {
tempInviteData = OnlineUserProxy.consult(inviteData.getSnsaccountid(), super.getOrgi(request));
tempInviteData = OnlineUserProxy.consult(inviteData.getSnsaccountid());
if (tempInviteData != null) {
tempInviteData.setConsult_invite_enable(inviteData.isConsult_invite_enable());
tempInviteData.setConsult_invite_content(inviteData.getConsult_invite_content());
@ -271,7 +272,7 @@ public class WebIMController extends Handler {
} else {
inviteRes.save(inviteData);
}
cache.putConsultInviteByOrgi(inviteData.getOrgi(), inviteData);
cache.putConsultInvite(inviteData);
return request(super.createView("redirect:/admin/webim/invote.html?snsid=" + inviteData.getSnsaccountid()));
}
@ -283,7 +284,7 @@ public class WebIMController extends Handler {
*/
private List<Organ> getSkillGroups(HttpServletRequest request) {
List<Organ> skillgroups = new ArrayList<>();
List<Organ> allgroups = organRes.findByOrgi(super.getOrgi(request));
List<Organ> allgroups = organRes.findAll();
for (Organ o : allgroups) {
if (o.isSkill()) {
skillgroups.add(o);
@ -299,7 +300,7 @@ public class WebIMController extends Handler {
* @return
*/
private List<User> getUsers(HttpServletRequest request) {
List<User> userList = userRes.findByOrgiAndAgentAndDatastatus(super.getOrgi(request), true, false);
List<User> userList = userRes.findByAgentAndDatastatus(true, false);
return userList;
}
}

View File

@ -1,18 +1,16 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.controller.admin.config;
@ -32,10 +30,8 @@ import com.cskefu.cc.persistence.repository.SystemMessageRepository;
import com.cskefu.cc.persistence.repository.TemplateRepository;
import com.cskefu.cc.util.Menu;
import com.corundumstudio.socketio.SocketIOServer;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
@ -44,27 +40,18 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.io.File;
import java.io.FileOutputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import java.util.Properties;
@Controller
@RequestMapping("/admin/config")
public class SystemConfigController extends Handler {
@Value("${uk.im.server.port}")
private Integer port;
@Value("${web.upload-path}")
private String path;
@Autowired
private SocketIOServer server;
@ -96,7 +83,8 @@ public class SystemConfigController extends Handler {
}
map.addAttribute("server", server);
map.addAttribute("imServerStatus", MainContext.getIMServerStatus());
List<Secret> secretConfig = secRes.findByOrgi(super.getOrgi(request));
List<Secret> secretConfig = secRes.findAll();
// check out secretConfig
if (secretConfig != null && secretConfig.size() > 0) {
map.addAttribute("secret", secretConfig.get(0));
@ -118,20 +106,19 @@ public class SystemConfigController extends Handler {
if (callCenterDic != null) {
map.addAttribute(
"templateList",
templateRes.findByTemplettypeAndOrgi(callCenterDic.getId(), super.getOrgi(request)));
templateRes.findByTemplettype(callCenterDic.getId()));
}
if (workOrderDic != null) {
map.addAttribute(
"workOrderList",
templateRes.findByTemplettypeAndOrgi(workOrderDic.getId(), super.getOrgi(request)));
templateRes.findByTemplettype(workOrderDic.getId()));
}
if (smsDic != null) {
map.addAttribute("smsList", templateRes.findByTemplettypeAndOrgi(smsDic.getId(), super.getOrgi(request)));
map.addAttribute("smsList", templateRes.findByTemplettype(smsDic.getId()));
}
map.addAttribute(
"sysMessageList", systemMessageRes.findByMsgtypeAndOrgi(MainContext.SystemMessageType.EMAIL.toString(),
super.getOrgi(request)));
"sysMessageList", systemMessageRes.findByMsgtype(MainContext.SystemMessageType.EMAIL.toString()));
if (StringUtils.isNotBlank(execute) && execute.equals("false")) {
map.addAttribute("execute", execute);
@ -151,10 +138,10 @@ public class SystemConfigController extends Handler {
}
@RequestMapping("/stopimserver")
@Menu(type = "admin", subtype = "stopimserver", access = false, admin = true)
@Menu(type = "admin", subtype = "stopimserver", admin = true)
public ModelAndView stopimserver(ModelMap map, HttpServletRequest request, @Valid String confirm) throws SQLException {
boolean execute;
if (execute = MainUtils.secConfirm(secRes, super.getOrgi(request), confirm)) {
if (execute = MainUtils.secConfirm(secRes, confirm)) {
server.stop();
MainContext.setIMServerStatus(false);
}
@ -162,14 +149,14 @@ public class SystemConfigController extends Handler {
}
@RequestMapping("/startentim")
@Menu(type = "admin", subtype = "startentim", access = false, admin = true)
@Menu(type = "admin", subtype = "startentim", admin = true)
public ModelAndView startentim(ModelMap map, HttpServletRequest request) throws SQLException {
MainContext.enableModule(Constants.CSKEFU_MODULE_ENTIM);
return request(super.createView("redirect:/admin/config/index.html"));
}
@RequestMapping("/stopentim")
@Menu(type = "admin", subtype = "stopentim", access = false, admin = true)
@Menu(type = "admin", subtype = "stopentim", admin = true)
public ModelAndView stopentim(ModelMap map, HttpServletRequest request) throws SQLException {
MainContext.removeModule(Constants.CSKEFU_MODULE_ENTIM);
return request(super.createView("redirect:/admin/config/index.html"));
@ -184,10 +171,10 @@ public class SystemConfigController extends Handler {
* @throws SQLException
*/
@RequestMapping("/stop")
@Menu(type = "admin", subtype = "stop", access = false, admin = true)
@Menu(type = "admin", subtype = "stop", admin = true)
public ModelAndView stop(ModelMap map, HttpServletRequest request, @Valid String confirm) throws SQLException {
boolean execute = false;
if (execute = MainUtils.secConfirm(secRes, super.getOrgi(request), confirm)) {
if (execute = MainUtils.secConfirm(secRes, confirm)) {
server.stop();
MainContext.setIMServerStatus(false);
System.exit(0);
@ -207,14 +194,8 @@ public class SystemConfigController extends Handler {
@RequestParam(value = "consolelogo", required = false) MultipartFile consolelogo,
@RequestParam(value = "favlogo", required = false) MultipartFile favlogo,
@Valid Secret secret) throws SQLException, IOException, NoSuchAlgorithmException {
/*SystemConfig systemConfig = systemConfigRes.findByOrgi(super.getOrgi(request)) ;
config.setOrgi(super.getOrgi(request));*/
SystemConfig systemConfig = systemConfigRes.findByOrgi(Constants.SYSTEM_ORGI);
config.setOrgi(Constants.SYSTEM_ORGI);
SystemConfig systemConfig = systemConfigRes.findOne();
String msg = "0";
if (StringUtils.isBlank(config.getJkspassword())) {
config.setJkspassword(null);
}
if (systemConfig == null) {
config.setCreater(super.getUser(request).getId());
config.setCreatetime(new Date());
@ -222,29 +203,6 @@ public class SystemConfigController extends Handler {
} else {
MainUtils.copyProperties(config, systemConfig);
}
if (config.isEnablessl()) {
if (keyfile != null && keyfile.getBytes() != null && keyfile.getBytes().length > 0 && keyfile.getOriginalFilename() != null && keyfile.getOriginalFilename().length() > 0) {
FileUtils.writeByteArrayToFile(
new File(path, "ssl/" + keyfile.getOriginalFilename()), keyfile.getBytes());
systemConfig.setJksfile(keyfile.getOriginalFilename());
File sslFilePath = new File(path, "ssl/https.properties");
if (!sslFilePath.getParentFile().exists()) {
sslFilePath.getParentFile().mkdirs();
}
Properties prop = new Properties();
FileOutputStream oFile = new FileOutputStream(sslFilePath);//true表示追加打开
prop.setProperty("key-store-password", MainUtils.encryption(systemConfig.getJkspassword()));
prop.setProperty("key-store", systemConfig.getJksfile());
prop.store(oFile, "SSL Properties File");
oFile.close();
}
} else if (new File(path, "ssl").exists()) {
File[] sslFiles = new File(path, "ssl").listFiles();
for (File sslFile : sslFiles) {
sslFile.delete();
}
}
if (loginlogo != null && StringUtils.isNotBlank(
loginlogo.getOriginalFilename()) && loginlogo.getOriginalFilename().lastIndexOf(".") > 0) {
systemConfig.setLoginlogo(super.saveImageFileWithMultipart(loginlogo));
@ -259,7 +217,7 @@ public class SystemConfigController extends Handler {
}
if (secret != null && StringUtils.isNotBlank(secret.getPassword())) {
List<Secret> secretConfig = secRes.findByOrgi(super.getOrgi(request));
List<Secret> secretConfig = secRes.findAll();
String repassword = request.getParameter("repassword");
if (StringUtils.isNotBlank(repassword) && repassword.equals(secret.getPassword())) {
if (secretConfig != null && secretConfig.size() > 0) {
@ -274,7 +232,6 @@ public class SystemConfigController extends Handler {
msg = "3";
}
} else {
secret.setOrgi(super.getOrgi(request));
secret.setCreater(super.getUser(request).getId());
secret.setCreatetime(new Date());
secret.setPassword(MainUtils.md5(secret.getPassword()));
@ -294,7 +251,7 @@ public class SystemConfigController extends Handler {
// 保存到数据库
systemConfigRes.save(systemConfig);
MainContext.getCache().putSystemByIdAndOrgi("systemConfig", super.getOrgi(request), systemConfig);
MainContext.getCache().putSystemById("systemConfig", systemConfig);
map.addAttribute("imServerStatus", MainContext.getIMServerStatus());
return request(super.createView("redirect:/admin/config/index.html?msg=" + msg));

View File

@ -1,18 +1,16 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.controller.admin.config;
@ -34,8 +32,8 @@ import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
@ -53,8 +51,8 @@ public class SystemMessageController extends Handler {
@RequestMapping("/email/index")
@Menu(type = "setting", subtype = "email")
public ModelAndView index(ModelMap map, HttpServletRequest request) throws IOException {
Page<SystemMessage> emails = systemMessageRepository.findByMsgtypeAndOrgi("email", super.getOrgi(request), new PageRequest(super.getP(request), super.getPs(request)));
List<Organ> organs = organRes.findByOrgi(super.getOrgi(request));
Page<SystemMessage> emails = systemMessageRepository.findByMsgtype("email", PageRequest.of(super.getP(request), super.getPs(request)));
List<Organ> organs = organRes.findAll();
emails.getContent().stream().forEach(p -> {
organs.stream().filter(o -> StringUtils.equals(p.getOrgan(), o.getId())).findAny().ifPresent(o -> p.setOrgan(o.getName()));
@ -67,14 +65,13 @@ public class SystemMessageController extends Handler {
@RequestMapping("/email/add")
@Menu(type = "admin", subtype = "email")
public ModelAndView add(ModelMap map, HttpServletRequest request) {
map.put("organList", organRes.findByOrgi(super.getOrgi(request)));
map.put("organList", organRes.findAll());
return request(super.createView("/admin/email/add"));
}
@RequestMapping("/email/save")
@Menu(type = "admin", subtype = "user")
public ModelAndView save(HttpServletRequest request, @Valid SystemMessage email) throws NoSuchAlgorithmException {
email.setOrgi(super.getOrgi(request));
email.setMsgtype(MainContext.SystemMessageType.EMAIL.toString());
if (!StringUtils.isBlank(email.getSmtppassword())) {
email.setSmtppassword(MainUtils.encryption(email.getSmtppassword()));
@ -86,18 +83,17 @@ public class SystemMessageController extends Handler {
@RequestMapping("/email/edit")
@Menu(type = "admin", subtype = "email")
public ModelAndView edit(ModelMap map, HttpServletRequest request, @Valid String id) {
map.put("organList", organRes.findByOrgi(super.getOrgi(request)));
map.addAttribute("email", systemMessageRepository.findByIdAndOrgi(id, super.getOrgi(request)));
map.put("organList", organRes.findAll());
map.addAttribute("email", systemMessageRepository.findById(id).orElse(null));
return request(super.createView("/admin/email/edit"));
}
@RequestMapping("/email/update")
@Menu(type = "admin", subtype = "user", admin = true)
public ModelAndView update(HttpServletRequest request, @Valid SystemMessage email) throws NoSuchAlgorithmException {
SystemMessage temp = systemMessageRepository.findByIdAndOrgi(email.getId(), super.getOrgi(request));
SystemMessage temp = systemMessageRepository.findById(email.getId()).orElse(null);
if (email != null) {
email.setCreatetime(temp.getCreatetime());
email.setOrgi(temp.getOrgi());
email.setMsgtype(MainContext.SystemMessageType.EMAIL.toString());
if (!StringUtils.isBlank(email.getSmtppassword())) {
email.setSmtppassword(MainUtils.encryption(email.getSmtppassword()));
@ -112,7 +108,7 @@ public class SystemMessageController extends Handler {
@RequestMapping("/email/delete")
@Menu(type = "admin", subtype = "user")
public ModelAndView delete(HttpServletRequest request, @Valid SystemMessage email) {
SystemMessage temp = systemMessageRepository.findByIdAndOrgi(email.getId(), super.getOrgi(request));
SystemMessage temp = systemMessageRepository.findById(email.getId()).orElse(null);
if (email != null) {
systemMessageRepository.delete(temp);
}
@ -123,7 +119,7 @@ public class SystemMessageController extends Handler {
@RequestMapping("/sms/index")
@Menu(type = "setting", subtype = "sms")
public ModelAndView smsindex(ModelMap map, HttpServletRequest request) throws IOException {
map.addAttribute("smsList", systemMessageRepository.findByMsgtypeAndOrgi("sms", super.getOrgi(request), new PageRequest(super.getP(request), super.getPs(request))));
map.addAttribute("smsList", systemMessageRepository.findByMsgtype("sms", PageRequest.of(super.getP(request), super.getPs(request))));
return request(super.createView("/admin/sms/index"));
}
@ -137,7 +133,6 @@ public class SystemMessageController extends Handler {
@RequestMapping("/sms/save")
@Menu(type = "admin", subtype = "sms")
public ModelAndView smssave(HttpServletRequest request, @Valid SystemMessage sms) throws NoSuchAlgorithmException {
sms.setOrgi(super.getOrgi(request));
sms.setMsgtype(MainContext.SystemMessageType.SMS.toString());
if (!StringUtils.isBlank(sms.getSmtppassword())) {
sms.setSmtppassword(MainUtils.encryption(sms.getSmtppassword()));
@ -150,17 +145,16 @@ public class SystemMessageController extends Handler {
@Menu(type = "admin", subtype = "sms")
public ModelAndView smsedit(ModelMap map, HttpServletRequest request, @Valid String id) {
map.addAttribute("smsType", Dict.getInstance().getDic("com.dic.sms.type"));
map.addAttribute("sms", systemMessageRepository.findByIdAndOrgi(id, super.getOrgi(request)));
map.addAttribute("sms", systemMessageRepository.findById(id).orElse(null));
return request(super.createView("/admin/sms/edit"));
}
@RequestMapping("/sms/update")
@Menu(type = "admin", subtype = "sms", admin = true)
public ModelAndView smsupdate(HttpServletRequest request, @Valid SystemMessage sms) throws NoSuchAlgorithmException {
SystemMessage temp = systemMessageRepository.findByIdAndOrgi(sms.getId(), super.getOrgi(request));
SystemMessage temp = systemMessageRepository.findById(sms.getId()).orElse(null);
if (sms != null) {
sms.setCreatetime(temp.getCreatetime());
sms.setOrgi(temp.getOrgi());
sms.setMsgtype(MainContext.SystemMessageType.SMS.toString());
if (!StringUtils.isBlank(sms.getSmtppassword())) {
sms.setSmtppassword(MainUtils.encryption(sms.getSmtppassword()));
@ -175,7 +169,7 @@ public class SystemMessageController extends Handler {
@RequestMapping("/sms/delete")
@Menu(type = "admin", subtype = "sms")
public ModelAndView smsdelete(HttpServletRequest request, @Valid SystemMessage sms) {
SystemMessage temp = systemMessageRepository.findByIdAndOrgi(sms.getId(), super.getOrgi(request));
SystemMessage temp = systemMessageRepository.findById(sms.getId()).orElse(null);
if (sms != null) {
systemMessageRepository.delete(temp);
}

View File

@ -1,22 +1,19 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.controller.admin.system;
import com.cskefu.cc.basic.MainContext;
import com.cskefu.cc.basic.MainUtils;
import com.cskefu.cc.controller.Handler;
import com.cskefu.cc.model.*;
@ -24,35 +21,31 @@ import com.cskefu.cc.persistence.hibernate.BaseService;
import com.cskefu.cc.persistence.repository.MetadataRepository;
import com.cskefu.cc.persistence.repository.SysDicRepository;
import com.cskefu.cc.persistence.repository.TablePropertiesRepository;
import com.cskefu.cc.util.CskefuList;
import com.cskefu.cc.util.Menu;
import com.cskefu.cc.util.metadata.DatabaseMetaDataHandler;
import com.cskefu.cc.util.metadata.UKColumnMetadata;
import com.cskefu.cc.util.metadata.UKTableMetaData;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.Session;
import org.hibernate.jdbc.Work;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
@Controller
@RequestMapping("/admin/metadata")
@ -79,21 +72,21 @@ public class MetadataController extends Handler {
@RequestMapping("/index")
@Menu(type = "admin", subtype = "metadata", admin = true)
public ModelAndView index(ModelMap map, HttpServletRequest request) throws SQLException {
map.addAttribute("metadataList", metadataRes.findAll(new PageRequest(super.getP(request), super.getPs(request))));
map.addAttribute("metadataList", metadataRes.findAll(PageRequest.of(super.getP(request), super.getPs(request))));
return request(super.createView("/admin/system/metadata/index"));
}
@RequestMapping("/edit")
@Menu(type = "admin", subtype = "metadata", admin = true)
public ModelAndView edit(ModelMap map, HttpServletRequest request, @Valid String id) {
map.addAttribute("metadata", metadataRes.findById(id));
map.addAttribute("metadata", metadataRes.findById(id).orElse(null));
return request(super.createView("/admin/system/metadata/edit"));
}
@RequestMapping("/update")
@Menu(type = "admin", subtype = "metadata", admin = true)
public ModelAndView update(ModelMap map, HttpServletRequest request, @Valid MetadataTable metadata) throws SQLException {
MetadataTable table = metadataRes.findById(metadata.getId());
MetadataTable table = metadataRes.findById(metadata.getId()).orElse(null);
table.setName(metadata.getName());
table.setFromdb(metadata.isFromdb());
table.setListblocktemplet(metadata.getListblocktemplet());
@ -105,7 +98,7 @@ public class MetadataController extends Handler {
@RequestMapping("/properties/edit")
@Menu(type = "admin", subtype = "metadata", admin = true)
public ModelAndView propertiesedit(ModelMap map, HttpServletRequest request, @Valid String id) {
map.addAttribute("tp", tablePropertiesRes.findById(id));
map.addAttribute("tp", tablePropertiesRes.findById(id).orElse(null));
map.addAttribute("sysdicList", sysDicRes.findByParentid("0"));
map.addAttribute("dataImplList", Dict.getInstance().getDic("com.dic.data.impl"));
@ -115,7 +108,7 @@ public class MetadataController extends Handler {
@RequestMapping("/properties/update")
@Menu(type = "admin", subtype = "metadata", admin = true)
public ModelAndView propertiesupdate(ModelMap map, HttpServletRequest request, @Valid TableProperties tp) throws SQLException {
TableProperties tableProperties = tablePropertiesRes.findById(tp.getId());
TableProperties tableProperties = tablePropertiesRes.findById(tp.getId()).orElse(null);
tableProperties.setName(tp.getName());
tableProperties.setSeldata(tp.isSeldata());
tableProperties.setSeldatacode(tp.getSeldatacode());
@ -140,7 +133,7 @@ public class MetadataController extends Handler {
@RequestMapping("/delete")
@Menu(type = "admin", subtype = "metadata", admin = true)
public ModelAndView delete(ModelMap map, HttpServletRequest request, @Valid String id) throws SQLException {
MetadataTable table = metadataRes.findById(id);
MetadataTable table = metadataRes.findById(id).orElse(null);
metadataRes.delete(table);
return request(super.createView("redirect:/admin/metadata/index.html"));
}
@ -149,7 +142,7 @@ public class MetadataController extends Handler {
@Menu(type = "admin", subtype = "metadata", admin = true)
public ModelAndView batdelete(ModelMap map, HttpServletRequest request, @Valid String[] ids) throws SQLException {
if (ids != null && ids.length > 0) {
metadataRes.delete(metadataRes.findAll(Arrays.asList(ids)));
metadataRes.deleteAll(metadataRes.findAllById(Arrays.asList(ids)));
}
return request(super.createView("redirect:/admin/metadata/index.html"));
}
@ -157,7 +150,7 @@ public class MetadataController extends Handler {
@RequestMapping("/properties/delete")
@Menu(type = "admin", subtype = "metadata", admin = true)
public ModelAndView propertiesdelete(ModelMap map, HttpServletRequest request, @Valid String id, @Valid String tbid) throws SQLException {
TableProperties prop = tablePropertiesRes.findById(id);
TableProperties prop = tablePropertiesRes.findById(id).orElse(null);
tablePropertiesRes.delete(prop);
return request(super.createView("redirect:/admin/metadata/table.html?id=" + (!StringUtils.isBlank(tbid) ? tbid : prop.getDbtableid())));
}
@ -166,7 +159,7 @@ public class MetadataController extends Handler {
@Menu(type = "admin", subtype = "metadata", admin = true)
public ModelAndView propertiesbatdelete(ModelMap map, HttpServletRequest request, @Valid String[] ids, @Valid String tbid) throws SQLException {
if (ids != null && ids.length > 0) {
tablePropertiesRes.delete(tablePropertiesRes.findAll(Arrays.asList(ids)));
tablePropertiesRes.deleteAll(tablePropertiesRes.findAllById(Arrays.asList(ids)));
}
return request(super.createView("redirect:/admin/metadata/table.html?id=" + tbid));
}
@ -176,7 +169,7 @@ public class MetadataController extends Handler {
public ModelAndView table(ModelMap map, HttpServletRequest request, @Valid String id) throws SQLException {
map.addAttribute("propertiesList", tablePropertiesRes.findByDbtableid(id));
map.addAttribute("tbid", id);
map.addAttribute("table", metadataRes.findById(id));
map.addAttribute("table", metadataRes.findById(id).orElse(null));
return request(super.createView("/admin/system/metadata/table"));
}
@ -185,14 +178,12 @@ public class MetadataController extends Handler {
public ModelAndView imptb(final ModelMap map, HttpServletRequest request) throws Exception {
Session session = (Session) em.getDelegate();
session.doWork(new Work() {
public void execute(Connection connection) throws SQLException {
try {
map.addAttribute("tablesList",
DatabaseMetaDataHandler.getTables(connection));
} catch (Exception e) {
logger.error("When import metadata", e);
}
session.doWork(connection -> {
try {
map.addAttribute("tablesList",
DatabaseMetaDataHandler.getTables(connection));
} catch (Exception e) {
logger.error("When import metadata", e);
}
});
@ -207,29 +198,26 @@ public class MetadataController extends Handler {
if (tables != null && tables.length > 0) {
Session session = (Session) em.getDelegate();
session.doWork(
new Work() {
public void execute(Connection connection) throws SQLException {
try {
for (String table : tables) {
int count = metadataRes.countByTablename(table);
if (count == 0) {
MetadataTable metaDataTable = new MetadataTable();
//当前记录没有被添加过进行正常添加
metaDataTable.setTablename(table);
metaDataTable.setOrgi(user.getOrgi());
metaDataTable.setId(MainUtils.md5(metaDataTable.getTablename()));
metaDataTable.setTabledirid("0");
metaDataTable.setCreater(user.getId());
metaDataTable.setCreatername(user.getUsername());
metaDataTable.setName(table);
metaDataTable.setUpdatetime(new Date());
metaDataTable.setCreatetime(new Date());
metadataRes.save(processMetadataTable(DatabaseMetaDataHandler.getTable(connection, metaDataTable.getTablename()), metaDataTable));
}
connection -> {
try {
for (String table : tables) {
int count = metadataRes.countByTablename(table);
if (count == 0) {
MetadataTable metaDataTable = new MetadataTable();
//当前记录没有被添加过进行正常添加
metaDataTable.setTablename(table);
metaDataTable.setId(MainUtils.md5(metaDataTable.getTablename()));
metaDataTable.setTabledirid("0");
metaDataTable.setCreater(user.getId());
metaDataTable.setCreatername(user.getUsername());
metaDataTable.setName(table);
metaDataTable.setUpdatetime(new Date());
metaDataTable.setCreatetime(new Date());
metadataRes.save(processMetadataTable(DatabaseMetaDataHandler.getTable(connection, metaDataTable.getTablename()), metaDataTable));
}
} catch (Exception e) {
logger.error("When import metadata", e);
}
} catch (Exception e) {
logger.error("When import metadata", e);
}
}
);
@ -240,12 +228,10 @@ public class MetadataController extends Handler {
}
private MetadataTable processMetadataTable(UKTableMetaData metaData, MetadataTable table) {
table.setTableproperty(new ArrayList<TableProperties>());
table.setTableproperty(new ArrayList<>());
if (metaData != null) {
for (UKColumnMetadata colum : metaData.getColumnMetadatas()) {
TableProperties tablePorperties = new TableProperties(colum.getName().toLowerCase(), colum.getTypeName(), colum.getColumnSize(), metaData.getName().toLowerCase());
tablePorperties.setOrgi(table.getOrgi());
tablePorperties.setDatatypecode(0);
tablePorperties.setLength(colum.getColumnSize());
tablePorperties.setDatatypename(getDataTypeName(colum.getTypeName()));
@ -267,7 +253,7 @@ public class MetadataController extends Handler {
public String getDataTypeName(String type) {
String typeName = "text";
if (type.indexOf("varchar") >= 0) {
if (type.contains("varchar")) {
typeName = "text";
} else if (type.equalsIgnoreCase("date") || type.equalsIgnoreCase("datetime")) {
typeName = type.toLowerCase();
@ -281,17 +267,7 @@ public class MetadataController extends Handler {
@Menu(type = "admin", subtype = "metadata", admin = true)
public ModelAndView clean(ModelMap map, HttpServletRequest request, @Valid String id) throws SQLException, BeansException, ClassNotFoundException {
if (!StringUtils.isBlank(id)) {
MetadataTable table = metadataRes.findById(id);
if (table.isFromdb() && !StringUtils.isBlank(table.getListblocktemplet())) {
SysDic dic = Dict.getInstance().getDicItem(table.getListblocktemplet());
if (dic != null) {
Object bean = MainContext.getContext().getBean(Class.forName(dic.getCode()));
if (bean instanceof ElasticsearchRepository) {
ElasticsearchRepository<?, ?> jpa = (ElasticsearchRepository<?, ?>) bean;
jpa.deleteAll();
}
}
}
MetadataTable table = metadataRes.findById(id).orElse(null);
}
return request(super.createView("redirect:/admin/metadata/index.html"));
}
@ -301,27 +277,9 @@ public class MetadataController extends Handler {
@Menu(type = "admin", subtype = "metadata", admin = true)
public ModelAndView synctoes(ModelMap map, HttpServletRequest request, @Valid String id) throws SQLException, BeansException, ClassNotFoundException {
if (!StringUtils.isBlank(id)) {
MetadataTable table = metadataRes.findById(id);
MetadataTable table = metadataRes.findById(id).orElse(null);
if (table.isFromdb() && !StringUtils.isBlank(table.getListblocktemplet())) {
SysDic dic = Dict.getInstance().getDicItem(table.getListblocktemplet());
if (dic != null) {
Object bean = MainContext.getContext().getBean(Class.forName(dic.getCode()));
if (bean instanceof ElasticsearchRepository) {
ElasticsearchRepository jpa = (ElasticsearchRepository) bean;
if (!StringUtils.isBlank(table.getPreviewtemplet())) {
SysDic jpaDic = Dict.getInstance().getDicItem(table.getPreviewtemplet());
List dataList = service.list(jpaDic.getCode());
List values = new CskefuList();
for (Object object : dataList) {
values.add(object);
}
if (dataList.size() > 0) {
jpa.save(values);
}
}
}
}
}
}
return request(super.createView("redirect:/admin/metadata/index.html"));
@ -332,23 +290,9 @@ public class MetadataController extends Handler {
@Menu(type = "admin", subtype = "metadata", admin = true)
public ModelAndView synctodb(ModelMap map, HttpServletRequest request, @Valid String id) throws SQLException, BeansException, ClassNotFoundException {
if (!StringUtils.isBlank(id)) {
MetadataTable table = metadataRes.findById(id);
MetadataTable table = metadataRes.findById(id).orElse(null);
if (table.isFromdb() && !StringUtils.isBlank(table.getListblocktemplet())) {
SysDic dic = Dict.getInstance().getDicItem(table.getListblocktemplet());
if (dic != null) {
Object bean = MainContext.getContext().getBean(Class.forName(dic.getCode()));
if (bean instanceof ElasticsearchRepository) {
ElasticsearchRepository jpa = (ElasticsearchRepository) bean;
if (!StringUtils.isBlank(table.getPreviewtemplet())) {
Iterable dataList = jpa.findAll();
for (Object object : dataList) {
service.delete(object);
service.save(object);
}
}
}
}
}
}
return request(super.createView("redirect:/admin/metadata/index.html"));

View File

@ -1,18 +1,16 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.controller.admin.system;
@ -21,7 +19,7 @@ import com.cskefu.cc.controller.Handler;
import com.cskefu.cc.model.SysDic;
import com.cskefu.cc.persistence.repository.SysDicRepository;
import com.cskefu.cc.util.Menu;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort.Direction;
@ -30,8 +28,8 @@ import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import java.util.Date;
import java.util.List;
@ -49,7 +47,7 @@ public class SysDicController extends Handler {
@RequestMapping("/index")
@Menu(type = "admin", subtype = "sysdic")
public ModelAndView index(ModelMap map, HttpServletRequest request) {
map.addAttribute("sysDicList", sysDicRes.findByParentid("0", new PageRequest(super.getP(request), super.getPs(request), Direction.DESC, "createtime")));
map.addAttribute("sysDicList", sysDicRes.findByParentid("0", PageRequest.of(super.getP(request), super.getPs(request), Direction.DESC, "createtime")));
return request(super.createView("/admin/system/sysdic/index"));
}
@ -64,14 +62,13 @@ public class SysDicController extends Handler {
public ModelAndView save(HttpServletRequest request, @Valid SysDic dic) {
List<SysDic> sysDicList = sysDicRes.findByCodeOrName(dic.getCode(), dic.getName());
String msg = null;
String orgi = super.getOrgi(request);
if (sysDicList.size() == 0) {
dic.setParentid("0");
dic.setHaschild(true);
dic.setCreater(super.getUser(request).getId());
dic.setCreatetime(new Date());
sysDicRes.save(dic);
reloadSysDicItem(dic, orgi);
reloadSysDicItem(dic);
} else {
msg = "exist";
}
@ -81,7 +78,7 @@ public class SysDicController extends Handler {
@RequestMapping("/edit")
@Menu(type = "admin", subtype = "sysdic")
public ModelAndView edit(ModelMap map, HttpServletRequest request, @Valid String id, @Valid String p) {
map.addAttribute("sysDic", sysDicRes.findById(id));
map.addAttribute("sysDic", sysDicRes.findById(id).orElse(null));
map.addAttribute("p", p);
return request(super.createView("/admin/system/sysdic/edit"));
}
@ -91,7 +88,7 @@ public class SysDicController extends Handler {
public ModelAndView update(HttpServletRequest request, @Valid SysDic dic, @Valid String p) {
List<SysDic> sysDicList = sysDicRes.findByCodeOrName(dic.getCode(), dic.getName());
if (sysDicList.size() == 0 || (sysDicList.size() == 1 && sysDicList.get(0).getId().equals(dic.getId()))) {
SysDic sysDic = sysDicRes.findById(dic.getId());
SysDic sysDic = sysDicRes.findById(dic.getId()).orElse(null);
sysDic.setName(dic.getName());
sysDic.setCode(dic.getCode());
sysDic.setCtype(dic.getCtype());
@ -99,8 +96,7 @@ public class SysDicController extends Handler {
sysDic.setIconstr(dic.getIconstr());
sysDic.setDescription(dic.getDescription());
sysDicRes.save(sysDic);
String orgi = super.getOrgi(request);
reloadSysDicItem(sysDic, orgi);
reloadSysDicItem(sysDic);
}
return request(super.createView("redirect:/admin/sysdic/index.html?p=" + p));
}
@ -108,11 +104,11 @@ public class SysDicController extends Handler {
@RequestMapping("/delete")
@Menu(type = "admin", subtype = "sysdic")
public ModelAndView delete(ModelMap map, HttpServletRequest request, @Valid String id, @Valid String p) {
SysDic sysDic = sysDicRes.findById(id);
sysDicRes.delete(sysDicRes.findByDicid(id));
SysDic sysDic = sysDicRes.findById(id).orElse(null);
sysDicRes.deleteAll(sysDicRes.findByDicid(id));
sysDicRes.delete(sysDic);
reloadSysDicItem(sysDic, super.getOrgi(request));
reloadSysDicItem(sysDic);
return request(super.createView("redirect:/admin/sysdic/index.html?p=" + p));
}
@ -120,15 +116,15 @@ public class SysDicController extends Handler {
@RequestMapping("/dicitem")
@Menu(type = "admin", subtype = "sysdic")
public ModelAndView dicitem(ModelMap map, HttpServletRequest request, @Valid String id) {
map.addAttribute("sysDic", sysDicRes.findById(id));
map.addAttribute("sysDicList", sysDicRes.findByParentid(id, new PageRequest(super.getP(request), super.getPs(request), Direction.DESC, "createtime")));
map.addAttribute("sysDic", sysDicRes.findById(id).orElse(null));
map.addAttribute("sysDicList", sysDicRes.findByParentid(id, PageRequest.of(super.getP(request), super.getPs(request), Direction.DESC, "createtime")));
return request(super.createView("/admin/system/sysdic/dicitem"));
}
@RequestMapping("/dicitem/add")
@Menu(type = "admin", subtype = "sysdic")
public ModelAndView dicitemadd(ModelMap map, HttpServletRequest request, @Valid String id, @Valid String p) {
map.addAttribute("sysDic", sysDicRes.findById(id));
map.addAttribute("sysDic", sysDicRes.findById(id).orElse(null));
map.addAttribute("p", p);
return request(super.createView("/admin/system/sysdic/dicitemadd"));
}
@ -138,14 +134,12 @@ public class SysDicController extends Handler {
public ModelAndView dicitemsave(HttpServletRequest request, @Valid SysDic dic, @Valid String p) {
List<SysDic> sysDicList = sysDicRes.findByDicidAndName(dic.getDicid(), dic.getName());
String msg = null;
String orgi = super.getOrgi(request);
if (sysDicList.size() == 0) {
dic.setHaschild(true);
dic.setOrgi(orgi);
dic.setCreater(super.getUser(request).getId());
dic.setCreatetime(new Date());
sysDicRes.save(dic);
reloadSysDicItem(dic, orgi);
reloadSysDicItem(dic);
} else {
msg = "exist";
}
@ -155,29 +149,28 @@ public class SysDicController extends Handler {
/**
* 更新系统词典缓存
* @param dic
* @param orgi
*/
public void reloadSysDicItem(final SysDic dic, final String orgi) {
cache.putSysDicByOrgi(dic.getId(), orgi, dic);
public void reloadSysDicItem(final SysDic dic) {
cache.putSysDic(dic.getId(), dic);
if (StringUtils.isNotBlank(dic.getDicid())) { // 该数据为某词典的子项
// 首先获得根词典
SysDic root = cache.findOneSysDicByIdAndOrgi(dic.getDicid(), orgi);
SysDic root = cache.findOneSysDicById(dic.getDicid());
// 获得其目前的全部子项此处是从数据库提取
// 而不是缓存因为缓存的数据已经旧了
List<SysDic> sysDicList = sysDicRes.findByDicid(dic.getDicid());
// 更新其全部子项数据到缓存
cache.putSysDicByOrgi(root.getCode(), orgi, sysDicList);
cache.putSysDic(root.getCode(), sysDicList);
} else if (dic.getParentid().equals("0")) {
// 如果该数据为某根词典
List<SysDic> sysDicList = sysDicRes.findByDicid(dic.getId());
cache.putSysDicByOrgi(dic.getCode(), orgi, sysDicList);
cache.putSysDic(dic.getCode(), sysDicList);
}
}
@RequestMapping("/dicitem/batadd")
@Menu(type = "admin", subtype = "sysdic")
public ModelAndView dicitembatadd(ModelMap map, HttpServletRequest request, @Valid String id, @Valid String p) {
map.addAttribute("sysDic", sysDicRes.findById(id));
map.addAttribute("sysDic", sysDicRes.findById(id).orElse(null));
map.addAttribute("p", p);
return request(super.createView("/admin/system/sysdic/batadd"));
}
@ -187,13 +180,10 @@ public class SysDicController extends Handler {
public ModelAndView dicitembatsave(HttpServletRequest request, @Valid SysDic sysDic, @Valid String content, @Valid String p) {
String[] dicitems = content.split("[\n\r\n]");
int count = 0;
String orig = super.getOrgi(request);
for (String dicitem : dicitems) {
String[] dicValues = dicitem.split("[\t, ;]{1,}");
if (dicValues.length == 2 && dicValues[0].length() > 0 && dicValues[1].length() > 0) {
SysDic dic = new SysDic();
dic.setOrgi(orig);
dic.setName(dicValues[0]);
dic.setCode(dicValues[1]);
dic.setCreater(super.getUser(request).getId());
@ -208,7 +198,7 @@ public class SysDicController extends Handler {
}
}
reloadSysDicItem(sysDicRes.getOne(sysDic.getParentid()), orig);
reloadSysDicItem(sysDicRes.findById(sysDic.getParentid()).orElse(null));
return request(super.createView("redirect:/admin/sysdic/dicitem.html?id=" + sysDic.getParentid() + "&p=" + p));
}
@ -216,7 +206,7 @@ public class SysDicController extends Handler {
@RequestMapping("/dicitem/edit")
@Menu(type = "admin", subtype = "sysdic")
public ModelAndView dicitemedit(ModelMap map, HttpServletRequest request, @Valid String id, @Valid String p) {
map.addAttribute("sysDic", sysDicRes.findById(id));
map.addAttribute("sysDic", sysDicRes.findById(id).orElse(null));
map.addAttribute("p", p);
return request(super.createView("/admin/system/sysdic/dicitemedit"));
}
@ -225,20 +215,18 @@ public class SysDicController extends Handler {
@Menu(type = "admin", subtype = "sysdic")
public ModelAndView dicitemupdate(HttpServletRequest request, @Valid SysDic dic, @Valid String p) {
List<SysDic> sysDicList = sysDicRes.findByDicidAndName(dic.getDicid(), dic.getName());
String orgi = super.getOrgi(request);
if (sysDicList.size() == 0 || (sysDicList.size() == 1 && sysDicList.get(0).getId().equals(dic.getId()))) {
SysDic sysDic = sysDicRes.findById(dic.getId());
SysDic sysDic = sysDicRes.findById(dic.getId()).orElse(null);
sysDic.setName(dic.getName());
sysDic.setCode(dic.getCode());
sysDic.setCtype(dic.getCtype());
sysDic.setOrgi(orgi);
sysDic.setIconskin(dic.getIconskin());
sysDic.setIconstr(dic.getIconstr());
sysDic.setDiscode(dic.isDiscode());
sysDic.setDescription(dic.getDescription());
sysDicRes.save(sysDic);
reloadSysDicItem(sysDic, orgi);
reloadSysDicItem(sysDic);
}
return request(super.createView("redirect:/admin/sysdic/dicitem.html?id=" + dic.getParentid() + "&p=" + p));
}
@ -246,10 +234,10 @@ public class SysDicController extends Handler {
@RequestMapping("/dicitem/delete")
@Menu(type = "admin", subtype = "sysdic")
public ModelAndView dicitemdelete(ModelMap map, HttpServletRequest request, @Valid String id, @Valid String p) {
sysDicRes.delete(sysDicRes.findByDicid(id));
SysDic dic = sysDicRes.getOne(id);
sysDicRes.deleteAll(sysDicRes.findByDicid(id));
SysDic dic = sysDicRes.findById(id).orElse(null);
sysDicRes.delete(dic);
reloadSysDicItem(dic, super.getOrgi(request));
reloadSysDicItem(dic);
return request(super.createView("redirect:/admin/sysdic/dicitem.html?id=" + dic.getParentid() + "&p=" + p));
}

View File

@ -1,18 +1,16 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.controller.admin.system;
@ -35,158 +33,157 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
@Controller
@RequestMapping("/admin/template")
public class TemplateController extends Handler{
@Autowired
private TemplateRepository templateRes;
@Autowired
private SysDicRepository dicRes;
public class TemplateController extends Handler {
@Autowired
private Cache cache;
@Autowired
private TemplateRepository templateRes;
@Autowired
private SysDicRepository dicRes;
@Autowired
private Cache cache;
@RequestMapping("/index")
@Menu(type = "admin" , subtype = "template" , access = false , admin = true)
public ModelAndView index(ModelMap map , HttpServletRequest request) {
map.addAttribute("sysDicList", Dict.getInstance().getDic(Constants.CSKEFU_SYSTEM_DIC));
@Menu(type = "admin", subtype = "template", admin = true)
public ModelAndView index(ModelMap map, HttpServletRequest request) {
map.addAttribute("sysDicList", Dict.getInstance().getDic(Constants.CSKEFU_SYSTEM_DIC));
return request(super.createView("/admin/system/template/index"));
}
@RequestMapping("/expall")
@Menu(type = "admin" , subtype = "template" , access = false , admin = true)
public void expall(ModelMap map , HttpServletRequest request , HttpServletResponse response) throws Exception {
List<Template> templateList = templateRes.findByOrgi(super.getOrgi(request)) ;
response.setHeader("content-disposition", "attachment;filename=CSKeFu-Template-Export-"+new SimpleDateFormat("yyyy-MM-dd").format(new Date())+".data");
response.getOutputStream().write(MainUtils.toBytes(templateList));
return ;
@Menu(type = "admin", subtype = "template", admin = true)
public void expall(ModelMap map, HttpServletRequest request, HttpServletResponse response) throws Exception {
List<Template> templateList = templateRes.findAll();
response.setHeader("content-disposition", "attachment;filename=CSKeFu-Template-Export-" + new SimpleDateFormat("yyyy-MM-dd").format(new Date()) + ".data");
response.getOutputStream().write(MainUtils.toBytes(templateList));
return;
}
@RequestMapping("/imp")
@Menu(type = "admin" , subtype = "template" , access = false , admin = true)
public ModelAndView imp(ModelMap map , HttpServletRequest request) {
@Menu(type = "admin", subtype = "template", admin = true)
public ModelAndView imp(ModelMap map, HttpServletRequest request) {
return request(super.createView("/admin/system/template/imp"));
}
@SuppressWarnings("unchecked")
@RequestMapping("/impsave")
@Menu(type = "admin" , subtype = "template" , access = false , admin = true)
public ModelAndView impsave(ModelMap map , HttpServletRequest request , @RequestParam(value = "dataFile", required = false) MultipartFile dataFile) throws Exception {
if(dataFile!=null && dataFile.getSize() > 0){
List<Template> templateList = (List<Template>) MainUtils.toObject(dataFile.getBytes()) ;
if(templateList!=null && templateList.size() >0){
templateRes.deleteInBatch(templateList);
for(Template template : templateList){
templateRes.save(template) ;
}
}
}
return request(super.createView("redirect:/admin/template/index.html"));
@RequestMapping("/impsave")
@Menu(type = "admin", subtype = "template", admin = true)
public ModelAndView impsave(ModelMap map, HttpServletRequest request, @RequestParam(value = "dataFile", required = false) MultipartFile dataFile) throws Exception {
if (dataFile != null && dataFile.getSize() > 0) {
List<Template> templateList = (List<Template>) MainUtils.toObject(dataFile.getBytes());
if (templateList != null && templateList.size() > 0) {
templateRes.deleteInBatch(templateList);
for (Template template : templateList) {
templateRes.save(template);
}
}
}
return request(super.createView("redirect:/admin/template/index.html"));
}
@RequestMapping("/list")
@Menu(type = "admin" , subtype = "template" , access = false , admin = true)
public ModelAndView list(ModelMap map , HttpServletRequest request ,@Valid String type) {
map.addAttribute("sysDic", dicRes.findById(type));
map.addAttribute("templateList", templateRes.findByTemplettypeAndOrgi(type, super.getOrgi(request)));
@Menu(type = "admin", subtype = "template", admin = true)
public ModelAndView list(ModelMap map, HttpServletRequest request, @Valid String type) {
map.addAttribute("sysDic", dicRes.findById(type).orElse(null));
map.addAttribute("templateList", templateRes.findByTemplettype(type));
return request(super.createView("/admin/system/template/list"));
}
@RequestMapping("/add")
@Menu(type = "admin" , subtype = "template" , access = false , admin = true)
public ModelAndView add(ModelMap map , HttpServletRequest request ,@Valid String type) {
map.addAttribute("sysDic", dicRes.findById(type));
@Menu(type = "admin", subtype = "template", admin = true)
public ModelAndView add(ModelMap map, HttpServletRequest request, @Valid String type) {
map.addAttribute("sysDic", dicRes.findById(type).orElse(null));
return request(super.createView("/admin/system/template/add"));
}
@RequestMapping( "/save")
@Menu(type = "admin" , subtype = "template" , access = false , admin = true)
public ModelAndView save(HttpServletRequest request , @Valid Template template) {
template.setOrgi(super.getOrgi(request));
template.setCreatetime(new Date());
SysDic dic = dicRes.findById(template.getTemplettype());
if(dic!=null && StringUtils.isBlank(template.getCode())) {
template.setCode(dic.getCode());
}
templateRes.save(template) ;
return request(super.createView("redirect:/admin/template/list.html?type="+template.getTemplettype()));
@RequestMapping("/save")
@Menu(type = "admin", subtype = "template", admin = true)
public ModelAndView save(HttpServletRequest request, @Valid Template template) {
template.setCreatetime(new Date());
SysDic dic = dicRes.findById(template.getTemplettype()).orElse(null);
if (dic != null && StringUtils.isBlank(template.getCode())) {
template.setCode(dic.getCode());
}
templateRes.save(template);
return request(super.createView("redirect:/admin/template/list.html?type=" + template.getTemplettype()));
}
@RequestMapping("/edit")
@Menu(type = "admin" , subtype = "template" , access = false , admin = true)
public ModelAndView edit(ModelMap map , HttpServletRequest request , @Valid String id, @Valid String type) {
map.addAttribute("sysDic", dicRes.findById(type));
map.addAttribute("template", templateRes.findByIdAndOrgi(id, super.getOrgi(request))) ;
@Menu(type = "admin", subtype = "template", admin = true)
public ModelAndView edit(ModelMap map, HttpServletRequest request, @Valid String id, @Valid String type) {
map.addAttribute("sysDic", dicRes.findById(type).orElse(null));
map.addAttribute("template", templateRes.findById(id).orElse(null));
return request(super.createView("/admin/system/template/edit"));
}
@RequestMapping( "/update")
@Menu(type = "admin" , subtype = "template" , access = false , admin = true)
public ModelAndView update(HttpServletRequest request , @Valid Template template) {
Template oldTemplate = templateRes.findByIdAndOrgi(template.getId(), super.getOrgi(request)) ;
if(oldTemplate!=null){
SysDic dic = dicRes.findById(oldTemplate.getTemplettype());
if(dic!=null) {
oldTemplate.setCode(dic.getCode());
}
if(!StringUtils.isBlank(template.getCode())) {
oldTemplate.setCode(template.getCode());
}
oldTemplate.setName(template.getName());
oldTemplate.setLayoutcols(template.getLayoutcols());
oldTemplate.setIconstr(template.getIconstr());
oldTemplate.setDatatype(template.getDatatype());
oldTemplate.setCharttype(template.getCharttype());
templateRes.save(oldTemplate) ;
cache.deleteSystembyIdAndOrgi(template.getId(), super.getOrgi(request));
}
return request(super.createView("redirect:/admin/template/list.html?type="+template.getTemplettype()));
@RequestMapping("/update")
@Menu(type = "admin", subtype = "template", admin = true)
public ModelAndView update(HttpServletRequest request, @Valid Template template) {
Template oldTemplate = templateRes.findById(template.getId()).orElse(null);
if (oldTemplate != null) {
SysDic dic = dicRes.findById(oldTemplate.getTemplettype()).orElse(null);
if (dic != null) {
oldTemplate.setCode(dic.getCode());
}
if (!StringUtils.isBlank(template.getCode())) {
oldTemplate.setCode(template.getCode());
}
oldTemplate.setName(template.getName());
oldTemplate.setLayoutcols(template.getLayoutcols());
oldTemplate.setIconstr(template.getIconstr());
oldTemplate.setDatatype(template.getDatatype());
oldTemplate.setCharttype(template.getCharttype());
templateRes.save(oldTemplate);
cache.deleteSystembyId(template.getId());
}
return request(super.createView("redirect:/admin/template/list.html?type=" + template.getTemplettype()));
}
@RequestMapping("/code")
@Menu(type = "admin" , subtype = "template" , access = false , admin = true)
public ModelAndView code(ModelMap map , HttpServletRequest request , @Valid String id, @Valid String type) {
map.addAttribute("sysDic", dicRes.findById(type));
map.addAttribute("template", templateRes.findByIdAndOrgi(id, super.getOrgi(request))) ;
@Menu(type = "admin", subtype = "template", admin = true)
public ModelAndView code(ModelMap map, HttpServletRequest request, @Valid String id, @Valid String type) {
map.addAttribute("sysDic", dicRes.findById(type).orElse(null));
map.addAttribute("template", templateRes.findById(id).orElse(null));
return request(super.createView("/admin/system/template/code"));
}
@RequestMapping( "/codesave")
@Menu(type = "admin" , subtype = "template" , access = false , admin = true)
public ModelAndView codesave(HttpServletRequest request , @Valid Template template) {
Template oldTemplate = templateRes.findByIdAndOrgi(template.getId(), super.getOrgi(request)) ;
if(oldTemplate!=null){
oldTemplate.setTemplettext(template.getTemplettext());
oldTemplate.setTemplettitle(template.getTemplettitle());
templateRes.save(oldTemplate) ;
cache.deleteSystembyIdAndOrgi(template.getId(), super.getOrgi(request));
}
return request(super.createView("redirect:/admin/template/list.html?type="+template.getTemplettype()));
@RequestMapping("/codesave")
@Menu(type = "admin", subtype = "template", admin = true)
public ModelAndView codesave(HttpServletRequest request, @Valid Template template) {
Template oldTemplate = templateRes.findById(template.getId()).orElse(null);
if (oldTemplate != null) {
oldTemplate.setTemplettext(template.getTemplettext());
oldTemplate.setTemplettitle(template.getTemplettitle());
templateRes.save(oldTemplate);
cache.deleteSystembyId(template.getId());
}
return request(super.createView("redirect:/admin/template/list.html?type=" + template.getTemplettype()));
}
@RequestMapping("/delete")
@Menu(type = "admin" , subtype = "template" , access = false , admin = true)
public ModelAndView delete(HttpServletRequest request ,@Valid Template template) {
if(template!=null){
templateRes.delete(template) ;
cache.deleteSystembyIdAndOrgi(template.getId(), super.getOrgi(request));
}
return request(super.createView("redirect:/admin/template/list.html?type="+template.getTemplettype()));
@Menu(type = "admin", subtype = "template", admin = true)
public ModelAndView delete(HttpServletRequest request, @Valid Template template) {
if (template != null) {
templateRes.delete(template);
cache.deleteSystembyId(template.getId());
}
return request(super.createView("redirect:/admin/template/list.html?type=" + template.getTemplettype()));
}
}

View File

@ -1,18 +1,16 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.controller.api;
@ -24,7 +22,7 @@ import com.cskefu.cc.basic.MainContext.*;
import com.cskefu.cc.basic.MainUtils;
import com.cskefu.cc.cache.Cache;
import com.cskefu.cc.controller.Handler;
import com.cskefu.cc.controller.api.request.RestUtils;
import com.cskefu.cc.util.restapi.RestUtils;
import com.cskefu.cc.exception.CSKefuException;
import com.cskefu.cc.model.*;
import com.cskefu.cc.peer.PeerSyncIM;
@ -37,10 +35,11 @@ import com.cskefu.cc.util.Menu;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@ -49,8 +48,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import java.util.Date;
import java.util.List;
@ -76,6 +75,7 @@ public class ApiAgentUserController extends Handler {
private Cache cache;
@Autowired
@Lazy
private PeerSyncIM peerSyncIM;
@Autowired
@ -129,7 +129,7 @@ public class ApiAgentUserController extends Handler {
}
}
return new ResponseEntity<String>(json.toString(), headers, HttpStatus.OK);
return new ResponseEntity<>(json.toString(), headers, HttpStatus.OK);
}
/**
@ -142,7 +142,6 @@ public class ApiAgentUserController extends Handler {
*/
private JsonObject transout(final HttpServletRequest request, final JsonObject payload) {
logger.info("[transout] payload ", payload.toString());
final String orgi = super.getOrgi(request);
final User logined = super.getUser(request);
JsonObject resp = new JsonObject();
@ -159,15 +158,15 @@ public class ApiAgentUserController extends Handler {
if (StringUtils.isNotBlank(agentUserId) &&
StringUtils.isNotBlank(transAgentId) &&
StringUtils.isNotBlank(agentServiceId)) {
final User targetAgent = userRes.findOne(transAgentId);
final AgentService agentService = agentServiceRes.findByIdAndOrgi(agentServiceId, orgi);
final User targetAgent = userRes.findById(transAgentId).orElse(null);
final AgentService agentService = agentServiceRes.findById(agentServiceId).orElse(null);
/**
* 更新AgentUser
*/
final AgentUser agentUser = agentUserProxy.findOne(agentUserId).orElseGet(null);
if (agentUser != null) {
final AgentUserAudit agentAudits = cache.findOneAgentUserAuditByOrgiAndId(orgi, agentUserId).orElseGet(
final AgentUserAudit agentAudits = cache.findOneAgentUserAuditById(agentUserId).orElseGet(
null);
// 当前服务于访客的坐席
@ -200,18 +199,18 @@ public class ApiAgentUserController extends Handler {
* 坐席状态
*/
// 转接目标坐席
final AgentStatus transAgentStatus = cache.findOneAgentStatusByAgentnoAndOrig(transAgentId, orgi);
final AgentStatus transAgentStatus = cache.findOneAgentStatusByAgentno(transAgentId);
// 转接源坐席
final AgentStatus currentAgentStatus = cache.findOneAgentStatusByAgentnoAndOrig(currentAgentno, orgi);
final AgentStatus currentAgentStatus = cache.findOneAgentStatusByAgentno(currentAgentno);
if (StringUtils.equals(
AgentUserStatusEnum.INSERVICE.toString(),
agentUser.getStatus())) { //转接 发送消息给 目标坐席
// 更新当前坐席的服务访客列表
if (currentAgentStatus != null) {
cache.deleteOnlineUserIdFromAgentStatusByUseridAndAgentnoAndOrgi(userId, currentAgentno, orgi);
agentUserProxy.updateAgentStatus(currentAgentStatus, orgi);
cache.deleteOnlineUserIdFromAgentStatusByUseridAndAgentno(userId, currentAgentno);
agentUserProxy.updateAgentStatus(currentAgentStatus);
}
if (transAgentStatus != null) {
@ -222,7 +221,7 @@ public class ApiAgentUserController extends Handler {
// 转接坐席提示消息
Message outMessage = new Message();
outMessage.setMessage(
acdMessageHelper.getSuccessMessage(agentService, agentUser.getChannel(), orgi));
acdMessageHelper.getSuccessMessage(agentService, agentUser.getChanneltype()));
outMessage.setMessageType(MediaType.TEXT.toString());
outMessage.setCalltype(CallType.IN.toString());
outMessage.setCreatetime(MainUtils.dateFormate.format(new Date()));
@ -232,7 +231,7 @@ public class ApiAgentUserController extends Handler {
if (StringUtils.isNotBlank(agentUser.getUserid())) {
peerSyncIM.send(
ReceiverType.VISITOR,
ChannelType.toValue(agentUser.getChannel()),
ChannelType.toValue(agentUser.getChanneltype()),
agentUser.getAppid(),
MessageType.STATUS,
agentUser.getUserid(),
@ -254,8 +253,8 @@ public class ApiAgentUserController extends Handler {
// 该登录用户可能是坐席监控或当前坐席那么如果是坐席监控就有必要
// 通知前坐席这个事件
peerSyncIM.send(ReceiverType.AGENT, ChannelType.WEBIM, agentUser.getAppid(),
MessageType.TRANSOUT,
currentAgentno, outMessage, true);
MessageType.TRANSOUT,
currentAgentno, outMessage, true);
}
}
@ -293,17 +292,16 @@ public class ApiAgentUserController extends Handler {
*/
private JsonObject end(final HttpServletRequest request, final JsonObject payload) {
logger.info("[end] payload {}", payload.toString());
final String orgi = super.getOrgi(request);
final User logined = super.getUser(request);
JsonObject resp = new JsonObject();
final AgentUser agentUser = agentUserRes.findByIdAndOrgi(payload.get("id").getAsString(), orgi);
final AgentUser agentUser = agentUserRes.findById(payload.get("id").getAsString()).orElse(null);
if (agentUser != null) {
if ((StringUtils.equals(
logined.getId(), agentUser.getAgentno()) || logined.isAdmin())) {
// 删除访客-坐席关联关系包括缓存
try {
acdAgentService.finishAgentUser(agentUser, orgi);
acdAgentService.finishAgentUser(agentUser);
} catch (CSKefuException e) {
// 未能删除成功
logger.error("[end]", e);
@ -335,7 +333,6 @@ public class ApiAgentUserController extends Handler {
JsonObject resp = new JsonObject();
ACDComposeContext ctx = new ACDComposeContext();
ctx.setAgentno(super.getUser(request).getId());
ctx.setOrgi(super.getOrgi(request));
acdAgentDispatcher.dequeue(ctx);
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_SUCC);
return resp;
@ -354,15 +351,15 @@ public class ApiAgentUserController extends Handler {
JsonObject resp = new JsonObject();
JsonArray data = new JsonArray();
List<AgentUser> lis = cache.findInservAgentUsersByAgentnoAndOrgi(
super.getUser(request).getId(), super.getOrgi(request));
List<AgentUser> lis = cache.findInservAgentUsersByAgentno(
super.getUser(request).getId());
for (final AgentUser au : lis) {
JsonObject obj = new JsonObject();
obj.addProperty("id", au.getId());
obj.addProperty("userid", au.getUserid());
obj.addProperty("status", au.getStatus());
obj.addProperty("agentno", au.getAgentno());
obj.addProperty("channel", au.getChannel());
obj.addProperty("channel", au.getChanneltype());
obj.addProperty("nickname", au.getNickname());
data.add(obj);
}

View File

@ -1,27 +1,28 @@
/*
* Copyright (C) 2018-2022 Chatopera Inc, All rights reserved.
* <https://www.chatopera.com>
* This software and related documentation are provided under a license agreement containing
* restrictions on use and disclosure and are protected by intellectual property laws.
* Except as expressly permitted in your license agreement or allowed by law, you may not use,
* copy, reproduce, translate, broadcast, modify, license, transmit, distribute, exhibit, perform,
* publish, or display any part, in any form, or by any means. Reverse engineering, disassembly,
* or decompilation of this software, unless required by law for interoperability, is prohibited.
/**
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright 2018-Jun. 2023 Chatopera Inc. <https://www.chatopera.com>. All rights reserved.
*/
package com.cskefu.cc.controller.api;
import com.cskefu.cc.basic.MainContext;
import com.cskefu.cc.controller.Handler;
import com.cskefu.cc.controller.api.request.RestUtils;
import com.cskefu.cc.util.restapi.RestUtils;
import com.cskefu.cc.model.InviteRecord;
import com.cskefu.cc.model.OnlineUser;
import com.cskefu.cc.model.PassportWebIMUser;
import com.cskefu.cc.persistence.repository.InviteRecordRepository;
import com.cskefu.cc.persistence.repository.OnlineUserRepository;
import com.cskefu.cc.persistence.repository.PassportWebIMUserRepository;
import com.cskefu.cc.proxy.OnlineUserProxy;
import com.cskefu.cc.util.Menu;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -33,8 +34,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
@RestController
@RequestMapping("/api/apps")
@ -42,7 +43,7 @@ public class ApiAppsController extends Handler {
private final static Logger logger = LoggerFactory.getLogger(ApiAppsController.class);
@Autowired
private OnlineUserRepository onlineUserRes;
private PassportWebIMUserRepository onlineUserRes;
@Autowired
private InviteRecordRepository inviteRecordRes;
@ -71,7 +72,7 @@ public class ApiAppsController extends Handler {
}
}
return new ResponseEntity<String>(json.toString(), headers, HttpStatus.OK);
return new ResponseEntity<>(json.toString(), headers, HttpStatus.OK);
}
@ -84,31 +85,29 @@ public class ApiAppsController extends Handler {
*/
private JsonObject invite(final HttpServletRequest request, final JsonObject j) {
JsonObject resp = new JsonObject();
final String orgi = super.getOrgi(request);
final String agentno = super.getUser(request).getId();
final String userid = j.get("userid").getAsString();
logger.info("[invite] agentno {} invite onlineUser {}", agentno, userid);
OnlineUser onlineUser = OnlineUserProxy.onlineuser(userid, orgi);
PassportWebIMUser passportWebIMUser = OnlineUserProxy.onlineuser(userid);
if (onlineUser != null) {
logger.info("[invite] userid {}, agentno {}, orgi {}", userid, agentno, orgi);
onlineUser.setInvitestatus(MainContext.OnlineUserInviteStatus.INVITE.toString());
onlineUser.setInvitetimes(onlineUser.getInvitetimes() + 1);
onlineUserRes.save(onlineUser);
if (passportWebIMUser != null) {
logger.info("[invite] userid {}, agentno {}", userid, agentno);
passportWebIMUser.setInvitestatus(MainContext.OnlineUserInviteStatus.INVITE.toString());
passportWebIMUser.setInvitetimes(passportWebIMUser.getInvitetimes() + 1);
onlineUserRes.save(passportWebIMUser);
InviteRecord record = new InviteRecord();
record.setAgentno(super.getUser(request).getId());
// 对于OnlineUser, 其userId与id是相同的
record.setUserid(onlineUser.getUserid());
record.setAppid(onlineUser.getAppid());
record.setOrgi(super.getOrgi(request));
record.setUserid(passportWebIMUser.getUserid());
record.setAppid(passportWebIMUser.getAppid());
inviteRecordRes.save(record);
logger.info("[invite] new invite record {} of onlineUser id {} saved.", record.getId(), onlineUser.getId());
logger.info("[invite] new invite record {} of onlineUser id {} saved.", record.getId(), passportWebIMUser.getId());
try {
OnlineUserProxy.sendWebIMClients(onlineUser.getUserid(), "invite:" + agentno);
OnlineUserProxy.sendWebIMClients(passportWebIMUser.getUserid(), "invite:" + agentno);
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_SUCC);
} catch (Exception e) {
logger.error("[invite] error", e);

View File

@ -1,18 +1,16 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2018- Jun. 2023 Chatopera Inc, <https://www.chatopera.com>, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
* Copyright (C) 2017 优客服-多渠道客服系统, Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.controller.api;
@ -31,8 +29,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
/**
* 获取对话内容
@ -40,26 +38,27 @@ import javax.validation.Valid;
*/
@RestController
@RequestMapping("/api/chatmessage")
public class ApiChatMessageController extends Handler{
@Autowired
private ChatMessageRepository chatMessageRes ;
public class ApiChatMessageController extends Handler {
/**
* 获取访客对话内容
* @param request
* @param serviceid AgentServiceID
* @return
*/
@RequestMapping( method = RequestMethod.GET)
@Menu(type = "apps" , subtype = "agentuser" , access = true)
public ResponseEntity<RestResult> list(HttpServletRequest request , @Valid String serviceid) {
ResponseEntity<RestResult> result = null ;
if(!StringUtils.isBlank(serviceid)) {
result = new ResponseEntity<>(new RestResult(RestResultType.OK , chatMessageRes.findByAgentserviceidAndOrgi(serviceid , super.getUser(request).getOrgi(),new PageRequest(super.getP(request), super.getPs(request) , Sort.Direction.DESC, "createtime"))), HttpStatus.OK) ;
}else {
result = new ResponseEntity<>(new RestResult(RestResultType.LACKDATA , RestResultType.LACKDATA.getMessage()), HttpStatus.OK) ;
}
return result ;
@Autowired
private ChatMessageRepository chatMessageRes;
/**
* 获取访客对话内容
*
* @param request
* @param serviceid AgentServiceID
* @return
*/
@RequestMapping(method = RequestMethod.GET)
@Menu(type = "apps", subtype = "agentuser", access = true)
public ResponseEntity<RestResult> list(HttpServletRequest request, @Valid String serviceid) {
ResponseEntity<RestResult> result = null;
if (!StringUtils.isBlank(serviceid)) {
result = new ResponseEntity<>(new RestResult(RestResultType.OK, chatMessageRes.findByAgentserviceid(serviceid, PageRequest.of(super.getP(request), super.getPs(request), Sort.Direction.DESC, "createtime"))), HttpStatus.OK);
} else {
result = new ResponseEntity<>(new RestResult(RestResultType.LACKDATA, RestResultType.LACKDATA.getMessage()), HttpStatus.OK);
}
return result;
}
}

View File

@ -1,28 +1,26 @@
/*
* Copyright (C) 2018-2022 Chatopera Inc, <https://www.chatopera.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright (C) 2019-Jun. 2023 Chatopera Inc, <https://www.chatopera.com>,
* Licensed under the Apache License, Version 2.0,
* http://www.apache.org/licenses/LICENSE-2.0
*/
package com.cskefu.cc.controller.api;
import com.cskefu.cc.basic.Constants;
import com.cskefu.cc.basic.MainUtils;
import com.cskefu.cc.controller.Handler;
import com.cskefu.cc.controller.api.request.RestUtils;
import com.cskefu.cc.util.restapi.RestUtils;
import com.cskefu.cc.exception.CSKefuRestException;
import com.cskefu.cc.model.*;
import com.cskefu.cc.persistence.es.ContactNotesRepository;
import com.cskefu.cc.persistence.es.ContactsRepository;
import com.cskefu.cc.persistence.repository.ContactNotesRepository;
import com.cskefu.cc.persistence.repository.ContactsRepository;
import com.cskefu.cc.persistence.repository.OrganRepository;
import com.cskefu.cc.persistence.repository.OrganUserRepository;
import com.cskefu.cc.persistence.repository.UserRepository;
@ -31,7 +29,7 @@ import com.cskefu.cc.util.json.GsonTools;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -45,7 +43,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;
@ -86,12 +84,12 @@ public class ApiContactNotesController extends Handler {
private JsonObject creater(final String creater) {
JsonObject data = new JsonObject();
// 增加创建人
User u = userRes.findById(creater);
User u = userRes.findById(creater).orElse(null);
if (u != null) {
data.addProperty("creater", u.getId());
data.addProperty("creatername", u.getUname());
final List<OrganUser> organs = organUserRes.findByUseridAndOrgi(u.getId(), u.getOrgi());
final List<OrganUser> organs = organUserRes.findByUserid(u.getId());
// 获取创建者部门
@ -100,7 +98,7 @@ public class ApiContactNotesController extends Handler {
JsonArray y = new JsonArray();
for (final OrganUser organ : organs) {
Organ o = organRes.findOne(organ.getOrgan());
Organ o = organRes.findById(organ.getOrgan()).orElse(null);
if (o != null) {
JsonObject x = new JsonObject();
x.addProperty("createrorgan", o.getName());
@ -127,7 +125,7 @@ public class ApiContactNotesController extends Handler {
JsonObject resp = new JsonObject();
// TODO 增加权限检查
if (j.has("id") && StringUtils.isNotBlank(j.get("id").getAsString())) {
ContactNotes cn = contactNotesRes.findOne(j.get("id").getAsString());
ContactNotes cn = contactNotesRes.findById(j.get("id").getAsString()).orElse(null);
if (cn != null) {
JsonObject data = new JsonObject();
data.addProperty("contactid", cn.getContactid());
@ -170,7 +168,6 @@ public class ApiContactNotesController extends Handler {
cn.setCategory(payload.get("category").getAsString());
cn.setContent(payload.get("content").getAsString());
cn.setCreater(payload.get("creater").getAsString());
cn.setOrgi(payload.get("orgi").getAsString());
cn.setContactid(payload.get("contactid").getAsString());
cn.setDatastatus(false);
@ -214,7 +211,7 @@ public class ApiContactNotesController extends Handler {
if ((!payload.has("contactid")) || StringUtils.isBlank(payload.get("contactid").getAsString())) {
return "参数传递不合法,没有[contactid]。";
} else {
Contacts c = contactsRes.findOne(payload.get("contactid").getAsString());
Contacts c = contactsRes.findById(payload.get("contactid").getAsString()).orElse(null);
if (c == null)
return "参数不合法,不存在该联系人。";
}
@ -230,12 +227,6 @@ public class ApiContactNotesController extends Handler {
*/
private String querybuilder(final JsonObject j) {
StringBuffer sb = new StringBuffer();
if (j.has("orgi")) {
sb.append("orgi:");
sb.append(j.get("orgi").getAsString());
sb.append(" ");
}
return sb.toString();
}
@ -255,7 +246,7 @@ public class ApiContactNotesController extends Handler {
return resp;
}
final String cid = j.get("contactid").getAsString();
Contacts c = contactsRes.findOne(cid);
Contacts c = contactsRes.findById(cid).orElse(null);
if (c == null) {
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_4);
@ -265,8 +256,7 @@ public class ApiContactNotesController extends Handler {
String q = querybuilder(j);
Page<ContactNotes> cns = contactNotesRes.findByContactidAndOrgiOrderByCreatetimeDesc(cid,
q, new PageRequest(super.getP(request), super.getPs(request)));
Page<ContactNotes> cns = contactNotesRes.findByContactidOrderByCreatetimeDesc(cid, PageRequest.of(super.getP(request), super.getPs(request)));
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_SUCC);
resp.addProperty("size", cns.getSize());
@ -312,7 +302,6 @@ public class ApiContactNotesController extends Handler {
JsonObject json = new JsonObject();
HttpHeaders headers = RestUtils.header();
j.addProperty("creater", super.getUser(request).getId());
j.addProperty("orgi", Constants.SYSTEM_ORGI);
if (!j.has("ops")) {
json.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_1);
@ -334,7 +323,7 @@ public class ApiContactNotesController extends Handler {
break;
}
}
return new ResponseEntity<String>(json.toString(), headers, HttpStatus.OK);
return new ResponseEntity<>(json.toString(), headers, HttpStatus.OK);
}

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