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

https://gitee.com/cskefu/cskefu/issues/I836RO add webim channel creation as billing resource

Signed-off-by: Hai Liang Wang <hai@chatopera.com>
This commit is contained in:
Hai Liang Wang 2023-09-25 09:43:07 +08:00
parent 3cb64fa664
commit 2e4a71c175
6 changed files with 186 additions and 55 deletions

View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2023 Beijing Huaxia Chunsong Technology Co., Ltd.
* <https://www.chatopera.com>, Licensed under the Chunsong Public
* License, Version 1.0 (the "License"), https://docs.cskefu.com/licenses/v1.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cskefu.cc.aspect;
import com.cskefu.cc.basic.MainContext;
import com.cskefu.cc.exception.BillingQuotaException;
import com.cskefu.cc.exception.BillingResourceException;
import com.cskefu.cc.model.Channel;
import com.cskefu.cc.model.User;
import com.cskefu.cc.proxy.LicenseProxy;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class ChannelAspect {
private final static Logger logger = LoggerFactory.getLogger(ChannelAspect.class);
@Autowired
private LicenseProxy licenseProxy;
@Before("execution(* com.cskefu.cc.persistence.repository.ChannelRepository.save(..))")
public void beforeSave(final JoinPoint joinPoint) throws BillingResourceException, BillingQuotaException {
final Channel channel = (Channel) joinPoint.getArgs()[0];
logger.info("[beforeSave] before channel id {}, type {}", channel.getId(), channel.getType());
if (StringUtils.isBlank(channel.getId())) {
// create new Channel
if (StringUtils.equals(channel.getType(), MainContext.ChannelType.WEBIM.toString())) {
// create new WEBIM channel
licenseProxy.writeDownResourceUsageInStore(MainContext.BillingResource.CHANNELWEBIM, 1);
}
} else {
// update existed Channel
}
}
}

View File

@ -18,6 +18,7 @@ import com.cskefu.cc.basic.MainContext;
import com.cskefu.cc.basic.MainUtils; import com.cskefu.cc.basic.MainUtils;
import com.cskefu.cc.cache.Cache; import com.cskefu.cc.cache.Cache;
import com.cskefu.cc.controller.Handler; import com.cskefu.cc.controller.Handler;
import com.cskefu.cc.exception.BillingQuotaException;
import com.cskefu.cc.model.*; import com.cskefu.cc.model.*;
import com.cskefu.cc.persistence.repository.ConsultInviteRepository; import com.cskefu.cc.persistence.repository.ConsultInviteRepository;
import com.cskefu.cc.persistence.repository.OrganRepository; import com.cskefu.cc.persistence.repository.OrganRepository;
@ -27,6 +28,8 @@ import com.cskefu.cc.proxy.OrganProxy;
import com.cskefu.cc.util.Base62; import com.cskefu.cc.util.Base62;
import com.cskefu.cc.util.Menu; import com.cskefu.cc.util.Menu;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
@ -37,6 +40,8 @@ import org.springframework.web.servlet.ModelAndView;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import java.lang.reflect.UndeclaredThrowableException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -48,6 +53,7 @@ import java.util.Map;
@Controller @Controller
@RequestMapping("/admin/im") @RequestMapping("/admin/im")
public class ChannelController extends Handler { public class ChannelController extends Handler {
private final static Logger logger = LoggerFactory.getLogger(ChannelController.class);
@Autowired @Autowired
private ChannelRepository snsAccountRes; private ChannelRepository snsAccountRes;
@ -93,13 +99,22 @@ public class ChannelController extends Handler {
return request(super.createView("/admin/channel/im/add")); return request(super.createView("/admin/channel/im/add"));
} }
/**
* 创建新的网站渠道
*
* @param request
* @param channel
* @return
* @throws NoSuchAlgorithmException
*/
@RequestMapping("/save") @RequestMapping("/save")
@Menu(type = "admin", subtype = "weixin") @Menu(type = "admin", subtype = "im")
public ModelAndView save(HttpServletRequest request, public ModelAndView save(HttpServletRequest request,
@Valid Channel channel) throws NoSuchAlgorithmException { @Valid Channel channel) throws NoSuchAlgorithmException {
Organ currentOrgan = super.getOrgan(request); Organ currentOrgan = super.getOrgan(request);
String status = "new_webim_fail"; String status = "new_webim_fail";
if (StringUtils.isNotBlank(channel.getBaseURL())) { if (StringUtils.isNotBlank(channel.getBaseURL())) {
try {
channel.setSnsid(Base62.encode(channel.getBaseURL()).toLowerCase()); channel.setSnsid(Base62.encode(channel.getBaseURL()).toLowerCase());
int count = snsAccountRes.countBySnsid(channel.getSnsid()); int count = snsAccountRes.countBySnsid(channel.getSnsid());
if (count == 0) { if (count == 0) {
@ -129,6 +144,16 @@ public class ChannelController extends Handler {
invite.save(coultInvite); invite.save(coultInvite);
} }
} }
} catch (Exception e) {
if (e instanceof UndeclaredThrowableException) {
logger.error("[save] BillingQuotaException", e);
if (StringUtils.startsWith(e.getCause().getMessage(), BillingQuotaException.SUFFIX)) {
status = e.getCause().getMessage();
}
} else {
logger.error("[save] err", e);
}
}
} }
return request(super.createView("redirect:/admin/im/index.html?status=" + status)); return request(super.createView("redirect:/admin/im/index.html?status=" + status));
} }

View File

@ -11,6 +11,11 @@
* Licensed under the Apache License, Version 2.0 * Licensed under the Apache License, Version 2.0
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
*/ */
/**
* 处理系统用户的创建的返回值
* @param responsecode
* @param cb
*/
function processUserAddOrUpdateResult(responsecode, cb) { function processUserAddOrUpdateResult(responsecode, cb) {
switch (responsecode) { switch (responsecode) {
case 'username_exist': case 'username_exist':
@ -56,35 +61,86 @@ function processUserAddOrUpdateResult(responsecode, cb){
layer.msg('用户编辑成功', {icon: 1, time: 1000}); layer.msg('用户编辑成功', {icon: 1, time: 1000});
cb(); cb();
break; break;
default:
handleGeneralCodeInQueryPathOrApiResp(responsecode, cb);
}
}
/**
* 处理在 RedirectURL, API 中返回的 code 信息 status, msg, etc.
* code 为约定的返回值通过下面的函数进行展示
* @param code
* @param cb
*/
function handleGeneralCodeInQueryPathOrApiResp(code, cb) {
switch (code) {
case 'billingquotaexception.no_license_found': case 'billingquotaexception.no_license_found':
layer.msg('【使用授权证书】证书不存在,联系系统超级管理员导入。', {icon: 2, time: 5000}); layer.msg('【使用授权证书】证书不存在,联系系统超级管理员导入。', {icon: 2, time: 5000});
if (cb && (typeof (x) === 'function')) {
cb()
}
break; break;
case 'billingquotaexception.response_unexpected': case 'billingquotaexception.response_unexpected':
layer.msg('【使用授权证书】证书商店返回异常,稍后再试。', {icon: 2, time: 5000}); layer.msg('【使用授权证书】证书商店返回异常,稍后再试。', {icon: 2, time: 5000});
if (cb && (typeof (x) === 'function')) {
cb()
}
break; break;
case 'billingquotaexception.invalid_request_body': case 'billingquotaexception.invalid_request_body':
layer.msg('【使用授权证书】请求证书商店参数不合法,请获取最新软件代码。', {icon: 2, time: 5000}); layer.msg('【使用授权证书】请求证书商店参数不合法,请获取最新软件代码。', {icon: 2, time: 5000});
if (cb && (typeof (x) === 'function')) {
cb()
}
break; break;
case 'billingquotaexception.license_invalid': case 'billingquotaexception.license_invalid':
layer.msg('【使用授权证书】证书商店中不存在该证书,请联系系统超级管理员导入。', {icon: 2, time: 5000}); layer.msg('【使用授权证书】证书商店中不存在该证书,请联系系统超级管理员导入。', {icon: 2, time: 5000});
if (cb && (typeof (x) === 'function')) {
cb()
}
break; break;
case 'billingquotaexception.product_invalid': case 'billingquotaexception.product_invalid':
layer.msg('【使用授权证书】产品或产品款式不存在,请联系系统超级管理员导入新证书。', {icon: 2, time: 5000}); layer.msg('【使用授权证书】产品或产品款式不存在,请联系系统超级管理员导入新证书。', {icon: 2, time: 5000});
if (cb && (typeof (x) === 'function')) {
cb()
}
break; break;
case 'billingquotaexception.license_expired_or_exhausted': case 'billingquotaexception.license_expired_or_exhausted':
layer.msg('【使用授权证书】证书过期或耗尽,请升级证书或绑定新证书。', {icon: 2, time: 5000}); layer.msg('【使用授权证书】证书过期或耗尽,请升级证书或绑定新证书。', {icon: 2, time: 5000});
if (cb && (typeof (x) === 'function')) {
cb()
}
break; break;
case 'billingquotaexception.license_disabled_serverinst': case 'billingquotaexception.license_disabled_serverinst':
layer.msg('【使用授权证书】证书商店禁用了本服务实例。', {icon: 2, time: 5000}); layer.msg('【使用授权证书】证书商店禁用了本服务实例。', {icon: 2, time: 5000});
if (cb && (typeof (x) === 'function')) {
cb()
}
break; break;
case 'billingquotaexception.license_unsupport_refund': case 'billingquotaexception.license_unsupport_refund':
layer.msg('【使用授权证书】目前使用的证书不支持回退配额。', {icon: 2, time: 5000}); layer.msg('【使用授权证书】目前使用的证书不支持回退配额。', {icon: 2, time: 5000});
if (cb && (typeof (x) === 'function')) {
cb()
}
break; break;
case 'billingquotaexception.license_quota_inadequate': case 'billingquotaexception.license_quota_inadequate':
layer.msg('【使用授权证书】本次操作需要使用的配额资源超过证书中剩余配额,请联系系统超级管理员升级证书。',{icon: 2, time: 5000}); layer.msg('【使用授权证书】本次操作需要使用的配额资源超过证书中剩余配额,请联系系统超级管理员升级证书。', {
icon: 2,
time: 5000
});
if (cb && (typeof (x) === 'function')) {
cb()
}
break; break;
case 'billingquotaexception.internal_error': case 'billingquotaexception.internal_error':
layer.msg('【使用授权证书】系统错误,稍后再试。', {icon: 2, time: 5000}); layer.msg('【使用授权证书】系统错误,稍后再试。', {icon: 2, time: 5000});
if (cb && (typeof (x) === 'function')) {
cb()
}
break; break;
default:
console.log("[handleGeneralCodeInQueryPathOrApiResp] none code matched", code);
if (cb && (typeof (x) === 'function')) {
cb("no_code_matched");
}
} }
} }

View File

@ -63,13 +63,13 @@ block content
layui.use('layer', function () { layui.use('layer', function () {
var layer = layui.layer; var layer = layui.layer;
console.log(window.location.href)
var status = '#{status}'; var status = '#{status}';
if (status == 'new_webim_success') if (status == 'new_webim_success')
layer.msg('网站添加成功', {icon: 1, time: 1000}) layer.msg('网站添加成功', {icon: 1, time: 1000})
else if (status == 'new_webim_fail') else if (status == 'new_webim_fail')
layer.msg('网站添加失败', {icon: 2, time: 3000}) layer.msg('网站添加失败', {icon: 2, time: 3000})
else
handleGeneralCodeInQueryPathOrApiResp(status);
}); });
layui.use(['laypage', 'layer'], function () { layui.use(['laypage', 'layer'], function () {
var laypage = layui.laypage var laypage = layui.laypage

View File

@ -33,6 +33,7 @@ html(xmlns='http://www.w3.org/1999/xhtml', xmlns:th='http://www.thymeleaf.org',
script(src='/js/echarts.common.min.js') script(src='/js/echarts.common.min.js')
script(language='javascript', src='/js/theme/wonderland.js') script(language='javascript', src='/js/theme/wonderland.js')
script(src='/layui.js') script(src='/layui.js')
script(src="/js/CSKeFu_Admin.v1.js")
script(src='/js/cskefu.js') script(src='/js/cskefu.js')
if userExpTelemetry == 'on' if userExpTelemetry == 'on'
script(src='https://www.googletagmanager.com/gtag/js?id=G-SBBX10RKTC' async) script(src='https://www.googletagmanager.com/gtag/js?id=G-SBBX10RKTC' async)

View File

@ -38,8 +38,6 @@ html(xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xm
script(src="/js/moment-timezone.js") script(src="/js/moment-timezone.js")
script(src="/js/moment-timezone-with-data.js") script(src="/js/moment-timezone-with-data.js")
script(src="/layui.js") script(src="/layui.js")
//- #894 和原生Map行为不一致
//- <script src="/js/utils.js"></script>
script(src="/js/cskefu.js") script(src="/js/cskefu.js")
script(src="/im/js/socket.io.js") script(src="/im/js/socket.io.js")
script(src="/js/CSKeFu_IM.v1.js") script(src="/js/CSKeFu_IM.v1.js")