1
0
mirror of https://github.com/chatopera/cosin.git synced 2025-06-16 18:30:03 +08:00

Release new version 5.0.0

This commit is contained in:
Hai Liang Wang 2019-11-06 11:28:37 +08:00
parent 4e764b6c0a
commit e7b233dafd
641 changed files with 2246 additions and 10758 deletions

View File

@ -1,20 +0,0 @@
pipeline:
build-contact-center:
group: build
image: plugins/docker
context: contact-center
dockerfile: contact-center/Dockerfile
repo: chatopera/contact-center
tags: develop
secrets: [ docker_username, docker_password ]
build-cc-switch:
group: build
image: plugins/docker
context: cc-switch/app
dockerfile: cc-switch/app/Dockerfile
repo: chatopera/cc-switch
tags: develop
secrets: [ docker_username, docker_password ]
branches: develop

1
.gitignore vendored
View File

@ -19,3 +19,4 @@ backups/
.env
build.gradle
.vscode/
private

15
.vscode/sftp.json vendored
View File

@ -1,15 +0,0 @@
{
"name": "sftp",
"remotePath": "git/cosinee",
"protocol": "sftp",
"uploadOnSave": true,
"port": 22,
"profiles": {
"gamera": {
"name": "gamera",
"host": "gamera",
"username": "hain",
"privateKeyPath": "/Users/hain/.ssh/id_rsa"
}
}
}

249
README.md
View File

@ -1,8 +1,247 @@
# 春松客服企业版
[![Docker Layers](https://images.microbadger.com/badges/image/chatopera/contact-center:develop.svg)](https://microbadger.com/images/chatopera/contact-center:develop "Get your own image badge on microbadger.com") [![Docker Version](https://images.microbadger.com/badges/version/chatopera/contact-center:develop.svg)](https://microbadger.com/images/chatopera/contact-center:develop "Get your own version badge on microbadger.com") [![Docker Pulls](https://img.shields.io/docker/pulls/chatopera/contact-center.svg)](https://hub.docker.com/r/chatopera/contact-center/) [![Docker Stars](https://img.shields.io/docker/stars/chatopera/contact-center.svg)](https://hub.docker.com/r/chatopera/contact-center/) [![Docker Commit](https://images.microbadger.com/badges/commit/chatopera/contact-center:develop.svg)](https://microbadger.com/images/chatopera/contact-center:develop "Get your own commit badge on microbadger.com")
https://gitlab.chatopera.com/chatopera
<p align="center">
<b>春松客服QQ交流群185659917 <a href="https://jq.qq.com/?_wv=1027&k=5I1cJLP" target="_blank">点击链接加入群聊</a></b><br>
<img src="https://user-images.githubusercontent.com/3538629/44917177-432d9700-ad6a-11e8-9420-46b0281073e6.png" width="200">
</p>
## License
# 春松客服: 全渠道智能客服
Copyright 2019 北京华夏春松科技有限公司 <https://www.chatopera.com>. All rights reserved.
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.
春松客服是帮助中小型企业快速而低成本的获得好用的智能客服系统。
<img src="https://user-images.githubusercontent.com/3538629/61031891-fc311900-a3f2-11e9-80cf-c8d0700538a0.png" width="600">
春松客服是 Chatopera 自主研发以及基于且增强其它开源软件的方式实现的,春松客服会不断增强客服系统的智能化,这包括利用自然语言处理、机器学习和语音识别等技术让客服工作更有效率、客服满意度更高、成本更低。
**开源项目地址:** [https://github.com/chatopera/cosin](https://github.com/chatopera/cosin)
**开发环境搭建:** [https://github.com/chatopera/cosin/wiki/春松客服:开发环境](https://github.com/chatopera/cosin/wiki/%E6%98%A5%E6%9D%BE%E5%AE%A2%E6%9C%8D%EF%BC%9A%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83)
## 内容结构
[产品演示](https://github.com/chatopera/cosin#%E4%BA%A7%E5%93%81%E6%BC%94%E7%A4%BA)
[功能](https://github.com/chatopera/cosin#%E5%8A%9F%E8%83%BD)
[开发文档](https://github.com/chatopera/cosin#%E5%BC%80%E5%8F%91%E6%96%87%E6%A1%A3)
[产品截图](https://github.com/chatopera/cosin#%E4%BA%A7%E5%93%81%E6%88%AA%E5%9B%BE)
[产品体系](https://github.com/chatopera/cosin#%E4%BA%A7%E5%93%81%E4%BD%93%E7%B3%BB)
[立即部署](https://github.com/chatopera/cosin#%E7%AB%8B%E5%8D%B3%E9%83%A8%E7%BD%B2)
[鸣谢](https://github.com/chatopera/cosin#%E9%B8%A3%E8%B0%A2)
[开源许可协议](https://github.com/chatopera/cosin#%E5%BC%80%E6%BA%90%E8%AE%B8%E5%8F%AF%E5%8D%8F%E8%AE%AE)
## 产品演示
- 坐席工作台
[http://cc.chatopera.com/](http://cc.chatopera.com/)
| **登录账号** | **密码** |
| ------------ | --------- |
| admin | admin1234 |
- 网页端访客程序
[http://cc.chatopera.com/testclient.html](http://cc.chatopera.com/testclient.html)
## 功能
- 账号及组织机构管理:按组织、角色分配账号权限
- 联系人管理:细粒度维护客户信息
- 网页聊天组件:一分钟接入对话窗口
- 坐席工作台:汇聚多渠道访客请求
- 机器人客服:集成机器人平台服务,完成多轮对话和知识库问答
- 外呼系统:自动外呼,手动外呼,监听和报表等
<b> 《春松客服产品系列视频》 </b>
<table align="center">
<tr>
<th>序号</th>
<th>内容</th>
<th>腾讯视频</th>
<th>百度网盘</th>
</tr>
<tr>
<td>No. 1</td>
<td>产品概述</td>
<td><a href="https://v.qq.com/x/page/z0776g0osqu.html" target="_blank">观看</a></td>
<td><a href="https://pan.baidu.com/s/1BzUveFSkCtfyeU1gUIjp1Q" target="_blank">下载</a></td>
</tr>
<tr>
<td>No. 2</td>
<td>安装部署</td>
<td><a href="https://v.qq.com/x/page/b07760u7f8t.html" target="_blank">观看</a></td>
<td><a href="https://pan.baidu.com/s/1CnZBIIuWpDWATjKTMluzUA" target="_blank">下载</a></td>
</tr>
<tr>
<td>No. 3</td>
<td>功能演示</td>
<td><a href="https://v.qq.com/x/page/h077670ceg2.html" target="_blank">观看</a></td>
<td><a href="https://pan.baidu.com/s/1bCAqUWwk_KQGyfUyvUMt9w" target="_blank">下载</a></td>
</tr>
<tr>
<td>No. 4</td>
<td>账号体系</td>
<td><a href="https://v.qq.com/x/page/b0776jwl6w1.html" target="_blank">观看</a></td>
<td><a href="https://pan.baidu.com/s/18QA9jvXYtwa8Zt78Di9wrg" target="_blank">下载</a></td>
</tr>
<tr>
<td>No. 5</td>
<td>客户关系管理</td>
<td><a href="https://v.qq.com/x/page/d0776p8ghpr.html" target="_blank">观看</a></td>
<td><a href="https://pan.baidu.com/s/1stfkufWkF4byWqvF-ch9Dw" target="_blank">下载</a></td>
</tr>
<tr>
<td>No. 6</td>
<td>即时通信</td>
<td><a href="https://v.qq.com/x/page/r0776rdgt6z.html" target="_blank">观看</a></td>
<td><a href="https://pan.baidu.com/s/1eYEO5OtVu0gyxDI9a-xqJQ" target="_blank">下载</a></td>
</tr>
<tr>
<td>No. 7</td>
<td>呼叫中心</td>
<td><a href="https://v.qq.com/x/page/i07785u58jm.html" target="_blank">观看</a></td>
<td><a href="https://pan.baidu.com/s/1qQOSNMHgcNdXuq0Xib1wXA" target="_blank">下载</a></td>
</tr>
<tr>
<td>No. 8</td>
<td>数据报表</td>
<td><a href="https://v.qq.com/x/page/e0778ptg6b0.html" target="_blank">观看</a></td>
<td><a href="https://pan.baidu.com/s/1iQOz9HR3dkO4lgf5VI4CVw" target="_blank">下载</a></td>
</tr>
</table>
[_下载视频合集_](https://pan.baidu.com/s/1YH7d7nMm5wZQp7P8kID3KA)
## 使用说明
关于产品的具体使用说明,请参考[文档中心](https://docs.chatopera.com/omni-channel-customer-support-system.html)。
## 来自真实用户的反馈
```
项目代码写的挺好的,容易维护,是不错的开源项目。
```
-- 海洋 (深圳银之杰项目经理)
```
Amazing! 要的就是这个效果。
```
-- 常经理 (某电器世界五百强企业)
```
我要在APP内集成我看了好多项目了就你们这个最好基本就是一个商用化的项目。
```
-- Engine X (某二手车出售平台技术负责人)
## 开发文档
<p align="center">
<b><a href="https://github.com/chatopera/cosin/wiki" target="_blank">开发文档</a></b><br>
<a href="https://github.com/chatopera/cosin/wiki" target="_blank">
<img src="https://user-images.githubusercontent.com/3538629/44992890-38be0800-afcb-11e8-8fde-a5a671d29764.png" width="300">
</a>
</p>
## 产品截图
<p align="center">
<b>欢迎页</b><br>
<img src="https://user-images.githubusercontent.com/3538629/44915395-6bff5d80-ad65-11e8-817a-8abb812fb5ee.png" width="900">
</p>
<p align="center">
<b>坐席工作台</b><br>
<img src="https://user-images.githubusercontent.com/3538629/44915582-eb8d2c80-ad65-11e8-8876-86c8b5bb5cc7.png" width="900">
</p>
<p align="center">
<b>坐席监控</b><br>
<img src="https://user-images.githubusercontent.com/3538629/44915711-432b9800-ad66-11e8-899b-1ea02244925d.png" width="900">
</p>
<p align="center">
<b>外呼计划</b><br>
<img src="https://user-images.githubusercontent.com/3538629/44915831-ab7a7980-ad66-11e8-88a5-a2cd23b8c689.png" width="900">
</p>
<p align="center">
<b>通话记录</b><br>
<img src="https://user-images.githubusercontent.com/3538629/44915218-feebc800-ad64-11e8-90fc-36ce96b0c09a.png" width="900">
</p>
<p align="center">
<b>集成客服机器人</b><br>
<img src="https://user-images.githubusercontent.com/3538629/51080565-4b82df00-1719-11e9-8cc4-dbbec0459224.png" width="900">
</p>
<p align="center">
<b>客服机器人应答</b><br>
<img src="https://user-images.githubusercontent.com/3538629/51080567-50479300-1719-11e9-85d8-d209370c9d10.png" width="900">
</p>
<p align="center">
<b>更多功能,敬请期待 ...</b><br>
<img src="https://user-images.githubusercontent.com/3538629/44916014-28a5ee80-ad67-11e8-936a-a2cdbe62f529.png" width="900">
</p>
## 产品体系
<p align="center">
<b>观看视频介绍</b><br>
<a href="https://pan.baidu.com/s/1tqxqfYSvtjDGhh6bDQ-Vog" target="_blank">
<img src="https://user-images.githubusercontent.com/3538629/45403926-6a039b80-b68f-11e8-86e2-5d1f04e3a7c7.png" width="900">
</a>
</p>
## 立即部署
- 企业版
通过青云 AppCenter 部署,青云 AppCenter 是开发运维一体化(DevOps)管理企业应用的平台Chatopera 的春松客服在 2018 年 10 月登录 AppCenter并借助 PaaS 平台强大的计算能力实现计算节点集群、存储节点 HADR。从而保证了服务高可靠性、高性能、动态伸缩、一键备份和一键回滚等功能。
青云 AppCenter 以其提供的资源秒级计算特点,企业使用 AppCenter 中的春松客服应用可以按需付费灵活升配和降配Chatopera 也非常推荐客户使用青云服务。
<p align="center">
<b>春松客服 on QingCloud</b><br>
<a href="https://appcenter.qingcloud.com/apps/app-zdh88kz7/%E6%98%A5%E6%9D%BE%E5%AE%A2%E6%9C%8D" target="_blank">
<img src="https://user-images.githubusercontent.com/3538629/47984143-a17f4900-e110-11e8-95c9-d8302e000c34.png" width="900">
</a>
</p>
更为详细的部署文档见[春松客服上架青云 AppCenter](https://github.com/chatopera/cosin/wiki/%E6%98%A5%E6%9D%BE%E5%AE%A2%E6%9C%8D%E4%B8%8A%E6%9E%B6%E9%9D%92%E4%BA%91AppCenter)。
- 社区版
参考部署[开源社区版本文档](https://github.com/chatopera/cosin/wiki/%E6%9C%8D%E5%8A%A1%E5%99%A8%E9%83%A8%E7%BD%B2)。
## 鸣谢
[优客服](https://gitee.com/beimigame/ukefu)
[FreeSWITCH 中国社区](http://www.freeswitch.org.cn/)
## 开源许可协议
Copyright (2018) <a href="https://www.chatopera.com/" target="_blank">北京华夏春松科技有限公司</a>
[Apache License Version 2.0](https://github.com/chatopera/cosin/blob/master/LICENSE)
[![chatoper banner][co-banner-image]][co-url]
[co-banner-image]: https://user-images.githubusercontent.com/3538629/42383104-da925942-8168-11e8-8195-868d5fcec170.png
[co-url]: https://www.chatopera.com

18
cc-chatbot/.gitignore vendored
View File

@ -1,18 +0,0 @@
*.swp
*.swo
*.sublime-*
*.pyc
jmeter.log
__pycache__
tmp/
node_modules/
sftp-config.json
.DS_Store
*.iml
*.ipr
*.iws
*.idea
~$*.xls*
~$*.ppt*
~$*.doc*
app/target/

View File

@ -1,73 +0,0 @@
# cc-chatbot
Chatopera智能问答引擎的Java SDK.
https://docs.chatopera.com/
支持
* 创建聊天机器人
* 查询聊天机器人列表
* 更新聊天机器人画像
* 查询聊天机器人使用情况
* 管理和检索多轮对话
* 管理和检索知识库
* 检索意图识别
# 配置
使用maven需要配置Chatopera的Nexus OSS仓库具体见[文档](https://github.com/chatopera/cosin/wiki/%E6%98%A5%E6%9D%BE%E5%AE%A2%E6%9C%8D%EF%BC%9A%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83#%E4%BF%AE%E6%94%B9maven2%E9%85%8D%E7%BD%AE)。
```
<dependency>
<groupId>com.chatopera.chatbot</groupId>
<artifactId>sdk</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
```
# API
## Chatbot v1
聊天机器人类,构造参数(tcp协议hostname, 端口, 版本)
### Chatbot#getChatbots
获取聊天机器人列表,支持检索查询,分页
### Chatbot#getChatbot
通过聊天机器人ID获得聊天机器人详情
### Chatbot#conversation
与指定的聊天机器人进行多轮对话
### Chatbot#faq
与指定的聊天机器人进行知识库问答
# 测试
```
mvn test
```
# 示例
```
Chatbot cb = new Chatbot("http", "lhc-dev", 8003, "v1");
JSONObject resp = cb.conversation("co_bot_1", "sdktest", "华夏春松在哪里", false);
```
返回值参考 [智能问答引擎文档](https://docs.chatopera.com/chatbot-engine.html)。
## 开源许可协议
Copyright (2018) <a href="https://www.chatopera.com/" target="_blank">北京华夏春松科技有限公司</a>
[Apache License Version 2.0](https://github.com/chatopera/cosin/blob/master/LICENSE)
[![chatoper banner][co-banner-image]][co-url]
[co-banner-image]: https://user-images.githubusercontent.com/3538629/42383104-da925942-8168-11e8-8195-868d5fcec170.png
[co-url]: https://www.chatopera.com

View File

@ -1,13 +0,0 @@
#! /bin/bash
###########################################
#
###########################################
# constants
baseDir=$(cd `dirname "$0"`;pwd)
# functions
# main
[ -z "${BASH_SOURCE[0]}" -o "${BASH_SOURCE[0]}" = "$0" ] || return
cd $baseDir/../app
mvn clean deploy -Dmaven.test.skip=true

View File

@ -1,13 +0,0 @@
#! /bin/bash
###########################################
#
###########################################
# constants
baseDir=$(cd `dirname "$0"`;pwd)
# functions
# main
[ -z "${BASH_SOURCE[0]}" -o "${BASH_SOURCE[0]}" = "$0" ] || return
cd $baseDir/../app
mvn idea:idea

View File

@ -1,13 +0,0 @@
#! /bin/bash
###########################################
#
###########################################
# constants
baseDir=$(cd `dirname "$0"`;pwd)
# functions
# main
[ -z "${BASH_SOURCE[0]}" -o "${BASH_SOURCE[0]}" = "$0" ] || return
cd $baseDir/../app
mvn package

View File

@ -1,13 +0,0 @@
#! /bin/bash
###########################################
#
###########################################
# constants
baseDir=$(cd `dirname "$0"`;pwd)
# functions
# main
[ -z "${BASH_SOURCE[0]}" -o "${BASH_SOURCE[0]}" = "$0" ] || return
cd $baseDir/../app
mvn test

View File

@ -1,44 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="target/generated-sources/annotations">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="m2e-apt" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="m2e-apt" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>sdk</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

View File

@ -1,4 +0,0 @@
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/test/java=UTF-8
encoding/<project>=UTF-8

View File

@ -1,2 +0,0 @@
eclipse.preferences.version=1
org.eclipse.jdt.apt.aptEnabled=false

View File

@ -1,7 +0,0 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.processAnnotations=disabled
org.eclipse.jdt.core.compiler.release=disabled
org.eclipse.jdt.core.compiler.source=1.8

View File

@ -1,4 +0,0 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

View File

@ -1,141 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.chatopera.chatbot</groupId>
<artifactId>sdk</artifactId>
<version>1.1.0</version>
<packaging>jar</packaging>
<name>sdk</name>
<description>Java SDK for Chatopera Conversational Engine.</description>
<url>https://www.chatopera.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.6</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpasyncclient</artifactId>
<version>4.0.2</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.3.6</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20140107</version>
</dependency>
<dependency>
<groupId>com.mashape.unirest</groupId>
<artifactId>unirest-java</artifactId>
<version>1.4.9</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.0.0</version>
</plugin>
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>2.9</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
<distributionManagement>
<snapshotRepository>
<id>chatopera</id>
<url>http://192.168.2.217:8029/repository/maven-snapshots/</url>
</snapshotRepository>
<repository>
<id>chatopera</id>
<url>http://192.168.2.217:8029/repository/maven-releases/</url>
</repository>
</distributionManagement>
<developers>
<developer>
<id>hain</id>
<name>Hai Liang Wang</name>
<email>hailiang.hl.wang@gmail.com</email>
<url>https://github.com/Samurais</url>
<organization>Chatopera Inc.</organization>
<organizationUrl>http://www.chatopera.com</organizationUrl>
<roles>
<role>architect</role>
<role>developer</role>
</roles>
<timezone>Asia/Shanghai</timezone>
</developer>
</developers>
<reporting>
<plugins>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
</plugin>
</plugins>
</reporting>
</project>

View File

@ -1,332 +0,0 @@
/*
* Copyright (C) 2018 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.chatopera.chatbot;
import com.mashape.unirest.http.exceptions.UnirestException;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONObject;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
public class ChatbotAPI {
private String schema;
private String hostname;
private int port;
private String baseUrl;
private ChatbotAPI() {
}
public ChatbotAPI(final String baseUrl) throws ChatbotAPIRuntimeException, MalformedURLException {
if (StringUtils.isBlank(baseUrl))
throw new ChatbotAPIRuntimeException("智能问答引擎URL不能为空。");
URL url = new URL(baseUrl);
this.schema = url.getProtocol();
this.hostname = url.getHost();
this.port = url.getPort();
if (port == -1) {
this.baseUrl = this.schema + "://" + this.hostname + "/api/v1";
} else {
this.baseUrl = this.schema + "://" + this.hostname + ":" + this.port + "/api/v1";
}
}
public ChatbotAPI(final String schema, final String hostname, final int port, final String version) {
this.schema = schema;
this.hostname = hostname;
this.port = port;
this.baseUrl = schema + "://" + hostname + ":" + Integer.toString(this.port) + "/api/" + version;
}
public ChatbotAPI(final String schema, final String hostname, final int port) {
this(schema, hostname, port, "v1");
}
public ChatbotAPI(final String hostname, final int port) {
this("http", hostname, port);
}
public String getSchema() {
return schema;
}
public String getHostname() {
return hostname;
}
public int getPort() {
return port;
}
public String getBaseUrl() {
return baseUrl;
}
/**
* 获取聊天机器人列表
*
* @return
* @throws ChatbotAPIRuntimeException
*/
public JSONObject getChatbots(final String fields, final String q, final int page, final int limit) throws ChatbotAPIRuntimeException {
try {
HashMap<String, Object> queryString = new HashMap<String, Object>();
if (StringUtils.isNotBlank(fields)) {
queryString.put("fields", fields);
}
if (StringUtils.isNotBlank(q)) {
queryString.put("q", q);
}
queryString.put("page", page);
if (limit > 0) {
queryString.put("limit", limit);
}
return RestAPI.get(this.getBaseUrl() + "/chatbot", queryString);
} catch (UnirestException e) {
throw new ChatbotAPIRuntimeException(e.toString());
}
}
/**
* 通过ChatbotID检查一个聊天机器人是否存在
*
* @param chatbotID
* @return
*/
public boolean exists(final String chatbotID) throws ChatbotAPIRuntimeException {
try {
JSONObject result = this.getChatbot(chatbotID);
int rc = result.getInt("rc");
if (rc == 0) {
return true;
} else if (rc == 3) {
return false;
} else {
throw new ChatbotAPIRuntimeException("查询聊天机器人异常返回。");
}
} catch (Exception e) {
throw new ChatbotAPIRuntimeException(e.toString());
}
}
/**
* 创建聊天机器人
*
* @param chatbotID 聊天机器人标识[a-zA-Z0-9-]组成字母开头
* @param name 拟人化的名字
* @param primaryLanguage 首选语言支持 [zh_CN|en_US]
* @param fallback 兜底回复
* @param description 描述
* @param welcome 欢迎语
* @return
*/
public JSONObject createBot(final String chatbotID,
final String name,
final String primaryLanguage,
final String fallback,
final String description,
final String welcome) throws ChatbotAPIRuntimeException {
HashMap<String, Object> body = new HashMap<String, Object>();
body.put("chatbotID", chatbotID);
body.put("name", name);
body.put("primaryLanguage", primaryLanguage);
body.put("description", description);
body.put("fallback", fallback);
body.put("welcome", welcome);
try {
return RestAPI.post(this.getBaseUrl() + "/chatbot/" + chatbotID, body);
} catch (UnirestException e) {
throw new ChatbotAPIRuntimeException(e.toString());
}
}
/**
* 更新聊天机器人
*
* @param chatbotID
* @param description
* @param fallback
* @param welcome
* @return
* @throws ChatbotAPIRuntimeException
*/
public boolean updateByChatbotID(final String chatbotID,
final String name,
final String description,
final String fallback,
final String welcome) throws ChatbotAPIRuntimeException {
if (StringUtils.isBlank(chatbotID))
throw new ChatbotAPIRuntimeException("不合法的参数【chatbotID】不能为空。");
HashMap<String, Object> body = new HashMap<String, Object>();
if (StringUtils.isNotBlank(description))
body.put("description", description);
if (StringUtils.isNotBlank(fallback))
body.put("fallback", fallback);
if (StringUtils.isNotBlank(welcome))
body.put("welcome", welcome);
if (StringUtils.isNotBlank(name))
body.put("name", name);
try {
JSONObject result = RestAPI.put(this.baseUrl + "/chatbot/" + chatbotID, body, null);
if (result.getInt("rc") == 0) {
return true;
} else {
return false;
}
} catch (UnirestException e) {
throw new ChatbotAPIRuntimeException(e.toString());
}
}
/**
* 删除聊天机器人
*
* @param chatbotID
* @return
* @throws ChatbotAPIRuntimeException
*/
public boolean deleteByChatbotID(final String chatbotID) throws ChatbotAPIRuntimeException {
if (StringUtils.isBlank(chatbotID))
throw new ChatbotAPIRuntimeException("聊天机器人ID不能为空。");
try {
JSONObject result = RestAPI.delete(this.getBaseUrl() + "/chatbot/" + chatbotID, null);
if (result.getInt("rc") == 0)
return true;
return false;
} catch (UnirestException e) {
throw new ChatbotAPIRuntimeException(e.toString());
}
}
/**
* 获取聊天机器人详情
*
* @param chatbotID
* @return
* @throws ChatbotAPIRuntimeException
*/
public JSONObject getChatbot(final String chatbotID) throws ChatbotAPIRuntimeException {
try {
return RestAPI.get(this.getBaseUrl() + "/chatbot/" + chatbotID);
} catch (UnirestException e) {
throw new ChatbotAPIRuntimeException(e.toString());
}
}
/**
* validate params
*
* @param chatbotID
* @param fromUserId
* @param textMessage
*/
private void v(final String chatbotID, final String fromUserId, final String textMessage) throws ChatbotAPIRuntimeException {
if (StringUtils.isBlank(chatbotID))
throw new ChatbotAPIRuntimeException("[conversation] 不合法的聊天机器人标识。");
if (StringUtils.isBlank(fromUserId))
throw new ChatbotAPIRuntimeException("[conversation] 不合法的用户标识。");
if (StringUtils.isBlank(textMessage))
throw new ChatbotAPIRuntimeException("[conversation] 不合法的消息内容。");
}
/**
* 与聊天机器人进行多轮对话
*
* @param fromUserId
* @param textMessage
* @param debug
* @return
*/
public JSONObject conversation(final String chatbotID, final String fromUserId, final String textMessage, boolean debug) throws ChatbotAPIRuntimeException {
v(chatbotID, fromUserId, textMessage);
HashMap<String, Object> body = new HashMap<String, Object>();
body.put("fromUserId", fromUserId);
body.put("textMessage", textMessage);
body.put("isDebug", debug);
try {
JSONObject resp = RestAPI.post(this.getBaseUrl() + "/chatbot/" + chatbotID + "/conversation/query", body);
return resp;
} catch (UnirestException e) {
throw new ChatbotAPIRuntimeException(e.toString());
}
}
/**
* 意图识别
* @param chatbotID
* @param clientId
* @param textMessage
* @return
* @throws UnirestException
*/
public JSONObject intent(final String chatbotID, final String clientId, final String textMessage) throws ChatbotAPIRuntimeException {
if(StringUtils.isBlank(chatbotID) || StringUtils.isBlank(clientId) || StringUtils.isBlank(textMessage))
throw new ChatbotAPIRuntimeException("参数不合法,不能为空。");
HashMap<String, Object> body = new HashMap<String, Object>();
body.put("clientId", clientId);
body.put("query", textMessage);
try {
JSONObject result = RestAPI.post(this.baseUrl + "/chatbot/" + chatbotID, body);
return result;
} catch (UnirestException e) {
throw new ChatbotAPIRuntimeException(e.toString());
}
}
/**
* 检索知识库
*
* @param chatbotID
* @param fromUserId
* @param textMessage
* @param isDebug
* @return
*/
public JSONObject faq(final String chatbotID, final String fromUserId, final String textMessage, final boolean isDebug) throws ChatbotAPIRuntimeException {
v(chatbotID, fromUserId, textMessage);
HashMap<String, Object> body = new HashMap<String, Object>();
body.put("fromUserId", fromUserId);
body.put("query", textMessage);
body.put("isDebug", isDebug);
try {
JSONObject resp = RestAPI.post(this.getBaseUrl() + "/chatbot/" + chatbotID + "/faq/query", body);
return resp;
} catch (UnirestException e) {
throw new ChatbotAPIRuntimeException(e.toString());
}
}
}

View File

@ -1,24 +0,0 @@
/*
* Copyright (C) 2018 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.chatopera.chatbot;
import com.mashape.unirest.http.exceptions.UnirestException;
public class ChatbotAPIRuntimeException extends Exception{
public ChatbotAPIRuntimeException(String msg) {
super(msg);
}
}

View File

@ -1,120 +0,0 @@
/*
* Copyright (C) 2018 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.chatopera.chatbot;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;
import com.mashape.unirest.request.GetRequest;
import com.mashape.unirest.request.HttpRequestWithBody;
import org.json.JSONObject;
import java.util.HashMap;
/**
* RestAPI接口
*/
public class RestAPI {
/**
* patch headers
*
* @param headers
*/
private static void x(HashMap<String, String> headers) {
if (headers == null) {
headers = new HashMap<String, String>();
headers.put("accept", "application/json");
return;
}
if (!headers.containsKey("Content-Type"))
headers.put("Content-Type", "application/json");
if (!headers.containsKey("accept"))
headers.put("accept", "application/json");
}
/**
* Post
*
* @param url
* @param body
* @param query
* @param headers
* @return
* @throws UnirestException
*/
public static JSONObject post(final String url, final HashMap<String, Object> body, final HashMap<String, Object> query, HashMap<String, String> headers) throws UnirestException {
HttpRequestWithBody request = Unirest.post(url);
x(headers);
HttpResponse<JsonNode> resp = request
.headers(headers)
.queryString(query)
.fields(body)
.asJson();
// parse response
JSONObject obj = resp.getBody().getObject();
return obj;
}
public static JSONObject post(final String url, final HashMap<String, Object> body) throws UnirestException {
return post(url, body, null, null);
}
/**
* Get
*
* @param url
* @param queryString
* @param headers
* @return
* @throws UnirestException
*/
public static JSONObject get(final String url, final HashMap<String, Object> queryString, HashMap<String, String> headers) throws UnirestException {
GetRequest request = Unirest.get(url);
x(headers);
HttpResponse<JsonNode> resp = request
.headers(headers)
.queryString(queryString)
.asJson();
// parse response
JSONObject obj = resp.getBody().getObject();
return obj;
}
public static JSONObject get(final String url) throws UnirestException {
return get(url, null, null);
}
public static JSONObject get(final String url, HashMap<String, Object> queryString) throws UnirestException {
return get(url, queryString, null);
}
public static JSONObject delete(final String url, HashMap<String, String> headers) throws UnirestException {
x(headers);
return Unirest.delete(url).headers(headers).asJson().getBody().getObject();
}
public static JSONObject put(final String url, HashMap<String, Object> body, HashMap<String, String> headers) throws UnirestException {
x(headers);
return Unirest.put(url).headers(headers).fields(body).asJson().getBody().getObject();
}
}

View File

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="sdk" xmlns="http://maven.apache.org/DECORATION/1.8.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/DECORATION/1.8.0 http://maven.apache.org/xsd/decoration-1.8.0.xsd">
<bannerLeft>
<name>sdk</name>
<src>https://maven.apache.org/images/apache-maven-project.png</src>
<href>https://www.apache.org/</href>
</bannerLeft>
<bannerRight>
<src>https://maven.apache.org/images/maven-logo-black-on-white.png</src>
<href>https://maven.apache.org/</href>
</bannerRight>
<skin>
<groupId>org.apache.maven.skins</groupId>
<artifactId>maven-fluido-skin</artifactId>
<version>1.7</version>
</skin>
<body>
<menu ref="parent" />
<menu ref="reports" />
</body>
</project>

View File

@ -1,132 +0,0 @@
/*
* Copyright (C) 2018 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.chatopera.chatbot;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.json.JSONObject;
import java.net.MalformedURLException;
/**
* Unit test for simple App.
*/
public class ChatbotAPITest
extends TestCase {
private ChatbotAPI cb;
/**
* Create the test case
*
* @param testName name of the test case
*/
public ChatbotAPITest(String testName) {
super(testName);
}
/**
* @return the suite of tests being tested
*/
public static Test suite() {
return new TestSuite(ChatbotAPITest.class);
}
public void setUp() {
this.cb = new ChatbotAPI("http", "lhc-dev", 8003, "v1");
}
/**
* Rigourous Test :-)
*/
public void testChatbot() {
assertEquals(this.cb.getPort(), 8003);
}
public void testGetChatbot() {
try {
JSONObject resp = this.cb.getChatbot("co_bot_1");
System.out.println("[testGetChatbot] " + resp.toString());
} catch (ChatbotAPIRuntimeException e) {
e.printStackTrace();
}
}
public void testGetChatbots() {
try {
JSONObject resp = this.cb.getChatbots("name chatbotID", null, 0, 10);
System.out.println("[testGetChatbots] resp " + resp.toString());
} catch (ChatbotAPIRuntimeException e) {
e.printStackTrace();
}
}
public void testConversation() {
try {
JSONObject resp = this.cb.conversation("co_bot_1", "sdktest", "华夏春松在哪里", false);
System.out.println("[testConversation] resp " + resp.toString());
} catch (ChatbotAPIRuntimeException e) {
e.printStackTrace();
}
}
public void testFaq() {
try {
JSONObject resp = this.cb.faq("co_bot_1", "sdktest", "华夏春松在哪里", false);
System.out.print("[testFaq] resp " + resp.toString());
} catch (ChatbotAPIRuntimeException e) {
e.printStackTrace();
}
}
public void testParseUrl() {
try {
ChatbotAPI c = new ChatbotAPI("https://local:8000/");
System.out.println("chatbot baseUrl " + c.getBaseUrl());
assertEquals("https://local:8000/api/v1", c.getBaseUrl());
} catch (ChatbotAPIRuntimeException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
public void testExists() {
JSONObject profile = null;
try {
assertTrue(this.cb.exists("co_bot_1"));
} catch (ChatbotAPIRuntimeException e) {
e.printStackTrace();
}
}
public void testCreateBot() {
try {
JSONObject j = this.cb.createBot("cc_bot_2",
"小云2",
"zh_CN",
"我不了解。",
"小云机器人",
"你好,我是小云。");
} catch (ChatbotAPIRuntimeException e) {
e.printStackTrace();
}
}
}

View File

@ -7,7 +7,7 @@
baseDir=$(cd `dirname "$0"`;pwd)
# functions
# main
# main
[ -z "${BASH_SOURCE[0]}" -o "${BASH_SOURCE[0]}" = "$0" ] || return
cd $baseDir/../app
mvn clean package

View File

@ -2,6 +2,7 @@
src/main/java/com/chatopera/cc/plugins/
# ignore views within plugins
!src/main/resources/templates/admin/channel/callout/
!src/main/resources/templates/admin/channel/im/
src/main/resources/templates/admin/channel/*
src/main/resources/templates/apps/callout
src/main/resources/templates/apps/chatbot

View File

@ -6,7 +6,7 @@
<version>5.0.0</version>
<packaging>war</packaging>
<name>cskefu</name>
<description>春松客服企业版:多媒体呼叫中心,下一代呼叫中心</description>
<description>春松客服:多渠道智能客服系统</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.
@ -65,52 +65,34 @@ public class Application {
/**
* 记载模块
*/
// 外呼模块
private final static boolean isCalloutModule = SystemEnvHelper.parseModuleFlag("cskefu.module.callout");
// CRM模块
private final static boolean isContactsModule = SystemEnvHelper.parseModuleFlag("cskefu.module.contacts");
// 聊天机器人模块
private final static boolean isChatbotModule = SystemEnvHelper.parseModuleFlag("cskefu.module.chatbot");
// 访客聊天监控模块
private final static boolean isCcaModule = SystemEnvHelper.parseModuleFlag("cskefu.module.cca");
// 企业聊天模块
private final static boolean isEntImModule = SystemEnvHelper.parseModuleFlag("cskefu.module.entim");
// 渠道:Skype渠道
private final static boolean isSkypeModule = SystemEnvHelper.isClassExistByFullName(
PluginRegistry.PLUGIN_ENTRY_SKYPE);
static {
// 外呼模块
if (isCalloutModule) {
MainContext.enableModule(Constants.CSKEFU_MODULE_CALLOUT);
}
// CRM模块
if (isContactsModule) {
MainContext.enableModule(Constants.CSKEFU_MODULE_CONTACTS);
}
// 聊天机器人模块
if (isChatbotModule) {
MainContext.enableModule(Constants.CSKEFU_MODULE_CHATBOT);
MainContext.enableModule(Constants.CSKEFU_MODULE_CONTACTS);
// 会话监控模块 Customer Chats Audit
MainContext.enableModule(Constants.CSKEFU_MODULE_CCA);
// 企业聊天模块
MainContext.enableModule(Constants.CSKEFU_MODULE_ENTIM);
/**
* 插件组
*/
// 外呼模块
if (SystemEnvHelper.isClassExistByFullName(
PluginRegistry.PLUGIN_ENTRY_CALLOUT)) {
MainContext.enableModule(Constants.CSKEFU_MODULE_CALLOUT);
}
// skype模块
if (isSkypeModule) {
if (SystemEnvHelper.isClassExistByFullName(
PluginRegistry.PLUGIN_ENTRY_SKYPE)) {
MainContext.enableModule(Constants.CSKEFU_MODULE_SKYPE);
}
// 会话监控模块 Customer Chats Audit
if (isCcaModule) {
MainContext.enableModule(Constants.CSKEFU_MODULE_CCA);
}
// 企业聊天模块
if (isEntImModule) {
MainContext.enableModule(Constants.CSKEFU_MODULE_ENTIM);
// 聊天机器人模块
if (SystemEnvHelper.isClassExistByFullName(PluginRegistry.PLUGIN_ENTRY_CHATBOT)) {
MainContext.enableModule(Constants.CSKEFU_MODULE_CHATBOT);
}
}

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,143 +0,0 @@
/*
* Copyright (C) 2019 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.chatopera.cc.activemq;
import com.chatopera.bot.exception.ChatbotException;
import com.chatopera.cc.basic.MainContext;
import com.chatopera.cc.cache.Cache;
import com.chatopera.cc.handler.api.request.RestUtils;
import com.chatopera.cc.socketio.message.ChatMessage;
import com.chatopera.cc.proxy.ChatbotProxy;
import com.chatopera.cc.model.AgentUser;
import com.chatopera.cc.model.Chatbot;
import com.chatopera.cc.persistence.repository.AgentUserRepository;
import com.chatopera.cc.persistence.repository.ChatbotRepository;
import com.chatopera.cc.basic.Constants;
import com.chatopera.cc.util.SerializeUtil;
import org.json.JSONException;
import org.json.JSONObject;
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.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
import java.net.MalformedURLException;
/**
* 发送消息给聊天机器人并处理返回结果
*/
@Component
public class ChatbotEventSubscription {
private final static Logger logger = LoggerFactory.getLogger(ChatbotEventSubscription.class);
@Autowired
private Cache cache;
@Autowired
private AgentUserRepository agentUserRes;
@Autowired
private ChatbotRepository chatbotRes;
@Value("${bot.baseurl}")
private static String botBaseUrl;
@Autowired
private ChatbotProxy chatbotProxy;
/**
* 接收发送消息给聊天机器人的请求
*
* @param payload
*/
@JmsListener(destination = Constants.INSTANT_MESSAGING_MQ_QUEUE_CHATBOT, containerFactory = "jmsListenerContainerQueue")
public void onMessage(final String payload) {
ChatMessage message = SerializeUtil.deserialize(payload);
try {
chat(message);
} catch (MalformedURLException e) {
logger.error("[onMessage] error", e);
} catch (ChatbotException e) {
logger.error("[onMessage] error", e);
}
}
private void chat(final ChatMessage request) throws MalformedURLException, ChatbotException, JSONException {
Chatbot c = chatbotRes
.findOne(request.getAiid());
logger.info(
"[chat] chat request baseUrl {}, chatbot {}, fromUserId {}, textMessage {}", botBaseUrl, c.getName(),
request.getUserid(), request.getMessage());
// Get response from Conversational Engine.
com.chatopera.bot.sdk.Chatbot bot = new com.chatopera.bot.sdk.Chatbot(
c.getClientId(), c.getSecret(), botBaseUrl);
JSONObject result = bot.conversation(request.getUserid(), request.getMessage());
// parse response
if (result != null) {
logger.info("[chat] chat response {}", result.toString());
if (result.getInt(RestUtils.RESP_KEY_RC) == 0) {
// reply
JSONObject data = result.getJSONObject("data");
ChatMessage resp = new ChatMessage();
resp.setCalltype(MainContext.CallType.OUT.toString());
resp.setAppid(resp.getAppid());
resp.setOrgi(request.getOrgi());
resp.setAiid(request.getAiid());
resp.setMessage(data.getString("string"));
resp.setTouser(request.getUserid());
resp.setAgentserviceid(request.getAgentserviceid());
resp.setMsgtype(request.getMsgtype());
resp.setUserid(request.getUserid());
resp.setType(request.getType());
resp.setChannel(request.getChannel());
if (data.has("params")) {
resp.setExpmsg(data.get("params").toString());
}
resp.setContextid(request.getContextid());
resp.setSessionid(request.getSessionid());
resp.setUsession(request.getUsession());
resp.setUsername(c.getName());
resp.setUpdatetime(System.currentTimeMillis());
// 更新聊天机器人累计值
updateAgentUserWithRespData(request.getUserid(), request.getOrgi(), data);
// 保存并发送
chatbotProxy.saveAndPublish(resp);
} else {
logger.warn("[chat] can not get expected response {}", result.toString());
}
}
}
/**
* 根据聊天机器人返回数据更新agentUser
*
* @param userid
* @param data
*/
private void updateAgentUserWithRespData(final String userid, final String orgi, final JSONObject data) throws JSONException {
cache.findOneAgentUserByUserIdAndOrgi(userid, orgi).ifPresent(p -> {
p.setChatbotround(p.getChatbotround() + 1);
if (data.has("logic_is_unexpected") && data.getBoolean("logic_is_unexpected")) {
p.setChatbotlogicerror(p.getChatbotlogicerror() + 1);
}
agentUserRes.save(p);
});
}
}

View File

@ -1,107 +0,0 @@
/*
* Copyright (C) 2019 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.chatopera.cc.activemq;
import com.chatopera.cc.config.conditions.CalloutBeanCondition;
import com.chatopera.cc.persistence.interfaces.CalloutWireEvent;
import com.chatopera.cc.schedule.CalloutWireTask;
import com.chatopera.cc.basic.Constants;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Conditional;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
* FreeSWITCH
*/
@Component
@Conditional(CalloutBeanCondition.class)
public class PbxEventSubscription {
private final static Logger logger = LoggerFactory.getLogger(PbxEventSubscription.class);
@PostConstruct
public void setup() {
logger.info("ActiveMQ Subscription is setup successfully.");
}
@Autowired
private BrokerPublisher brokerPublisher;
@Autowired
private CalloutWireTask callOutWireTask;
public void publish(final String dest, final String payload) {
brokerPublisher.send(dest, payload);
}
@JmsListener(destination = Constants.INSTANT_MESSAGING_MQ_QUEUE_PBX, containerFactory = "jmsListenerContainerQueue")
public void onMessage(final String payload) {
logger.info("[onMessage] payload {}", payload);
JsonParser parser = new JsonParser();
JsonObject j = parser.parse(payload).getAsJsonObject();
// validate message
if (!(j.has("type")
&& j.has("to")
&& j.has("ops")
&& j.has("channel")
&& j.has("createtime"))) {
logger.error(String.format("[callout wire] 接线数据格式不对, %s", payload));
} else {
try {
CalloutWireEvent event = CalloutWireEvent.parse(j);
switch (event.getEventType()) {
case 1: // 自动外呼接通
logger.info("[callout wire] 自动外呼接通 {}", j.toString());
callOutWireTask.callOutConnect(event);
break;
case 2: // 自动外呼挂断
logger.info("[callout wire] 自动外呼挂断 {}", j.toString());
callOutWireTask.callOutDisconnect(event);
break;
case 3: // 自动外呼失败
logger.info("[callout wire] 自动外呼失败 {}", j.toString());
callOutWireTask.callOutFail(event);
break;
case 4: // 手动外呼接通
logger.info("[callout wire] 手动外呼接通 {}", j.toString());
callOutWireTask.callOutConnect(event);
break;
case 5: // 手动外呼挂断
logger.info("[callout wire] 手动外呼挂断 {}", j.toString());
callOutWireTask.callOutDisconnect(event);
break;
case 6: // 手动外呼失败
logger.info("[callout wire] 手动外呼失败 {}", j.toString());
callOutWireTask.callOutFail(event);
break;
case 7: // 呼入接通
logger.info("[callin wire] 呼入接通 {}", j.toString());
break;
case 8: // 呼入挂断
logger.info("[callin wire] 呼入挂断 {}", j.toString());
break;
case 9: // 呼入失败
logger.info("[callin wire] 呼入失败 {}", j.toString());
break;
}
} catch (Exception e) {
logger.error("[callout wire] ", e);
}
}
}
}

View File

@ -15,7 +15,6 @@ import com.chatopera.cc.basic.MainContext;
import com.chatopera.cc.cache.Cache;
import com.chatopera.cc.model.AgentStatus;
import com.chatopera.cc.persistence.repository.AgentStatusRepository;
import com.chatopera.cc.persistence.repository.UserRepository;
import com.chatopera.cc.basic.Constants;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
@ -33,16 +32,13 @@ import java.util.Date;
* 处理SocketIO的离线事件
*/
@Component
public class ConnectionEventSubscription {
public class SocketioConnEventSubscription {
private final static Logger logger = LoggerFactory.getLogger(ConnectionEventSubscription.class);
private final static Logger logger = LoggerFactory.getLogger(SocketioConnEventSubscription.class);
@Autowired
private AgentStatusRepository agentStatusRes;
@Autowired
private UserRepository userRes;
@Autowired
private Cache cache;

View File

@ -1,3 +1,18 @@
/*
* Copyright (C) 2019 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.chatopera.cc.aop;
import com.chatopera.cc.basic.MainContext;

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Copyright (C) 2019 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.
@ -86,7 +86,7 @@ public class Constants {
/**
* Modules
*/
public final static String CSKEFU_MODULE_CALLOUT = "sales";
public final static String CSKEFU_MODULE_CALLOUT = "callout";
public final static String CSKEFU_MODULE_CHATBOT = "chatbot";
public final static String CSKEFU_MODULE_CONTACTS = "contacts";
public final static String CSKEFU_MODULE_SKYPE = "skype";

View File

@ -1,8 +0,0 @@
package com.chatopera.cc.basic;
/**
* 国际化字段
*/
public class I18N {
}

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.
@ -786,6 +786,7 @@ public class MainContext {
MESSAGE,
END,
TRANS,
TRANSOUT, // 当前会话被转接出去
STATUS,
AGENTSTATUS,
SERVICE,
@ -1031,26 +1032,6 @@ public class MainContext {
return csKeFuResourceMap.get(resource);
}
/**
* 是否开启机器人客服模块
*
* @return
*/
public static boolean isEnableChatbotModule() {
return modules.contains(Constants.CSKEFU_MODULE_CHATBOT);
}
/**
* 是否开启外呼模块
*
* @return
*/
public static boolean isEnableCalloutModule() {
return modules.contains(Constants.CSKEFU_MODULE_CALLOUT);
}
/**
* Redis底层接口
*/

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,5 +1,21 @@
/*
* Copyright (C) 2019 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.chatopera.cc.basic.plugins;
public interface IPluginDescriptor {
String getPluginName();
String getIOEventHandler();
}

View File

@ -1,3 +1,18 @@
/*
* Copyright (C) 2019 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.chatopera.cc.basic.plugins;
/**
@ -10,5 +25,7 @@ public class PluginRegistry {
*/
public final static String PLUGIN_CHANNEL_MESSAGER_SUFFIX = "ChannelMessager";
public final static String PLUGIN_ENTRY_SKYPE = "com.chatopera.cc.plugins.skype.PluginDescriptor";
public final static String PLUGIN_ENTRY_CALLOUT = "com.chatopera.cc.plugins.callout.PluginDescriptor";
public final static String PLUGIN_ENTRY_CHATBOT = "com.chatopera.cc.plugins.chatbot.PluginDescriptor";
}

View File

@ -1,13 +1,72 @@
/*
* Copyright (C) 2019 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.chatopera.cc.basic.plugins;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 插架装载器
* TODO Placeholder
* 插架装载器
* TODO Placeholder
*/
public class PluginsLoader {
private final static Logger logger = LoggerFactory.getLogger(PluginsLoader.class);
/**
* 通过插件entry获得PluginName
*
* @param pluginEntry
* @return
*/
public static String getPluginName(final String pluginEntry) {
Class<?> clazz;
try {
clazz = Class.forName(pluginEntry);
IPluginDescriptor clazzInst = (IPluginDescriptor) clazz.newInstance();
Method method = clazz.getMethod("getPluginName");
return (String) method.invoke(clazzInst);
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
logger.info("[postConstruct] error", e);
}
return null;
}
/**
* 通过插件entry获得Plugin SocketIO Event Handler
*
* @param pluginEntry
* @return
*/
public static String getIOEventHandler(final String pluginEntry) {
Class<?> clazz;
try {
clazz = Class.forName(pluginEntry);
IPluginDescriptor clazzInst = (IPluginDescriptor) clazz.newInstance();
Method method = clazz.getMethod("getIOEventHandler");
return (String) method.invoke(clazzInst);
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
logger.info("[postConstruct] error", e);
}
return null;
}
}

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,12 +1,12 @@
/**
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2019 Chatopera Inc, <https://www.chatopera.com>
*
* http://www.apache.org/licenses/LICENSE-2.0
* webapps/LICENSE-Rivulet
* 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,

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.
@ -16,7 +16,7 @@
*/
package com.chatopera.cc.config;
import com.chatopera.cc.config.conditions.CalloutBeanCondition;
import com.chatopera.cc.config.plugins.CalloutPluginPresentCondition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@ -60,7 +60,7 @@ public class ExecutorConfig {
* 外呼线程池
* @return
*/
@Conditional(CalloutBeanCondition.class)
@Conditional(CalloutPluginPresentCondition.class)
@Bean(name = "callOutTaskExecutor")
public ThreadPoolTaskExecutor callout() {
ThreadPoolTaskExecutor poolTaskExecutor = new ThreadPoolTaskExecutor();

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Copyright (C) 2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,86 +0,0 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 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.chatopera.cc.config;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.Properties;
import com.chatopera.cc.basic.MainUtils;
import org.apache.catalina.connector.Connector;
import org.apache.commons.lang3.StringUtils;
import org.apache.coyote.http11.Http11NioProtocol;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.Ssl;
import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class WebServerConfiguration {
private Integer maxthread = 2000;
private Integer maxconnections = 2000;
@Value("${web.upload-path}")
private String path;
@Bean
public EmbeddedServletContainerFactory createEmbeddedServletContainerFactory() throws IOException, NoSuchAlgorithmException {
TomcatEmbeddedServletContainerFactory tomcatFactory = new TomcatEmbeddedServletContainerFactory();
tomcatFactory.addConnectorCustomizers(new UKeFuTomcatConnectorCustomizer(maxthread, maxconnections));
File sslFile = new File(path, "ssl/https.properties");
if (sslFile.exists()) {
Properties sslProperties = new Properties();
FileInputStream in = new FileInputStream(sslFile);
sslProperties.load(in);
in.close();
if (!StringUtils.isBlank(sslProperties.getProperty("key-store")) && !StringUtils.isBlank(
sslProperties.getProperty("key-store-password"))) {
Ssl ssl = new Ssl();
ssl.setKeyStore(new File(path, "ssl/" + sslProperties.getProperty("key-store")).getAbsolutePath());
ssl.setKeyStorePassword(MainUtils.decryption(sslProperties.getProperty("key-store-password")));
tomcatFactory.setSsl(ssl);
}
}
return tomcatFactory;
}
}
class UKeFuTomcatConnectorCustomizer implements TomcatConnectorCustomizer {
private Integer maxthread;
private Integer maxconnection;
UKeFuTomcatConnectorCustomizer(Integer maxthread, Integer maxconnection) {
this.maxthread = maxthread;
this.maxconnection = maxconnection;
}
public void customize(Connector connector) {
Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
//设置最大连接数
protocol.setMaxConnections(maxthread != null ? maxthread : 2000);
//设置最大线程数
protocol.setMaxThreads(maxconnection != null ? maxconnection : 2000);
protocol.setConnectionTimeout(30000);
}
}

View File

@ -0,0 +1,69 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2019 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.chatopera.cc.config;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import org.apache.catalina.connector.Connector;
import org.apache.coyote.http11.Http11NioProtocol;
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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class WebServerContainerConfigure {
@Value("${server.threads.max}")
private Integer maxthread;
@Value("${server.connection.max}")
private Integer maxconnections;
@Value("${web.upload-path}")
private String path;
@Bean
public EmbeddedServletContainerFactory createEmbeddedServletContainerFactory() throws IOException, NoSuchAlgorithmException {
TomcatEmbeddedServletContainerFactory tomcatFactory = new TomcatEmbeddedServletContainerFactory();
tomcatFactory.addConnectorCustomizers(new CSKeFuTomcatConnectorCustomizer(maxthread, maxconnections));
return tomcatFactory;
}
class CSKeFuTomcatConnectorCustomizer implements TomcatConnectorCustomizer {
private Integer maxthread;
private Integer maxconnection;
CSKeFuTomcatConnectorCustomizer(Integer maxthread, Integer maxconnection) {
this.maxthread = maxthread;
this.maxconnection = maxconnection;
}
public void customize(Connector connector) {
Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
//设置最大连接数
protocol.setMaxConnections(maxthread != null ? maxthread : 2000);
//设置最大线程数
protocol.setMaxThreads(maxconnection != null ? maxconnection : 2000);
protocol.setConnectionTimeout(30000);
}
}
}

View File

@ -1,3 +1,18 @@
/*
* Copyright (C) 2019 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.chatopera.cc.config;
import com.chatopera.cc.cache.RedisKey;

View File

@ -8,8 +8,9 @@
* 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.chatopera.cc.config.conditions;
package com.chatopera.cc.config.plugins;
import com.chatopera.cc.basic.Constants;
import com.chatopera.cc.basic.MainContext;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
@ -19,9 +20,9 @@ import org.springframework.core.type.AnnotatedTypeMetadata;
* Init bean based on conditions
* https://javapapers.com/spring/spring-conditional-annotation/
*/
public class CalloutBeanCondition implements Condition {
public class CalloutPluginPresentCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
return MainContext.isEnableCalloutModule();
return MainContext.hasModule(Constants.CSKEFU_MODULE_CALLOUT);
}
}

View File

@ -0,0 +1,28 @@
/*
* Copyright (C) 2019 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.chatopera.cc.config.plugins;
import com.chatopera.cc.basic.Constants;
import com.chatopera.cc.basic.MainContext;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
* Init bean based on conditions
* https://javapapers.com/spring/spring-conditional-annotation/
*/
public class ChatbotPluginPresentCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
return MainContext.hasModule(Constants.CSKEFU_MODULE_CHATBOT);
}
}

View File

@ -1,3 +1,18 @@
/*
* Copyright (C) 2019 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.chatopera.cc.config.plugins;
import com.chatopera.cc.basic.Constants;

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Copyright (C) 2018-2019 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Copyright (C) 2018-2019 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Copyright (C) 2018-2019 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.

View File

@ -1,23 +0,0 @@
/*
* Copyright (C) 2018 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.chatopera.cc.exception;
public class CalloutRecordException extends Exception {
public CalloutRecordException(String msg){
super(msg);
}
}

View File

@ -1,23 +0,0 @@
/*
* Copyright (C) 2018 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.chatopera.cc.exception;
public class CalloutRuntimeException extends Exception {
public CalloutRuntimeException(String msg){
super(msg);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.
@ -20,7 +20,7 @@ import com.chatopera.cc.basic.MainContext;
import com.chatopera.cc.basic.MainUtils;
import com.chatopera.cc.basic.Viewport;
import com.chatopera.cc.cache.Cache;
import com.chatopera.cc.handler.api.rest.QueryParams;
import com.chatopera.cc.handler.api.QueryParams;
import com.chatopera.cc.model.StreamingFile;
import com.chatopera.cc.model.SystemConfig;
import com.chatopera.cc.model.Tenant;
@ -102,7 +102,7 @@ public class Handler {
user.setSessionid(user.getId());
}
} else {
user.setSessionid(user.getId());
user.setSessionid(MainUtils.getContextID(request.getSession().getId()));
}
return user;
}

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.
@ -18,7 +18,6 @@ package com.chatopera.cc.handler;
import com.chatopera.cc.acd.AutomaticServiceDist;
import com.chatopera.cc.basic.Constants;
import com.chatopera.cc.basic.I18N;
import com.chatopera.cc.basic.MainContext;
import com.chatopera.cc.basic.MainUtils;
import com.chatopera.cc.cache.Cache;
@ -177,51 +176,54 @@ public class LoginController extends Handler {
user.getUsername(), MainUtils.md5(user.getPassword()), false);
if (loginUser != null && StringUtils.isNotBlank(loginUser.getId())) {
view = this.processLogin(request, loginUser, referer);
if (StringUtils.isNotBlank(sla) && sla.equals("1")) {
// 自动登录
if (StringUtils.equals("1", sla)) {
Cookie flagid = new Cookie(
Constants.CSKEFU_SYSTEM_COOKIES_FLAG, MainUtils.encryption(loginUser.getId()));
flagid.setMaxAge(7 * 24 * 60 * 60);
response.addCookie(flagid);
// add authorization code for rest api
final String orgi = loginUser.getOrgi();
String auth = MainUtils.getUUID();
cache.putLoginUserByAuthAndOrgi(auth, loginUser, orgi);
userRepository.save(loginUser); // 更新登录状态到数据库
response.addCookie((new Cookie("authorization", auth)));
}
// 该登录用户是坐席并且具有坐席对话的角色
if ((loginUser.isAgent() &&
loginUser.getRoleAuthMap().containsKey("A01") &&
((boolean) loginUser.getRoleAuthMap().get("A01") == true))
|| loginUser.isSuperuser()) {
try {
/****************************************
* 登录成功设置该坐席为就绪状态默认
****************************************/
// https://gitlab.chatopera.com/chatopera/cosinee.w4l/issues/306
final AgentStatus agentStatus = agentProxy.resolveAgentStatusByAgentnoAndOrgi(
loginUser.getId(), orgi, loginUser.getSkills());
agentStatus.setBusy(false);
agentProxy.ready(loginUser, agentStatus);
// add authorization code for rest api
final String orgi = loginUser.getOrgi();
String auth = MainUtils.getUUID();
cache.putLoginUserByAuthAndOrgi(auth, loginUser, orgi);
userRepository.save(loginUser); // 更新登录状态到数据库
response.addCookie((new Cookie("authorization", auth)));
// 更新缓存和数据库
cache.putAgentStatusByOrgi(agentStatus, loginUser.getOrgi());
agentStatusRes.save(agentStatus);
// 该登录用户是坐席并且具有坐席对话的角色
if ((loginUser.isAgent() &&
loginUser.getRoleAuthMap().containsKey("A01") &&
((boolean) loginUser.getRoleAuthMap().get("A01") == true))
|| loginUser.isSuperuser()) {
try {
/****************************************
* 登录成功设置该坐席为就绪状态默认
****************************************/
// https://gitlab.chatopera.com/chatopera/cosinee.w4l/issues/306
final AgentStatus agentStatus = agentProxy.resolveAgentStatusByAgentnoAndOrgi(
loginUser.getId(), orgi, loginUser.getSkills());
agentStatus.setBusy(false);
agentProxy.ready(loginUser, agentStatus);
// 工作状态记录
AutomaticServiceDist.recordAgentStatus(agentStatus.getAgentno(),
agentStatus.getUsername(),
agentStatus.getAgentno(),
user.isSuperuser(), // 0代表admin
agentStatus.getAgentno(),
MainContext.AgentStatusEnum.OFFLINE.toString(),
MainContext.AgentStatusEnum.READY.toString(),
MainContext.AgentWorkType.MEIDIACHAT.toString(),
orgi, null);
// 更新缓存和数据库
cache.putAgentStatusByOrgi(agentStatus, loginUser.getOrgi());
agentStatusRes.save(agentStatus);
} catch (Exception e) {
logger.error("[login] set agent status", e);
}
// 工作状态记录
AutomaticServiceDist.recordAgentStatus(agentStatus.getAgentno(),
agentStatus.getUsername(),
agentStatus.getAgentno(),
user.isSuperuser(), // 0代表admin
agentStatus.getAgentno(),
MainContext.AgentStatusEnum.OFFLINE.toString(),
MainContext.AgentStatusEnum.READY.toString(),
MainContext.AgentWorkType.MEIDIACHAT.toString(),
orgi, null);
} catch (Exception e) {
logger.error("[login] set agent status", e);
}
}
} else {
@ -260,6 +262,8 @@ public class LoginController extends Handler {
// 更新redis session信息用以支持sso
agentSessionProxy.updateUserSession(
loginUser.getId(), MainUtils.getContextID(request.getSession().getId()), loginUser.getOrgi());
loginUser.setSessionid(MainUtils.getContextID(request.getSession().getId()));
if (StringUtils.isNotBlank(referer)) {
view = new ModelAndView("redirect:" + referer);
@ -327,7 +331,7 @@ public class LoginController extends Handler {
*
* @param request
* @param response
* @param code 登出的代码
* @param code 登出的代码
* @return
*/
@RequestMapping("/logout")

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.
@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.chatopera.cc.handler.admin.skill;
package com.chatopera.cc.handler.admin;
import java.util.Date;
import java.util.List;

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.
@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.chatopera.cc.handler.admin.area;
package com.chatopera.cc.handler.admin;
import java.io.IOException;
import java.util.Date;

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.
@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.chatopera.cc.handler.admin.organ;
package com.chatopera.cc.handler.admin;
import com.chatopera.cc.basic.MainContext;
import com.chatopera.cc.cache.Cache;

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.
@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.chatopera.cc.handler.admin.role;
package com.chatopera.cc.handler.admin;
import com.chatopera.cc.basic.MainContext;
import com.chatopera.cc.handler.Handler;

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.
@ -14,8 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.chatopera.cc.handler.admin.users;
package com.chatopera.cc.handler.admin;
import com.chatopera.cc.basic.Constants;
import com.chatopera.cc.basic.MainContext;
import com.chatopera.cc.basic.MainUtils;
import com.chatopera.cc.cache.Cache;
@ -78,8 +79,8 @@ public class UsersController extends Handler {
Sort.Direction.ASC,
"createtime"
)
)
);
)
);
return request(super.createAdminTempletResponse("/admin/user/index"));
}
@ -193,8 +194,10 @@ public class UsersController extends Handler {
tempUser.setSipaccount(user.getSipaccount());
//切换成非坐席 判断是否坐席 以及 是否有对话
if (!user.isAgent()) {
AgentStatus agentStatus = cache.findOneAgentStatusByAgentnoAndOrig((super.getUser(request)).getId(), super.getOrgi(request));
if (!(agentStatus == null && cache.getInservAgentUsersSizeByAgentnoAndOrgi(super.getUser(request).getId(), super.getOrgi(request)) == 0)) {
AgentStatus agentStatus = cache.findOneAgentStatusByAgentnoAndOrig(
(super.getUser(request)).getId(), super.getOrgi(request));
if (!(agentStatus == null && cache.getInservAgentUsersSizeByAgentnoAndOrgi(
super.getUser(request).getId(), super.getOrgi(request)) == 0)) {
return request(super.createRequestPageTempletResponse("redirect:/admin/user/index.html?msg=t1"));
}
}
@ -258,7 +261,9 @@ public class UsersController extends Handler {
return msg;
}
if (user.getUsername().equals(oldUser.getUsername()) && user.getEmail().equals(oldUser.getEmail()) && user.getMobile().equals(oldUser.getMobile()) && validUserCallcenterParams(user)) {
if (user.getUsername().equals(oldUser.getUsername()) && user.getEmail().equals(
oldUser.getEmail()) && user.getMobile().equals(oldUser.getMobile()) && validUserCallcenterParams(
user)) {
return "";
}
@ -292,7 +297,7 @@ public class UsersController extends Handler {
* @return
*/
private boolean validUserCallcenterParams(final User user) {
if (user.isCallcenter() && MainContext.isEnableCalloutModule()) {
if (user.isCallcenter() && MainContext.hasModule(Constants.CSKEFU_MODULE_CALLOUT)) {
List<User> tempUserList = userRepository.findBySipaccountAndDatastatus(user.getSipaccount(), false);
return tempUserList.size() == 0 || user.getSipaccount() == "";
}

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.
@ -21,7 +21,7 @@ import com.chatopera.cc.handler.Handler;
import com.chatopera.cc.model.Extention;
import com.chatopera.cc.model.PbxHost;
import com.chatopera.cc.model.User;
import com.chatopera.cc.proxy.CalloutQueneProxy;
import com.chatopera.cc.proxy.CallcenterOutboundProxy;
import com.chatopera.cc.persistence.repository.*;
import com.chatopera.cc.util.Menu;
import com.chatopera.cc.util.freeswitch.model.CallCenterAgent;
@ -187,7 +187,7 @@ public class CallCenterExtentionController extends Handler {
ext.setUpdatetime(new Date());
extentionRes.save(ext);
List<CallCenterAgent> callOutAgentList = CalloutQueneProxy.extention(ext.getExtention());
List<CallCenterAgent> callOutAgentList = CallcenterOutboundProxy.extention(ext.getExtention());
for (CallCenterAgent callOutAgent : callOutAgentList) {
callOutAgent.setSiptrunk(ext.getSiptrunk());
cache.putCallCenterAgentByIdAndOrgi(callOutAgent.getUserid(), callOutAgent.getOrgi(), callOutAgent);

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,164 +0,0 @@
/*
* Copyright (C) 2018 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.chatopera.cc.handler.admin.channel;
import com.chatopera.cc.basic.MainContext;
import com.chatopera.cc.basic.MainUtils;
import com.chatopera.cc.handler.Handler;
import com.chatopera.cc.model.CousultInvite;
import com.chatopera.cc.model.SNSAccount;
import com.chatopera.cc.model.Secret;
import com.chatopera.cc.persistence.repository.ConsultInviteRepository;
import com.chatopera.cc.persistence.repository.SNSAccountRepository;
import com.chatopera.cc.persistence.repository.SecretRepository;
import com.chatopera.cc.exception.CSKefuException;
import com.chatopera.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;
@Controller
@RequestMapping("/admin/callout")
public class CalloutChannelController extends Handler {
@Autowired
private SNSAccountRepository snsAccountRes;
@Autowired
private ConsultInviteRepository invite;
@Autowired
private SecretRepository secRes;
@RequestMapping("/index")
@Menu(type = "callout", subtype = "channel", access = false, admin = true)
public ModelAndView index(ModelMap map, HttpServletRequest request, @Valid String execute, @RequestParam(name = "status", required = false) String status) {
map.addAttribute("snsAccountList", snsAccountRes.findBySnstypeAndOrgi(MainContext.ChannelType.PHONE.toString(), super.getOrgi(request), 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.createAdminTempletResponse("/admin/channel/callout/index"));
}
@RequestMapping("/add")
@Menu(type = "callout", subtype = "channel", access = false, admin = true)
public ModelAndView add(ModelMap map, HttpServletRequest request) {
return request(super.createRequestPageTempletResponse("/admin/channel/callout/add"));
}
@RequestMapping("/save")
@Menu(type = "callout", subtype = "channel")
public ModelAndView save(HttpServletRequest request, @Valid SNSAccount snsAccount) throws NoSuchAlgorithmException, CSKefuException {
String status = "new_webim_fail";
if (StringUtils.isNotBlank(snsAccount.getBaseURL())) {
snsAccount.setSnsid(snsAccount.getBaseURL()); // set sns ID the same SNSAccount
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.PHONE.toString());
snsAccount.setCreatetime(new Date());
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());
invite.save(coultInvite);
}
}
}
return request(super.createRequestPageTempletResponse("redirect:/admin/callout/index.html?status=" + status));
}
@RequestMapping("/delete")
@Menu(type = "callout", subtype = "delete")
public ModelAndView delete(ModelMap map, HttpServletRequest request, @Valid String id, @Valid String confirm) {
boolean execute = false;
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);
}
}
}
return request(super.createRequestPageTempletResponse("redirect:/admin/callout/index.html?execute=" + execute));
}
@RequestMapping("/edit")
@Menu(type = "callout", subtype = "channel", access = false, admin = true)
public ModelAndView edit(ModelMap map, HttpServletRequest request, @Valid String id) {
map.addAttribute("snsAccount", snsAccountRes.findByIdAndOrgi(id, super.getOrgi(request)));
return request(super.createRequestPageTempletResponse("/admin/channel/callout/edit"));
}
@RequestMapping("/update")
@Menu(type = "callout", subtype = "channel", 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.PHONE.toString());
snsAccountRes.save(oldSnsAccount);
}
return request(super.createRequestPageTempletResponse("redirect:/admin/callout/index.html"));
}
}

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018 Chatopera Inc, <https://www.chatopera.com>
* Modifications copyright (C) 2018-2019 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.

View File

@ -0,0 +1,371 @@
/*
* Copyright (C) 2017 优客服-多渠道客服系统
* Modifications copyright (C) 2018-2019 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.chatopera.cc.handler.api;
import com.chatopera.cc.acd.AutomaticServiceDist;
import com.chatopera.cc.basic.MainContext.*;
import com.chatopera.cc.basic.MainUtils;
import com.chatopera.cc.cache.Cache;
import com.chatopera.cc.exception.CSKefuException;
import com.chatopera.cc.handler.Handler;
import com.chatopera.cc.handler.api.request.RestUtils;
import com.chatopera.cc.model.*;
import com.chatopera.cc.peer.PeerSyncIM;
import com.chatopera.cc.persistence.repository.AgentServiceRepository;
import com.chatopera.cc.persistence.repository.AgentUserRepository;
import com.chatopera.cc.persistence.repository.UserRepository;
import com.chatopera.cc.proxy.AgentAuditProxy;
import com.chatopera.cc.proxy.AgentUserProxy;
import com.chatopera.cc.socketio.message.Message;
import com.chatopera.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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
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 java.util.Date;
import java.util.List;
/**
* ACD服务 获取当前对话中的访客
*/
@RestController
@RequestMapping("/api/agentuser")
public class ApiAgentUserController extends Handler {
private final static Logger logger = LoggerFactory.getLogger(ApiAgentUserController.class);
@Autowired
private Cache cache;
@Autowired
private PeerSyncIM peerSyncIM;
@Autowired
private AgentUserRepository agentUserRes;
@Autowired
private UserRepository userRes;
@Autowired
private AgentServiceRepository agentServiceRes;
@Autowired
private AgentUserProxy agentUserProxy;
@Autowired
private AgentAuditProxy agentAuditProxy;
/**
* 获取当前对话中的访客
* 坐席相关 RestAPI
*
* @param request
* @return
*/
@RequestMapping(method = RequestMethod.POST)
@Menu(type = "apps", subtype = "agentuser", access = true)
public ResponseEntity<String> operations(HttpServletRequest request, @RequestBody final String body, @Valid String q) {
logger.info("[operations] body {}, q {}", body, q);
final JsonObject j = StringUtils.isBlank(body) ? (new JsonObject()) : (new JsonParser()).parse(
body).getAsJsonObject();
JsonObject json = new JsonObject();
HttpHeaders headers = RestUtils.header();
if (!j.has("ops")) {
json.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_1);
json.addProperty(RestUtils.RESP_KEY_ERROR, "不合法的请求参数。");
} else {
switch (StringUtils.lowerCase(j.get("ops").getAsString())) {
case "inserv":
json = inserv(request, j);
break;
case "withdraw":
json = withdraw(request, j);
break;
case "end":
json = end(request, j);
break;
case "transout":
json = transout(request, j);
break;
default:
json.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_2);
json.addProperty(RestUtils.RESP_KEY_ERROR, "不合法的操作。");
}
}
return new ResponseEntity<String>(json.toString(), headers, HttpStatus.OK);
}
/**
* 执行坐席转接
* 将会话转接给别人
*
* @param request
* @param payload
* @return
*/
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();
/**
* 必填参数
*/
// 目标坐席
final String transAgentId = payload.get("agentno").getAsString();
// 当前会话的ID
final String agentUserId = payload.get("agentUserId").getAsString();
// 坐席服务ID
final String agentServiceId = payload.get("agentServiceId").getAsString();
if (StringUtils.isNotBlank(agentUserId) &&
StringUtils.isNotBlank(transAgentId) &&
StringUtils.isNotBlank(agentServiceId)) {
final User targetAgent = userRes.findOne(transAgentId);
final AgentService agentService = agentServiceRes.findByIdAndOrgi(agentServiceId, orgi);
/**
* 更新AgentUser
*/
final AgentUser agentUser = agentUserProxy.findOne(agentUserId).orElseGet(null);
if (agentUser != null) {
final AgentUserAudit agentAudits = cache.findOneAgentUserAuditByOrgiAndId(orgi, agentUserId).orElseGet(
null);
// 当前服务于访客的坐席
final String currentAgentno = agentUser.getAgentno();
// 当前访客的ID
final String userId = agentUser.getUserid();
// 检查权限
if ((!logined.isSuperuser()) && (!StringUtils.equals(
agentUser.getAgentno(),
logined.getId())) && (!isTransPermissionAllowed(
agentAudits, logined))) {
// 1. 不是超级用户2. 也是不是会话的所有者; 3. 也不是坐席监控人员
logger.info("[end] Permission not fulfill.");
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_3);
resp.addProperty(RestUtils.RESP_KEY_ERROR, "Permission denied.");
return resp;
}
agentUser.setAgentno(transAgentId);
agentUser.setAgentname(targetAgent.getUname());
agentUserRes.save(agentUser);
/**
* 坐席状态
*/
// 转接目标坐席
final AgentStatus transAgentStatus = cache.findOneAgentStatusByAgentnoAndOrig(transAgentId, orgi);
// 转接源坐席
final AgentStatus currentAgentStatus = cache.findOneAgentStatusByAgentnoAndOrig(currentAgentno, orgi);
if (StringUtils.equals(
AgentUserStatusEnum.INSERVICE.toString(),
agentUser.getStatus())) { //转接 发送消息给 目标坐席
// 更新当前坐席的服务访客列表
if (currentAgentStatus != null) {
cache.deleteOnlineUserIdFromAgentStatusByUseridAndAgentnoAndOrgi(userId, currentAgentno, orgi);
AutomaticServiceDist.updateAgentStatus(currentAgentStatus, orgi);
}
if (transAgentStatus != null) {
agentService.setAgentno(transAgentId);
agentService.setAgentusername(transAgentStatus.getUsername());
}
// 转接坐席提示消息
Message outMessage = new Message();
outMessage.setMessage(
AutomaticServiceDist.getSuccessMessage(agentService, agentUser.getChannel(), orgi));
outMessage.setMessageType(MediaType.TEXT.toString());
outMessage.setCalltype(CallType.IN.toString());
outMessage.setCreatetime(MainUtils.dateFormate.format(new Date()));
outMessage.setAgentUser(agentUser);
outMessage.setAgentService(agentService);
if (StringUtils.isNotBlank(agentUser.getUserid())) {
peerSyncIM.send(
ReceiverType.VISITOR,
ChannelType.toValue(agentUser.getChannel()),
agentUser.getAppid(),
MessageType.STATUS,
agentUser.getUserid(),
outMessage,
true);
}
// 通知转接消息给新坐席
outMessage.setChannelMessage(agentUser);
outMessage.setAgentUser(agentUser);
peerSyncIM.send(
ReceiverType.AGENT, ChannelType.WEBIM,
agentUser.getAppid(), MessageType.NEW, agentService.getAgentno(),
outMessage, true);
// 通知消息给前坐席
if (!StringUtils.equals(logined.getId(), currentAgentno)) {
// 如果当前坐席不是登录用户因为登录用户会从RestAPI返回转接的结果
// 该登录用户可能是坐席监控或当前坐席那么如果是坐席监控就有必要
// 通知前坐席这个事件
peerSyncIM.send(ReceiverType.AGENT, ChannelType.WEBIM, agentUser.getAppid(),
MessageType.TRANSOUT,
currentAgentno, outMessage, true);
}
}
if (agentService != null) {
agentService.setAgentno(transAgentId);
if (payload.has("memo") && StringUtils.isNotBlank(payload.get("memo").getAsString())) {
agentService.setTransmemo(payload.get("memo").getAsString());
}
agentService.setTrans(true);
agentService.setTranstime(new Date());
agentServiceRes.save(agentService);
}
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_SUCC);
resp.addProperty(RestUtils.RESP_KEY_DATA, "success");
} else {
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_4);
resp.addProperty(RestUtils.RESP_KEY_ERROR, "Can not find agent user.");
}
} else {
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_5);
resp.addProperty(RestUtils.RESP_KEY_ERROR, "Invalid params.");
}
return resp;
}
/**
* 结束坐席会话
*
* @param request
* @param payload
* @return
*/
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);
if (agentUser != null) {
if ((StringUtils.equals(
logined.getId(), agentUser.getAgentno()) || logined.isSuperuser())) {
// 删除访客-坐席关联关系包括缓存
try {
AutomaticServiceDist.deleteAgentUser(agentUser, orgi);
} catch (CSKefuException e) {
// 未能删除成功
logger.error("[end]", e);
}
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_SUCC);
resp.addProperty(RestUtils.RESP_KEY_DATA, "success");
} else {
logger.info("[end] Permission not fulfill.");
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_3);
resp.addProperty(RestUtils.RESP_KEY_ERROR, "Permission denied.");
}
} else {
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_FAIL_4);
resp.addProperty(RestUtils.RESP_KEY_ERROR, "Agent User not found.");
}
return resp;
}
/**
* 撤退一个坐席
* 将当前坐席服务中的访客分配给其他就绪的坐席
*
* @param request
* @param j
* @return
*/
private JsonObject withdraw(final HttpServletRequest request, final JsonObject j) {
JsonObject resp = new JsonObject();
AutomaticServiceDist.withdrawAgent(super.getOrgi(request), super.getUser(request).getId());
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_SUCC);
return resp;
}
/**
* 获得当前访客服务中的访客信息
* 获取当前正在对话的访客信息包含多种渠道来源的访客
*
* @param request
* @param j
* @return
*/
private JsonObject inserv(final HttpServletRequest request, final JsonObject j) {
JsonObject resp = new JsonObject();
JsonArray data = new JsonArray();
List<AgentUser> lis = cache.findInservAgentUsersByAgentnoAndOrgi(
super.getUser(request).getId(), super.getOrgi(request));
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("nickname", au.getNickname());
data.add(obj);
}
resp.addProperty(RestUtils.RESP_KEY_RC, RestUtils.RESP_RC_SUCC);
resp.add("data", data);
return resp;
}
/**
* 检查是否具备该会话的坐席监控权限
*
* @param agentUserAudit
* @param user
* @return
*/
private boolean isTransPermissionAllowed(final AgentUserAudit agentUserAudit, final User user) {
if (agentUserAudit != null && agentUserAudit.getSubscribers().containsKey(user.getId())) {
return true;
}
return false;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 Chatopera Inc, All rights reserved.
* Copyright (C) 2018-2019 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.
@ -8,7 +8,7 @@
* 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.chatopera.cc.handler.api.rest;
package com.chatopera.cc.handler.api;
import com.chatopera.cc.basic.MainContext;
import com.chatopera.cc.cache.Cache;

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