From 24d1881fa0902aed5d5e3b6e1943fd2171603c41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=9C=E7=9A=87=E5=A4=A7=E5=8F=94?= Date: Fri, 10 Jul 2020 10:00:11 +0800 Subject: [PATCH] add dial group/queue --- .../yo-cms-web-0.0.1-SNAPSHOT.jar | Bin 1687246 -> 1686095 bytes .../cms/controller/AgentStatusController.java | 35 +++++ .../cms/form/create/CreateFormSequence.java | 9 +- .../yo/cms/service/AgentStatusService.java | 12 ++ .../yo/cms/service/SequenceService.java | 13 +- .../service/impl/AgentGroupServiceImpl.java | 3 +- .../yo/cms/service/impl/AgentServiceImpl.java | 2 +- .../service/impl/AgentStatusServiceImpl.java | 19 +++ .../yo/cms/service/impl/QueueServiceImpl.java | 4 +- .../cms/service/impl/SequenceServiceImpl.java | 44 ++++-- .../yo/cms/service/impl/TrunkServiceImpl.java | 15 +- .../resources/application-test.properties | 3 +- .../controller/BaseDialplanController.java | 10 +- .../fsagent/controller/ConfigController.java | 4 +- .../DialplanInternalController.java | 127 +++++++++++++--- .../yo/fsagent/listener/ChannelAnswer.java | 13 +- .../yo/fsagent/listener/ChannelCreate.java | 4 +- .../yo/fsagent/listener/ChannelDestroy.java | 6 +- .../listener/ChannelHangupComplete.java | 6 +- .../yo/fsagent/listener/ChannelProgress.java | 6 +- .../yo/fsagent/service/GatewayService.java | 16 ++ .../yo/fsagent/service/TrunkService.java | 9 ++ .../service/impl/GatewayerviceImpl.java | 21 ++- .../service/impl/TrunkServiceImpl.java | 39 ++++- ...hannelNameUtils.java => CallStrUtils.java} | 38 ++++- .../templates/dialplan/trunk-outbound.xml | 39 +++++ .../src/main/resources/templates/empty.xml | 2 +- .../yo/fsagent/ChannelNameUtilsTest.java | 6 +- .../pudonghot/yo/model/domain/Sequence.java | 2 + .../controller/AgentStatusController.java | 3 +- web/cms/app/nav-items.js | 14 +- web/cms/app/router.js | 14 +- web/cms/app/routes/agent-status/list.js | 6 + web/cms/app/routes/calling-list/create.js | 34 ----- web/cms/app/routes/calling-list/edit.js | 28 ---- web/cms/app/routes/calling-list/list.js | 6 - web/cms/app/routes/sequence/create.js | 1 + .../services/nlp-component-group/service.js | 14 -- web/cms/app/services/nlp-component/service.js | 32 ---- .../app/services/nlp-node-sample/service.js | 15 -- web/cms/app/services/nlp-node/service.js | 25 ---- .../app/services/nlp-term-group/service.js | 14 -- web/cms/app/services/nlp-term/service.js | 24 --- web/cms/app/services/sequence/service.js | 17 ++- .../app/services/talk-component/service.js | 53 ------- web/cms/app/services/talk-group/service.js | 14 -- web/cms/app/services/talk/service.js | 57 -------- web/cms/app/services/voice-actor/service.js | 21 --- web/cms/app/templates/agent-status/list.hbs | 88 +++++++++++ web/cms/app/templates/calling-list/create.hbs | 41 ------ web/cms/app/templates/calling-list/edit.hbs | 60 -------- web/cms/app/templates/calling-list/list.hbs | 137 ------------------ web/cms/app/templates/campaign/list.hbs | 7 - web/cms/app/templates/sequence/create.hbs | 1 + web/cms/app/templates/sequence/edit.hbs | 3 +- web/cms/app/templates/sequence/list.hbs | 6 + .../unit/routes/agent-status/list-test.js | 11 ++ 57 files changed, 556 insertions(+), 697 deletions(-) create mode 100644 cms/src/main/java/com/pudonghot/yo/cms/controller/AgentStatusController.java create mode 100644 cms/src/main/java/com/pudonghot/yo/cms/service/AgentStatusService.java create mode 100644 cms/src/main/java/com/pudonghot/yo/cms/service/impl/AgentStatusServiceImpl.java rename fsagent/src/main/java/com/pudonghot/yo/fsagent/util/{ChannelNameUtils.java => CallStrUtils.java} (56%) create mode 100644 fsagent/src/main/resources/templates/dialplan/trunk-outbound.xml create mode 100644 web/cms/app/routes/agent-status/list.js delete mode 100644 web/cms/app/routes/calling-list/create.js delete mode 100644 web/cms/app/routes/calling-list/edit.js delete mode 100644 web/cms/app/routes/calling-list/list.js delete mode 100644 web/cms/app/services/nlp-component-group/service.js delete mode 100644 web/cms/app/services/nlp-component/service.js delete mode 100644 web/cms/app/services/nlp-node-sample/service.js delete mode 100644 web/cms/app/services/nlp-node/service.js delete mode 100644 web/cms/app/services/nlp-term-group/service.js delete mode 100644 web/cms/app/services/nlp-term/service.js delete mode 100644 web/cms/app/services/talk-component/service.js delete mode 100644 web/cms/app/services/talk-group/service.js delete mode 100644 web/cms/app/services/talk/service.js delete mode 100644 web/cms/app/services/voice-actor/service.js create mode 100644 web/cms/app/templates/agent-status/list.hbs delete mode 100644 web/cms/app/templates/calling-list/create.hbs delete mode 100644 web/cms/app/templates/calling-list/edit.hbs delete mode 100644 web/cms/app/templates/calling-list/list.hbs create mode 100644 web/cms/tests/unit/routes/agent-status/list-test.js diff --git a/cms/local-repo/com/pudonghot/yo/yo-cms-web/0.0.1-SNAPSHOT/yo-cms-web-0.0.1-SNAPSHOT.jar b/cms/local-repo/com/pudonghot/yo/yo-cms-web/0.0.1-SNAPSHOT/yo-cms-web-0.0.1-SNAPSHOT.jar index 12fdc462e216ff494a6a5c64f628b3c73aa08f48..afb4490007a760075c9da5c61e8fac17abb631bc 100644 GIT binary patch delta 44687 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 Q7ry*@C>^#`A`~G0e`>+eumAu6 delta 45915 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

S|yTOH}u<>#4M`O&Ae2L7!+Sh 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 z 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 WK@^DB|1N_tH-e~;JJLbWX#WRghGcXA diff --git a/cms/src/main/java/com/pudonghot/yo/cms/controller/AgentStatusController.java b/cms/src/main/java/com/pudonghot/yo/cms/controller/AgentStatusController.java new file mode 100644 index 00000000..56fec62e --- /dev/null +++ b/cms/src/main/java/com/pudonghot/yo/cms/controller/AgentStatusController.java @@ -0,0 +1,35 @@ +package com.pudonghot.yo.cms.controller; + +import com.wacai.tigon.form.FormList; +import com.pudonghot.yo.model.domain.Agent; +import com.wacai.tigon.web.annotation.ListApi; +import com.wacai.tigon.web.annotation.FilterCol; +import com.pudonghot.yo.model.domain.AgentStatus; +import org.springframework.stereotype.Controller; +import com.pudonghot.yo.cms.annotation.TenantResource; +import com.wacai.tigon.web.controller.BaseQueryController; +import org.springframework.web.bind.annotation.RequestMapping; + +/** + * @author Donghuang + * @date Jul 09, 2020 16:44:23 + */ +@Controller +@ListApi(searchCols = { + Agent.NAME, + Agent.ACCOUNT, + Agent.AGENT, + Agent.NOTE +}, +filterCols = { + @FilterCol(param = AgentStatus.STATUS, type = AgentStatus.Status.class), + @FilterCol(param = AgentStatus.STATE, type = AgentStatus.State.class), + @FilterCol(param = AgentStatus.REGISTERED, type = boolean.class), +}) +@TenantResource +@RequestMapping("/agent-status") +public class AgentStatusController + extends BaseQueryController { +} diff --git a/cms/src/main/java/com/pudonghot/yo/cms/form/create/CreateFormSequence.java b/cms/src/main/java/com/pudonghot/yo/cms/form/create/CreateFormSequence.java index 977d4598..b32bb5cc 100644 --- a/cms/src/main/java/com/pudonghot/yo/cms/form/create/CreateFormSequence.java +++ b/cms/src/main/java/com/pudonghot/yo/cms/form/create/CreateFormSequence.java @@ -2,10 +2,7 @@ package com.pudonghot.yo.cms.form.create; import lombok.Getter; import lombok.Setter; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.NotBlank; +import javax.validation.constraints.*; import com.wacai.tigon.format.annotation.Trim; import com.pudonghot.yo.cms.form.BaseCreateForm; @@ -20,10 +17,14 @@ public class CreateFormSequence extends BaseCreateForm { @NotBlank @Pattern(regexp = "^\\w+$", message = "序列名必须是字母数字下划线构成") private String name; + @Min(2) + @Max(16) + private int length; @Min(1) @NotNull private Long initVal; @Min(1) + @Max(128) @NotNull private Long step; } diff --git a/cms/src/main/java/com/pudonghot/yo/cms/service/AgentStatusService.java b/cms/src/main/java/com/pudonghot/yo/cms/service/AgentStatusService.java new file mode 100644 index 00000000..f3e9e4f9 --- /dev/null +++ b/cms/src/main/java/com/pudonghot/yo/cms/service/AgentStatusService.java @@ -0,0 +1,12 @@ +package com.pudonghot.yo.cms.service; + +import com.pudonghot.yo.model.domain.AgentStatus; +import com.wacai.tigon.service.BaseQueryService; + +/** + * @author Donghuang + * @date Jul 09, 2020 16:53:30 + */ +public interface AgentStatusService + extends BaseQueryService { +} diff --git a/cms/src/main/java/com/pudonghot/yo/cms/service/SequenceService.java b/cms/src/main/java/com/pudonghot/yo/cms/service/SequenceService.java index 41f30e59..688aa3a2 100644 --- a/cms/src/main/java/com/pudonghot/yo/cms/service/SequenceService.java +++ b/cms/src/main/java/com/pudonghot/yo/cms/service/SequenceService.java @@ -1,9 +1,9 @@ package com.pudonghot.yo.cms.service; -import com.pudonghot.yo.cms.form.create.CreateFormSequence; -import com.pudonghot.yo.cms.form.update.UpdateFormSequence; import com.pudonghot.yo.model.domain.Sequence; import com.wacai.tigon.service.BaseCrudByFormService; +import com.pudonghot.yo.cms.form.create.CreateFormSequence; +import com.pudonghot.yo.cms.form.update.UpdateFormSequence; /** * @author Donghuang
@@ -22,4 +22,13 @@ public interface SequenceService * @return next seq val */ Long nextVal(Integer tenantId, String name); + + /** + * next seq val string, padding 0 to length + * + * @param tenantId tenant id + * @param name seq name + * @return next val + */ + String nextValStr(Integer tenantId, String name); } diff --git a/cms/src/main/java/com/pudonghot/yo/cms/service/impl/AgentGroupServiceImpl.java b/cms/src/main/java/com/pudonghot/yo/cms/service/impl/AgentGroupServiceImpl.java index 8e0d0aa7..46193fc3 100644 --- a/cms/src/main/java/com/pudonghot/yo/cms/service/impl/AgentGroupServiceImpl.java +++ b/cms/src/main/java/com/pudonghot/yo/cms/service/impl/AgentGroupServiceImpl.java @@ -99,8 +99,7 @@ public class AgentGroupServiceImpl super.beforeInsert(model); if (StringUtils.isBlank(model.getIdentifier())) { model.setIdentifier(identifierPrefix + - StringUtils.leftPad(String.valueOf( - seqService.nextVal(model.getTenantId(), seqName)), 6, '0')); + seqService.nextValStr(model.getTenantId(), seqName)); } } diff --git a/cms/src/main/java/com/pudonghot/yo/cms/service/impl/AgentServiceImpl.java b/cms/src/main/java/com/pudonghot/yo/cms/service/impl/AgentServiceImpl.java index a8b3a743..0d5d032d 100644 --- a/cms/src/main/java/com/pudonghot/yo/cms/service/impl/AgentServiceImpl.java +++ b/cms/src/main/java/com/pudonghot/yo/cms/service/impl/AgentServiceImpl.java @@ -131,7 +131,7 @@ public class AgentServiceImpl protected void beforeInsert(final Agent model) { super.beforeInsert(model); if (StringUtils.isBlank(model.getAgent())) { - model.setAgent(String.valueOf(seqService.nextVal(model.getTenantId(), seqName))); + model.setAgent(seqService.nextValStr(model.getTenantId(), seqName)); } if (StringUtils.isBlank(model.getPassword())) { diff --git a/cms/src/main/java/com/pudonghot/yo/cms/service/impl/AgentStatusServiceImpl.java b/cms/src/main/java/com/pudonghot/yo/cms/service/impl/AgentStatusServiceImpl.java new file mode 100644 index 00000000..f0c12dca --- /dev/null +++ b/cms/src/main/java/com/pudonghot/yo/cms/service/impl/AgentStatusServiceImpl.java @@ -0,0 +1,19 @@ +package com.pudonghot.yo.cms.service.impl; + +import org.springframework.stereotype.Service; +import com.pudonghot.yo.mapper.AgentStatusMapper; +import com.pudonghot.yo.model.domain.AgentStatus; +import com.pudonghot.yo.cms.service.AgentStatusService; +import com.wacai.tigon.service.support.BaseQueryServiceSupport; + +/** + * @author Donghuang
+ * Dec 24, 2019 16:49:51 + */ +@Service +public class AgentStatusServiceImpl + extends BaseQueryServiceSupport + implements AgentStatusService { +} diff --git a/cms/src/main/java/com/pudonghot/yo/cms/service/impl/QueueServiceImpl.java b/cms/src/main/java/com/pudonghot/yo/cms/service/impl/QueueServiceImpl.java index a1bdb821..dd8b693e 100644 --- a/cms/src/main/java/com/pudonghot/yo/cms/service/impl/QueueServiceImpl.java +++ b/cms/src/main/java/com/pudonghot/yo/cms/service/impl/QueueServiceImpl.java @@ -50,9 +50,7 @@ public class QueueServiceImpl final Tenant tenant = tenantMapper.find(tenantId); Assert.state(tenant != null, () -> "No tenant [" + tenantId + "] found"); - model.setIdentifier(identifierPrefix + - StringUtils.leftPad(String.valueOf( - seqService.nextVal(tenantId, seqName)), 6, '0')); + model.setIdentifier(identifierPrefix + seqService.nextValStr(tenantId, seqName)); } } } diff --git a/cms/src/main/java/com/pudonghot/yo/cms/service/impl/SequenceServiceImpl.java b/cms/src/main/java/com/pudonghot/yo/cms/service/impl/SequenceServiceImpl.java index 334b2840..590cc2e5 100644 --- a/cms/src/main/java/com/pudonghot/yo/cms/service/impl/SequenceServiceImpl.java +++ b/cms/src/main/java/com/pudonghot/yo/cms/service/impl/SequenceServiceImpl.java @@ -1,13 +1,14 @@ package com.pudonghot.yo.cms.service.impl; -import com.pudonghot.yo.cms.form.create.CreateFormSequence; import lombok.extern.slf4j.Slf4j; import com.wacai.tigon.mybatis.Search; +import org.apache.commons.lang3.StringUtils; import org.springframework.util.Assert; import org.springframework.stereotype.Service; import com.pudonghot.yo.mapper.SequenceMapper; import com.pudonghot.yo.model.domain.Sequence; import com.pudonghot.yo.cms.service.SequenceService; +import com.pudonghot.yo.cms.form.create.CreateFormSequence; import com.pudonghot.yo.cms.form.update.UpdateFormSequence; import org.springframework.transaction.annotation.Transactional; import com.wacai.tigon.service.support.BaseCrudByFormServiceSupport; @@ -42,17 +43,18 @@ public class SequenceServiceImpl * {@inheritDoc} */ @Override - @Transactional + @Transactional(rollbackFor = RuntimeException.class) public Long nextVal(final Integer tenantId, final String name) { - final Sequence seq = mapper.findForUpdate( - new Search(Sequence.NAME, name) - .eq(Sequence.TENANT_ID, tenantId) - .eq(Sequence.ACTIVE, true)); - Assert.state(seq != null, () -> "No valid sequence [" + name + "] found"); - final Long nextVal = seq.getCurrentVal() + seq.getStep(); - seq.setCurrentVal(nextVal); - mapper.update(seq); - return nextVal; + return nextVal(tenantId, name, false); + } + + /** + * {@inheritDoc} + */ + @Override + @Transactional(rollbackFor = RuntimeException.class) + public String nextValStr(final Integer tenantId, final String name) { + return nextVal(tenantId, name, true); } /** @@ -61,8 +63,28 @@ public class SequenceServiceImpl @Override protected void beforeInsert(final Sequence model) { super.beforeInsert(model); + Assert.state(String.valueOf(model.getInitVal()).length() <= model.getLength(), + "Sequence init value exceeds length"); if (model.getCurrentVal() == null) { model.setCurrentVal(model.getInitVal()); } } + + T nextVal(final Integer tenantId, final String name, final boolean str) { + final Sequence seq = mapper.findForUpdate( + new Search(Sequence.TENANT_ID, tenantId) + .eq(Sequence.NAME, name) + .eq(Sequence.ACTIVE, true)); + Assert.state(seq != null, () -> + "No valid sequence [" + name + "] found"); + final Long nextVal = seq.getCurrentVal() + seq.getStep(); + final String strVal = String.valueOf(nextVal); + Assert.state(strVal.length() <= seq.getLength(), + "Sequence next value exceeds length"); + seq.setCurrentVal(nextVal); + mapper.update(seq); + return str ? (T) StringUtils.leftPad(strVal, seq.getLength(), '0') + : (T) nextVal; + } + } diff --git a/cms/src/main/java/com/pudonghot/yo/cms/service/impl/TrunkServiceImpl.java b/cms/src/main/java/com/pudonghot/yo/cms/service/impl/TrunkServiceImpl.java index 623e2459..d9e79e20 100644 --- a/cms/src/main/java/com/pudonghot/yo/cms/service/impl/TrunkServiceImpl.java +++ b/cms/src/main/java/com/pudonghot/yo/cms/service/impl/TrunkServiceImpl.java @@ -1,29 +1,27 @@ package com.pudonghot.yo.cms.service.impl; import java.util.*; - -import com.pudonghot.yo.cms.form.SessionForm; -import com.pudonghot.yo.cms.form.create.CreateFormTrunk; import com.pudonghot.yo.mapper.*; -import com.pudonghot.yo.model.domain.*; import lombok.extern.slf4j.Slf4j; import java.util.stream.Collectors; import java.util.function.BiConsumer; - import com.wacai.tigon.mybatis.Search; +import com.pudonghot.yo.model.domain.*; import com.wacai.tigon.model.ViewModel; import org.springframework.util.Assert; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.StringUtils; +import com.pudonghot.yo.cms.form.SessionForm; import org.springframework.stereotype.Service; import com.pudonghot.yo.cellphone.CellphoneInfo; import com.pudonghot.yo.common.util.MobileUtils; -import com.pudonghot.yo.cellphone.CellphoneService; import com.pudonghot.yo.cms.service.TrunkService; +import com.pudonghot.yo.cellphone.CellphoneService; import com.pudonghot.yo.cms.service.AreaCodeService; import com.pudonghot.yo.cms.service.SequenceService; -import org.springframework.beans.factory.annotation.Value; +import com.pudonghot.yo.cms.form.create.CreateFormTrunk; import com.pudonghot.yo.cms.form.update.UpdateFormTrunk; +import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Autowired; /** @@ -142,8 +140,7 @@ public class TrunkServiceImpl protected void beforeInsert(final Trunk model) { super.beforeInsert(model); if (StringUtils.isBlank(model.getPrefix())) { - model.setPrefix(String.valueOf( - seqService.nextVal(model.getTenantId(), seqName))); + model.setPrefix(seqService.nextValStr(model.getTenantId(), seqName)); } } diff --git a/cms/src/main/resources/application-test.properties b/cms/src/main/resources/application-test.properties index e604a9d0..d21d938e 100644 --- a/cms/src/main/resources/application-test.properties +++ b/cms/src/main/resources/application-test.properties @@ -24,7 +24,8 @@ spring.redis.port=6379 # CAS tigon.shiro.cas.server.addr=http://118.24.251.131:8080/cas -tigon.shiro.cas.client.addr=http://118.24.251.131:8080/cms/ +tigon.shiro.cas.client.addr=http://118.24.251.131:8080/cms +tigon.shiro.cas.login-success-url=/cms/ tigon.shiro.filter-chain=${site.context-path}/auth/login=anon \ /=anon \ /state-machine/**=anon \ diff --git a/fsagent/src/main/java/com/pudonghot/yo/fsagent/controller/BaseDialplanController.java b/fsagent/src/main/java/com/pudonghot/yo/fsagent/controller/BaseDialplanController.java index e21b336e..e6240c1f 100644 --- a/fsagent/src/main/java/com/pudonghot/yo/fsagent/controller/BaseDialplanController.java +++ b/fsagent/src/main/java/com/pudonghot/yo/fsagent/controller/BaseDialplanController.java @@ -1,8 +1,8 @@ package com.pudonghot.yo.fsagent.controller; -import com.pudonghot.yo.model.domain.Tenant; import lombok.extern.slf4j.Slf4j; import com.wacai.tigon.mybatis.Search; +import com.pudonghot.yo.model.domain.Tenant; import org.apache.commons.lang3.time.DateFormatUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.RequestMapping; @@ -43,4 +43,12 @@ public class BaseDialplanController extends BaseXmlController { thisDn + "-" + otherDn + recordingFileExt; } + + /** + * return empty dial plan + * @return empty dial plan + */ + protected FreeMarkerView empty() { + return empty(SECTION_DIALPLAN); + } } diff --git a/fsagent/src/main/java/com/pudonghot/yo/fsagent/controller/ConfigController.java b/fsagent/src/main/java/com/pudonghot/yo/fsagent/controller/ConfigController.java index f5a36b04..3509b689 100644 --- a/fsagent/src/main/java/com/pudonghot/yo/fsagent/controller/ConfigController.java +++ b/fsagent/src/main/java/com/pudonghot/yo/fsagent/controller/ConfigController.java @@ -5,7 +5,6 @@ import java.util.List; import javax.sql.DataSource; import lombok.extern.slf4j.Slf4j; import com.wacai.tigon.mybatis.Search; -import org.apache.commons.lang3.StringUtils; import com.pudonghot.yo.model.domain.Gateway; import com.alibaba.druid.pool.DruidDataSource; import com.pudonghot.yo.fsagent.util.OdbcUtils; @@ -55,8 +54,7 @@ public class ConfigController extends BaseXmlController { final FreeMarkerView view = view("config/sofia.conf.xml"); final List gateways = gatewayService.list( new Search(Gateway.ACTIVE, true)); - gateways.forEach(g -> g.setName( - "GW" + StringUtils.leftPad(String.valueOf(g.getId()), 6, '0'))); + gateways.forEach(g -> g.setName(gatewayService.genGatewayName(g))); attr(view, "gateways", gateways); return view; diff --git a/fsagent/src/main/java/com/pudonghot/yo/fsagent/controller/DialplanInternalController.java b/fsagent/src/main/java/com/pudonghot/yo/fsagent/controller/DialplanInternalController.java index cec4a2ee..502883a3 100644 --- a/fsagent/src/main/java/com/pudonghot/yo/fsagent/controller/DialplanInternalController.java +++ b/fsagent/src/main/java/com/pudonghot/yo/fsagent/controller/DialplanInternalController.java @@ -2,14 +2,20 @@ package com.pudonghot.yo.fsagent.controller; import java.util.Map; import lombok.extern.slf4j.Slf4j; +import com.pudonghot.yo.fsagent.service.*; +import com.pudonghot.yo.model.domain.Queue; +import com.pudonghot.yo.model.domain.Trunk; import com.pudonghot.yo.model.domain.Agent; import com.wacai.tigon.sequence.IdSequence; +import org.apache.commons.lang3.tuple.Pair; +import org.springframework.util.DigestUtils; +import com.pudonghot.yo.model.domain.AgentGroup; import org.springframework.stereotype.Controller; -import com.pudonghot.yo.fsagent.service.AgentService; -import com.pudonghot.yo.fsagent.service.LocalApiService; +import com.pudonghot.yo.fsagent.util.CallStrUtils; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; +import static com.pudonghot.yo.fsagent.util.CallStrUtils.DialTarget; import org.springframework.web.servlet.view.freemarker.FreeMarkerView; /** @@ -22,9 +28,17 @@ public class DialplanInternalController extends BaseDialplanController { @Autowired private AgentService agentService; @Autowired + private AgentGroupService agentGroupService; + @Autowired + private QueueService queueService; + @Autowired private LocalApiService localApiService; @Autowired private IdSequence idSeq; + @Autowired + private TrunkService trunkService; + @Autowired + private GatewayService gatewayService; @RequestMapping(params = { "variable_domain_name", @@ -41,31 +55,108 @@ public class DialplanInternalController extends BaseDialplanController { @RequestParam final Map params) { - log.info("XML dialplan of domain [{}].", domain); + log.info("XML dialplan of domain [{}] [{}] -> [{}].", domain, user, calledNumber); log.debug("XML dialplan params [{}].", params); + final Agent callerAgent = + agentService.findByDomainAndAgent(domain, user); + + final DialTarget dialTarget = + CallStrUtils.parseDialTarget(calledNumber); + + if (dialTarget != null) { + final Integer dialTargetId = dialTarget.getId(); + final DialTarget.Type dialTargetType = dialTarget.getType(); + + if (dialTargetType == DialTarget.Type.AGENT) { + final Agent calledAgent = agentService.find(dialTargetId); + if (calledAgent != null) { + return agentCallAgent(domain, callerAgent, calledAgent); + } + + log.warn("No agent found of dial target [{}].", calledNumber); + return empty(); + } + else if (dialTargetType == DialTarget.Type.AGENT_GROUP) { + final AgentGroup agentGroup = agentGroupService.find(dialTargetId); + if (agentGroup != null) { + final Agent calledAgent = + agentService.lockIdleOfGroup(dialTargetId); + if (calledAgent != null) { + return agentCallAgent(domain, callerAgent, calledAgent); + } + + log.warn("No idle agent found of group [{}].", calledNumber); + return empty(); + } + + log.warn("No agent group found of dial target [{}].", calledNumber); + return empty(); + } + else if (dialTargetType == DialTarget.Type.QUEUE) { + final Queue queue = queueService.find(dialTargetId); + if (queue != null) { + final Agent calledAgent = + agentService.lockIdleOfQueue(dialTargetId); + if (calledAgent != null) { + return agentCallAgent(domain, callerAgent, calledAgent); + } + + log.warn("No idle agent found of queue [{}].", calledNumber); + return empty(); + } + + log.warn("No queue found of dial target [{}].", calledNumber); + return empty(); + } + + log.error("Never here!!!"); + } + + final Pair trunkInfo = trunkService.parseDialTarget( + callerAgent.getTenantId(), calledNumber); + if (trunkInfo != null) { + log.info("Trunk outbound call found."); + final Trunk trunk = trunkInfo.getLeft(); + final String targetNumber = trunkInfo.getRight(); + + final FreeMarkerView view = view(domain, "trunk-outbound.xml"); + final String connId = idSeq.get(); + attr(view, "connId", connId); + attr(view, "callerAgent", callerAgent); + attr(view, "gatewayName", + gatewayService.genGatewayName(trunk.getGatewayId())); + attr(view, "targetNumber", targetNumber); + attr(view, "recordingLoc", recordingFile(connId, + callerAgent.getAccount(), + DigestUtils.md5DigestAsHex(targetNumber.getBytes()))); + attr(view, "postRecUrl", localApiService.getPostRecUrl()); + return view; + } + final Agent calledAgent = agentService.findOfCalled(domain, calledNumber); if (calledAgent != null) { log.info("Local extension [{}] found.", calledAgent); - final FreeMarkerView view = view(domain, "local-extension.xml"); - final String connId = idSeq.get(); - attr(view, "connId", connId); - attr(view, "destinationUser", calledAgent.getAgent()); - final Agent callerAgent = - agentService.findByDomainAndAgent(domain, user); - attr(view, "callerAgent", callerAgent); - attr(view, "calledAgent", calledAgent); - attr(view, "recordingLoc", recordingFile(connId, - callerAgent.getAccount(), - calledAgent.getAccount())); - attr(view, "postRecUrl", localApiService.getPostRecUrl()); - return view; + return agentCallAgent(domain, callerAgent, calledAgent); } - // TODO Dial Queue + log.warn("No correct dialplan found for called number [{}].", calledNumber); + return empty(); + } - return view(domain, "dialplan.xml"); + private FreeMarkerView agentCallAgent(final String domain, Agent callerAgent, Agent calledAgent) { + final FreeMarkerView view = view(domain, "local-extension.xml"); + final String connId = idSeq.get(); + attr(view, "connId", connId); + attr(view, "destinationUser", calledAgent.getAgent()); + attr(view, "callerAgent", callerAgent); + attr(view, "calledAgent", calledAgent); + attr(view, "recordingLoc", recordingFile(connId, + callerAgent.getAccount(), + calledAgent.getAccount())); + attr(view, "postRecUrl", localApiService.getPostRecUrl()); + return view; } } diff --git a/fsagent/src/main/java/com/pudonghot/yo/fsagent/listener/ChannelAnswer.java b/fsagent/src/main/java/com/pudonghot/yo/fsagent/listener/ChannelAnswer.java index b6127bc3..c78aa503 100644 --- a/fsagent/src/main/java/com/pudonghot/yo/fsagent/listener/ChannelAnswer.java +++ b/fsagent/src/main/java/com/pudonghot/yo/fsagent/listener/ChannelAnswer.java @@ -8,7 +8,7 @@ import org.springframework.stereotype.Component; import com.pudonghot.yo.fsagent.util.EslEventUtils; import com.pudonghot.yo.model.agentevent.AgentEvent; import com.pudonghot.yo.fsagent.service.AgentService; -import com.pudonghot.yo.fsagent.util.ChannelNameUtils; +import com.pudonghot.yo.fsagent.util.CallStrUtils; import org.freeswitch.esl.client.transport.event.Event; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; @@ -39,13 +39,8 @@ public class ChannelAnswer { public void onChannelAnswer(final Event event) { log.debug("On channel answer event [{}] [{}].", event, event.getHeaders()); - // sofia/internal/700001@d1.wacai.info - // sofia/external/013764268709 - final String channelName = event.getHeader("variable_channel_name"); - log.info("On channel [{}] answer event.", channelName); - - final ChannelNameUtils.ChannelInfo channelInfo = - ChannelNameUtils.parse(channelName); + final CallStrUtils.ChannelInfo channelInfo = + CallStrUtils.getChannelInfo(event); if (channelInfo.isAgent()) { final Agent agent = findAgent(channelInfo); @@ -81,7 +76,7 @@ public class ChannelAnswer { } } - private Agent findAgent(final ChannelNameUtils.ChannelInfo channelInfo) { + private Agent findAgent(final CallStrUtils.ChannelInfo channelInfo) { return agentService.findByDomainAndAgent( channelInfo.getDomain(), channelInfo.getNumber()); } diff --git a/fsagent/src/main/java/com/pudonghot/yo/fsagent/listener/ChannelCreate.java b/fsagent/src/main/java/com/pudonghot/yo/fsagent/listener/ChannelCreate.java index 86508eea..46777922 100644 --- a/fsagent/src/main/java/com/pudonghot/yo/fsagent/listener/ChannelCreate.java +++ b/fsagent/src/main/java/com/pudonghot/yo/fsagent/listener/ChannelCreate.java @@ -2,7 +2,7 @@ package com.pudonghot.yo.fsagent.listener; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; -import com.pudonghot.yo.fsagent.util.ChannelNameUtils; +import com.pudonghot.yo.fsagent.util.CallStrUtils; import org.freeswitch.esl.client.transport.event.Event; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; @@ -29,7 +29,7 @@ public class ChannelCreate { public void onChannelCreate(final Event event) { log.debug("On channel create event [{}] [{}].", event, event.getHeaders()); - final ChannelNameUtils.ChannelInfo channelInfo = ChannelNameUtils.get(event); + final CallStrUtils.ChannelInfo channelInfo = CallStrUtils.getChannelInfo(event); if (channelInfo.isAgent()) { agentStatusService.inACall(channelInfo.getDomain(), diff --git a/fsagent/src/main/java/com/pudonghot/yo/fsagent/listener/ChannelDestroy.java b/fsagent/src/main/java/com/pudonghot/yo/fsagent/listener/ChannelDestroy.java index 7740effc..cf5f76e1 100644 --- a/fsagent/src/main/java/com/pudonghot/yo/fsagent/listener/ChannelDestroy.java +++ b/fsagent/src/main/java/com/pudonghot/yo/fsagent/listener/ChannelDestroy.java @@ -9,14 +9,14 @@ import org.springframework.stereotype.Component; import com.pudonghot.yo.fsagent.util.EslEventUtils; import com.pudonghot.yo.model.agentevent.AgentEvent; import com.pudonghot.yo.fsagent.service.AgentService; -import com.pudonghot.yo.fsagent.util.ChannelNameUtils; +import com.pudonghot.yo.fsagent.util.CallStrUtils; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; import org.freeswitch.esl.client.transport.event.Event; import com.pudonghot.yo.service.CommonAgentStatusService; import com.pudonghot.yo.service.CommonAgentEventQueueService; import org.springframework.beans.factory.annotation.Autowired; -import com.pudonghot.yo.fsagent.util.ChannelNameUtils.ChannelInfo; +import com.pudonghot.yo.fsagent.util.CallStrUtils.ChannelInfo; import static com.pudonghot.yo.model.agentevent.EventType.AgentOther_PhoneRelease; import static com.pudonghot.yo.model.agentevent.EventType.AgentEvent_Customer_Release; @@ -47,7 +47,7 @@ public class ChannelDestroy { final String presenceId = event.getHeader("variable_presence_id"); final String callUuid = event.getCallUuid(); log.info("On channel [{}][{}] destroy event.", presenceId, callUuid); - final ChannelInfo channelInfo = ChannelNameUtils.get(event); + final ChannelInfo channelInfo = CallStrUtils.getChannelInfo(event); if (channelInfo.isAgent()) { agentStatusService.acw(channelInfo.getDomain(), diff --git a/fsagent/src/main/java/com/pudonghot/yo/fsagent/listener/ChannelHangupComplete.java b/fsagent/src/main/java/com/pudonghot/yo/fsagent/listener/ChannelHangupComplete.java index 2397fedb..5a7b8980 100644 --- a/fsagent/src/main/java/com/pudonghot/yo/fsagent/listener/ChannelHangupComplete.java +++ b/fsagent/src/main/java/com/pudonghot/yo/fsagent/listener/ChannelHangupComplete.java @@ -8,7 +8,7 @@ import org.springframework.stereotype.Component; import com.pudonghot.yo.fsagent.util.EslEventUtils; import com.pudonghot.yo.fsagent.service.AgentService; import com.pudonghot.yo.model.agentevent.AgentEvent; -import com.pudonghot.yo.fsagent.util.ChannelNameUtils; +import com.pudonghot.yo.fsagent.util.CallStrUtils; import org.freeswitch.esl.client.transport.event.Event; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; @@ -41,8 +41,8 @@ public class ChannelHangupComplete { if (!event.isHangupNormalClearing()) { - final ChannelNameUtils.ChannelInfo channelInfo = - ChannelNameUtils.get(event); + final CallStrUtils.ChannelInfo channelInfo = + CallStrUtils.getChannelInfo(event); if (channelInfo.isAgent()) { final Agent agent = agentService.findByDomainAndAgent( diff --git a/fsagent/src/main/java/com/pudonghot/yo/fsagent/listener/ChannelProgress.java b/fsagent/src/main/java/com/pudonghot/yo/fsagent/listener/ChannelProgress.java index cd718628..7c018a4d 100644 --- a/fsagent/src/main/java/com/pudonghot/yo/fsagent/listener/ChannelProgress.java +++ b/fsagent/src/main/java/com/pudonghot/yo/fsagent/listener/ChannelProgress.java @@ -8,7 +8,7 @@ import org.springframework.stereotype.Component; import com.pudonghot.yo.fsagent.util.EslEventUtils; import com.pudonghot.yo.model.agentevent.AgentEvent; import com.pudonghot.yo.fsagent.service.AgentService; -import com.pudonghot.yo.fsagent.util.ChannelNameUtils; +import com.pudonghot.yo.fsagent.util.CallStrUtils; import org.freeswitch.esl.client.transport.event.Event; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; @@ -42,8 +42,8 @@ public class ChannelProgress { log.info("On channel [{}] answer event.", channelName); if (EslEventUtils.isCalled(event)) { - final ChannelNameUtils.ChannelInfo channelInfo = - ChannelNameUtils.get(event); + final CallStrUtils.ChannelInfo channelInfo = + CallStrUtils.getChannelInfo(event); if (channelInfo.isAgent()) { final Agent agent = agentService.findByDomainAndAgent( channelInfo.getDomain(), diff --git a/fsagent/src/main/java/com/pudonghot/yo/fsagent/service/GatewayService.java b/fsagent/src/main/java/com/pudonghot/yo/fsagent/service/GatewayService.java index c4e1da14..0405f61c 100644 --- a/fsagent/src/main/java/com/pudonghot/yo/fsagent/service/GatewayService.java +++ b/fsagent/src/main/java/com/pudonghot/yo/fsagent/service/GatewayService.java @@ -8,4 +8,20 @@ import com.wacai.tigon.service.BaseQueryService; * Dec 04, 2019 19:04:12 */ public interface GatewayService extends BaseQueryService { + + /** + * generate gateway name + * + * @param gateway gateway + * @return gateway name + */ + String genGatewayName(Gateway gateway); + + /** + * generate gateway name + * + * @param gatewayId gatewayId + * @return gateway name + */ + String genGatewayName(Integer gatewayId); } diff --git a/fsagent/src/main/java/com/pudonghot/yo/fsagent/service/TrunkService.java b/fsagent/src/main/java/com/pudonghot/yo/fsagent/service/TrunkService.java index b9802fd4..88fecf3f 100644 --- a/fsagent/src/main/java/com/pudonghot/yo/fsagent/service/TrunkService.java +++ b/fsagent/src/main/java/com/pudonghot/yo/fsagent/service/TrunkService.java @@ -27,4 +27,13 @@ public interface TrunkService extends BaseQueryService { * @return called number */ String calledNumber(Trunk trunk, String number); + + /** + * parse dial target + * + * @param tenantId tenant id + * @param calledNumber called number + * @return trunk and called number + */ + Pair parseDialTarget(Integer tenantId, String calledNumber); } diff --git a/fsagent/src/main/java/com/pudonghot/yo/fsagent/service/impl/GatewayerviceImpl.java b/fsagent/src/main/java/com/pudonghot/yo/fsagent/service/impl/GatewayerviceImpl.java index aae3be78..84dd9ab8 100644 --- a/fsagent/src/main/java/com/pudonghot/yo/fsagent/service/impl/GatewayerviceImpl.java +++ b/fsagent/src/main/java/com/pudonghot/yo/fsagent/service/impl/GatewayerviceImpl.java @@ -1,10 +1,11 @@ package com.pudonghot.yo.fsagent.service.impl; -import com.pudonghot.yo.fsagent.service.GatewayService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import com.pudonghot.yo.mapper.GatewayMapper; import com.pudonghot.yo.model.domain.Gateway; -import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import com.pudonghot.yo.fsagent.service.GatewayService; import com.wacai.tigon.service.support.BaseQueryServiceSupport; /** @@ -18,4 +19,20 @@ public class GatewayerviceImpl Gateway, GatewayMapper> implements GatewayService { + + /** + * {@inheritDoc} + */ + @Override + public String genGatewayName(final Gateway gateway) { + return genGatewayName(gateway.getId()); + } + + /** + * {@inheritDoc} + */ + @Override + public String genGatewayName(Integer gatewayId) { + return "GW" + StringUtils.leftPad(String.valueOf(gatewayId), 6, '0'); + } } diff --git a/fsagent/src/main/java/com/pudonghot/yo/fsagent/service/impl/TrunkServiceImpl.java b/fsagent/src/main/java/com/pudonghot/yo/fsagent/service/impl/TrunkServiceImpl.java index 1419257e..f0f0a443 100644 --- a/fsagent/src/main/java/com/pudonghot/yo/fsagent/service/impl/TrunkServiceImpl.java +++ b/fsagent/src/main/java/com/pudonghot/yo/fsagent/service/impl/TrunkServiceImpl.java @@ -2,14 +2,19 @@ package com.pudonghot.yo.fsagent.service.impl; import java.util.List; +import com.pudonghot.yo.fsagent.service.GatewayService; import com.pudonghot.yo.fsagent.service.TrunkService; import com.pudonghot.yo.mapper.GatewayMapper; +import com.pudonghot.yo.mapper.SequenceMapper; import com.pudonghot.yo.mapper.TrunkMapper; import com.pudonghot.yo.mapper.TrunkStrategyMapper; import com.pudonghot.yo.model.domain.Gateway; +import com.pudonghot.yo.model.domain.Sequence; import com.pudonghot.yo.model.domain.Trunk; import com.pudonghot.yo.model.domain.TrunkStrategy; +import com.wacai.tigon.mybatis.Search; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.util.Assert; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.StringUtils; @@ -32,12 +37,18 @@ public class TrunkServiceImpl TrunkMapper> implements TrunkService { + @Value("${yo.fsagent.trunk-prefix.seq-name:TRUNK}") + private String seqName; + @Autowired + private SequenceMapper sequenceMapper; @Autowired private TrunkStrategyMapper trunkStrategyMapper; @Autowired private GatewayMapper gatewayMapper; @Autowired private CellphoneService cellphoneService; + @Autowired + private GatewayService gatewayService; /** * {@inheritDoc} @@ -70,8 +81,8 @@ public class TrunkServiceImpl Assert.state(gateway.getActive(), () -> "Trunk [" + trunk.getPrefix() + "] gateway is not active"); - return Pair.of(trunk, "sofia/gateway/GW" + - StringUtils.leftPad(String.valueOf(gateway.getId()), 6, '0') + + return Pair.of(trunk, "sofia/gateway/" + + gatewayService.genGatewayName(gateway) + "/" + calledNumber(trunk, number)); } @@ -100,6 +111,30 @@ public class TrunkServiceImpl return addPrefix(trunk, calledNumber); } + /** + * {@inheritDoc} + */ + @Override + public Pair parseDialTarget(final Integer tenantId, final String calledNumber) { + final Sequence trunkSeq = sequenceMapper.find( + new Search(Sequence.TENANT_ID, tenantId) + .eq(Sequence.NAME, seqName) + .eq(Sequence.ACTIVE, true)); + final int prefixLength = trunkSeq.getLength(); + if (calledNumber.length() > prefixLength) { + final String prefix = calledNumber.substring(0, prefixLength); + final Trunk trunk = mapper.find( + new Search(Trunk.TENANT_ID, tenantId) + .eq(Trunk.PREFIX, prefix) + .eq(Trunk.ACTIVE, true)); + if (trunk != null) { + return Pair.of(trunk, calledNumber.substring(prefixLength)); + } + } + + return null; + } + private String addPrefix(final Trunk trunk, String number) { final String gatewayPrefix = trunk.getGatewayPrefix(); return StringUtils.isNotBlank(gatewayPrefix) ? gatewayPrefix + number : number; diff --git a/fsagent/src/main/java/com/pudonghot/yo/fsagent/util/ChannelNameUtils.java b/fsagent/src/main/java/com/pudonghot/yo/fsagent/util/CallStrUtils.java similarity index 56% rename from fsagent/src/main/java/com/pudonghot/yo/fsagent/util/ChannelNameUtils.java rename to fsagent/src/main/java/com/pudonghot/yo/fsagent/util/CallStrUtils.java index 1a8efedd..b89cdedd 100644 --- a/fsagent/src/main/java/com/pudonghot/yo/fsagent/util/ChannelNameUtils.java +++ b/fsagent/src/main/java/com/pudonghot/yo/fsagent/util/CallStrUtils.java @@ -12,20 +12,23 @@ import org.freeswitch.esl.client.transport.event.Event; * @author Donghuang * @date Jul 08, 2020 11:42:21 */ -public class ChannelNameUtils { +public class CallStrUtils { public static final Pattern PATTERN_USER_AND_DOMAIN = Pattern.compile("^sofia/internal/([^@]+)@(.+)$"); public static final Pattern PATTERN_EXTERNAL_NUMBER = Pattern.compile("^sofia/external/(\\w+)$"); + public static final Pattern PATTERN_DIAL_TARGET = + Pattern.compile("^(\\d+)\\.(A|Q|(?:AG))$"); + /** * get channel info * * @param event event * @return channel info */ - public static ChannelInfo get(final Event event) { - return parse(event.getChannelName()); + public static ChannelInfo getChannelInfo(final Event event) { + return parseChannelName(event.getChannelName()); } /** @@ -34,7 +37,7 @@ public class ChannelNameUtils { * @param channelName channel name * @return channel info */ - public static ChannelInfo parse(final String channelName) { + public static ChannelInfo parseChannelName(final String channelName) { Matcher m = PATTERN_USER_AND_DOMAIN.matcher(channelName); if (m.find()) { return new ChannelInfo(m.group(1), m.group(2), true); @@ -49,6 +52,18 @@ public class ChannelNameUtils { "Invalid channel name: " + channelName); } + public static DialTarget parseDialTarget(final String target) { + Matcher m = PATTERN_DIAL_TARGET.matcher(target); + if (m.find()) { + final String type = m.group(2); + return new DialTarget(Integer.parseInt(m.group(1)), + "A".equals(type) ? DialTarget.Type.AGENT : + "AG".equals(type) ? DialTarget.Type.AGENT_GROUP : + DialTarget.Type.QUEUE); + } + return null; + } + @Getter @Setter @ToString @@ -58,4 +73,19 @@ public class ChannelNameUtils { private final String domain; private final boolean agent; } + + @Getter + @Setter + @ToString + @RequiredArgsConstructor + public static class DialTarget { + private final Integer id; + private final Type type; + + public enum Type { + AGENT, + AGENT_GROUP, + QUEUE + } + } } diff --git a/fsagent/src/main/resources/templates/dialplan/trunk-outbound.xml b/fsagent/src/main/resources/templates/dialplan/trunk-outbound.xml new file mode 100644 index 00000000..778ac16e --- /dev/null +++ b/fsagent/src/main/resources/templates/dialplan/trunk-outbound.xml @@ -0,0 +1,39 @@ + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/fsagent/src/main/resources/templates/empty.xml b/fsagent/src/main/resources/templates/empty.xml index 9223eda3..8d0b0245 100644 --- a/fsagent/src/main/resources/templates/empty.xml +++ b/fsagent/src/main/resources/templates/empty.xml @@ -1,6 +1,6 @@ -
+
diff --git a/fsagent/src/test/java/com/pudonghot/yo/fsagent/ChannelNameUtilsTest.java b/fsagent/src/test/java/com/pudonghot/yo/fsagent/ChannelNameUtilsTest.java index 28fcefca..0de1fefb 100644 --- a/fsagent/src/test/java/com/pudonghot/yo/fsagent/ChannelNameUtilsTest.java +++ b/fsagent/src/test/java/com/pudonghot/yo/fsagent/ChannelNameUtilsTest.java @@ -2,7 +2,7 @@ package com.pudonghot.yo.fsagent; import org.junit.Test; import lombok.extern.slf4j.Slf4j; -import com.pudonghot.yo.fsagent.util.ChannelNameUtils; +import com.pudonghot.yo.fsagent.util.CallStrUtils; /** * @author Donghuang @@ -13,7 +13,7 @@ public class ChannelNameUtilsTest { @Test public void testParse() { - log.info("User and domain [{}]", ChannelNameUtils.parse("sofia/internal/700001@d1.wacai.info")); - log.info("External number [{}]", ChannelNameUtils.parse("sofia/external/013764268709")); + log.info("User and domain [{}]", CallStrUtils.parseChannelName("sofia/internal/700001@d1.wacai.info")); + log.info("External number [{}]", CallStrUtils.parseChannelName("sofia/external/013764268709")); } } diff --git a/lib/model/src/main/java/com/pudonghot/yo/model/domain/Sequence.java b/lib/model/src/main/java/com/pudonghot/yo/model/domain/Sequence.java index 4185a0ba..7c19bd74 100644 --- a/lib/model/src/main/java/com/pudonghot/yo/model/domain/Sequence.java +++ b/lib/model/src/main/java/com/pudonghot/yo/model/domain/Sequence.java @@ -22,6 +22,8 @@ public class Sequence extends BaseDomain { @NotUpdate private String name; @NotUpdate + private int length; + @NotUpdate private Long initVal; private Long step; private Long currentVal; diff --git a/openapi/src/main/java/com/pudonghot/yo/openapi/controller/AgentStatusController.java b/openapi/src/main/java/com/pudonghot/yo/openapi/controller/AgentStatusController.java index 5ec23b7b..2c019085 100644 --- a/openapi/src/main/java/com/pudonghot/yo/openapi/controller/AgentStatusController.java +++ b/openapi/src/main/java/com/pudonghot/yo/openapi/controller/AgentStatusController.java @@ -28,8 +28,7 @@ public class AgentStatusController implements SessionAbility { @Autowired private AgentEventService agentEventService; - @RequestMapping({"/", "/forcelogin" - }) + @RequestMapping({"/", "/forcelogin"}) public RespAgentReady signIn( @PathVariable("account") final String account) { diff --git a/web/cms/app/nav-items.js b/web/cms/app/nav-items.js index b4c7b2c4..b8071676 100644 --- a/web/cms/app/nav-items.js +++ b/web/cms/app/nav-items.js @@ -60,6 +60,12 @@ export default (function() { route: 'agent.list', icon: 'fa-user', text: '坐席管理' + }, + { + perm: 'PERM_VIEW_AGENT_STATUS_LIST', + route: 'agent-status.list', + icon: 'fa-user', + text: '坐席状态管理' } ] }, { @@ -70,13 +76,7 @@ export default (function() { route: 'campaign.list', icon: 'fa-fax', text: '外呼活动管理' - }, - { - perm: 'PERM_VIEW_CAMPAIGN_LIST', - route: 'calling-list.list', - icon: 'fa fa-list-alt', - text: '拨打列表' - }, + } ] }, { text: '公共', diff --git a/web/cms/app/router.js b/web/cms/app/router.js index 41c029d9..4757d1d9 100644 --- a/web/cms/app/router.js +++ b/web/cms/app/router.js @@ -97,25 +97,19 @@ Router.map(function() { this.route('edit', {path: '/:id/edit'}); }); - this.route('campaign-stat', function() { - this.route('list'); - }); - this.route('trunk-attr', function() { this.route('list'); this.route('create'); this.route('edit', {path: '/:id/edit'}); }); - this.route('calling-list', function() { - this.route('list'); - this.route('create'); - this.route('edit', {path: '/:id/edit'}); - }); - this.route('call-detail-record', function() { this.route('list'); }); + + this.route('agent-status', function() { + this.route('list'); + }); }); export default Router; diff --git a/web/cms/app/routes/agent-status/list.js b/web/cms/app/routes/agent-status/list.js new file mode 100644 index 00000000..503f6c37 --- /dev/null +++ b/web/cms/app/routes/agent-status/list.js @@ -0,0 +1,6 @@ +import BaseListRoute from './../base-list'; + +export default BaseListRoute.extend({ + perm: 'PERM_VIEW_AGENT_STATUS_LIST', + breadcrumbs: [{text: '坐席状态列表'}], +}); diff --git a/web/cms/app/routes/calling-list/create.js b/web/cms/app/routes/calling-list/create.js deleted file mode 100644 index c9497e02..00000000 --- a/web/cms/app/routes/calling-list/create.js +++ /dev/null @@ -1,34 +0,0 @@ -import BaseRoute from '../base'; -import RSVP from 'rsvp'; - -export default BaseRoute.extend({ - perm: 'PERM_VIEW_CAMPAIGN_CREATE', - breadcrumbs: [{route: 'calling-list.list', text: '拨打列表'}, {text: '创建拨打名单'}], - model() { - const store = this.get('store'); - return RSVP.hash({ - active: true, - privacy: true, - campaignList: store.ajaxGet('campaign/list'), - callingListStatus: store.ajaxGet('calling-list/status'), - timeList:[{value:'25200', text:'7:00'}, - {value:'28800', text:'8:00'}, - {value:'32400', text:'9:00'}, - {value:'36000', text:'10:00'}, - {value:'39600', text:'11:00'}, - {value:'43200', text:'12:00'}, - {value:'46800', text:'13:00'}, - {value:'50400', text:'14:00'}, - {value:'54000', text:'15:00'}, - {value:'57600', text:'16:00'}, - {value:'61200', text:'17:00'}, - {value:'64800', text:'18:00'}, - {value:'68400', text:'19:00'}, - {value:'72000', text:'20:00'}, - {value:'75600', text:'21:00'}, - {value:'79200', text:'22:00'}, - {value:'82800', text:'23:00'} - ] - }); - } -}); \ No newline at end of file diff --git a/web/cms/app/routes/calling-list/edit.js b/web/cms/app/routes/calling-list/edit.js deleted file mode 100644 index 5aadbd87..00000000 --- a/web/cms/app/routes/calling-list/edit.js +++ /dev/null @@ -1,28 +0,0 @@ -import BaseEditRoute from '../base-edit'; - -export default BaseEditRoute.extend({ - perm: 'PERM_VIEW_CAMPAIGN_EDIT', - afterModel(model) { - this.set('breadcrumbs', - [{route: 'calling-list.list', text: '拨打列表'}, - {text: '编辑拨打名单'}]); - model.timeList=[{value:'25200', text:'7:00'}, - {value:'28800', text:'8:00'}, - {value:'32400', text:'9:00'}, - {value:'36000', text:'10:00'}, - {value:'39600', text:'11:00'}, - {value:'43200', text:'12:00'}, - {value:'46800', text:'13:00'}, - {value:'50400', text:'14:00'}, - {value:'54000', text:'15:00'}, - {value:'57600', text:'16:00'}, - {value:'61200', text:'17:00'}, - {value:'64800', text:'18:00'}, - {value:'68400', text:'19:00'}, - {value:'72000', text:'20:00'}, - {value:'75600', text:'21:00'}, - {value:'79200', text:'22:00'}, - {value:'82800', text:'23:00'} - ] - } -}); \ No newline at end of file diff --git a/web/cms/app/routes/calling-list/list.js b/web/cms/app/routes/calling-list/list.js deleted file mode 100644 index 6ab730eb..00000000 --- a/web/cms/app/routes/calling-list/list.js +++ /dev/null @@ -1,6 +0,0 @@ -import BaseListRoute from './../base-list'; - -export default BaseListRoute.extend({ - perm: 'PERM_VIEW_CAMPAIGN_LIST', - breadcrumbs: [{text: '拨打列表'}] -}); \ No newline at end of file diff --git a/web/cms/app/routes/sequence/create.js b/web/cms/app/routes/sequence/create.js index a3b67a96..1a889d07 100644 --- a/web/cms/app/routes/sequence/create.js +++ b/web/cms/app/routes/sequence/create.js @@ -7,6 +7,7 @@ export default BaseRoute.extend({ return { active: true, initVal: 1, + length: 4, step: 1 }; } diff --git a/web/cms/app/services/nlp-component-group/service.js b/web/cms/app/services/nlp-component-group/service.js deleted file mode 100644 index 9b6a39d9..00000000 --- a/web/cms/app/services/nlp-component-group/service.js +++ /dev/null @@ -1,14 +0,0 @@ -import Service from '../service'; - -export default Service.extend({ - modelName: 'NlpComponentGroup', - constraints: { - name: { - presence: true, - length: { - minimum: 1, - maximum: 36 - } - } - } -}); diff --git a/web/cms/app/services/nlp-component/service.js b/web/cms/app/services/nlp-component/service.js deleted file mode 100644 index a2322b6d..00000000 --- a/web/cms/app/services/nlp-component/service.js +++ /dev/null @@ -1,32 +0,0 @@ -import Service from '../service'; - -export default Service.extend({ - modelName: 'NlpComponent', - createConstraints: { - groupId: { - presence: true - }, - type: { - presence: true - }, - name: { - presence: true, - length: { - minimum: 1, - maximum: 36 - } - } - }, - constraints: { - groupId: { - presence: true - }, - name: { - presence: true, - length: { - minimum: 1, - maximum: 36 - } - } - } -}); diff --git a/web/cms/app/services/nlp-node-sample/service.js b/web/cms/app/services/nlp-node-sample/service.js deleted file mode 100644 index 73cc09fa..00000000 --- a/web/cms/app/services/nlp-node-sample/service.js +++ /dev/null @@ -1,15 +0,0 @@ -import Service from '../service'; - -export default Service.extend({ - modelName: 'NlpNodeSample', - constraints: { - sampleText: { - presence: true, - } - }, - batchCreateConstraints: { - sampleTexts: { - presence: true - } - }, -}); diff --git a/web/cms/app/services/nlp-node/service.js b/web/cms/app/services/nlp-node/service.js deleted file mode 100644 index 886b2b91..00000000 --- a/web/cms/app/services/nlp-node/service.js +++ /dev/null @@ -1,25 +0,0 @@ -import Service from '../service'; - -export default Service.extend({ - modelName: 'NlpNode', - constraints: { - componentId: { - presence: true - }, - name: { - presence: true, - length: { - minimum: 1, - maximum: 36 - } - }, - nodeIndex: { - presence: true, - numericality: { - onlyInteger: true, - greaterThanOrEqualTo: 0, - lessThanOrEqualTo: 128 - } - } - } -}); diff --git a/web/cms/app/services/nlp-term-group/service.js b/web/cms/app/services/nlp-term-group/service.js deleted file mode 100644 index d6413f7b..00000000 --- a/web/cms/app/services/nlp-term-group/service.js +++ /dev/null @@ -1,14 +0,0 @@ -import Service from '../service'; - -export default Service.extend({ - modelName: 'NlpTermGroup', - constraints: { - name: { - presence: true, - length: { - minimum: 1, - maximum: 36 - } - } - } -}); diff --git a/web/cms/app/services/nlp-term/service.js b/web/cms/app/services/nlp-term/service.js deleted file mode 100644 index da85b06a..00000000 --- a/web/cms/app/services/nlp-term/service.js +++ /dev/null @@ -1,24 +0,0 @@ -import Service from '../service'; - -export default Service.extend({ - modelName: 'NlpTerm', - constraints: { - groupId: { - presence: true - }, - term: { - presence: true, - length: { - minimum: 1, - maximum: 36 - } - }, - pinyin: { - presence: true, - length: { - minimum: 1, - maximum: 128 - } - } - } -}); diff --git a/web/cms/app/services/sequence/service.js b/web/cms/app/services/sequence/service.js index d7c05174..85dd5b71 100644 --- a/web/cms/app/services/sequence/service.js +++ b/web/cms/app/services/sequence/service.js @@ -10,6 +10,14 @@ export default Service.extend({ maximum: 36 } }, + length: { + presence: true, + numericality: { + onlyInteger: true, + greaterThan: 1, + lessThanOrEqualTo: 16 + } + }, initVal: { presence: true, numericality: { @@ -26,14 +34,7 @@ export default Service.extend({ } } }, - createConstraints: { - name: { - presence: true, - length: { - minimum: 1, - maximum: 36 - } - }, + updateConstraints: { step: { presence: true, numericality: { diff --git a/web/cms/app/services/talk-component/service.js b/web/cms/app/services/talk-component/service.js deleted file mode 100644 index 59924aae..00000000 --- a/web/cms/app/services/talk-component/service.js +++ /dev/null @@ -1,53 +0,0 @@ -import BaseService from '../service'; - -export default BaseService.extend({ - modelName: 'TalkComponent', - constraints: { - note: { - presence: true - }, - content: { - presence: true - }, - }, - voiceConstraints: { - note: { - presence: true - }, - voice: { - presence: true - } - }, - ttsConstraints: { - text: { - presence: true - }, - ttsVoiceActor: { - presence: true - }, - note: { - presence: true - }, - volume: { - presence: true, - numericality: { - notLessThan: -500, - notGreaterThan: 500 - } - }, - speechRate: { - presence: true, - numericality: { - notLessThan: -500, - notGreaterThan: 500 - } - }, - pitchRate: { - presence: true, - numericality: { - notLessThan: -500, - notGreaterThan: 500 - } - } - } -}); diff --git a/web/cms/app/services/talk-group/service.js b/web/cms/app/services/talk-group/service.js deleted file mode 100644 index fae6a2f3..00000000 --- a/web/cms/app/services/talk-group/service.js +++ /dev/null @@ -1,14 +0,0 @@ -import Service from '../service'; - -export default Service.extend({ - modelName: 'TalkGroup', - constraints: { - name: { - presence: true, - length: { - minimum: 1, - maximum: 36 - } - } - } -}); diff --git a/web/cms/app/services/talk/service.js b/web/cms/app/services/talk/service.js deleted file mode 100644 index 63aea515..00000000 --- a/web/cms/app/services/talk/service.js +++ /dev/null @@ -1,57 +0,0 @@ -import BaseService from '../service'; - -export default BaseService.extend({ - modelName: 'Talk', - normalConstraints: { - talk: { - presence: true - } - }, - audioConstraints: { - overwriteStrategy: { - presence: true - }, - files: { - presence: true - } - }, - ttsConstraints: { - talk: { - presence: true - }, - ttsVoiceActor: { - presence: true - }, - volume: { - presence: true, - numericality: { - notLessThan: -500, - notGreaterThan: 500 - } - }, - speechRate: { - presence: true, - numericality: { - notLessThan: -500, - notGreaterThan: 500 - } - }, - pitchRate: { - presence: true, - numericality: { - notLessThan: -500, - notGreaterThan: 500 - } - } - }, - updateConstraints: { - talk: { - presence: true - } - }, - importConstraints: { - archive: { - presence: true - } - } -}); diff --git a/web/cms/app/services/voice-actor/service.js b/web/cms/app/services/voice-actor/service.js deleted file mode 100644 index 769514f6..00000000 --- a/web/cms/app/services/voice-actor/service.js +++ /dev/null @@ -1,21 +0,0 @@ -import Service from '../service'; - -export default Service.extend({ - modelName: 'VoiceActor', - constraints: { - name: { - presence: true, - length: { - minimum: 1, - maximum: 36 - } - }, - code: { - presence: true, - length: { - minimum: 1, - maximum: 36 - } - } - } -}); diff --git a/web/cms/app/templates/agent-status/list.hbs b/web/cms/app/templates/agent-status/list.hbs new file mode 100644 index 00000000..03459fa1 --- /dev/null +++ b/web/cms/app/templates/agent-status/list.hbs @@ -0,0 +1,88 @@ +
+ {{grid-header search-box=false}} + +
+ +
+ + + + + + + + + + + + + + {{#each model.data as |it|}} + + + + + + + + + + {{/each}} + +
+ 账户 + + 分机 + + {{th-filter name='registerd' + text='注册状态' + options=(array + (hash value=true text='在线') + (hash value=false text='离线') + ) + }} + + {{th-filter name='status' + text='坐席状态' + options=(array + (hash value='READY' text='就绪') + (hash value='NOT_READY' text='未就绪') + (hash value='OFFLINE' text='离线') + ) + }} + + {{th-filter name='state' + text='话机状态' + options=(array + (hash value='IDLE' text='空闲') + (hash value='IN_A_CALL' text='通话中') + (hash value='ACW' text='话后事务') + ) + }} + + 通话ID + + 事件Key +
+ {{it.account}} + + {{it.agent}} + + {{status-cell model=it + field='registered' + enabled-text='在线' + disabled-text='离线'}} + + {{it.status}} + + {{it.state}} + + {{it.callUuid}} + + {{it.eventKey}} +
+
+ {{pagination-bar}} +
+
+{{outlet}} diff --git a/web/cms/app/templates/calling-list/create.hbs b/web/cms/app/templates/calling-list/create.hbs deleted file mode 100644 index 7139e652..00000000 --- a/web/cms/app/templates/calling-list/create.hbs +++ /dev/null @@ -1,41 +0,0 @@ -{{#form-content}} -
- {{form-input-select - name='campaignId' - label='外呼活动' - options=model.campaignList.data - value-field='id' - text-field='name' - enabled-field='active' - }} - {{form-input name='phone' label='号码'}} - {{form-input-select - name='status' - label='状态' - options=model.callingListStatus - value-field='value' - text-field='label' - }} - {{form-input-select - name='dailyFrom' - label='开始时间' - options=model.timeList - value-field='value' - text-field='text' - }} - {{form-input-select - name='dailyTo' - label='结束时间' - options=model.timeList - value-field='value' - text-field='text' - }} - {{form-input name='taskKey' label='任务KEY'}} - {{form-input name='recordKey' label='记录KEY'}} - {{form-input type='textarea' name='recordData' label='记录数据' placeholder='请在此输入业务数据,例如:{"username": "东皇", "gender": "MALE"}'}} - {{form-input name='attachedData' label='随路数据'}} - {{form-input name='note' label='备注'}} -
- {{form-footer-buttons type='create'}} -{{/form-content}} -{{outlet}} diff --git a/web/cms/app/templates/calling-list/edit.hbs b/web/cms/app/templates/calling-list/edit.hbs deleted file mode 100644 index 2894e593..00000000 --- a/web/cms/app/templates/calling-list/edit.hbs +++ /dev/null @@ -1,60 +0,0 @@ -{{#form-content}} -
- {{form-input type='hidden' name='id'}} - {{form-input-select - name='campaignId' - label='外呼活动' - options=model.campaignList - value-field='id' - text-field='name' - enabled-field='active' - }} - {{form-input name='phone' label='号码'}} - {{form-input-select - name='status' - label='状态' - options=model.callingListStatus - value-field='value' - text-field='label' - }} - {{form-input-select - name='dailyFrom' - label='开始时间' - options=model.timeList - value-field='value' - text-field='text' - }} - {{form-input-select - name='dailyTo' - label='结束时间' - options=model.timeList - value-field='value' - text-field='text' - }} - {{form-input name='callUuid' label='通话ID'}} - {{form-input-datetimepicker - labelClass='col-sm-3 col-md-3' - inputClass='col-sm-5 col-md-5' - name='callStartTime' - label='通话开始时间'}} - {{form-input-datetimepicker - labelClass='col-sm-3 col-md-3' - inputClass='col-sm-5 col-md-5' - name='callEstablishedTime' - label='通话接通时间'}} - {{form-input-datetimepicker - labelClass='col-sm-3 col-md-3' - inputClass='col-sm-5 col-md-5' - name='callEndTime' - label='通话结束时间'}} - {{form-input name='callResult' label='通话结果'}} - {{form-input name='taskKey' label='任务KEY'}} - {{form-input name='recordKey' label='记录KEY'}} - {{form-input type='textarea' name='recordData' label='记录数据' placeholder='请在此输入业务数据,例如:{"username": "东皇", "gender": "MALE"}'}} - {{form-input name='attachedData' label='随路数据'}} - {{form-input-enabled}} - {{form-input name='note' label='备注'}} -
- {{form-footer-buttons type='update'}} -{{/form-content}} -{{outlet}} diff --git a/web/cms/app/templates/calling-list/list.hbs b/web/cms/app/templates/calling-list/list.hbs deleted file mode 100644 index 9247ed81..00000000 --- a/web/cms/app/templates/calling-list/list.hbs +++ /dev/null @@ -1,137 +0,0 @@ -
- {{#grid-header}} - {{#has-perm 'PERM_VIEW_CAMPAIGN_CREATE'}} -
  • - {{#link-to 'calling-list.create'}} - - 新建名单 - {{/link-to}} -
  • - {{/has-perm}} - {{/grid-header}} - -
    - -
    - - - - - - - - - - - - - - - - - - - - - {{#each model.data as |it|}} - - - - - - - - - - - - - - - - - {{/each}} - -
    - {{th-filter name='campaignId' - text='外呼活动' - options=model.campaignList - value-field='id' - text-field='name' - }} - - 号码 - - {{th-filter name='status' - text='状态' - options=model.callingListStatus - value-field='value' - text-field='label' - }} - - 开始时间 - - 结束时间 - - 通话ID - - 拨打开始时间 - - 拨打接通时间 - - 拨打结束时间 - - 拨打结果 - - 任务KEY - - 记录KEY - - 创建时间 - - - 管理 -
    - {{it.campaign.name}} - - {{it.phone}} - - {{it.status}} - - {{second-time timeInSecond=it.dailyFrom}} - - {{second-time timeInSecond=it.dailyTo}} - - {{it.callUuid}} - - {{date-cell value=it.callStartTime format='YYYY-MM-DD H:mm:ss'}} - - {{date-cell value=it.callEstablishedTime format='YYYY-MM-DD H:mm:ss'}} - - {{date-cell value=it.callEndTime format='YYYY-MM-DD H:mm:ss'}} - - {{it.callResult}} - - {{it.taskKey}} - - {{it.recordKey}} - - {{date-cell value=it.createdTime format='YYYY-MM-DD H:mm:ss'}} - -
    - {{#has-perm 'PERM_VIEW_CAMPAIGN_EDIT'}} - {{status-toggle-button model=it}} - {{edit-btn route-name='calling-list.edit' model-id=it.id perm='PERM_VIEW_CAMPAIGN_EDIT'}} - {{/has-perm}} - {{#has-perm 'PERM_VIEW_CAMPAIGN_DELETE'}} - {{#unless it.active}} - {{delete-button model=it}} - {{/unless}} - {{/has-perm}} -
    -
    -
    - {{pagination-bar}} -
    -
    -{{outlet}} diff --git a/web/cms/app/templates/campaign/list.hbs b/web/cms/app/templates/campaign/list.hbs index 21ef6dd7..be143f14 100644 --- a/web/cms/app/templates/campaign/list.hbs +++ b/web/cms/app/templates/campaign/list.hbs @@ -140,13 +140,6 @@ {{delete-button model=it}} {{/unless}} {{/has-perm}} - {{#link-to 'calling-list.list' - (query-params filters=(concat '{"campaignId":[' it.id ']}')) - class='btn btn-xs btn-info' - data-rel='tooltip' - title='拨打列表'}} - - {{/link-to}} diff --git a/web/cms/app/templates/sequence/create.hbs b/web/cms/app/templates/sequence/create.hbs index e21ea092..76d27537 100644 --- a/web/cms/app/templates/sequence/create.hbs +++ b/web/cms/app/templates/sequence/create.hbs @@ -1,6 +1,7 @@ {{#form-content}}
    {{form-input name='name' label='名称'}} + {{form-input name='length' label='长度'}} {{form-input name='initVal' label='初始值'}} {{form-input name='step' label='递增值'}} diff --git a/web/cms/app/templates/sequence/edit.hbs b/web/cms/app/templates/sequence/edit.hbs index 917f5788..16d7b7cf 100644 --- a/web/cms/app/templates/sequence/edit.hbs +++ b/web/cms/app/templates/sequence/edit.hbs @@ -1,6 +1,7 @@ {{#form-content}} {{form-input type='hidden' name='id'}} - {{form-input name='name' label='名称'}} + {{form-input name='name' label='名称' readonly=true}} + {{form-input name='length' label='长度' readonly=true}} {{form-input name='initVal' label='初始值' readonly=true}} {{form-input name='step' label='递增值'}} diff --git a/web/cms/app/templates/sequence/list.hbs b/web/cms/app/templates/sequence/list.hbs index 9269c6ca..0c9cf16b 100644 --- a/web/cms/app/templates/sequence/list.hbs +++ b/web/cms/app/templates/sequence/list.hbs @@ -19,6 +19,9 @@ 名称 + + 长度 + 当前值 @@ -53,6 +56,9 @@ {{it.name}} + + {{it.length}} + {{it.currentVal}} diff --git a/web/cms/tests/unit/routes/agent-status/list-test.js b/web/cms/tests/unit/routes/agent-status/list-test.js new file mode 100644 index 00000000..1605e303 --- /dev/null +++ b/web/cms/tests/unit/routes/agent-status/list-test.js @@ -0,0 +1,11 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Route | agent-status/list', function(hooks) { + setupTest(hooks); + + test('it exists', function(assert) { + let route = this.owner.lookup('route:agent-status/list'); + assert.ok(route); + }); +});