feat(interaction): 支持游客互动与登录合并
This commit is contained in:
1 parent
2fe24b9db7
commit
4b0fbd73d3
41 files changed
+1207
-90
No files matched your search
+1
@@ -18,6 +18,7 @@ public class ContentLike {
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
private Long userId;
|
||||
private String deviceId;
|
||||
/** DRAMA/EPISODE/COMMENT */
|
||||
private String targetType;
|
||||
private Long targetId;
|
||||
|
||||
+4
@@ -4,6 +4,7 @@ package com.fruitshorts.interaction.dal.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.fruitshorts.interaction.dal.entity.ContentComment;
|
||||
import org.apache.ibatis.annotations.Delete;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
@@ -12,6 +13,9 @@ import java.util.List;
|
||||
|
||||
public interface ContentCommentMapper extends BaseMapper<ContentComment> {
|
||||
|
||||
@Delete("DELETE FROM content_comment WHERE id = #{id}")
|
||||
int physicalDeleteById(@Param("id") Long id);
|
||||
|
||||
/**
|
||||
* 后台举报工单按评论 id 批量读取,包含逻辑删除记录。
|
||||
*
|
||||
|
||||
+9
@@ -20,4 +20,13 @@ public interface ContentLikeMapper extends BaseMapper<ContentLike> {
|
||||
+ "AND target_id = #{targetId}")
|
||||
int physicalDelete(@Param("userId") Long userId, @Param("targetType") String targetType,
|
||||
@Param("targetId") Long targetId);
|
||||
|
||||
@Delete("DELETE FROM content_like WHERE user_id IS NULL AND device_id = #{deviceId} "
|
||||
+ "AND target_type = #{targetType} AND target_id = #{targetId}")
|
||||
int physicalDeleteDevice(@Param("deviceId") String deviceId,
|
||||
@Param("targetType") String targetType,
|
||||
@Param("targetId") Long targetId);
|
||||
|
||||
@Delete("DELETE FROM content_like WHERE id = #{id}")
|
||||
int physicalDeleteById(@Param("id") Long id);
|
||||
}
|
||||
+158
-23
@@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.fruitshorts.common.exception.ErrorCode;
|
||||
import com.fruitshorts.common.exception.ServiceException;
|
||||
import com.fruitshorts.common.interaction.InteractionIdentity;
|
||||
import com.fruitshorts.common.pojo.CursorResult;
|
||||
import com.fruitshorts.common.pojo.PageResult;
|
||||
import com.fruitshorts.content.dal.entity.Drama;
|
||||
@@ -78,6 +79,11 @@ public class CommentService {
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public CommentRespVO publish(Long userId, CommentPublishReqVO req, String ip, String deviceId) {
|
||||
return publish(new InteractionIdentity(userId, deviceId), req, ip);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public CommentRespVO publish(InteractionIdentity identity, CommentPublishReqVO req, String ip) {
|
||||
dramaService.getPublished(req.getDramaId());
|
||||
if (req.getEpisodeId() != null) {
|
||||
episodeService.getPublished(req.getEpisodeId());
|
||||
@@ -90,7 +96,8 @@ public class CommentService {
|
||||
throw new ServiceException(ErrorCode.BAD_REQUEST,
|
||||
"评论最多 " + properties.getCommentMaxLength() + " 字");
|
||||
}
|
||||
checkRate(userId);
|
||||
checkRate(identity);
|
||||
checkDuplicate(identity, req, text);
|
||||
|
||||
SensitiveWordCheck check = sensitiveWordService.check(text);
|
||||
if (check.blocked()) {
|
||||
@@ -110,7 +117,7 @@ public class CommentService {
|
||||
ContentComment comment = new ContentComment();
|
||||
comment.setDramaId(req.getDramaId());
|
||||
comment.setEpisodeId(req.getEpisodeId() == null ? 0L : req.getEpisodeId());
|
||||
comment.setUserId(userId);
|
||||
comment.setUserId(identity.userId());
|
||||
comment.setParentId(parent == null ? 0L : parent.getId());
|
||||
comment.setRootId(resolveRootId(parent));
|
||||
comment.setContent(check.sanitized());
|
||||
@@ -121,7 +128,7 @@ public class CommentService {
|
||||
comment.setReplyCount(0);
|
||||
comment.setReportCount(0);
|
||||
comment.setIp(ip == null ? "" : ip);
|
||||
comment.setDeviceId(deviceId == null ? "" : deviceId);
|
||||
comment.setDeviceId(identity.authenticated() ? "" : identity.deviceId());
|
||||
comment.setCountryCode("");
|
||||
commentMapper.insert(comment);
|
||||
|
||||
@@ -134,13 +141,22 @@ public class CommentService {
|
||||
.eq(ContentComment::getId, parent.getId())
|
||||
.setSql("reply_count = reply_count + 1"));
|
||||
}
|
||||
return toResp(comment, appUserMapper.selectById(userId), false, userId);
|
||||
return toResp(
|
||||
comment,
|
||||
identity.authenticated() ? appUserMapper.selectById(identity.userId()) : null,
|
||||
false,
|
||||
identity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 游标翻页。unsetRootId 表示只看顶层评论;传 rootId 则看该楼层的回复。
|
||||
*/
|
||||
public CursorResult<CommentRespVO> page(Long meUserId, CommentQueryReqVO req) {
|
||||
return page(meUserId, "", req);
|
||||
}
|
||||
|
||||
public CursorResult<CommentRespVO> page(
|
||||
Long meUserId, String meDeviceId, CommentQueryReqVO req) {
|
||||
if (req.getDramaId() == null) {
|
||||
throw new ServiceException(ErrorCode.BAD_REQUEST, "缺少 dramaId");
|
||||
}
|
||||
@@ -151,8 +167,13 @@ public class CommentService {
|
||||
.eq(req.getEpisodeId() != null, ContentComment::getEpisodeId, req.getEpisodeId())
|
||||
.eq(ContentComment::getRootId, rootFilter)
|
||||
.lt(req.getCursor() != null, ContentComment::getId, req.getCursor());
|
||||
if (meUserId == null) {
|
||||
if (meUserId == null && (meDeviceId == null || meDeviceId.isBlank())) {
|
||||
wrapper.eq(ContentComment::getStatus, STATUS_PUBLISHED);
|
||||
} else if (meUserId == null) {
|
||||
wrapper.and(w -> w.eq(ContentComment::getStatus, STATUS_PUBLISHED)
|
||||
.or(x -> x.eq(ContentComment::getStatus, STATUS_PENDING)
|
||||
.isNull(ContentComment::getUserId)
|
||||
.eq(ContentComment::getDeviceId, meDeviceId)));
|
||||
} else {
|
||||
// 已发布 + 自己待审核的
|
||||
wrapper.and(w -> w.eq(ContentComment::getStatus, STATUS_PUBLISHED)
|
||||
@@ -166,13 +187,25 @@ public class CommentService {
|
||||
rows = rows.subList(0, size);
|
||||
}
|
||||
Long nextCursor = rows.isEmpty() ? null : rows.get(rows.size() - 1).getId();
|
||||
return new CursorResult<>(toRespList(rows, meUserId), hasMore ? nextCursor : null, hasMore);
|
||||
return new CursorResult<>(
|
||||
toRespList(rows, new InteractionIdentity(meUserId, meDeviceId)),
|
||||
hasMore ? nextCursor : null,
|
||||
hasMore);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delete(Long userId, Long commentId) {
|
||||
delete(new InteractionIdentity(userId, ""), commentId);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delete(InteractionIdentity identity, Long commentId) {
|
||||
ContentComment comment = getExisting(commentId);
|
||||
if (!comment.getUserId().equals(userId)) {
|
||||
boolean mine = identity.authenticated()
|
||||
? identity.userId().equals(comment.getUserId())
|
||||
: comment.getUserId() == null
|
||||
&& identity.deviceId().equals(comment.getDeviceId());
|
||||
if (!mine) {
|
||||
throw new ServiceException(ErrorCode.FORBIDDEN, "只能删除自己的评论");
|
||||
}
|
||||
softDelete(comment);
|
||||
@@ -278,7 +311,7 @@ public class CommentService {
|
||||
req.getKeyword())
|
||||
.orderByDesc(ContentComment::getId));
|
||||
List<ContentComment> rows = result.getRecords();
|
||||
List<CommentRespVO> list = toRespList(rows, null);
|
||||
List<CommentRespVO> list = toRespList(rows, new InteractionIdentity(null, ""));
|
||||
fillAdminContentInfo(rows, list);
|
||||
return new PageResult<>(result.getTotal(), list);
|
||||
}
|
||||
@@ -349,15 +382,87 @@ public class CommentService {
|
||||
commentMapper.updateById(comment);
|
||||
}
|
||||
|
||||
private void checkRate(Long userId) {
|
||||
Long recent = commentMapper.selectCount(Wrappers.<ContentComment>lambdaQuery()
|
||||
.eq(ContentComment::getUserId, userId)
|
||||
.ge(ContentComment::getCreatedAt, LocalDateTime.now().minusMinutes(1)));
|
||||
private void checkRate(InteractionIdentity identity) {
|
||||
var query = Wrappers.<ContentComment>lambdaQuery()
|
||||
.ge(ContentComment::getCreatedAt, LocalDateTime.now().minusMinutes(1));
|
||||
if (identity.authenticated()) {
|
||||
query.eq(ContentComment::getUserId, identity.userId());
|
||||
} else {
|
||||
query.isNull(ContentComment::getUserId)
|
||||
.eq(ContentComment::getDeviceId, identity.deviceId());
|
||||
}
|
||||
Long recent = commentMapper.selectCount(query);
|
||||
if (recent != null && recent >= properties.getCommentPerMinute()) {
|
||||
throw new ServiceException(ErrorCode.TOO_MANY_REQUESTS, "发言过于频繁,请稍后再试");
|
||||
}
|
||||
}
|
||||
|
||||
private void checkDuplicate(
|
||||
InteractionIdentity identity, CommentPublishReqVO req, String text) {
|
||||
var query = Wrappers.<ContentComment>lambdaQuery()
|
||||
.eq(ContentComment::getDramaId, req.getDramaId())
|
||||
.eq(ContentComment::getEpisodeId,
|
||||
req.getEpisodeId() == null ? 0L : req.getEpisodeId())
|
||||
.eq(ContentComment::getParentId,
|
||||
req.getParentId() == null ? 0L : req.getParentId())
|
||||
.eq(ContentComment::getContent, text)
|
||||
.ne(ContentComment::getStatus, STATUS_DELETED)
|
||||
.ge(ContentComment::getCreatedAt, LocalDateTime.now().minusMinutes(1));
|
||||
if (identity.authenticated()) {
|
||||
query.eq(ContentComment::getUserId, identity.userId());
|
||||
} else {
|
||||
query.isNull(ContentComment::getUserId)
|
||||
.eq(ContentComment::getDeviceId, identity.deviceId());
|
||||
}
|
||||
Long count = commentMapper.selectCount(query);
|
||||
if (count != null && count > 0) {
|
||||
throw new ServiceException(ErrorCode.DATA_EXISTS, "请勿重复发送相同评论");
|
||||
}
|
||||
}
|
||||
|
||||
/** 登录时把设备评论归并到账号;重复内容删除设备侧记录。 */
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public MergeResult mergeDeviceIntoUser(Long userId, String deviceId) {
|
||||
if (userId == null || !StringUtils.hasText(deviceId)) {
|
||||
return new MergeResult(0, 0);
|
||||
}
|
||||
List<ContentComment> deviceComments = commentMapper.selectList(
|
||||
Wrappers.<ContentComment>lambdaQuery()
|
||||
.isNull(ContentComment::getUserId)
|
||||
.eq(ContentComment::getDeviceId, deviceId));
|
||||
int migrated = 0;
|
||||
int duplicates = 0;
|
||||
for (ContentComment deviceComment : deviceComments) {
|
||||
ContentComment existing = commentMapper.selectOne(
|
||||
Wrappers.<ContentComment>lambdaQuery()
|
||||
.eq(ContentComment::getUserId, userId)
|
||||
.eq(ContentComment::getDramaId, deviceComment.getDramaId())
|
||||
.eq(ContentComment::getEpisodeId, deviceComment.getEpisodeId())
|
||||
.eq(ContentComment::getParentId, deviceComment.getParentId())
|
||||
.eq(ContentComment::getContent, deviceComment.getContent())
|
||||
.ne(ContentComment::getStatus, STATUS_DELETED)
|
||||
.last("limit 1"));
|
||||
if (existing != null) {
|
||||
if (commentMapper.physicalDeleteById(deviceComment.getId()) > 0
|
||||
&& deviceComment.getParentId() != null
|
||||
&& deviceComment.getParentId() > 0) {
|
||||
commentMapper.update(null, Wrappers.<ContentComment>lambdaUpdate()
|
||||
.eq(ContentComment::getId, deviceComment.getParentId())
|
||||
.setSql("reply_count = GREATEST(reply_count - 1, 0)"));
|
||||
}
|
||||
duplicates++;
|
||||
continue;
|
||||
}
|
||||
deviceComment.setUserId(userId);
|
||||
commentMapper.updateById(deviceComment);
|
||||
migrated++;
|
||||
}
|
||||
return new MergeResult(migrated, duplicates);
|
||||
}
|
||||
|
||||
public record MergeResult(int migrated, int duplicates) {
|
||||
}
|
||||
|
||||
private Long resolveRootId(ContentComment parent) {
|
||||
if (parent == null) {
|
||||
return 0L;
|
||||
@@ -371,27 +476,45 @@ public class CommentService {
|
||||
return Math.min(value, properties.getPageMaxSize());
|
||||
}
|
||||
|
||||
private List<CommentRespVO> toRespList(List<ContentComment> rows, Long meUserId) {
|
||||
private List<CommentRespVO> toRespList(
|
||||
List<ContentComment> rows, InteractionIdentity identity) {
|
||||
if (rows.isEmpty()) {
|
||||
return List.of();
|
||||
}
|
||||
Map<Long, AppUser> users = new HashMap<>();
|
||||
List<Long> userIds = rows.stream().map(ContentComment::getUserId).distinct().toList();
|
||||
for (AppUser user : appUserMapper.selectBatchIds(userIds)) {
|
||||
users.put(user.getId(), user);
|
||||
List<Long> userIds = rows.stream()
|
||||
.map(ContentComment::getUserId)
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.toList();
|
||||
if (!userIds.isEmpty()) {
|
||||
for (AppUser user : appUserMapper.selectBatchIds(userIds)) {
|
||||
users.put(user.getId(), user);
|
||||
}
|
||||
}
|
||||
Set<Long> likedIds = new HashSet<>();
|
||||
if (meUserId != null) {
|
||||
for (ContentLike like : likeMapper.selectList(Wrappers.<ContentLike>lambdaQuery()
|
||||
.eq(ContentLike::getUserId, meUserId)
|
||||
if (identity.userId() != null || StringUtils.hasText(identity.deviceId())) {
|
||||
var query = Wrappers.<ContentLike>lambdaQuery()
|
||||
.eq(ContentLike::getTargetType, "COMMENT")
|
||||
.in(ContentLike::getTargetId, rows.stream().map(ContentComment::getId).toList()))) {
|
||||
.in(ContentLike::getTargetId,
|
||||
rows.stream().map(ContentComment::getId).toList());
|
||||
if (identity.authenticated()) {
|
||||
query.eq(ContentLike::getUserId, identity.userId());
|
||||
} else {
|
||||
query.isNull(ContentLike::getUserId)
|
||||
.eq(ContentLike::getDeviceId, identity.deviceId());
|
||||
}
|
||||
for (ContentLike like : likeMapper.selectList(query)) {
|
||||
likedIds.add(like.getTargetId());
|
||||
}
|
||||
}
|
||||
List<CommentRespVO> list = new ArrayList<>(rows.size());
|
||||
for (ContentComment row : rows) {
|
||||
list.add(toResp(row, users.get(row.getUserId()), likedIds.contains(row.getId()), meUserId));
|
||||
list.add(toResp(
|
||||
row,
|
||||
users.get(row.getUserId()),
|
||||
likedIds.contains(row.getId()),
|
||||
identity));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
@@ -429,7 +552,11 @@ public class CommentService {
|
||||
}
|
||||
}
|
||||
|
||||
private CommentRespVO toResp(ContentComment comment, AppUser author, boolean liked, Long meUserId) {
|
||||
private CommentRespVO toResp(
|
||||
ContentComment comment,
|
||||
AppUser author,
|
||||
boolean liked,
|
||||
InteractionIdentity identity) {
|
||||
CommentRespVO vo = new CommentRespVO();
|
||||
vo.setId(comment.getId());
|
||||
vo.setDramaId(comment.getDramaId());
|
||||
@@ -444,12 +571,20 @@ public class CommentService {
|
||||
vo.setReplyCount(comment.getReplyCount());
|
||||
vo.setReportCount(comment.getReportCount());
|
||||
vo.setCreatedAt(comment.getCreatedAt());
|
||||
vo.setMine(meUserId != null && meUserId.equals(comment.getUserId()));
|
||||
boolean mine = identity.authenticated()
|
||||
? identity.userId().equals(comment.getUserId())
|
||||
: comment.getUserId() == null
|
||||
&& identity.deviceId().equals(comment.getDeviceId());
|
||||
vo.setMine(mine);
|
||||
vo.setLiked(liked);
|
||||
if (author != null) {
|
||||
vo.setUid(author.getUid());
|
||||
vo.setNickname(author.getNickname());
|
||||
vo.setAvatarUrl(author.getAvatarUrl());
|
||||
} else {
|
||||
vo.setUid("");
|
||||
vo.setNickname("游客");
|
||||
vo.setAvatarUrl("");
|
||||
}
|
||||
return vo;
|
||||
}
|
||||
|
||||
+72
-7
@@ -5,6 +5,7 @@ package com.fruitshorts.interaction.service;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.fruitshorts.common.exception.ErrorCode;
|
||||
import com.fruitshorts.common.exception.ServiceException;
|
||||
import com.fruitshorts.common.interaction.InteractionIdentity;
|
||||
import com.fruitshorts.content.dal.entity.DramaEpisode;
|
||||
import com.fruitshorts.content.service.DramaService;
|
||||
import com.fruitshorts.content.service.EpisodeService;
|
||||
@@ -20,6 +21,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -44,6 +46,11 @@ public class LikeService {
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public LikeToggleRespVO toggle(Long userId, LikeToggleReqVO req) {
|
||||
return toggle(new InteractionIdentity(userId, ""), req);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public LikeToggleRespVO toggle(InteractionIdentity identity, LikeToggleReqVO req) {
|
||||
String type = req.getTargetType().trim().toUpperCase(Locale.ROOT);
|
||||
if (!TYPE_DRAMA.equals(type) && !TYPE_EPISODE.equals(type) && !TYPE_COMMENT.equals(type)) {
|
||||
throw new ServiceException(ErrorCode.BAD_REQUEST, "只支持对短剧、剧集或评论点赞");
|
||||
@@ -51,22 +58,26 @@ public class LikeService {
|
||||
Long targetId = req.getTargetId();
|
||||
validateTarget(type, targetId);
|
||||
|
||||
ContentLike existing = likeMapper.selectOne(Wrappers.<ContentLike>lambdaQuery()
|
||||
.eq(ContentLike::getUserId, userId)
|
||||
ContentLike existing = likeMapper.selectOne(identityQuery(identity)
|
||||
.eq(ContentLike::getTargetType, type)
|
||||
.eq(ContentLike::getTargetId, targetId)
|
||||
.last("limit 1"));
|
||||
boolean liked;
|
||||
if (existing == null) {
|
||||
ContentLike like = new ContentLike();
|
||||
like.setUserId(userId);
|
||||
like.setUserId(identity.userId());
|
||||
like.setDeviceId(identity.authenticated() ? "" : identity.deviceId());
|
||||
like.setTargetType(type);
|
||||
like.setTargetId(targetId);
|
||||
likeMapper.insert(like);
|
||||
liked = true;
|
||||
adjustCount(type, targetId, 1);
|
||||
} else {
|
||||
likeMapper.physicalDelete(userId, type, targetId);
|
||||
if (identity.authenticated()) {
|
||||
likeMapper.physicalDelete(identity.userId(), type, targetId);
|
||||
} else {
|
||||
likeMapper.physicalDeleteDevice(identity.deviceId(), type, targetId);
|
||||
}
|
||||
liked = false;
|
||||
adjustCount(type, targetId, -1);
|
||||
}
|
||||
@@ -91,7 +102,13 @@ public class LikeService {
|
||||
|
||||
/** 批量判断用户是否已点赞,一次查询覆盖多个目标。 */
|
||||
public Set<Long> likedTargetIds(Long userId, String type, Collection<Long> targetIds) {
|
||||
if (userId == null || targetIds == null || targetIds.isEmpty()) {
|
||||
return likedTargetIds(userId, "", type, targetIds);
|
||||
}
|
||||
|
||||
/** 登录用户优先;匿名状态按设备号查询。 */
|
||||
public Set<Long> likedTargetIds(Long userId, String deviceId, String type,
|
||||
Collection<Long> targetIds) {
|
||||
if (targetIds == null || targetIds.isEmpty()) {
|
||||
return Set.of();
|
||||
}
|
||||
Set<Long> normalized = new HashSet<>();
|
||||
@@ -103,8 +120,10 @@ public class LikeService {
|
||||
if (normalized.isEmpty()) {
|
||||
return Set.of();
|
||||
}
|
||||
return likeMapper.selectList(Wrappers.<ContentLike>lambdaQuery()
|
||||
.eq(ContentLike::getUserId, userId)
|
||||
if (userId == null && (deviceId == null || deviceId.isBlank())) {
|
||||
return Set.of();
|
||||
}
|
||||
return likeMapper.selectList(identityQuery(new InteractionIdentity(userId, deviceId))
|
||||
.eq(ContentLike::getTargetType, type)
|
||||
.in(ContentLike::getTargetId, normalized))
|
||||
.stream()
|
||||
@@ -112,6 +131,52 @@ public class LikeService {
|
||||
.collect(java.util.stream.Collectors.toSet());
|
||||
}
|
||||
|
||||
/** 登录时把设备点赞归并到账号;重复关系删除并回退目标计数。 */
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public MergeResult mergeDeviceIntoUser(Long userId, String deviceId) {
|
||||
if (userId == null || deviceId == null || deviceId.isBlank()) {
|
||||
return new MergeResult(0, 0);
|
||||
}
|
||||
List<ContentLike> deviceLikes = likeMapper.selectList(
|
||||
Wrappers.<ContentLike>lambdaQuery()
|
||||
.isNull(ContentLike::getUserId)
|
||||
.eq(ContentLike::getDeviceId, deviceId));
|
||||
int migrated = 0;
|
||||
int duplicates = 0;
|
||||
for (ContentLike deviceLike : deviceLikes) {
|
||||
ContentLike existing = likeMapper.selectOne(Wrappers.<ContentLike>lambdaQuery()
|
||||
.eq(ContentLike::getUserId, userId)
|
||||
.eq(ContentLike::getTargetType, deviceLike.getTargetType())
|
||||
.eq(ContentLike::getTargetId, deviceLike.getTargetId())
|
||||
.last("limit 1"));
|
||||
if (existing != null) {
|
||||
if (likeMapper.physicalDeleteById(deviceLike.getId()) > 0) {
|
||||
adjustCount(deviceLike.getTargetType(), deviceLike.getTargetId(), -1);
|
||||
}
|
||||
duplicates++;
|
||||
continue;
|
||||
}
|
||||
deviceLike.setUserId(userId);
|
||||
likeMapper.updateById(deviceLike);
|
||||
migrated++;
|
||||
}
|
||||
return new MergeResult(migrated, duplicates);
|
||||
}
|
||||
|
||||
private com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ContentLike>
|
||||
identityQuery(InteractionIdentity identity) {
|
||||
if (identity.authenticated()) {
|
||||
return Wrappers.<ContentLike>lambdaQuery()
|
||||
.eq(ContentLike::getUserId, identity.userId());
|
||||
}
|
||||
return Wrappers.<ContentLike>lambdaQuery()
|
||||
.isNull(ContentLike::getUserId)
|
||||
.eq(ContentLike::getDeviceId, identity.deviceId());
|
||||
}
|
||||
|
||||
public record MergeResult(int migrated, int duplicates) {
|
||||
}
|
||||
|
||||
private void adjustCount(String type, Long targetId, int delta) {
|
||||
if (TYPE_DRAMA.equals(type)) {
|
||||
dramaService.adjustLikeCount(targetId, delta);
|
||||
|
||||
+3
@@ -20,4 +20,7 @@ public class CommentPublishReqVO {
|
||||
|
||||
/** 回复某条评论时传它的 id;顶层评论不传 */
|
||||
private Long parentId;
|
||||
|
||||
/** 兼容旧调用;正常客户端通过 X-Device-Id 下发。 */
|
||||
private String deviceId;
|
||||
}
|
||||
+3
@@ -16,4 +16,7 @@ public class LikeToggleReqVO {
|
||||
|
||||
@NotNull(message = "缺少 targetId")
|
||||
private Long targetId;
|
||||
|
||||
/** 兼容旧调用;正常客户端通过 X-Device-Id 下发。 */
|
||||
private String deviceId;
|
||||
}
|
||||
Reference in new issue
Block a user