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 32623e55..9deefeec 100644 --- a/src/main/java/com/ai/da/common/enums/AuthenticationOperationTypeEnum.java +++ b/src/main/java/com/ai/da/common/enums/AuthenticationOperationTypeEnum.java @@ -33,7 +33,11 @@ public enum AuthenticationOperationTypeEnum { */ UPDATE_USERINFO, - REGISTER; + REGISTER, + /** + * Global_Award 活动验证 + */ + GLOBAL_AWARD; 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/controller/GlobalAwardController.java b/src/main/java/com/ai/da/controller/GlobalAwardController.java index 0c1cfc32..147b3fee 100644 --- a/src/main/java/com/ai/da/controller/GlobalAwardController.java +++ b/src/main/java/com/ai/da/controller/GlobalAwardController.java @@ -2,6 +2,8 @@ package com.ai.da.controller; import com.ai.da.common.response.Response; import com.ai.da.model.dto.*; +import com.ai.da.model.dto.ContestantDTO; +import com.ai.da.model.vo.CheckOTPVO; import com.ai.da.service.GlobalAwardService; import com.ai.da.service.upload.UploadService; import com.ai.da.service.upload.UploadTask; @@ -145,6 +147,18 @@ public class GlobalAwardController { ContestantDTO dto = globalAwardService.getContestantByEmail(email); return Response.success(dto); } + + @GetMapping("/checkEmail") + public Response checkEmail(@RequestParam("email") String email) { + globalAwardService.checkEmail(email); + return Response.success(); + } + + @GetMapping("/checkCode") + public Response checkOTP(@RequestParam("email") String email, @RequestParam("code") String code) { + return Response.success(globalAwardService.checkOTP(email, code)); + } + } diff --git a/src/main/java/com/ai/da/model/dto/ContestantDTO.java b/src/main/java/com/ai/da/model/dto/ContestantDTO.java index 47d033f3..ebf5a22c 100644 --- a/src/main/java/com/ai/da/model/dto/ContestantDTO.java +++ b/src/main/java/com/ai/da/model/dto/ContestantDTO.java @@ -2,6 +2,7 @@ package com.ai.da.model.dto; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +import jakarta.validation.constraints.NotBlank; import lombok.Data; /** @@ -54,6 +55,9 @@ public class ContestantDTO { */ @ApiModelProperty(value = "是否确认覆盖已存在记录", required = false, example = "false") private Boolean confirm = false; + + @NotBlank + private String secureToken; } diff --git a/src/main/java/com/ai/da/model/dto/DesignSingleItemDTO.java b/src/main/java/com/ai/da/model/dto/DesignSingleItemDTO.java index e6cfcbad..37e4d25f 100644 --- a/src/main/java/com/ai/da/model/dto/DesignSingleItemDTO.java +++ b/src/main/java/com/ai/da/model/dto/DesignSingleItemDTO.java @@ -73,10 +73,10 @@ public class DesignSingleItemDTO implements Serializable { @Schema(description = "45") private double rotate; - @Schema(description = "带overall印花未分割图片") + /*@Schema(description = "带overall印花未分割图片") private String undividedLayerBase64; @Schema(description = "带overall/single印花未分割图片") - private String undividedLayerWithSinglePrintBase64; + private String undividedLayerWithSinglePrintBase64;*/ } diff --git a/src/main/java/com/ai/da/model/vo/CheckOTPVO.java b/src/main/java/com/ai/da/model/vo/CheckOTPVO.java new file mode 100644 index 00000000..4b85950a --- /dev/null +++ b/src/main/java/com/ai/da/model/vo/CheckOTPVO.java @@ -0,0 +1,16 @@ +package com.ai.da.model.vo; + +import com.ai.da.model.dto.ContestantDTO; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CheckOTPVO { + + private String secureToken; + + private ContestantDTO contestantDTO; +} diff --git a/src/main/java/com/ai/da/model/vo/DesignItemClothesDetailVO.java b/src/main/java/com/ai/da/model/vo/DesignItemClothesDetailVO.java index 76e088fd..e7a4a401 100644 --- a/src/main/java/com/ai/da/model/vo/DesignItemClothesDetailVO.java +++ b/src/main/java/com/ai/da/model/vo/DesignItemClothesDetailVO.java @@ -1,5 +1,5 @@ -package com.ai.da.model.vo; - +package com.ai.da.model.vo; + import io.swagger.v3.oas.annotations.media.Schema; import com.ai.da.mapper.primary.entity.Gradient; @@ -62,11 +62,11 @@ public class DesignItemClothesDetailVO { @Schema(description = "渐变色信息") private Gradient gradient; - @Schema(description = "未分割的图层") +/* @Schema(description = "未分割的图层") private String undividedLayer; @Schema(description = "添加single印花的未分割的图层") - private String undividedLayerWithSinglePrint; + private String undividedLayerWithSinglePrint;*/ @Schema(description = "局部design") private PartialDesignDTO partialDesign; diff --git a/src/main/java/com/ai/da/service/DesignItemService.java b/src/main/java/com/ai/da/service/DesignItemService.java index 77488d87..43fa7c86 100644 --- a/src/main/java/com/ai/da/service/DesignItemService.java +++ b/src/main/java/com/ai/da/service/DesignItemService.java @@ -53,7 +53,7 @@ public interface DesignItemService extends IService { DesignSingleVO designSingleIncludeLayers(DesignSingleIncludeLayersDTO designSingleIncludeLayersDTO); - Map> setPriorityAndUndividedLayer(JSONArray layers, DesignSingleIncludeLayersDTO designSingleIncludeLayersDTO); + // Map> setPriorityAndUndividedLayer(JSONArray layers, DesignSingleIncludeLayersDTO designSingleIncludeLayersDTO); Map setTypeAndUndividedLayer(JSONArray layers); diff --git a/src/main/java/com/ai/da/service/GlobalAwardService.java b/src/main/java/com/ai/da/service/GlobalAwardService.java index 212a23e7..3b66579c 100644 --- a/src/main/java/com/ai/da/service/GlobalAwardService.java +++ b/src/main/java/com/ai/da/service/GlobalAwardService.java @@ -1,15 +1,23 @@ package com.ai.da.service; import com.ai.da.model.dto.ContestantDTO; +import com.ai.da.model.vo.CheckOTPVO; import org.springframework.web.multipart.MultipartFile; import java.util.Map; public interface GlobalAwardService { String uploadPdf(MultipartFile file, String email) throws Exception; + String uploadVideo(MultipartFile file, String email) throws Exception; + Map saveContestant(ContestantDTO request); + com.ai.da.model.dto.ContestantDTO getContestantByEmail(String email); + + void checkEmail(String email); + + CheckOTPVO checkOTP(String email, String otp); } diff --git a/src/main/java/com/ai/da/service/impl/DesignItemServiceImpl.java b/src/main/java/com/ai/da/service/impl/DesignItemServiceImpl.java index afd1137d..da91be51 100644 --- a/src/main/java/com/ai/da/service/impl/DesignItemServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/DesignItemServiceImpl.java @@ -363,7 +363,7 @@ public class DesignItemServiceImpl extends ServiceImpl saveDesignSingleItemDetailAndLayers(DesignPythonObjects pythonObjects , Long designId, Long designItemId, Long userId , JSONObject outfit, String timeZone, List designSingleItemDTOList - , Map> priorityAndUndividedLayer + /*, Map> priorityAndUndividedLayer*/ , boolean changeModelFlag , Long modelId, String modelType, boolean isSingleCollectionFlag, String designType) { @@ -424,6 +424,7 @@ public class DesignItemServiceImpl extends ServiceImpl { @@ -713,7 +717,7 @@ public class DesignItemServiceImpl extends ServiceImpl " + JSONObject.toJSONString(clone)); @@ -835,13 +839,13 @@ public class DesignItemServiceImpl extends ServiceImpl> priorityAndUndividedLayer = setPriorityAndUndividedLayer(layers, designSingleIncludeLayersDTO); +// Map> priorityAndUndividedLayer = setPriorityAndUndividedLayer(layers, designSingleIncludeLayersDTO); if (!designSingleIncludeLayersDTO.getIsPreview()) { // 更新及保存图层信息 tDesignPythonOutfitDetails = saveDesignSingleItemDetailAndLayers(objects, design.getId(), designSingleIncludeLayersDTO.getDesignItemId() , userId, outfit, designSingleIncludeLayersDTO.getTimeZone() , designSingleIncludeLayersDTO.getDesignSingleItemDTOList() - , priorityAndUndividedLayer, changeModelFlag, modelId, modelType, isSingleCollectionFlag, designSingleIncludeLayersDTO.getDesignType()); + /*, priorityAndUndividedLayer*/, changeModelFlag, modelId, modelType, isSingleCollectionFlag, designSingleIncludeLayersDTO.getDesignType()); saveCollectionElement(designSingleIncludeLayersDTO); } else { @@ -875,8 +879,8 @@ public class DesignItemServiceImpl extends ServiceImpl designSingleItemDTOS) { designSingleItemDTOS.forEach(item -> { if (!StringUtil.isNullOrEmpty(item.getUndividedLayerBase64())) { @@ -1006,9 +1023,10 @@ public class DesignItemServiceImpl extends ServiceImpl> setPriorityAndUndividedLayer(JSONArray layers, DesignSingleIncludeLayersDTO designSingleIncludeLayersDTO) { String designType = "default"; if (Objects.nonNull(designSingleIncludeLayersDTO)) { @@ -1037,7 +1055,7 @@ public class DesignItemServiceImpl extends ServiceImpl designSingleItemDTOList, List layersObject, - String singleOrOverall, - Map> priorityAndUndividedLayer) { + String singleOrOverall/*, + Map> priorityAndUndividedLayer*/) { DesignSingleVO designSingleVO = new DesignSingleVO(); ArrayList clothes = new ArrayList<>(); @@ -1191,6 +1209,7 @@ public class DesignItemServiceImpl extends ServiceImpl layers.getImageCategory().equals("body")).collect(Collectors.toList())); clothes.add(designItemClothesDetailVO); @@ -1374,6 +1393,9 @@ public class DesignItemServiceImpl extends ServiceImpl { if (!StringUtil.isNullOrEmpty(print.getDesignType()) && print.getDesignType().equals("Collection")) { diff --git a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java index 41d36c62..e018a3c2 100644 --- a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java @@ -713,9 +713,9 @@ public class DesignServiceImpl extends ServiceImpl impleme Map typePriority = list.stream().collect(Collectors.toMap(d -> d.getImageCategory().split("_")[0], d -> Math.abs(d.getPriority()), (existing, replacement) -> replacement)); - Map typeAndUndividedLayer = designItemService.setTypeAndUndividedLayer(layers); - log.info("all typeLayers Map:{}", typeAndUndividedLayer); - Map> priorityAndUndividedLayer = designItemService.setPriorityAndUndividedLayer(layers, null); +// Map typeAndUndividedLayer = designItemService.setTypeAndUndividedLayer(layers); +// log.info("all typeLayers Map:{}", typeAndUndividedLayer); +// Map> priorityAndUndividedLayer = designItemService.setPriorityAndUndividedLayer(layers, null); for (DesignPythonItem detail : item.getItems()) { if (null == detail) { continue; @@ -727,10 +727,10 @@ public class DesignServiceImpl extends ServiceImpl impleme designItemDetail.setCollectionElementId(detail.getElementId()); designItemDetail.setCreateDate(DateUtil.getByTimeZone(timeZone)); log.info("detail.getType():{}", detail.getType()); - if (!detail.getType().equals("Body")) { +/* if (!detail.getType().equals("Body")) { log.info("layer : {}", typeAndUndividedLayer.get(designItemDetail.getType())); designItemDetail.setUndividedLayer(typeAndUndividedLayer.get(designItemDetail.getType())); - } + }*/ if (SysFileLevel2TypeEnum.BODY.getRealName().equals(detail.getType())) { designItemDetail.setPath(detail.getBody_path()); //BODY不关联businessId @@ -742,8 +742,8 @@ public class DesignServiceImpl extends ServiceImpl impleme DesignPythonItemPrint printObject = detail.getPrint().getOverall(); // designItemDetail.setPrintPath(Objects.isNull(printObject) ? "" : printObject.getPath()); designItemDetail.setPrintPath(CollectionUtils.isEmpty(printObject.getPrint_path_list()) ? "" : printObject.getPrint_path_list().get(0)); - designItemDetail.setUndividedLayer(priorityAndUndividedLayer.get(designItemDetail.getPriority().toString()).get(0)); - designItemDetail.setUndividedLayerWithSinglePrint(priorityAndUndividedLayer.get(designItemDetail.getPriority().toString()).get(1)); + /*designItemDetail.setUndividedLayer(priorityAndUndividedLayer.get(designItemDetail.getPriority().toString()).get(0)); + designItemDetail.setUndividedLayerWithSinglePrint(priorityAndUndividedLayer.get(designItemDetail.getPriority().toString()).get(1));*/ } designItemDetailService.save(designItemDetail); if (!SysFileLevel2TypeEnum.BODY.getRealName().equals(detail.getType()) && !StringUtil.isNullOrEmpty(designItemDetail.getPrintPath())) { @@ -853,7 +853,7 @@ public class DesignServiceImpl extends ServiceImpl impleme Map typePriority = list.stream().collect(Collectors.toMap(d -> d.getImageCategory().split("_")[0], d -> Math.abs(d.getPriority()), (existing, replacement) -> replacement)); - Map typeAndUndividedLayer = designItemService.setTypeAndUndividedLayer(layers); +// Map typeAndUndividedLayer = designItemService.setTypeAndUndividedLayer(layers); for (DesignPythonItem detail : item.getItems()) { if (null == detail) { continue; @@ -864,9 +864,9 @@ public class DesignServiceImpl extends ServiceImpl impleme designItemDetail.setDesignItemId(designItemId); designItemDetail.setCollectionElementId(detail.getElementId()); designItemDetail.setCreateDate(DateUtil.getByTimeZone(timeZone)); - if (!detail.getType().equals("Body")) { + /*if (!detail.getType().equals("Body")) { designItemDetail.setUndividedLayer(typeAndUndividedLayer.get(designItemDetail.getType())); - } + }*/ if (SysFileLevel2TypeEnum.BODY.getRealName().equals(detail.getType())) { designItemDetail.setPath(detail.getBody_path()); @@ -1157,8 +1157,9 @@ public class DesignServiceImpl extends ServiceImpl impleme if (workspaceRelStyles != null) { //查不到记录,style应该是all userPreference.setWorkspaceRelStyleId(0L); + } else { + userPreference.setWorkspaceRelStyleId(workspaceRelStyles.get(0).getStyleId()); } - userPreference.setWorkspaceRelStyleId(workspaceRelStyles.get(0).getStyleId()); userPreferenceMapper.insert(userPreference); } } @@ -1330,12 +1331,13 @@ public class DesignServiceImpl extends ServiceImpl impleme d.setScope(o.getPath().startsWith("aida-sys-image") ? "sys" : "user"); d.setLevel1Type(converTypeToLevel1(o.getType())); d.setGradient(JSONObject.parseObject(o.getGradientString(), Gradient.class)); + /*// 取消存储/返回UndividedLayer和UndividedLayerWithSinglePrint字段 if (!StringUtil.isNullOrEmpty(o.getUndividedLayer())) { d.setUndividedLayer(minioUtil.getPreSignedUrl(o.getUndividedLayer(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME)); } if (!StringUtil.isNullOrEmpty(o.getUndividedLayerWithSinglePrint())) { d.setUndividedLayerWithSinglePrint(minioUtil.getPreSignedUrl(o.getUndividedLayerWithSinglePrint(), CommonConstant.MINIO_IMAGE_EXPIRE_TIME)); - } + }*/ // 根据designItemDetailId获取印花 List prints = designItemDetailPrintService.getByDesignItemDetailId(o.getId(), "print"); prints.removeIf(print -> !minioUtil.doesObjectExist(print.getPath())); @@ -2543,7 +2545,7 @@ public class DesignServiceImpl extends ServiceImpl impleme Map typePriority = list.stream().collect(Collectors.toMap(d -> d.getImageCategory().split("_")[0], d -> Math.abs(d.getPriority()), (existing, replacement) -> replacement)); - Map typeAndUndividedLayer = designItemService.setTypeAndUndividedLayer(layers); +// Map typeAndUndividedLayer = designItemService.setTypeAndUndividedLayer(layers); for (DesignPythonItem detail : item.getItems()) { if (null == detail) { continue; @@ -2554,9 +2556,9 @@ public class DesignServiceImpl extends ServiceImpl impleme designItemDetail.setDesignItemId(designItemId); designItemDetail.setCollectionElementId(detail.getElementId()); designItemDetail.setCreateDate(DateUtil.getByTimeZone(timeZone)); - if (!detail.getType().equals("Body")) { + /*if (!detail.getType().equals("Body")) { designItemDetail.setUndividedLayer(typeAndUndividedLayer.get(designItemDetail.getType())); - } + }*/ if (SysFileLevel2TypeEnum.BODY.getRealName().equals(detail.getType())) { designItemDetail.setPath(detail.getBody_path()); //BODY不关联businessId diff --git a/src/main/java/com/ai/da/service/impl/GlobalAwardServiceImpl.java b/src/main/java/com/ai/da/service/impl/GlobalAwardServiceImpl.java index 371ebb49..cfd1e41e 100644 --- a/src/main/java/com/ai/da/service/impl/GlobalAwardServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/GlobalAwardServiceImpl.java @@ -1,41 +1,64 @@ package com.ai.da.service.impl; import com.ai.da.common.config.exception.BusinessException; +import com.ai.da.common.enums.AuthenticationOperationTypeEnum; +import com.ai.da.common.utils.*; +import com.ai.da.mapper.primary.AccountMapper; import com.ai.da.mapper.primary.ContestantMapper; +import com.ai.da.mapper.primary.NotificationMapper; +import com.ai.da.mapper.primary.entity.Account; import com.ai.da.mapper.primary.entity.Contestant; +import com.ai.da.mapper.primary.entity.Notification; import com.ai.da.model.dto.ContestantDTO; +import com.ai.da.model.dto.PublishSysNotificationDTO; +import com.ai.da.model.vo.CheckOTPVO; import com.ai.da.service.GlobalAwardService; +import com.ai.da.service.MessageCenterService; +import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import jakarta.annotation.Resource; -import com.ai.da.common.utils.MinioUtil; -import java.io.File; + import java.io.IOException; -import java.nio.file.Files; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; +import java.util.*; @Service @Slf4j +@RequiredArgsConstructor public class GlobalAwardServiceImpl implements GlobalAwardService { @Resource private ContestantMapper contestantMapper; + private final AccountMapper accountMapper; + + private final MessageCenterService messageCenterService; + + private final NotificationMapper notificationMapper; + + private final RedisUtil redisUtil; + @Value("${file.upload.dir:uploads}") private String uploadDir; private static final DateTimeFormatter YYYY_MM_DD = DateTimeFormatter.ofPattern("yyyy/MM"); + + private static final String tokenCacheKey = AuthenticationOperationTypeEnum.GLOBAL_AWARD.name() + ":"; + @Value("${minio.bucket:contestants}") private String minioBucket; + @Value("${global.award.link}") + private String link; + @Resource private MinioUtil minioUtil; @@ -111,6 +134,14 @@ public class GlobalAwardServiceImpl implements GlobalAwardService { throw new BusinessException("Email is required."); } + String key = tokenCacheKey + request.getEmail(); + String tokenCache = redisUtil.getFromString(key); + if (StringUtils.isBlank(tokenCache)) { + throw new BusinessException("请先完成邮箱认证"); + } else if (!tokenCache.equals(request.getSecureToken())){ + throw new BusinessException("身份认证失败,请先完成邮箱认证"); + } + QueryWrapper qw = new QueryWrapper<>(); qw.eq("email", request.getEmail()); Contestant existing = contestantMapper.selectOne(qw); @@ -185,6 +216,59 @@ public class GlobalAwardServiceImpl implements GlobalAwardService { dto.setVideoPath(existing.getVideoPath()); return dto; } + + public void checkEmail(String email) { + List validRole = Arrays.asList(1, 2, 7, 8); + // 1. 验证邮箱在aida中有无账号 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.lambda().eq(Account::getUserEmail, email); + List accounts = accountMapper.selectList(queryWrapper); + if (accounts.isEmpty()) { + throw new BusinessException("请注册并订阅AiDA,再重新提交申请"); + } + + // 2. 验证账号是否是付费用户(如果首次提交是,但是修改的时候已经不是了,how?不允许修改吗) + if (validRole.contains(accounts.getFirst().getSystemUser())) { + String randomVerifyCode = RandomsUtil.generateVerifyCode(100000L, 999999L); + LocalCacheUtils.setVerifyCodeCache( + AuthenticationOperationTypeEnum.GLOBAL_AWARD.name() + "_" + email, randomVerifyCode); + SendEmailUtil.send(email, null, + SendEmailUtil.LOGIN_TEMPLATE_ID, randomVerifyCode); + } else { + throw new BusinessException("请订阅AiDA,再重新提交申请"); + } + } + + public CheckOTPVO checkOTP(String email, String otp) { + String otpCache = LocalCacheUtils.getVerifyCodeCache(AuthenticationOperationTypeEnum.GLOBAL_AWARD.name() + "_" + email); + assert otpCache != null; + if (otpCache.equals(otp)) { + // 1. 生成唯一token + String secureToken = UUID.randomUUID().toString().replace("-", ""); + redisUtil.addToString(tokenCacheKey + email, secureToken, 3 * 24 * 60 * 60L); + + return new CheckOTPVO(secureToken, getContestantByEmail(email)); + } else { + throw new BusinessException("验证码错误,请重试"); + } + } + + // 发送站内信 + public void sendSiteMsg(String applicationId, Long userId) { + PublishSysNotificationDTO sysNotificationDTO = new PublishSysNotificationDTO(); + Notification notification = new Notification(); + notification.setType("system"); + notification.setReceiverId(userId); + sysNotificationDTO.setTitle("System Notification 系统通知"); + // todo + sysNotificationDTO.setContent(link + applicationId); + notification.setContent(JSON.toJSONString(sysNotificationDTO)); + notification.setIsRead(0); + notification.setCreateTime(LocalDateTime.now()); + notificationMapper.insert(notification); + // 这里推送消息是在接受到视频生成结束后发生的,所以UserContext中没有用户信息 + messageCenterService.pushMessage("system", userId); + } } diff --git a/src/main/resources/application-dev.properties b/src/main/resources/application-dev.properties index 52eefa8d..88126011 100644 --- a/src/main/resources/application-dev.properties +++ b/src/main/resources/application-dev.properties @@ -181,4 +181,5 @@ file.upload.max.size.video=104857600 file.upload.task.expiry.hours=24 # MinIO配置 -minio.bucket=contestants \ No newline at end of file +minio.bucket=contestants +global.award.link=https://develop.aida.com.hk/ \ No newline at end of file diff --git a/src/main/resources/application-prod.properties b/src/main/resources/application-prod.properties index dfad3b33..184006d4 100644 --- a/src/main/resources/application-prod.properties +++ b/src/main/resources/application-prod.properties @@ -179,4 +179,5 @@ file.upload.max.size.video=104857600 file.upload.task.expiry.hours=24 # MinIO配置 -minio.bucket=contestants \ No newline at end of file +minio.bucket=contestants +global.award.link=https://www.aida.com.hk/ \ No newline at end of file