Bläddra i källkod

Merge branch 'master' into pre

# Conflicts:
#	netflix-common/src/main/java/com/cyksj/common/constant/Constant.java
zoujiajian 2 veckor sedan
förälder
incheckning
fb38ea2b40

+ 1 - 1
netflix-common/src/main/java/com/cyksj/common/constant/Constant.java

@@ -880,7 +880,7 @@ public interface Constant {
     /**
      * AI API调度域名
      */
-    String AI_API_SVC_DOMAIN = "https://ywfdev.apinebula.com";
+    String AI_API_SVC_DOMAIN = "https://ywfdev.apinebula.ai";
 
     /**
      * api auth

+ 1 - 1
netflix-service/src/main/java/com/cyksj/service/chatgpt/impl/ChatGptAccountServiceImpl.java

@@ -873,7 +873,7 @@ public class ChatGptAccountServiceImpl implements ChatGptAccountService {
             throw BusinessRuntimeException.getInstance("车票不存在");
         }
         try {
-            String res = HttpUtil.get(String.format("https://image.yhlxj.com/api/getCount?usertoken=%s&limit=%s&time=%s&isVip=%s", userToken, chatgptUser.getLimitNum(), chatgptUser.getLimitTime(), relation.getIsVip()), 5000);
+            String res = HttpUtil.get(String.format("https://image2.yhlxj.com/api/getCount?usertoken=%s&limit=%s&time=%s&isVip=%s", userToken, chatgptUser.getLimitNum(), chatgptUser.getLimitTime(), relation.getIsVip()), 5000);
             return new JSONObject(res);
         }catch (Exception e){
             return new JSONObject("{\"count\": 0,\"o1_mini\": 0,\"o1_p\": 0}");

+ 2 - 0
netflix-service/src/main/java/com/cyksj/service/corp/CorpFollowDynamicConfigService.java

@@ -15,5 +15,7 @@ public interface CorpFollowDynamicConfigService {
 
 	String createCorpFollowActiveCode(List<String> followIds, List<Integer> userIndxList, String state, Boolean isDuty) throws Exception;
 
+	String updateNormalCorpFollowActiveCode(String codeStr, List<String> followIds, List<Integer> userIndxList, String state) throws Exception;
+
 	void updateCorpFollowActiveCode(String oldMarkTag, String markTag) throws Exception;
 }

+ 34 - 0
netflix-service/src/main/java/com/cyksj/service/corp/impl/CorpFollowDynamicConfigServiceImpl.java

@@ -97,6 +97,40 @@ public class CorpFollowDynamicConfigServiceImpl implements CorpFollowDynamicConf
 		return Jsons.toJson(codeList);
 	}
 
+	@Override
+	public String updateNormalCorpFollowActiveCode(String codeStr, List<String> followIds, List<Integer> userIndxList, String state) throws Exception {
+		List<CorpFollowActiveCodeDto> codeList = Jsons.parseList(codeStr, CorpFollowActiveCodeDto.class);
+		if (codeList == null || codeList.size() != 1 || StrUtil.isBlank(codeList.get(0).getConfigId())) {
+			throw BusinessRuntimeException.getInstance("普通活码配置异常,无法更新");
+		}
+
+		List<SysCorpFollowView> corpFollowServiceDtos = beanSearcher.searchAll(SysCorpFollowView.class, MapUtils.builder().build());
+		String serviceNames = null;
+		if (corpFollowServiceDtos != null) {
+			serviceNames = corpFollowServiceDtos.stream()
+					.filter(cs -> userIndxList.contains(Integer.parseInt(cs.getSid().toString())))
+					.map(SysCorpFollowView::getShowName)
+					.collect(Collectors.joining(","));
+		}
+		if (StrUtil.isEmpty(serviceNames)) {
+			throw BusinessRuntimeException.getInstance("存在被删除的客服,请刷新页面重试");
+		}
+
+		CorpFollowActiveCodeDto codeDto = codeList.get(0);
+		CorpFollowContact contact = new CorpFollowContact();
+		contact.setConfigId(codeDto.getConfigId());
+		contact.setUser(followIds);
+		contact.setState(state);
+		contact.setRemark("客服活动活码");
+		contact.setSkip_verify(true);
+		wxCorpOps.updateCorpFollowContactConfig(contact);
+
+		codeDto.setFollowIds(followIds.toString());
+		codeDto.setUserIndxList(userIndxList.toString());
+		codeDto.setServiceNames(serviceNames);
+		return Jsons.toJson(codeList);
+	}
+
 	@Override
 	public void updateCorpFollowActiveCode(String oldMarkTag, String markTag) throws Exception {
 		CorpTag corpTag = corpTagMapper.selectOne(Wrappers.lambdaQuery(CorpTag.class)

+ 8 - 1
netflix-service/src/main/java/com/cyksj/service/corp/impl/CorpFollowServiceImpl.java

@@ -149,7 +149,14 @@ public class CorpFollowServiceImpl implements CorpFollowService {
 
 		//重新构建活码配置
 		if (isReCreateAcCode) {
-			String code_str = corpFollowDynamicConfigService.createCorpFollowActiveCode(up_followStrList, upUserIndxList, Constant.AC_CODE_KEY + activeCode.getId(), up_isDuty);
+			String code_str;
+			if (Boolean.TRUE.equals(db_isDuty) || Boolean.TRUE.equals(up_isDuty)) {
+				// 值班模式为一人一码,编辑时允许重新新增配置。
+				code_str = corpFollowDynamicConfigService.createCorpFollowActiveCode(up_followStrList, upUserIndxList, Constant.AC_CODE_KEY + activeCode.getId(), up_isDuty);
+			} else {
+				// 普通模式始终复用原 config_id,避免编辑产生新的企业微信活码。
+				code_str = corpFollowDynamicConfigService.updateNormalCorpFollowActiveCode(dbActiveCode.getCodeStr(), up_followStrList, upUserIndxList, Constant.AC_CODE_KEY + activeCode.getId());
+			}
 			activeCode.setCodeStr(code_str);
 			Set<String> keys = redisService.keys(RedisService.key.CORP_FOLLOW_ACTIVE_CODE_KEY.getNameFormat(activeCode.getId(), "*"));
 			redisService.del(keys.toArray(String[]::new));

+ 131 - 12
netflix-service/src/main/java/com/cyksj/service/mail/impl/CommonMailServiceImpl.java

@@ -7,11 +7,14 @@ import cn.hutool.http.HttpRequest;
 import cn.hutool.http.HttpResponse;
 import cn.hutool.http.HttpUtil;
 import cn.hutool.json.JSONObject;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.cyksj.common.constant.Constant;
 import com.cyksj.common.exception.BusinessRuntimeException;
 import com.cyksj.common.util.Jsons;
 import com.cyksj.common.util.StringUtil;
 import com.cyksj.common.util.TicketCodeCommonUtil;
+import com.cyksj.mapper.sys.SysEmailMapper;
+import com.cyksj.model.entity.SysEmail;
 import com.cyksj.model.response.AdobeEmailResp;
 import com.cyksj.model.response.DisneyCodeResp;
 import com.cyksj.service.mail.CommonMailService;
@@ -43,10 +46,18 @@ public class CommonMailServiceImpl implements CommonMailService {
 
 	private final YhMailService yhMailService;
 
+    private final SysEmailMapper sysEmailMapper;
+
 	//GPT修改密码匹配
 	private final static String GPT_RESET_PWD_LINK_REGEX = "https://auth0.openai.com/u/reset-verify";
 	@Override
 	public String getTicketMailCode(Long goodsId, String account, String relateEmail, String emailPwd, Date emailCreatedTime, Integer type, Integer linkType, Boolean isReturnDeviceUrl) throws Exception {
+        if (StrUtil.isEmpty(emailPwd)) {
+            SysEmail sysEmail = sysEmailMapper.selectOne(Wrappers.lambdaQuery(SysEmail.class).eq(SysEmail::getEmail, account).last("limit 1"));
+            if (sysEmail != null) {
+                emailPwd = sysEmail.getPassword();
+            }
+        }
 		if (StrUtil.isEmpty(relateEmail)) {
 			//25年的GPT账号获取验证码 特殊处理
 			//获取失败走下一步
@@ -107,14 +118,18 @@ public class CommonMailServiceImpl implements CommonMailService {
 			}
 		}
 
-		//Netflix get verify code
-		if (Constant.NETFLIX_GID.equals(goodsId) && linkType == null && (type == null || type == 1) && StrUtil.isNotBlank(emailPwd)) {
+		//Netflix get verify code or household device link
+		if (Constant.NETFLIX_GID.equals(goodsId) && StrUtil.isNotBlank(emailPwd)
+				&& ((linkType == null && (type == null || type == 1))
+				|| (linkType == 1 && Boolean.TRUE.equals(isReturnDeviceUrl)))) {
 			try {
 				String url = "https://ms.lqqq.cc/web/" + account + "----" + emailPwd;
 				HttpRequest post = HttpUtil.createGet(url).timeout(Constant.CONNECT_MILLISECONDS);
 				HttpResponse execute = post.execute();
 				String body = execute.body();
-				String code = getNetflixVerifyCodeByLqqqMail(account, emailPwd, body);
+				String code = linkType != null && linkType == 1
+						? getNetflixHouseholdDeviceUrlByLqqqMail(account, body)
+						: getNetflixVerifyCodeByLqqqMail(account, body);
 				if (StrUtil.isNotBlank(code)) {
 					return code;
 				}
@@ -126,37 +141,41 @@ public class CommonMailServiceImpl implements CommonMailService {
 		String checkEmail = StrUtil.isNotEmpty(relateEmail) ? relateEmail : account;
 		//关联邮箱
 		if (cuiQiuMailService.isCuiQiuEmail(checkEmail)) {
-			return cuiQiuMailService.getVerifyCode(account, relateEmail, goodsId, type, linkType, false);
+			return cuiQiuMailService.getVerifyCode(account, relateEmail, goodsId, type, linkType, Boolean.TRUE.equals(isReturnDeviceUrl));
 		}
 		//是否是 mail lu邮箱
 		if (mailLuService.isMailLuEmail(checkEmail)) {
-			return mailLuService.getVerifyCode(account, relateEmail, goodsId, type, linkType, false);
+			return mailLuService.getVerifyCode(account, relateEmail, goodsId, type, linkType, Boolean.TRUE.equals(isReturnDeviceUrl));
 		}
 		//银河域名邮件
-		return yhMailService.getVerifyCode(account, relateEmail, goodsId, type, linkType, false);
+		return yhMailService.getVerifyCode(account, relateEmail, goodsId, type, linkType, Boolean.TRUE.equals(isReturnDeviceUrl));
 	}
 
-	private String getNetflixVerifyCodeByLqqqMail(String account, String emailPwd, String body) {
+	private String getNetflixVerifyCodeByLqqqMail(String account, String body) {
 		if (StrUtil.isBlank(body)) {
 			return StrUtil.EMPTY;
 		}
 		if (!body.contains("/show_email/")) {
 			return getNetflixVerifyCode(body);
 		}
-		Matcher matcher = Pattern.compile("href=\"([^\"]*/show_email/[^\"]+)\"", Pattern.CASE_INSENSITIVE).matcher(body);
+		Matcher matcher = Pattern.compile("<a\\b[^>]*href=\"([^\"]*/show_email/[^\"]+)\"[^>]*>", Pattern.CASE_INSENSITIVE).matcher(body);
 		while (matcher.find()) {
 			String href = matcher.group(1);
-			int start = Math.max(0, matcher.start() - 800);
-			int end = Math.min(body.length(), matcher.end() + 200);
-			String emailItem = body.substring(start, end);
+			String emailItem = getMailListItemHtml(body, matcher.start());
 			if (!emailItem.contains(Constant.NETFLIX) || !isNetflixLoginCodeMail(emailItem)) {
 				continue;
 			}
+			String code = getNetflixVerifyCodeFromListItem(emailItem);
+			if (StrUtil.isNotBlank(code)) {
+				log.info("Netflix {} get verify code from lqqq mail list: {}", account, code);
+				return code;
+			}
 			try {
 				String detailUrl = href.startsWith("http") ? href : "https://ms.lqqq.cc" + href;
 				HttpResponse detailResp = HttpUtil.createGet(detailUrl).timeout(Constant.CONNECT_MILLISECONDS).execute();
-				String code = getNetflixVerifyCode(detailResp.body());
+				code = getNetflixVerifyCode(detailResp.body());
 				if (StrUtil.isNotBlank(code)) {
+					log.info("Netflix {} get verify code from lqqq mail detail: {}", account, code);
 					return code;
 				}
 			} catch (Exception e) {
@@ -166,6 +185,106 @@ public class CommonMailServiceImpl implements CommonMailService {
 		return StrUtil.EMPTY;
 	}
 
+	private String getNetflixHouseholdDeviceUrlByLqqqMail(String account, String body) {
+		if (StrUtil.isBlank(body)) {
+			return StrUtil.EMPTY;
+		}
+		String url = getNetflixHouseholdDeviceUrl(body);
+		if (StrUtil.isNotBlank(url)) {
+			return url;
+		}
+		Matcher matcher = Pattern.compile("<a\\b[^>]*href=\"([^\"]*/show_email/[^\"]+)\"[^>]*>", Pattern.CASE_INSENSITIVE).matcher(body);
+		while (matcher.find()) {
+			String emailItem = getMailListItemHtml(body, matcher.start());
+			if (!isNetflixHouseholdDeviceMail(emailItem)) {
+				continue;
+			}
+			try {
+				String href = decodeHtmlUrl(matcher.group(1));
+				String detailUrl = href.startsWith("http") ? href : "https://ms.lqqq.cc" + href;
+				HttpResponse detailResp = HttpUtil.createGet(detailUrl).timeout(Constant.CONNECT_MILLISECONDS).execute();
+				url = getNetflixHouseholdDeviceUrl(detailResp.body());
+				if (StrUtil.isNotBlank(url)) {
+					log.info("Netflix {} get household device url from lqqq mail detail", account);
+					return url;
+				}
+			} catch (Exception e) {
+				log.error("Netflix {} read household device mail failed: {}", account, StringUtil.getErrorMsg(e));
+			}
+		}
+		return StrUtil.EMPTY;
+	}
+
+	private boolean isNetflixHouseholdDeviceMail(String body) {
+		if (StrUtil.isBlank(body) || !body.toLowerCase().contains("netflix")) {
+			return false;
+		}
+		String text = cleanMailHtml(body).toLowerCase();
+		return text.contains("update netflix household")
+				|| text.contains("netflix household device")
+				|| text.contains("update-primary-location")
+				|| text.contains("\u66f4\u65b0 netflix \u540c\u6237\u8bbe\u5907")
+				|| text.contains("\u66f4\u65b0 netflix \u540c\u6236\u88dd\u7f6e");
+	}
+
+	private String getNetflixHouseholdDeviceUrl(String body) {
+		if (StrUtil.isBlank(body)) {
+			return StrUtil.EMPTY;
+		}
+		Matcher matcher = Pattern.compile("https://www\\.netflix\\.com/account/update-primary-location[^\\s\\\"'<>]*", Pattern.CASE_INSENSITIVE).matcher(body);
+		if (matcher.find()) {
+			return decodeHtmlUrl(matcher.group());
+		}
+		return StrUtil.EMPTY;
+	}
+
+	private String decodeHtmlUrl(String url) {
+		return StrUtil.blankToDefault(url, StrUtil.EMPTY)
+				.replace("&amp;", "&")
+				.replace("&#38;", "&")
+				.replace("&#x26;", "&");
+	}
+
+	private String getMailListItemHtml(String body, int hrefStart) {
+		int cardStart = body.lastIndexOf("<article", hrefStart);
+		if (cardStart < 0) {
+			cardStart = body.lastIndexOf("<div class=\"email-card", hrefStart);
+		}
+		if (cardStart < 0) {
+			cardStart = Math.max(0, hrefStart - 1200);
+		}
+		int nextCardStart = body.indexOf("<article", hrefStart + 1);
+		int legacyNextCardStart = body.indexOf("<div class=\"email-card", hrefStart + 1);
+		int cardEnd = body.length();
+		if (nextCardStart > 0) {
+			cardEnd = Math.min(cardEnd, nextCardStart);
+		}
+		if (legacyNextCardStart > 0) {
+			cardEnd = Math.min(cardEnd, legacyNextCardStart);
+		}
+		cardEnd = Math.min(cardEnd, hrefStart + 1200);
+		return body.substring(cardStart, cardEnd);
+	}
+
+	private String getNetflixVerifyCodeFromListItem(String emailItem) {
+		String text = cleanMailHtml(emailItem);
+		String[] startStrs = new String[]{
+				"Enter this code to sign in",
+				"Informe este c\u00f3digo para entrar",
+				"\u8f38\u5165\u6b64\u4ee3\u78bc\u767b\u5165",
+				"\u8f93\u5165\u6b64\u4ee3\u7801\u767b\u5f55"
+		};
+		for (String startStr : startStrs) {
+			if (text.contains(startStr)) {
+				String verifyCode = getNetflixCodePattern(StrUtil.subAfter(text, startStr, false));
+				if (StrUtil.isNotBlank(verifyCode)) {
+					return verifyCode;
+				}
+			}
+		}
+		return StrUtil.EMPTY;
+	}
+
 	private boolean isNetflixLoginCodeMail(String body) {
 		return body.contains("\u767b\u5f55\u4ee3\u7801")
 				|| body.contains("\u767b\u9304\u4ee3\u78bc")

+ 3 - 2
netflix-service/src/main/java/com/cyksj/service/order/impl/OrderDonServiceImpl.java

@@ -3385,8 +3385,9 @@ public class OrderDonServiceImpl extends ServiceImpl<OrderDonMapper, OrderDon> i
 			returnGalaxyCoin(orderDon);
 		}
 
-		//GPT独立会员续费 若为代充类型 同步代充次数
-		if (orderDon.getGoodsId() == Constant.GPT_PLUS_GID && sku.getNum() == 1) {
+        //GPT独立会员续费,名称包含pro的规格不进入代充
+        if (orderDon.getGoodsId() == Constant.GPT_PLUS_GID && sku.getNum() == 1
+                && !StrUtil.containsIgnoreCase(sku.getSpecVal(), "pro")) {
 			incrGroupsRelationRechargeRemainIfRecharge(orderDon.getRelationId(), sku.getMonths(), orderDon.getOrderType());
 			
 			// GPT独立会员购买,赠送sora邀请码