2026-04-25 17:27:06 +08:00
|
|
|
package com.xuqm.im.controller;
|
|
|
|
|
|
|
|
|
|
import com.xuqm.common.model.ApiResponse;
|
|
|
|
|
import com.xuqm.im.entity.ImFriendEntity;
|
|
|
|
|
import com.xuqm.im.repository.ImFriendRepository;
|
|
|
|
|
import org.springframework.http.ResponseEntity;
|
|
|
|
|
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|
|
|
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
|
|
|
|
import org.springframework.web.bind.annotation.GetMapping;
|
|
|
|
|
import org.springframework.web.bind.annotation.PathVariable;
|
|
|
|
|
import org.springframework.web.bind.annotation.PostMapping;
|
2026-05-02 12:30:31 +08:00
|
|
|
import org.springframework.web.bind.annotation.PutMapping;
|
2026-04-28 21:05:06 +08:00
|
|
|
import org.springframework.web.bind.annotation.RequestBody;
|
2026-04-25 17:27:06 +08:00
|
|
|
import org.springframework.web.bind.annotation.RequestMapping;
|
|
|
|
|
import org.springframework.web.bind.annotation.RequestParam;
|
|
|
|
|
import org.springframework.web.bind.annotation.RestController;
|
|
|
|
|
|
2026-04-28 21:05:06 +08:00
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.LinkedHashSet;
|
2026-04-25 17:27:06 +08:00
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
|
|
@RestController
|
|
|
|
|
@RequestMapping("/api/im/friends")
|
|
|
|
|
public class FriendController {
|
|
|
|
|
|
|
|
|
|
private final ImFriendRepository friendRepository;
|
|
|
|
|
|
|
|
|
|
public FriendController(ImFriendRepository friendRepository) {
|
|
|
|
|
this.friendRepository = friendRepository;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@GetMapping
|
|
|
|
|
public ResponseEntity<ApiResponse<List<String>>> listFriends(
|
|
|
|
|
@AuthenticationPrincipal String userId,
|
2026-05-07 19:39:42 +08:00
|
|
|
@RequestParam String appKey) {
|
|
|
|
|
List<String> friendIds = friendRepository.findByAppIdAndUserId(appKey, userId)
|
2026-04-25 17:27:06 +08:00
|
|
|
.stream()
|
|
|
|
|
.map(ImFriendEntity::getFriendId)
|
|
|
|
|
.toList();
|
|
|
|
|
return ResponseEntity.ok(ApiResponse.success(friendIds));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@PostMapping
|
|
|
|
|
public ResponseEntity<ApiResponse<ImFriendEntity>> addFriend(
|
|
|
|
|
@AuthenticationPrincipal String userId,
|
2026-05-07 19:39:42 +08:00
|
|
|
@RequestParam String appKey,
|
2026-04-25 17:27:06 +08:00
|
|
|
@RequestParam String friendId) {
|
2026-05-07 19:39:42 +08:00
|
|
|
return ResponseEntity.ok(ApiResponse.success(addFriendLink(appKey, userId, friendId)));
|
2026-04-28 21:05:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@PostMapping("/batch")
|
|
|
|
|
public ResponseEntity<ApiResponse<List<ImFriendEntity>>> addFriends(
|
|
|
|
|
@AuthenticationPrincipal String userId,
|
2026-05-07 19:39:42 +08:00
|
|
|
@RequestParam String appKey,
|
2026-04-28 21:05:06 +08:00
|
|
|
@RequestBody FriendBatchRequest req) {
|
|
|
|
|
List<ImFriendEntity> links = new ArrayList<>();
|
|
|
|
|
for (String friendId : unique(req.friendIds())) {
|
|
|
|
|
if (friendId == null || friendId.isBlank() || userId.equals(friendId)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2026-05-07 19:39:42 +08:00
|
|
|
links.add(addFriendLink(appKey, userId, friendId));
|
2026-04-28 21:05:06 +08:00
|
|
|
}
|
|
|
|
|
return ResponseEntity.ok(ApiResponse.success(links));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@DeleteMapping("/{friendId}")
|
|
|
|
|
public ResponseEntity<ApiResponse<Void>> removeFriend(
|
|
|
|
|
@AuthenticationPrincipal String userId,
|
|
|
|
|
@PathVariable String friendId,
|
2026-05-07 19:39:42 +08:00
|
|
|
@RequestParam String appKey) {
|
|
|
|
|
friendRepository.deleteByAppIdAndUserIdAndFriendId(appKey, userId, friendId);
|
|
|
|
|
friendRepository.deleteByAppIdAndUserIdAndFriendId(appKey, friendId, userId);
|
2026-04-28 21:05:06 +08:00
|
|
|
return ResponseEntity.ok(ApiResponse.success(null));
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-02 12:30:31 +08:00
|
|
|
@DeleteMapping
|
|
|
|
|
public ResponseEntity<ApiResponse<Void>> removeAllFriends(
|
|
|
|
|
@AuthenticationPrincipal String userId,
|
2026-05-07 19:39:42 +08:00
|
|
|
@RequestParam String appKey) {
|
|
|
|
|
friendRepository.deleteByAppIdAndUserId(appKey, userId);
|
|
|
|
|
friendRepository.deleteByAppIdAndFriendId(appKey, userId);
|
2026-05-02 12:30:31 +08:00
|
|
|
return ResponseEntity.ok(ApiResponse.ok());
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-28 21:05:06 +08:00
|
|
|
@PostMapping("/batch/remove")
|
|
|
|
|
public ResponseEntity<ApiResponse<Void>> removeFriends(
|
|
|
|
|
@AuthenticationPrincipal String userId,
|
2026-05-07 19:39:42 +08:00
|
|
|
@RequestParam String appKey,
|
2026-04-28 21:05:06 +08:00
|
|
|
@RequestBody FriendBatchRequest req) {
|
|
|
|
|
for (String friendId : unique(req.friendIds())) {
|
|
|
|
|
if (friendId == null || friendId.isBlank() || userId.equals(friendId)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2026-05-07 19:39:42 +08:00
|
|
|
friendRepository.deleteByAppIdAndUserIdAndFriendId(appKey, userId, friendId);
|
|
|
|
|
friendRepository.deleteByAppIdAndUserIdAndFriendId(appKey, friendId, userId);
|
2026-04-28 21:05:06 +08:00
|
|
|
}
|
|
|
|
|
return ResponseEntity.ok(ApiResponse.success(null));
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-02 12:30:31 +08:00
|
|
|
@PutMapping("/{friendId}/group")
|
|
|
|
|
public ResponseEntity<ApiResponse<ImFriendEntity>> setFriendGroup(
|
|
|
|
|
@AuthenticationPrincipal String userId,
|
|
|
|
|
@PathVariable String friendId,
|
2026-05-07 19:39:42 +08:00
|
|
|
@RequestParam String appKey,
|
2026-05-02 12:30:31 +08:00
|
|
|
@RequestParam(required = false) String groupName) {
|
2026-05-07 19:39:42 +08:00
|
|
|
ImFriendEntity link = friendRepository.findByAppIdAndUserIdAndFriendId(appKey, userId, friendId)
|
|
|
|
|
.orElseGet(() -> addFriendLink(appKey, userId, friendId));
|
2026-05-02 12:30:31 +08:00
|
|
|
link.setFriendGroup(normalizeGroup(groupName));
|
|
|
|
|
return ResponseEntity.ok(ApiResponse.success(friendRepository.save(link)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@GetMapping("/groups")
|
|
|
|
|
public ResponseEntity<ApiResponse<List<String>>> listFriendGroups(
|
|
|
|
|
@AuthenticationPrincipal String userId,
|
2026-05-07 19:39:42 +08:00
|
|
|
@RequestParam String appKey) {
|
|
|
|
|
List<String> groups = friendRepository.findByAppIdAndUserId(appKey, userId).stream()
|
2026-05-02 12:30:31 +08:00
|
|
|
.map(ImFriendEntity::getFriendGroup)
|
|
|
|
|
.filter(group -> group != null && !group.isBlank())
|
|
|
|
|
.distinct()
|
|
|
|
|
.sorted()
|
|
|
|
|
.toList();
|
|
|
|
|
return ResponseEntity.ok(ApiResponse.success(groups));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@GetMapping("/groups/{groupName}")
|
|
|
|
|
public ResponseEntity<ApiResponse<List<String>>> listFriendsByGroup(
|
|
|
|
|
@AuthenticationPrincipal String userId,
|
2026-05-07 19:39:42 +08:00
|
|
|
@RequestParam String appKey,
|
2026-05-02 12:30:31 +08:00
|
|
|
@PathVariable String groupName) {
|
|
|
|
|
List<String> friendIds = friendRepository
|
2026-05-07 19:39:42 +08:00
|
|
|
.findByAppIdAndUserIdAndFriendGroup(appKey, userId, normalizeGroup(groupName))
|
2026-05-02 12:30:31 +08:00
|
|
|
.stream()
|
|
|
|
|
.map(ImFriendEntity::getFriendId)
|
|
|
|
|
.toList();
|
|
|
|
|
return ResponseEntity.ok(ApiResponse.success(friendIds));
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-07 19:39:42 +08:00
|
|
|
private ImFriendEntity addFriendLink(String appKey, String userId, String friendId) {
|
2026-04-25 17:27:06 +08:00
|
|
|
ImFriendEntity forward = friendRepository
|
2026-05-07 19:39:42 +08:00
|
|
|
.findByAppIdAndUserIdAndFriendId(appKey, userId, friendId)
|
2026-04-25 17:27:06 +08:00
|
|
|
.orElseGet(() -> {
|
|
|
|
|
ImFriendEntity e = new ImFriendEntity();
|
2026-05-07 19:39:42 +08:00
|
|
|
e.setAppId(appKey);
|
2026-04-25 17:27:06 +08:00
|
|
|
e.setUserId(userId);
|
|
|
|
|
e.setFriendId(friendId);
|
|
|
|
|
return friendRepository.save(e);
|
|
|
|
|
});
|
|
|
|
|
|
2026-05-07 19:39:42 +08:00
|
|
|
friendRepository.findByAppIdAndUserIdAndFriendId(appKey, friendId, userId)
|
2026-04-25 17:27:06 +08:00
|
|
|
.orElseGet(() -> {
|
|
|
|
|
ImFriendEntity e = new ImFriendEntity();
|
2026-05-07 19:39:42 +08:00
|
|
|
e.setAppId(appKey);
|
2026-04-25 17:27:06 +08:00
|
|
|
e.setUserId(friendId);
|
|
|
|
|
e.setFriendId(userId);
|
|
|
|
|
return friendRepository.save(e);
|
|
|
|
|
});
|
2026-04-28 21:05:06 +08:00
|
|
|
return forward;
|
2026-04-25 17:27:06 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-28 21:05:06 +08:00
|
|
|
private List<String> unique(List<String> friendIds) {
|
|
|
|
|
return friendIds == null ? List.of() : new ArrayList<>(new LinkedHashSet<>(friendIds));
|
2026-04-25 17:27:06 +08:00
|
|
|
}
|
2026-04-28 21:05:06 +08:00
|
|
|
|
2026-05-02 12:30:31 +08:00
|
|
|
private String normalizeGroup(String groupName) {
|
|
|
|
|
return groupName == null || groupName.isBlank() ? null : groupName.trim();
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-01 23:13:09 +08:00
|
|
|
@PostMapping("/check")
|
|
|
|
|
public ResponseEntity<ApiResponse<List<FriendCheckResult>>> checkFriends(
|
|
|
|
|
@AuthenticationPrincipal String userId,
|
2026-05-07 19:39:42 +08:00
|
|
|
@RequestParam String appKey,
|
2026-05-01 23:13:09 +08:00
|
|
|
@RequestBody FriendCheckRequest req) {
|
|
|
|
|
List<FriendCheckResult> results = new ArrayList<>();
|
|
|
|
|
for (String friendId : req.friendIds() == null ? List.<String>of() : req.friendIds()) {
|
2026-05-07 19:39:42 +08:00
|
|
|
boolean isFriend = friendRepository.existsByAppIdAndUserIdAndFriendId(appKey, userId, friendId)
|
|
|
|
|
|| friendRepository.existsByAppIdAndUserIdAndFriendId(appKey, friendId, userId);
|
2026-05-01 23:13:09 +08:00
|
|
|
results.add(new FriendCheckResult(friendId, isFriend));
|
|
|
|
|
}
|
|
|
|
|
return ResponseEntity.ok(ApiResponse.success(results));
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-28 21:05:06 +08:00
|
|
|
public record FriendBatchRequest(List<String> friendIds) {}
|
2026-05-01 23:13:09 +08:00
|
|
|
public record FriendCheckRequest(List<String> friendIds) {}
|
|
|
|
|
public record FriendCheckResult(String userId, boolean isFriend) {}
|
2026-04-25 17:27:06 +08:00
|
|
|
}
|