diff --git a/src/main/java/com/ai/da/common/constant/CommonConstant.java b/src/main/java/com/ai/da/common/constant/CommonConstant.java index b167f4b6..ff539ec1 100644 --- a/src/main/java/com/ai/da/common/constant/CommonConstant.java +++ b/src/main/java/com/ai/da/common/constant/CommonConstant.java @@ -65,4 +65,7 @@ public class CommonConstant { public static final Long MAXIMUM_USER_ID = 704L; // public static final Long MAXIMUM_USER_ID = 225L; + // 激活更改邮箱 链接有效期 毫秒 3天 + public static final Long CHANGE_MAILBOX_LINK_VALIDITY = 259200000L; + } diff --git a/src/main/java/com/ai/da/common/enums/AuthenticationOperationTypeEnum.java b/src/main/java/com/ai/da/common/enums/AuthenticationOperationTypeEnum.java index e8ea46d1..a8300691 100644 --- a/src/main/java/com/ai/da/common/enums/AuthenticationOperationTypeEnum.java +++ b/src/main/java/com/ai/da/common/enums/AuthenticationOperationTypeEnum.java @@ -23,7 +23,11 @@ public enum AuthenticationOperationTypeEnum { /** * 忘记密码 */ - FORGET_PWD; + FORGET_PWD, + /** + * 更改邮箱 + */ + CHANGE_MAILBOX; public static AuthenticationOperationTypeEnum of(String name) { return Stream.of(AuthenticationOperationTypeEnum.values()).filter(v -> v.name().equals(name)).findFirst().orElse(null); diff --git a/src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java b/src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java index fbf43e60..532934b0 100644 --- a/src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java +++ b/src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java @@ -31,6 +31,7 @@ public enum CreditsEventsEnum { TO_PRODUCT_IMAGE("ToProductImage","5"), RELIGHT("Relight","5"), QUESTIONNAIRE("Questionnaire","100"), + IMAGE_TO_SKETCH("ImageToSketch","5"), OTHER("Other","5"); diff --git a/src/main/java/com/ai/da/common/security/filter/AuthenticationFilter.java b/src/main/java/com/ai/da/common/security/filter/AuthenticationFilter.java index bc6071c8..bd1052be 100644 --- a/src/main/java/com/ai/da/common/security/filter/AuthenticationFilter.java +++ b/src/main/java/com/ai/da/common/security/filter/AuthenticationFilter.java @@ -51,7 +51,7 @@ public class AuthenticationFilter extends OncePerRequestFilter { "/api/python/flush","/api/account/healthy","/api/ali-pay/trade/notify","/api/paypal/ipn/back","/api/alipay-hk/trade/notify", "/api/portfolio/page", "/api/portfolio/detail", "/api/portfolio/commentPage", "/api/portfolio/viewsIncrease", "/api/account/designWorksRegister","/api/account/questionnaire","/api/stripe/trade/notify", - "/notification" + "/notification","/api/account/activateNewEmail" ); @Override diff --git a/src/main/java/com/ai/da/common/security/jwt/JWTTokenHelper.java b/src/main/java/com/ai/da/common/security/jwt/JWTTokenHelper.java index a43a21f0..d536ab29 100644 --- a/src/main/java/com/ai/da/common/security/jwt/JWTTokenHelper.java +++ b/src/main/java/com/ai/da/common/security/jwt/JWTTokenHelper.java @@ -2,6 +2,7 @@ package com.ai.da.common.security.jwt; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.StrUtil; +import com.ai.da.common.constant.CommonConstant; import com.ai.da.common.security.config.SecurityProperties; import com.ai.da.model.vo.AuthPrincipalVo; import com.alibaba.fastjson.JSON; @@ -30,6 +31,7 @@ public class JWTTokenHelper { private static final String ISSUER = "DWJ"; private static final String AUTHORITIES = "authorities"; + private static final String CHANGE_MAILBOX = "changeMailbox"; public String createToken(AuthPrincipalVo principal) { String token = Jwts.builder() @@ -65,4 +67,21 @@ public class JWTTokenHelper { token = token.replaceAll(securityProperties.getJwtTokenPrefix(), ""); return Jwts.parser().setSigningKey(securityProperties.getJwtSecret()).parseClaimsJws(token).getBody(); } + + public String createToken(Long userId, String userEmail){ + String token = Jwts.builder() + .setId(String.valueOf(userId)) + .setSubject(userEmail + "_" + userId) + .setIssuedAt(new Date()) + .setIssuer(ISSUER) + .claim(CHANGE_MAILBOX, JSON.toJSONString(new ArrayList<>()))//自定义属性 权限 + .setExpiration(new Date(System.currentTimeMillis() + CommonConstant.CHANGE_MAILBOX_LINK_VALIDITY)) + .signWith(SignatureAlgorithm.HS256, securityProperties.getJwtSecret()) + .compact(); + return token; + } + + public String parseToEmailAndId(String token) { + return parser(token).getSubject(); + } } diff --git a/src/main/java/com/ai/da/common/utils/RedisUtil.java b/src/main/java/com/ai/da/common/utils/RedisUtil.java index f1a1c0be..780d0c3a 100644 --- a/src/main/java/com/ai/da/common/utils/RedisUtil.java +++ b/src/main/java/com/ai/da/common/utils/RedisUtil.java @@ -1,6 +1,7 @@ package com.ai.da.common.utils; import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.HashOperations; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ZSetOperations; import org.springframework.stereotype.Component; @@ -249,4 +250,22 @@ public class RedisUtil { public String getMoodboardPosition(Long id) { return getFromString(MOODBOARD_POSITION_KEY + id); } + public final static String NICKNAME_MODIFY_TIMES = "NicknameModifyTimes:"; + public void increaseCount(String key) { + redisTemplate.opsForValue().increment(key); + } + + public Long getIncrementCount(String key) { + return redisTemplate.opsForValue().increment(key, 0); + } + + public void setKeyExpire(String key, Long expire) { + redisTemplate.expire(key, expire, TimeUnit.DAYS); + } + + public final static String CHANGE_MAILBOX = "ChangeMailbox:"; + + // 每天允许通知3次 + public final static String UPLOAD_TIMEOUT_REMINDER_COUNTER = "UploadTimeoutReminderCounter"; + } diff --git a/src/main/java/com/ai/da/common/utils/SendEmailUtil.java b/src/main/java/com/ai/da/common/utils/SendEmailUtil.java index 16fcfe21..67ec92e5 100644 --- a/src/main/java/com/ai/da/common/utils/SendEmailUtil.java +++ b/src/main/java/com/ai/da/common/utils/SendEmailUtil.java @@ -53,6 +53,7 @@ public class SendEmailUtil { * 绑定邮箱 */ public static String BIND_MAILBOX_SUBJECT = "绑定邮箱"; + public static String CHANGE_MAILBOX_SUBJECT = "Change Mailbox"; /** * 登入模板id */ @@ -71,6 +72,8 @@ public class SendEmailUtil { */ public static Long BIND_MAILBOX_TEMPLATE_ID = 45619L; + public static Long CHANGE_MAILBOX_TEMPLATE_ID = 128210L; + public static Boolean send(String receiverAddress, String ip, Long templateId, String verifyCode) { try { @@ -92,7 +95,8 @@ public class SendEmailUtil { req.setDestination(new String[]{receiverAddress}); String subject = templateId == LOGIN_TEMPLATE_ID ? LOGIN_SUBJECT : templateId == UPDATE_PWD_TEMPLATE_ID ? FORGET_PWD_SUBJECT : - templateId == EXCEPTION_ID_TEMPLATE_ID ? EXCEPTION_ID_SUBJECT : BIND_MAILBOX_SUBJECT; + templateId == EXCEPTION_ID_TEMPLATE_ID ? EXCEPTION_ID_SUBJECT : + templateId == CHANGE_MAILBOX_TEMPLATE_ID ? CHANGE_MAILBOX_SUBJECT : BIND_MAILBOX_SUBJECT; req.setSubject(subject); req.setTemplate(contractTemplate(templateId, verifyCode, ip)); @@ -626,4 +630,92 @@ public class SendEmailUtil { throw new BusinessException("failed.to.send.mail"); } } + + private final static Long CHANGE_MAILBOX_CONFIRM_CN = 128278L; + private final static Long CHANGE_MAILBOX_CONFIRM_EN = 128277L; + + public static void changeMailboxConfirm(String receiverAddress, String language, String name, String link){ + try{ + // 实例化一个认证对象,入参需要传入腾讯云账户 SecretId 和 SecretKey,此处还需注意密钥对的保密 + // 代码泄露可能会导致 SecretId 和 SecretKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考,建议采用更安全的方式来使用密钥,请参见:https://cloud.tencent.com/document/product/1278/85305 + // 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取 + Credential cred = new Credential(SECRET_ID, SECRET_KEy); + // 实例化一个http选项,可选的,没有特殊需求可以跳过 + HttpProfile httpProfile = new HttpProfile(); + httpProfile.setEndpoint("ses.tencentcloudapi.com"); + // 实例化一个client选项,可选的,没有特殊需求可以跳过 + ClientProfile clientProfile = new ClientProfile(); + clientProfile.setHttpProfile(httpProfile); + // 实例化要请求产品的client对象,clientProfile是可选的 + SesClient client = new SesClient(cred, "ap-hongkong", clientProfile); + // 实例化一个请求对象,每个接口都会对应一个request对象 + SendEmailRequest req = new SendEmailRequest(); + req.setFromEmailAddress(SEND_ADDRESS); + req.setDestination(new String[]{receiverAddress}); + Template template = new Template(); + if (language.equals("ENGLISH")){ + req.setSubject("Change the email address bound to the AiDA account"); + template.setTemplateID(CHANGE_MAILBOX_CONFIRM_EN); + }else { + req.setSubject("更换AiDA账号绑定的邮箱地址"); + template.setTemplateID(CHANGE_MAILBOX_CONFIRM_CN); + } + JSONObject param = new JSONObject(); + param.put("userName", name); + param.put("link", link); + + template.setTemplateData(param.toJSONString()); + req.setTemplate(template); + + // 返回的resp是一个SendEmailResponse的实例,与请求对象对应 + SendEmailResponse resp = client.SendEmail(req); + log.info("短信发送结果res###{}", SendEmailResponse.toJsonString(resp)); + } catch (TencentCloudSDKException e) { + log.info("邮件发送失败###{}", e.toString()); + throw new BusinessException("failed.to.send.mail"); + } + } + + private final static Long UPLOAD_TIMEOUT_REMINDER = 128324L; + + public static void uploadTimeoutReminder(String userName, String time){ + String xp = "xupei3360@163.com"; + String shb = "shahaibodd99@gmail.com"; + String wxd = "X1627315083@163.com"; + String pkc = "kaicpang.pang@connect.polyu.hk"; + try{ + // 实例化一个认证对象,入参需要传入腾讯云账户 SecretId 和 SecretKey,此处还需注意密钥对的保密 + // 代码泄露可能会导致 SecretId 和 SecretKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考,建议采用更安全的方式来使用密钥,请参见:https://cloud.tencent.com/document/product/1278/85305 + // 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取 + Credential cred = new Credential(SECRET_ID, SECRET_KEy); + // 实例化一个http选项,可选的,没有特殊需求可以跳过 + HttpProfile httpProfile = new HttpProfile(); + httpProfile.setEndpoint("ses.tencentcloudapi.com"); + // 实例化一个client选项,可选的,没有特殊需求可以跳过 + ClientProfile clientProfile = new ClientProfile(); + clientProfile.setHttpProfile(httpProfile); + // 实例化要请求产品的client对象,clientProfile是可选的 + SesClient client = new SesClient(cred, "ap-hongkong", clientProfile); + // 实例化一个请求对象,每个接口都会对应一个request对象 + SendEmailRequest req = new SendEmailRequest(); + req.setFromEmailAddress(SEND_ADDRESS); + req.setDestination(new String[]{shb, xp, wxd, pkc}); + Template template = new Template(); + req.setSubject("上传图片超时提醒"); + template.setTemplateID(UPLOAD_TIMEOUT_REMINDER); + JSONObject param = new JSONObject(); + param.put("userName", userName); + param.put("time", time); + + template.setTemplateData(param.toJSONString()); + req.setTemplate(template); + + // 返回的resp是一个SendEmailResponse的实例,与请求对象对应 + SendEmailResponse resp = client.SendEmail(req); + log.info("短信发送结果res###{}", SendEmailResponse.toJsonString(resp)); + } catch (TencentCloudSDKException e) { + log.info("邮件发送失败###{}", e.toString()); + throw new BusinessException("failed.to.send.mail"); + } + } } diff --git a/src/main/java/com/ai/da/controller/AccountController.java b/src/main/java/com/ai/da/controller/AccountController.java index 8cf6a5a9..60fb806c 100644 --- a/src/main/java/com/ai/da/controller/AccountController.java +++ b/src/main/java/com/ai/da/controller/AccountController.java @@ -219,4 +219,40 @@ public class AccountController { public Response getPersonalHomepage(@RequestParam("id") Long id){ return Response.success(accountService.getPersonalHomepage(id)); } + + @ApiOperation(value = "getUsernameModifyTimes") + @GetMapping("/getNicknameModifyTimes") + public Response> getNicknameModifyTimes(){ + return Response.success(accountService.getNicknameModifyTimes()); + } + + @ApiOperation(value = "editUserName") + @GetMapping("/editUserName") + public Response editUserName(@RequestParam("newUserName") String newUserName){ + accountService.editUserName(newUserName); + return Response.success("success"); + } + + @ApiOperation(value = "verifyUserEmail") + @GetMapping("/verifyUserEmail") + public Response verifyUserEmail(@RequestParam("verifyCode") String verifyCode){ + accountService.verifyUserEmail(verifyCode); + return Response.success("success"); + } + + @ApiOperation(value = "changeUserEmail") + @GetMapping("/changeUserEmail") + public Response changeUserEmail(@RequestParam("newMailbox") String newMailbox){ + accountService.changeUserEmail(newMailbox); + return Response.success("success"); + } + + @ApiOperation(value = "activateNewEmail") + @GetMapping("/activateNewEmail") + public Response activateNewEmail(@RequestParam("token") String token){ + accountService.activateNewEmail(token); + return Response.success("success"); + } + + } diff --git a/src/main/java/com/ai/da/controller/GenerateController.java b/src/main/java/com/ai/da/controller/GenerateController.java index 17fc811b..94a0da8a 100644 --- a/src/main/java/com/ai/da/controller/GenerateController.java +++ b/src/main/java/com/ai/da/controller/GenerateController.java @@ -94,7 +94,7 @@ public class GenerateController { // modifySketch @ApiOperation(value = "modifySketch") @PostMapping("/modifySketch") - public Response modifySketch(@Valid @RequestBody GenerateModifyDTO generateModifyDTO) { + public Response modifySketch(@Valid @RequestBody GenerateModifyDTO generateModifyDTO) { return Response.success(generateService.modifySketch(generateModifyDTO)); } diff --git a/src/main/java/com/ai/da/model/dto/EmailSendDTO.java b/src/main/java/com/ai/da/model/dto/EmailSendDTO.java index e79da073..eed614bb 100644 --- a/src/main/java/com/ai/da/model/dto/EmailSendDTO.java +++ b/src/main/java/com/ai/da/model/dto/EmailSendDTO.java @@ -15,7 +15,7 @@ public class EmailSendDTO { private String email; @NotBlank(message = "operationType.cannot.be.empty") - @ApiModelProperty("操作类型 LOGIN 注册 FORGET_PWD 忘记密码 BIND_MAILBOX 绑定邮箱") + @ApiModelProperty("操作类型 LOGIN 注册 FORGET_PWD 忘记密码 BIND_MAILBOX 绑定邮箱 CHANGE_MAILBOX 更改邮箱") private String operationType; @ApiModelProperty("异常ip") diff --git a/src/main/java/com/ai/da/model/dto/GenerateModifyDTO.java b/src/main/java/com/ai/da/model/dto/GenerateModifyDTO.java index 5cc4a77f..da56be9c 100644 --- a/src/main/java/com/ai/da/model/dto/GenerateModifyDTO.java +++ b/src/main/java/com/ai/da/model/dto/GenerateModifyDTO.java @@ -4,15 +4,27 @@ import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; +import javax.validation.constraints.NotNull; + @ApiModel("修改imageToSketch提取出的sketch") @Data public class GenerateModifyDTO { - @ApiModelProperty("需要保存的图片的base64格式") + @NotNull(message = "image cannot be empty") + @ApiModelProperty(value = "需要保存的图片的base64格式", required = true) private String base64; - @ApiModelProperty("sketch所属性别") + @NotNull(message = "gender cannot be empty") + @ApiModelProperty(value = "sketch所属性别", required = true) private String gender; - @ApiModelProperty("sketch所属分类") + @NotNull(message = "category cannot be empty") + @ApiModelProperty(value = "sketch所属分类", required = true) private String category; + + @NotNull(message = "id cannot be empty") + @ApiModelProperty(value = "原图id", required = true) + private String originalId; + + @ApiModelProperty("是否覆盖原图") + private Boolean isOverride; } diff --git a/src/main/java/com/ai/da/model/enums/SketchStyle.java b/src/main/java/com/ai/da/model/enums/SketchStyle.java index 475b3a01..f4ca7894 100644 --- a/src/main/java/com/ai/da/model/enums/SketchStyle.java +++ b/src/main/java/com/ai/da/model/enums/SketchStyle.java @@ -6,7 +6,9 @@ public enum SketchStyle implements IEnumDisplay{ MEDIUM("2"), - THIN("3"); + THIN("3"), + + CUSTOM("Custom"); private String value; diff --git a/src/main/java/com/ai/da/service/AccountService.java b/src/main/java/com/ai/da/service/AccountService.java index 69aec0f2..24ec1248 100644 --- a/src/main/java/com/ai/da/service/AccountService.java +++ b/src/main/java/com/ai/da/service/AccountService.java @@ -132,7 +132,7 @@ public interface AccountService extends IService { void moveLibraryDate(); - void updateCredits(Long accountId, String value); + void updateCreditsAndEndTime(Long accountId, String value); void updateCreditsAndEndTime(Long accountId, String value, Long endTime); Boolean designWorksRegister(AccountDesignWorksRegisterDTO accountDesignWorksRegisterDTO); @@ -169,4 +169,14 @@ public interface AccountService extends IService { void registerUserToVisitor(); String updateNoLoginRequiredNew(NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request); + + Map getNicknameModifyTimes(); + + void editUserName(String newUserName); + + void verifyUserEmail(String verifyCode); + + void changeUserEmail(String newMailbox); + + void activateNewEmail(String token); } diff --git a/src/main/java/com/ai/da/service/CreditsService.java b/src/main/java/com/ai/da/service/CreditsService.java index faf19ce7..1d076527 100644 --- a/src/main/java/com/ai/da/service/CreditsService.java +++ b/src/main/java/com/ai/da/service/CreditsService.java @@ -33,7 +33,7 @@ public interface CreditsService extends IService { CreditsDetail getByAccountIdAndChangeEvent(Long accountId, String changeEvent, String changedCredits); - void preInsert(Long accountId, String changeEventName, String taskId); + void preInsert(Long accountId, String changeEventName, String taskId, Boolean isPreInsert, String changedCredits); void updateChangedCredits(String accountId, String taskId); } diff --git a/src/main/java/com/ai/da/service/GenerateService.java b/src/main/java/com/ai/da/service/GenerateService.java index 1bb28186..dda193e6 100644 --- a/src/main/java/com/ai/da/service/GenerateService.java +++ b/src/main/java/com/ai/da/service/GenerateService.java @@ -46,5 +46,5 @@ public interface GenerateService extends IService { GenerateResultVO imageToSketch(ImageToSketchDTO imageToSketchDTO); - CollectionElementVO modifySketch(GenerateModifyDTO generateModifyDTO); + GenerateResultVO modifySketch(GenerateModifyDTO generateModifyDTO); } diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index e8daaa59..905ab175 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -384,6 +384,10 @@ public class AccountServiceImpl extends ServiceImpl impl result = SendEmailUtil.send(emailSendDTO.getEmail(), null, SendEmailUtil.BIND_MAILBOX_TEMPLATE_ID, randomVerifyCode); break; + case CHANGE_MAILBOX: + result = SendEmailUtil.send(emailSendDTO.getEmail(), null, + SendEmailUtil.CHANGE_MAILBOX_TEMPLATE_ID, randomVerifyCode); + break; default: } if (!result) { @@ -1042,7 +1046,7 @@ public class AccountServiceImpl extends ServiceImpl impl // 未迁移过的进行迁移,注意模特数据迁移打点信息以及转换模特格式 } - public void updateCredits(Long accountId, String value) { + public void updateCreditsAndEndTime(Long accountId, String value) { Account account = new Account(); account.setId(accountId); account.setCredits(new BigDecimal(value)); @@ -1053,7 +1057,10 @@ public class AccountServiceImpl extends ServiceImpl impl Account account = new Account(); account.setId(accountId); account.setCredits(new BigDecimal(value)); - account.setValidEndTime(toDayEnd(endTime)); + if (!Objects.isNull(endTime)){ + account.setValidEndTime(toDayEnd(endTime)); + } + account.setUpdateDate(new Date()); accountMapper.updateById(account); } @@ -1631,8 +1638,99 @@ public class AccountServiceImpl extends ServiceImpl impl } private Long viewPersonalHomepageCount(Long accountId) { - redisUtil.getPersonalHomepageViewCount(accountId); - return null; + return redisUtil.getPersonalHomepageViewCount(accountId); + } + + // 获取当前用户30天内 剩余昵称修改次数 + public Map getNicknameModifyTimes(){ + Long accountId = UserContext.getUserHolder().getId(); + String key = RedisUtil.NICKNAME_MODIFY_TIMES + accountId; + Long times = redisUtil.getIncrementCount(key); + HashMap resp = new HashMap<>(); + resp.put("remainingTimes", 5L - times); + resp.put("remainingDays", redisUtil.getExpire(key) == -1 ? 30L : (long) Math.ceil((double) redisUtil.getExpire(key) / (24 * 60 * 60))); + return resp; + } + + // 修改用户名 允许用户30天内修改5次 + @Transactional(rollbackFor = Exception.class) + public void editUserName(String newUserName){ + Long accountId = UserContext.getUserHolder().getId(); + // 判断当前用户是否还有修改昵称的次数 + Map remainTimes = getNicknameModifyTimes(); + Long remainingModifyTimes = remainTimes.get("remainingTimes"); + if (remainingModifyTimes > 0){ + Account account = new Account().setUserName(newUserName); + account.setId(accountId); + baseMapper.updateById(account); + + String key = RedisUtil.NICKNAME_MODIFY_TIMES + accountId; + // 先判断有没有这个key,若没有这个key, 需要为key添加有效期 + if (remainingModifyTimes == 5){ + redisUtil.setKeyExpire(key, 30L); + } + // 增加修改次数 + redisUtil.increaseCount(key); + }else { + throw new BusinessException("remaining.modifications", 1); + } + } + + // 验证是否是本人进行邮箱绑定更改 + public void verifyUserEmail(String verifyCode){ + // 向旧邮箱发送验证码,以保证是当前邮箱拥有者在进行更改 + String userEmail = baseMapper.selectById(UserContext.getUserHolder().getId()).getUserEmail(); + //校验邮箱验证码 + String verifyCodeCatch = LocalCacheUtils.getVerifyCodeCache(AuthenticationOperationTypeEnum.CHANGE_MAILBOX.name() + "_" + userEmail); + if (StringUtils.isBlank(verifyCodeCatch)) { + throw new BusinessException("the.verification.code.has.expired", ResultEnum.PROMPT.getCode()); + } + if (!verifyCode.equals(verifyCodeCatch)) { + throw new BusinessException("verification.code.error", ResultEnum.PROMPT.getCode()); + } + } + + // 修改邮箱地址 + public void changeUserEmail(String newMailbox){ + AuthPrincipalVo userHolder = UserContext.getUserHolder(); + Long accountId = userHolder.getId(); + // 将新邮箱信息存储到redis + String key = RedisUtil.CHANGE_MAILBOX + accountId; + redisUtil.addToString(key, newMailbox, CommonConstant.CHANGE_MAILBOX_LINK_VALIDITY / 1000); + + String username = userHolder.getUsername(); + String token = jwtTokenHelper.createToken(accountId, newMailbox); + // 准备激活链接,链接应该要有有效期 + String link = "?" + token; + // 向新邮箱发送邮件,邮件附带激活链接,点击链接进行验证 + SendEmailUtil.changeMailboxConfirm(newMailbox, userHolder.getLanguage(), username, link); + } + + // 验证激活链接 + public void activateNewEmail(String token){ + // 获取链接地址信息,更新指定用户邮箱 + + String emailAndId = jwtTokenHelper.parseToEmailAndId(token); + String newMailbox = emailAndId.substring(0, emailAndId.lastIndexOf("_")); + String accountId = emailAndId.substring(emailAndId.lastIndexOf("_") + 1); + + // 与redis的数据对比 + String key = RedisUtil.CHANGE_MAILBOX + accountId; + String preInfo = redisUtil.getFromString(key); + if (StringUtil.isNullOrEmpty(preInfo)){ + throw new BusinessException("申请已过期", 1); + }else if (!preInfo.equals(newMailbox)){ + throw new BusinessException("信息不匹配,请重新申请"); + } + + // 执行替换 + log.info("执行邮箱替换,用户id:{},新邮箱:{}", accountId, newMailbox); + + Account account = new Account(); + account.setUserEmail(newMailbox); + account.setId(Long.parseLong(accountId)); + baseMapper.updateById(account); + log.info("邮箱绑定更改完成,用户id:{},新邮箱:{}", accountId, newMailbox); } } diff --git a/src/main/java/com/ai/da/service/impl/CollectionElementServiceImpl.java b/src/main/java/com/ai/da/service/impl/CollectionElementServiceImpl.java index c2a807f7..cd2bd981 100644 --- a/src/main/java/com/ai/da/service/impl/CollectionElementServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/CollectionElementServiceImpl.java @@ -27,6 +27,7 @@ import com.google.common.collect.Lists; import io.netty.util.internal.StringUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -77,6 +78,8 @@ public class CollectionElementServiceImpl extends ServiceImpl 5 && incrementCount < 3) { + // 邮件通知 一天最多通知3次 + log.info("上传超过5秒,发送邮件通知"); + SendEmailUtil.uploadTimeoutReminder(userInfo.getUsername(), String.valueOf(((end - start) / 1000))); + redisUtil.increaseCount(RedisUtil.UPLOAD_TIMEOUT_REMINDER_COUNTER); + } return collectionElementVO; } diff --git a/src/main/java/com/ai/da/service/impl/CreditsServiceImpl.java b/src/main/java/com/ai/da/service/impl/CreditsServiceImpl.java index 013451a6..9cc17ce8 100644 --- a/src/main/java/com/ai/da/service/impl/CreditsServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/CreditsServiceImpl.java @@ -51,7 +51,7 @@ public class CreditsServiceImpl extends ServiceImpl i @Value("${access.python.generate_sr_port}") private String generateServicePort; + @Resource + private AccountService accountService; + // 创建 Random 对象 Random random = new Random(); - @Autowired - private ProductServiceImpl productServiceImpl; @Override public GenerateCaptionVO generateCaption(Long sketchElementId) { @@ -591,7 +590,7 @@ public class GenerateServiceImpl extends ServiceImpl i // 6、添加预扣除积分到redis creditsService.addRecordToCreditsDeduction(generateThroughImageTextDTO.getUserId(), uuid, creditsEventsEnum); // 6.1 添加积分扣除记录到db - creditsService.preInsert(generateThroughImageTextDTO.getUserId(), creditsEventsEnum.getName(), uuid); + creditsService.preInsert(generateThroughImageTextDTO.getUserId(), creditsEventsEnum.getName(), uuid, Boolean.TRUE, null); // 7、返回唯一id return new PrepareForGenerateVO(taskIdList, 2); @@ -775,6 +774,7 @@ public class GenerateServiceImpl extends ServiceImpl i @Override @Transactional(rollbackFor = Exception.class) public GenerateResultVO imageToSketch(ImageToSketchDTO imageToSketchDTO) { + String bucket = userBucket; Long accountId = UserContext.getUserHolder().getId(); log.info("imageToSketch parameter : {}", imageToSketchDTO); @@ -822,7 +822,12 @@ public class GenerateServiceImpl extends ServiceImpl i generateDetailMapper.insert(generateDetail); String clothCategory = pythonService.getClothCategory(sketchPath, imageToSketchDTO.getGender()); - clothCategory = BusinessException.getMessageFromResource(clothCategory.toUpperCase()); + + CreditsEventsEnum event = CreditsEventsEnum.IMAGE_TO_SKETCH; + BigDecimal existingCredits = accountService.getById(accountId).getCredits(); + BigDecimal subtract = existingCredits.subtract(new BigDecimal(event.getValue())); + accountService.updateCreditsAndEndTime(accountId, subtract.toString(), null); + creditsService.preInsert(accountId, event.getName(), null, Boolean.FALSE, event.getValue()); return new GenerateResultVO(generateDetail.getId(), minioUtil.getPreSignedUrl(sketchPath, CommonConstant.MINIO_IMAGE_EXPIRE_TIME), "Success", clothCategory); } @@ -831,7 +836,7 @@ public class GenerateServiceImpl extends ServiceImpl i // 输入 base64,以及 性别 分类,将图片添加到library @Override @Transactional(rollbackFor = Exception.class) - public CollectionElementVO modifySketch(GenerateModifyDTO generateModifyDTO) { + public GenerateResultVO modifySketch(GenerateModifyDTO generateModifyDTO) { log.info("修改提取出的sketch,并加入到library"); Long accountId = UserContext.getUserHolder().getId(); String base64 = generateModifyDTO.getBase64(); @@ -839,28 +844,32 @@ public class GenerateServiceImpl extends ServiceImpl i String category = generateModifyDTO.getCategory(); // 将base64上传到minio - String path = accountId + "/sketchboard/" + gender.toLowerCase() + "/" + category + "/" + UUID.randomUUID(); + String path; + GenerateDetail originalDetail = generateDetailMapper.selectById(generateModifyDTO.getOriginalId()); + Long generateDetailId = originalDetail.getId(); + if (generateModifyDTO.getIsOverride()){ + path = originalDetail.getUrl(); + }else { + path = accountId + "/sketchboard/" + gender.toLowerCase() + "/" + category + "/" + UUID.randomUUID(); + } + String minioPath = minioUtil.base64UploadToPath(base64, userBucket, path); log.info("修改后的图片 : {}", minioPath); - // 存入db 保存到t_collection_element - CollectionElement collectionElement = new CollectionElement(); - collectionElement.setAccountId(accountId); - collectionElement.setCollectionId(0L); - collectionElement.setLevel1Type(SKETCH_BOARD.getRealName()); - collectionElement.setLevel2Type(generateModifyDTO.getCategory()); - collectionElement.setName(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"))); - collectionElement.setUrl(minioPath); - collectionElement.setHasPin((byte)0); - collectionElement.setMd5(MD5Utils.encryptFile(minioUtil.getPreSignedUrl(minioPath, CommonConstant.MINIO_IMAGE_EXPIRE_TIME), Boolean.FALSE)); - collectionElement.setCreateDate(new Date()); - collectionElementService.save(collectionElement); + // 存入db 保存到t_generate_detail + if (!generateModifyDTO.getIsOverride()){ + GenerateDetail generateDetail = new GenerateDetail(); + generateDetail.setGenerateId(originalDetail.getGenerateId()); + generateDetail.setUrl(path); + generateDetail.setIsLike((byte)0); + generateDetail.setMd5(MD5Utils.encryptFile(minioUtil.getPreSignedUrl(minioPath, CommonConstant.MINIO_IMAGE_EXPIRE_TIME), Boolean.FALSE)); + generateDetail.setCreateDate(LocalDateTime.now()); + generateDetailMapper.insert(generateDetail); - CollectionElementVO collectionElementVO = CopyUtil.copyObject(collectionElement, CollectionElementVO.class); - collectionElementVO.setMinIOPath(collectionElementVO.getUrl()); - collectionElementVO.setUrl(minioUtil.getPreSignedUrl(collectionElementVO.getUrl(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME)); - collectionElementVO.setDesignType(DesignTypeEnum.COLLECTION.getRealName()); - return collectionElementVO; + generateDetailId = generateDetail.getId(); + } + + return new GenerateResultVO(generateDetailId, minioUtil.getPreSignedUrl(minioPath, CommonConstant.MINIO_IMAGE_EXPIRE_TIME), "Success", category); } } diff --git a/src/main/resources/messages_en.properties b/src/main/resources/messages_en.properties index 8985db45..dd1beb67 100644 --- a/src/main/resources/messages_en.properties +++ b/src/main/resources/messages_en.properties @@ -144,6 +144,7 @@ you.have.already.followed.this.user=You have already followed this user subscription.success=Subscription Success unsubscribe.success=Unsubscribe Success you.have.not.followed.the.current.user=You have not followed the current user +remaining.modifications=Remaining modifications are 0 # 可能会报异常 # Informative: @@ -213,6 +214,7 @@ POCKET=Pocket THICK=Thick Lines MEDIUM=Medium Lines THIN=Thin lines +CUSTOM=Custom GENERATE=Generate Sketch EXTRACT=Extract Sketch \ No newline at end of file diff --git a/src/main/resources/messages_zh.properties b/src/main/resources/messages_zh.properties index 4219585f..92d5e58a 100644 --- a/src/main/resources/messages_zh.properties +++ b/src/main/resources/messages_zh.properties @@ -139,6 +139,7 @@ you.have.already.followed.this.user=您已经关注当前用户 subscription.success=关注成功 unsubscribe.success=取消关注成功 you.have.not.followed.the.current.user=您还未关注当前用户 +remaining.modifications=剩余修改次数为0 # 可能会报异常 # Informative: @@ -206,6 +207,7 @@ POCKET=口袋 THICK=粗线条 MEDIUM=中线条 THIN=细线条 +CUSTOM=自定义 GENERATE=生成线稿 EXTRACT=提取线稿 \ No newline at end of file