Merge remote-tracking branch 'origin/dev-ltx' into dev/3.1_release_merge

This commit is contained in:
litianxiang
2026-01-16 16:37:49 +08:00
6 changed files with 361 additions and 0 deletions

View File

@@ -0,0 +1,190 @@
package com.ai.da.service.impl;
import com.ai.da.common.config.exception.BusinessException;
import com.ai.da.mapper.primary.ContestantMapper;
import com.ai.da.mapper.primary.entity.Contestant;
import com.ai.da.model.dto.ContestantDTO;
import com.ai.da.service.GlobalAwardService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
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;
@Service
@Slf4j
public class GlobalAwardServiceImpl implements GlobalAwardService {
@Resource
private ContestantMapper contestantMapper;
@Value("${file.upload.dir:uploads}")
private String uploadDir;
private static final DateTimeFormatter YYYY_MM_DD = DateTimeFormatter.ofPattern("yyyy/MM");
@Value("${minio.bucket:contestants}")
private String minioBucket;
@Resource
private MinioUtil minioUtil;
@Override
public String uploadPdf(MultipartFile file, String email) throws Exception {
validatePdf(file);
String path = storeFile(file, email, "pdf");
return path;
}
@Override
public String uploadVideo(MultipartFile file, String email) throws Exception {
validateVideo(file);
String path = storeFile(file, email, "video");
return path;
}
private void validatePdf(MultipartFile file) {
if (file == null || file.isEmpty()) {
throw new BusinessException("file is empty");
}
String ct = file.getContentType();
if (ct == null || !ct.toLowerCase().contains("pdf")) {
throw new BusinessException("only pdf allowed");
}
// size limit example 20MB
if (file.getSize() > 20L * 1024 * 1024) {
throw new BusinessException("pdf too large");
}
}
private void validateVideo(MultipartFile file) {
if (file == null || file.isEmpty()) {
throw new BusinessException("file is empty");
}
String ct = file.getContentType();
if (ct == null || !(ct.toLowerCase().contains("mp4") || ct.toLowerCase().contains("video") )) {
throw new BusinessException("invalid video type");
}
// size limit example 100MB
if (file.getSize() > 100L * 1024 * 1024) {
throw new BusinessException("video too large");
}
}
private String normalizeEmail(String email) {
if (email == null) {
return "anonymous";
}
return email.replaceAll("[^a-zA-Z0-9]", "_");
}
private String storeFile(MultipartFile file, String email, String kind) throws IOException {
String normalized = normalizeEmail(email);
String datePart = LocalDateTime.now().format(YYYY_MM_DD);
String ext = "";
String original = file.getOriginalFilename();
if (original != null && original.contains(".")) {
ext = original.substring(original.lastIndexOf('.'));
}
String filename = System.currentTimeMillis() + "_" + UUID.randomUUID().toString() + ext;
String relativePath = "contestants/" + normalized + "/" + datePart + "/" + filename;
String uploadedPath = minioUtil.upload(minioBucket, relativePath, file, null);
log.info("uploaded via MinioUtil: {}", uploadedPath);
return uploadedPath;
}
@Override
public Map<String, Object> saveContestant(ContestantDTO request) {
Map<String,Object> resp = new HashMap<>();
if (request.getEmail() == null) {
throw new IllegalArgumentException("email required");
}
QueryWrapper<Contestant> qw = new QueryWrapper<>();
qw.eq("email", request.getEmail());
Contestant existing = contestantMapper.selectOne(qw);
LocalDateTime now = LocalDateTime.now();
if (existing == null) {
Contestant toInsert = Contestant.builder()
.email(request.getEmail())
.firstName(request.getFirstName())
.lastName(request.getLastName())
.gender(request.getGender())
.occupation(request.getOccupation())
.age(request.getAge())
.countryRegionCity(request.getCountryRegionCity())
.phoneNumber(request.getPhoneNumber())
.portfolioUrl(request.getPortfolioUrl())
.designTitle(request.getDesignTitle())
.designDescription(request.getDesignDescription())
.pdfPath(request.getPdfPath())
.videoPath(request.getVideoPath())
.createdAt(now)
.updatedAt(now)
.build();
contestantMapper.insert(toInsert);
resp.put("success", true);
return resp;
} else {
// update existing contestant
existing.setFirstName(request.getFirstName());
existing.setLastName(request.getLastName());
existing.setGender(request.getGender());
existing.setOccupation(request.getOccupation());
existing.setAge(request.getAge());
existing.setCountryRegionCity(request.getCountryRegionCity());
existing.setPhoneNumber(request.getPhoneNumber());
existing.setPortfolioUrl(request.getPortfolioUrl());
existing.setDesignTitle(request.getDesignTitle());
existing.setDesignDescription(request.getDesignDescription());
existing.setPdfPath(request.getPdfPath());
existing.setVideoPath(request.getVideoPath());
existing.setUpdatedAt(now);
contestantMapper.updateById(existing);
resp.put("success", true);
return resp;
}
}
@Override
public ContestantDTO getContestantByEmail(String email) {
if (email == null) {
throw new BusinessException("email required");
}
QueryWrapper<Contestant> qw = new QueryWrapper<>();
qw.eq("email", email);
Contestant existing = contestantMapper.selectOne(qw);
if (existing == null) {
return null;
}
ContestantDTO dto = new ContestantDTO();
dto.setEmail(existing.getEmail());
dto.setFirstName(existing.getFirstName());
dto.setLastName(existing.getLastName());
dto.setGender(existing.getGender());
dto.setOccupation(existing.getOccupation());
dto.setAge(existing.getAge());
dto.setCountryRegionCity(existing.getCountryRegionCity());
dto.setPhoneNumber(existing.getPhoneNumber());
dto.setPortfolioUrl(existing.getPortfolioUrl());
dto.setDesignTitle(existing.getDesignTitle());
dto.setDesignDescription(existing.getDesignDescription());
dto.setPdfPath(existing.getPdfPath());
dto.setVideoPath(existing.getVideoPath());
return dto;
}
}