2026-04-24 16:16:33 +08:00
|
|
|
package com.xuqm.im.controller;
|
|
|
|
|
|
|
|
|
|
import com.xuqm.common.model.ApiResponse;
|
|
|
|
|
import com.xuqm.im.entity.ImAccountEntity;
|
2026-04-28 17:29:17 +08:00
|
|
|
import com.xuqm.im.entity.ImGlobalMuteEntity;
|
2026-04-24 16:16:33 +08:00
|
|
|
import com.xuqm.im.entity.ImGroupEntity;
|
2026-04-28 17:29:17 +08:00
|
|
|
import com.xuqm.im.entity.ImMessageEntity;
|
|
|
|
|
import com.xuqm.im.entity.KeywordFilterEntity;
|
|
|
|
|
import com.xuqm.im.entity.WebhookConfigEntity;
|
2026-04-24 16:16:33 +08:00
|
|
|
import com.xuqm.im.repository.ImAccountRepository;
|
|
|
|
|
import com.xuqm.im.repository.ImGroupRepository;
|
|
|
|
|
import com.xuqm.im.repository.ImMessageRepository;
|
2026-04-24 20:53:48 +08:00
|
|
|
import com.xuqm.im.service.ImAccountService;
|
|
|
|
|
import com.xuqm.im.service.ImGroupService;
|
2026-04-28 17:29:17 +08:00
|
|
|
import com.xuqm.im.service.GlobalMuteService;
|
|
|
|
|
import com.xuqm.im.service.KeywordFilterService;
|
2026-04-28 09:45:20 +08:00
|
|
|
import com.xuqm.im.service.MessageService;
|
2026-04-29 00:34:17 +08:00
|
|
|
import com.xuqm.im.service.OperationLogService;
|
2026-04-28 17:29:17 +08:00
|
|
|
import com.xuqm.im.service.WebhookConfigService;
|
2026-04-24 16:16:33 +08:00
|
|
|
import org.springframework.data.domain.Page;
|
|
|
|
|
import org.springframework.data.domain.PageRequest;
|
|
|
|
|
import org.springframework.http.ResponseEntity;
|
2026-04-29 00:34:17 +08:00
|
|
|
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
2026-04-24 16:16:33 +08:00
|
|
|
import org.springframework.web.bind.annotation.*;
|
|
|
|
|
|
2026-04-28 09:45:20 +08:00
|
|
|
import java.time.LocalDateTime;
|
2026-04-24 16:16:33 +08:00
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
|
|
|
|
|
@RestController
|
|
|
|
|
@RequestMapping("/api/im/admin")
|
|
|
|
|
public class ImAdminController {
|
|
|
|
|
|
|
|
|
|
private final ImAccountRepository accountRepository;
|
|
|
|
|
private final ImGroupRepository groupRepository;
|
|
|
|
|
private final ImMessageRepository messageRepository;
|
2026-04-24 20:53:48 +08:00
|
|
|
private final ImAccountService accountService;
|
|
|
|
|
private final ImGroupService groupService;
|
2026-04-28 09:45:20 +08:00
|
|
|
private final MessageService messageService;
|
2026-04-28 17:29:17 +08:00
|
|
|
private final WebhookConfigService webhookConfigService;
|
|
|
|
|
private final KeywordFilterService keywordFilterService;
|
|
|
|
|
private final GlobalMuteService globalMuteService;
|
2026-04-29 00:34:17 +08:00
|
|
|
private final OperationLogService operationLogService;
|
2026-04-24 16:16:33 +08:00
|
|
|
|
|
|
|
|
public ImAdminController(ImAccountRepository accountRepository,
|
|
|
|
|
ImGroupRepository groupRepository,
|
2026-04-24 20:53:48 +08:00
|
|
|
ImMessageRepository messageRepository,
|
|
|
|
|
ImAccountService accountService,
|
2026-04-28 09:45:20 +08:00
|
|
|
ImGroupService groupService,
|
2026-04-28 17:29:17 +08:00
|
|
|
MessageService messageService,
|
|
|
|
|
WebhookConfigService webhookConfigService,
|
|
|
|
|
KeywordFilterService keywordFilterService,
|
2026-04-29 00:34:17 +08:00
|
|
|
GlobalMuteService globalMuteService,
|
|
|
|
|
OperationLogService operationLogService) {
|
2026-04-24 16:16:33 +08:00
|
|
|
this.accountRepository = accountRepository;
|
|
|
|
|
this.groupRepository = groupRepository;
|
|
|
|
|
this.messageRepository = messageRepository;
|
2026-04-24 20:53:48 +08:00
|
|
|
this.accountService = accountService;
|
|
|
|
|
this.groupService = groupService;
|
2026-04-28 09:45:20 +08:00
|
|
|
this.messageService = messageService;
|
2026-04-28 17:29:17 +08:00
|
|
|
this.webhookConfigService = webhookConfigService;
|
|
|
|
|
this.keywordFilterService = keywordFilterService;
|
|
|
|
|
this.globalMuteService = globalMuteService;
|
2026-04-29 00:34:17 +08:00
|
|
|
this.operationLogService = operationLogService;
|
2026-04-24 16:16:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** List all registered IM users for the given appId. */
|
|
|
|
|
@GetMapping("/users")
|
|
|
|
|
public ResponseEntity<ApiResponse<Page<ImAccountEntity>>> listUsers(
|
|
|
|
|
@RequestParam String appId,
|
|
|
|
|
@RequestParam(defaultValue = "0") int page,
|
|
|
|
|
@RequestParam(defaultValue = "20") int size) {
|
|
|
|
|
return ResponseEntity.ok(ApiResponse.success(
|
|
|
|
|
accountRepository.findByAppId(appId, PageRequest.of(page, size))));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Ban or unban a user. */
|
|
|
|
|
@PutMapping("/users/{userId}/status")
|
|
|
|
|
public ResponseEntity<ApiResponse<ImAccountEntity>> updateUserStatus(
|
|
|
|
|
@RequestParam String appId,
|
|
|
|
|
@PathVariable String userId,
|
2026-04-29 00:34:17 +08:00
|
|
|
@AuthenticationPrincipal String operatorId,
|
2026-04-24 16:16:33 +08:00
|
|
|
@RequestBody Map<String, String> body) {
|
|
|
|
|
ImAccountEntity account = accountRepository.findByAppIdAndUserId(appId, userId)
|
|
|
|
|
.orElseThrow(() -> new RuntimeException("User not found"));
|
|
|
|
|
account.setStatus(ImAccountEntity.Status.valueOf(body.get("status").toUpperCase()));
|
2026-04-29 00:34:17 +08:00
|
|
|
ImAccountEntity saved = accountRepository.save(account);
|
|
|
|
|
operationLogService.record(appId, operatorId, "UPDATE_USER_STATUS", "ACCOUNT", userId, body.get("status"));
|
|
|
|
|
return ResponseEntity.ok(ApiResponse.success(saved));
|
2026-04-24 16:16:33 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-29 10:04:17 +08:00
|
|
|
/** Update a registered IM user profile without changing userId. */
|
|
|
|
|
@PutMapping("/users/{userId}")
|
|
|
|
|
public ResponseEntity<ApiResponse<ImAccountEntity>> updateUser(
|
|
|
|
|
@RequestParam String appId,
|
|
|
|
|
@PathVariable String userId,
|
|
|
|
|
@AuthenticationPrincipal String operatorId,
|
|
|
|
|
@RequestBody UpdateUserRequest req) {
|
|
|
|
|
ImAccountEntity saved = accountService.updateAccount(
|
|
|
|
|
appId,
|
|
|
|
|
userId,
|
|
|
|
|
req.nickname(),
|
|
|
|
|
req.avatar(),
|
|
|
|
|
req.gender(),
|
|
|
|
|
req.status());
|
|
|
|
|
operationLogService.record(appId, operatorId, "UPDATE_USER", "ACCOUNT", userId, req.nickname());
|
|
|
|
|
return ResponseEntity.ok(ApiResponse.success(saved));
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-24 16:16:33 +08:00
|
|
|
/** List all groups for the given appId. */
|
|
|
|
|
@GetMapping("/groups")
|
|
|
|
|
public ResponseEntity<ApiResponse<List<ImGroupEntity>>> listGroups(@RequestParam String appId) {
|
|
|
|
|
return ResponseEntity.ok(ApiResponse.success(groupRepository.findByAppId(appId)));
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-24 20:53:48 +08:00
|
|
|
/** Admin registers a new IM user (or returns existing). */
|
|
|
|
|
@PostMapping("/users")
|
|
|
|
|
public ResponseEntity<ApiResponse<ImAccountEntity>> registerUser(
|
|
|
|
|
@RequestParam String appId,
|
2026-04-29 00:34:17 +08:00
|
|
|
@AuthenticationPrincipal String operatorId,
|
2026-04-24 20:53:48 +08:00
|
|
|
@RequestBody RegisterUserRequest req) {
|
2026-04-29 10:04:17 +08:00
|
|
|
ImAccountEntity account = accountService.importAccount(
|
|
|
|
|
appId,
|
|
|
|
|
req.userId(),
|
|
|
|
|
req.nickname(),
|
|
|
|
|
req.avatar(),
|
|
|
|
|
req.gender(),
|
|
|
|
|
req.status());
|
2026-04-29 00:34:17 +08:00
|
|
|
operationLogService.record(appId, operatorId, "REGISTER_USER", "ACCOUNT", req.userId(), req.nickname());
|
2026-04-24 20:53:48 +08:00
|
|
|
return ResponseEntity.ok(ApiResponse.success(account));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Admin creates a group. */
|
|
|
|
|
@PostMapping("/groups")
|
|
|
|
|
public ResponseEntity<ApiResponse<ImGroupEntity>> createGroup(
|
|
|
|
|
@RequestParam String appId,
|
2026-04-29 00:34:17 +08:00
|
|
|
@AuthenticationPrincipal String operatorId,
|
2026-04-24 20:53:48 +08:00
|
|
|
@RequestBody CreateGroupRequest req) {
|
2026-04-29 10:04:17 +08:00
|
|
|
ImGroupEntity group = groupService.create(
|
|
|
|
|
appId,
|
|
|
|
|
req.name(),
|
|
|
|
|
req.creatorId(),
|
|
|
|
|
req.memberIds(),
|
|
|
|
|
req.groupType(),
|
|
|
|
|
req.announcement());
|
2026-04-29 00:34:17 +08:00
|
|
|
operationLogService.record(appId, operatorId, "CREATE_GROUP", "GROUP", group.getId(), group.getName());
|
|
|
|
|
return ResponseEntity.ok(ApiResponse.success(group));
|
2026-04-24 20:53:48 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-29 10:04:17 +08:00
|
|
|
/** Admin updates a group without changing its id. */
|
|
|
|
|
@PutMapping("/groups/{groupId}")
|
|
|
|
|
public ResponseEntity<ApiResponse<ImGroupEntity>> updateGroup(
|
|
|
|
|
@RequestParam String appId,
|
|
|
|
|
@PathVariable String groupId,
|
|
|
|
|
@AuthenticationPrincipal String operatorId,
|
|
|
|
|
@RequestBody UpdateGroupRequest req) {
|
|
|
|
|
ImGroupEntity group = groupService.update(
|
|
|
|
|
groupId,
|
|
|
|
|
operatorId,
|
|
|
|
|
req.name(),
|
|
|
|
|
req.groupType(),
|
|
|
|
|
req.announcement());
|
|
|
|
|
operationLogService.record(appId, operatorId, "UPDATE_GROUP", "GROUP", groupId, req.name());
|
|
|
|
|
return ResponseEntity.ok(ApiResponse.success(group));
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-25 16:41:10 +08:00
|
|
|
/** Fuzzy search users by userId or nickname. */
|
|
|
|
|
@GetMapping("/users/search")
|
|
|
|
|
public ResponseEntity<ApiResponse<List<ImAccountEntity>>> searchUsers(
|
|
|
|
|
@RequestParam String appId,
|
2026-04-29 00:34:17 +08:00
|
|
|
@AuthenticationPrincipal String operatorId,
|
2026-04-25 16:41:10 +08:00
|
|
|
@RequestParam String keyword,
|
|
|
|
|
@RequestParam(defaultValue = "20") int size) {
|
|
|
|
|
List<ImAccountEntity> results = accountRepository.searchByKeyword(appId, keyword, PageRequest.of(0, size));
|
2026-04-29 00:34:17 +08:00
|
|
|
operationLogService.record(appId, operatorId, "SEARCH_USERS", "ACCOUNT", null, keyword);
|
2026-04-25 16:41:10 +08:00
|
|
|
return ResponseEntity.ok(ApiResponse.success(results));
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-28 17:29:17 +08:00
|
|
|
/** Fuzzy search groups by id, name, creator or announcement. */
|
|
|
|
|
@GetMapping("/groups/search")
|
|
|
|
|
public ResponseEntity<ApiResponse<List<ImGroupEntity>>> searchGroups(
|
|
|
|
|
@RequestParam String appId,
|
2026-04-29 00:34:17 +08:00
|
|
|
@AuthenticationPrincipal String operatorId,
|
2026-04-28 17:29:17 +08:00
|
|
|
@RequestParam String keyword,
|
|
|
|
|
@RequestParam(defaultValue = "20") int size) {
|
|
|
|
|
List<ImGroupEntity> results = groupRepository.searchByKeyword(appId, keyword, PageRequest.of(0, size));
|
2026-04-29 00:34:17 +08:00
|
|
|
operationLogService.record(appId, operatorId, "SEARCH_GROUPS", "GROUP", null, keyword);
|
2026-04-28 17:29:17 +08:00
|
|
|
return ResponseEntity.ok(ApiResponse.success(results));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Search messages across the application. */
|
|
|
|
|
@GetMapping("/messages/search")
|
|
|
|
|
public ResponseEntity<ApiResponse<Page<ImMessageEntity>>> searchMessages(
|
|
|
|
|
@RequestParam String appId,
|
2026-04-29 00:34:17 +08:00
|
|
|
@AuthenticationPrincipal String operatorId,
|
2026-04-28 17:29:17 +08:00
|
|
|
@RequestParam(required = false) ImMessageEntity.ChatType chatType,
|
|
|
|
|
@RequestParam(required = false) ImMessageEntity.MsgType msgType,
|
|
|
|
|
@RequestParam(required = false) String keyword,
|
|
|
|
|
@RequestParam(required = false) LocalDateTime startTime,
|
|
|
|
|
@RequestParam(required = false) LocalDateTime endTime,
|
|
|
|
|
@RequestParam(defaultValue = "0") int page,
|
|
|
|
|
@RequestParam(defaultValue = "20") int size) {
|
2026-04-29 00:34:17 +08:00
|
|
|
operationLogService.record(appId, operatorId, "SEARCH_MESSAGES", "MESSAGE", null, keyword);
|
2026-04-28 17:29:17 +08:00
|
|
|
return ResponseEntity.ok(ApiResponse.success(
|
|
|
|
|
messageRepository.searchByKeyword(
|
|
|
|
|
appId, chatType, msgType, keyword, startTime, endTime, PageRequest.of(page, size))));
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-24 16:16:33 +08:00
|
|
|
/** Message statistics for the given appId. */
|
|
|
|
|
@GetMapping("/stats")
|
2026-04-29 00:34:17 +08:00
|
|
|
public ResponseEntity<ApiResponse<Map<String, Object>>> stats(
|
|
|
|
|
@RequestParam String appId,
|
|
|
|
|
@AuthenticationPrincipal String operatorId) {
|
2026-04-24 16:16:33 +08:00
|
|
|
long totalMessages = messageRepository.countByAppId(appId);
|
|
|
|
|
long totalUsers = accountRepository.countByAppId(appId);
|
|
|
|
|
long totalGroups = groupRepository.countByAppId(appId);
|
|
|
|
|
long todayMessages = messageRepository.countTodayByAppId(appId);
|
2026-04-29 00:34:17 +08:00
|
|
|
operationLogService.record(appId, operatorId, "VIEW_STATS", "STATS", null, "summary");
|
2026-04-24 16:16:33 +08:00
|
|
|
|
|
|
|
|
return ResponseEntity.ok(ApiResponse.success(Map.of(
|
|
|
|
|
"totalMessages", totalMessages,
|
|
|
|
|
"totalUsers", totalUsers,
|
|
|
|
|
"totalGroups", totalGroups,
|
|
|
|
|
"todayMessages", todayMessages
|
|
|
|
|
)));
|
|
|
|
|
}
|
2026-04-24 20:53:48 +08:00
|
|
|
|
2026-04-28 09:45:20 +08:00
|
|
|
/** Admin queries conversation history between any two users. */
|
|
|
|
|
@GetMapping("/messages")
|
|
|
|
|
public ResponseEntity<ApiResponse<Page<com.xuqm.im.entity.ImMessageEntity>>> history(
|
|
|
|
|
@RequestParam String appId,
|
2026-04-29 00:34:17 +08:00
|
|
|
@AuthenticationPrincipal String operatorId,
|
2026-04-28 09:45:20 +08:00
|
|
|
@RequestParam String userA,
|
|
|
|
|
@RequestParam String userB,
|
|
|
|
|
@RequestParam(required = false) com.xuqm.im.entity.ImMessageEntity.MsgType msgType,
|
|
|
|
|
@RequestParam(required = false) String keyword,
|
|
|
|
|
@RequestParam(required = false) LocalDateTime startTime,
|
|
|
|
|
@RequestParam(required = false) LocalDateTime endTime,
|
|
|
|
|
@RequestParam(defaultValue = "0") int page,
|
|
|
|
|
@RequestParam(defaultValue = "20") int size) {
|
2026-04-29 00:34:17 +08:00
|
|
|
operationLogService.record(appId, operatorId, "VIEW_HISTORY", "MESSAGE", userA + "," + userB, keyword);
|
2026-04-28 09:45:20 +08:00
|
|
|
return ResponseEntity.ok(ApiResponse.success(
|
|
|
|
|
messageRepository.findSingleConversationFiltered(
|
|
|
|
|
appId, userA, userB, msgType, keyword, startTime, endTime, PageRequest.of(page, size))));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Admin revokes an arbitrary message. */
|
|
|
|
|
@PostMapping("/messages/{messageId}/revoke")
|
|
|
|
|
public ResponseEntity<ApiResponse<com.xuqm.im.entity.ImMessageEntity>> adminRevoke(
|
|
|
|
|
@RequestParam String appId,
|
2026-04-29 00:34:17 +08:00
|
|
|
@AuthenticationPrincipal String operatorId,
|
2026-04-28 09:45:20 +08:00
|
|
|
@PathVariable String messageId) {
|
2026-04-29 00:34:17 +08:00
|
|
|
ImMessageEntity revoked = messageService.adminRevoke(appId, messageId);
|
|
|
|
|
operationLogService.record(appId, operatorId, "ADMIN_REVOKE_MESSAGE", "MESSAGE", messageId, null);
|
|
|
|
|
return ResponseEntity.ok(ApiResponse.success(revoked));
|
2026-04-28 09:45:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Admin force dismisses a group. */
|
|
|
|
|
@DeleteMapping("/groups/{groupId}")
|
2026-04-29 00:34:17 +08:00
|
|
|
public ResponseEntity<ApiResponse<Void>> adminDismissGroup(
|
|
|
|
|
@RequestParam String appId,
|
|
|
|
|
@AuthenticationPrincipal String operatorId,
|
|
|
|
|
@PathVariable String groupId) {
|
2026-04-28 09:45:20 +08:00
|
|
|
groupService.adminDismiss(groupId);
|
2026-04-29 00:34:17 +08:00
|
|
|
operationLogService.record(appId, operatorId, "ADMIN_DISMISS_GROUP", "GROUP", groupId, null);
|
2026-04-28 09:45:20 +08:00
|
|
|
return ResponseEntity.ok(ApiResponse.ok());
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-28 17:29:17 +08:00
|
|
|
@GetMapping("/webhooks")
|
|
|
|
|
public ResponseEntity<ApiResponse<List<WebhookConfigEntity>>> listWebhooks(@RequestParam String appId) {
|
|
|
|
|
return ResponseEntity.ok(ApiResponse.success(webhookConfigService.list(appId)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@PostMapping("/webhooks")
|
|
|
|
|
public ResponseEntity<ApiResponse<WebhookConfigEntity>> createWebhook(
|
|
|
|
|
@RequestParam String appId,
|
2026-04-29 00:34:17 +08:00
|
|
|
@AuthenticationPrincipal String operatorId,
|
2026-04-28 17:29:17 +08:00
|
|
|
@RequestBody WebhookConfigRequest req) {
|
2026-04-29 00:34:17 +08:00
|
|
|
WebhookConfigEntity saved = webhookConfigService.create(appId, req.url(), req.secret(), req.enabled());
|
|
|
|
|
operationLogService.record(appId, operatorId, "CREATE_WEBHOOK", "WEBHOOK", saved.getId(), req.url());
|
|
|
|
|
return ResponseEntity.ok(ApiResponse.success(saved));
|
2026-04-28 17:29:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@PutMapping("/webhooks/{id}")
|
|
|
|
|
public ResponseEntity<ApiResponse<WebhookConfigEntity>> updateWebhook(
|
|
|
|
|
@RequestParam String appId,
|
|
|
|
|
@PathVariable String id,
|
2026-04-29 00:34:17 +08:00
|
|
|
@AuthenticationPrincipal String operatorId,
|
2026-04-28 17:29:17 +08:00
|
|
|
@RequestBody WebhookConfigRequest req) {
|
2026-04-29 00:34:17 +08:00
|
|
|
WebhookConfigEntity saved = webhookConfigService.update(appId, id, req.url(), req.secret(), req.enabled());
|
|
|
|
|
operationLogService.record(appId, operatorId, "UPDATE_WEBHOOK", "WEBHOOK", id, req.url());
|
|
|
|
|
return ResponseEntity.ok(ApiResponse.success(saved));
|
2026-04-28 17:29:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@DeleteMapping("/webhooks/{id}")
|
|
|
|
|
public ResponseEntity<ApiResponse<Void>> deleteWebhook(
|
|
|
|
|
@RequestParam String appId,
|
2026-04-29 00:34:17 +08:00
|
|
|
@AuthenticationPrincipal String operatorId,
|
2026-04-28 17:29:17 +08:00
|
|
|
@PathVariable String id) {
|
|
|
|
|
webhookConfigService.delete(appId, id);
|
2026-04-29 00:34:17 +08:00
|
|
|
operationLogService.record(appId, operatorId, "DELETE_WEBHOOK", "WEBHOOK", id, null);
|
2026-04-28 17:29:17 +08:00
|
|
|
return ResponseEntity.ok(ApiResponse.ok());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@GetMapping("/keyword-filters")
|
|
|
|
|
public ResponseEntity<ApiResponse<List<KeywordFilterEntity>>> listKeywordFilters(@RequestParam String appId) {
|
|
|
|
|
return ResponseEntity.ok(ApiResponse.success(keywordFilterService.list(appId)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@PostMapping("/keyword-filters")
|
|
|
|
|
public ResponseEntity<ApiResponse<KeywordFilterEntity>> createKeywordFilter(
|
|
|
|
|
@RequestParam String appId,
|
2026-04-29 00:34:17 +08:00
|
|
|
@AuthenticationPrincipal String operatorId,
|
2026-04-28 17:29:17 +08:00
|
|
|
@RequestBody KeywordFilterRequest req) {
|
2026-04-29 00:34:17 +08:00
|
|
|
KeywordFilterEntity saved = keywordFilterService.add(appId, req.pattern(), req.replacement(), req.action());
|
|
|
|
|
operationLogService.record(appId, operatorId, "CREATE_KEYWORD_FILTER", "KEYWORD_FILTER", saved.getId(), req.pattern());
|
|
|
|
|
return ResponseEntity.ok(ApiResponse.success(saved));
|
2026-04-28 17:29:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@PutMapping("/keyword-filters/{id}")
|
|
|
|
|
public ResponseEntity<ApiResponse<KeywordFilterEntity>> updateKeywordFilter(
|
|
|
|
|
@RequestParam String appId,
|
|
|
|
|
@PathVariable String id,
|
2026-04-29 00:34:17 +08:00
|
|
|
@AuthenticationPrincipal String operatorId,
|
2026-04-28 17:29:17 +08:00
|
|
|
@RequestBody KeywordFilterRequest req) {
|
2026-04-29 00:34:17 +08:00
|
|
|
KeywordFilterEntity saved = keywordFilterService.update(appId, id, req.pattern(), req.replacement(), req.action(), req.enabled());
|
|
|
|
|
operationLogService.record(appId, operatorId, "UPDATE_KEYWORD_FILTER", "KEYWORD_FILTER", id, req.pattern());
|
|
|
|
|
return ResponseEntity.ok(ApiResponse.success(saved));
|
2026-04-28 17:29:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@DeleteMapping("/keyword-filters/{id}")
|
|
|
|
|
public ResponseEntity<ApiResponse<Void>> deleteKeywordFilter(
|
|
|
|
|
@RequestParam String appId,
|
2026-04-29 00:34:17 +08:00
|
|
|
@AuthenticationPrincipal String operatorId,
|
2026-04-28 17:29:17 +08:00
|
|
|
@PathVariable String id) {
|
|
|
|
|
keywordFilterService.delete(appId, id);
|
2026-04-29 00:34:17 +08:00
|
|
|
operationLogService.record(appId, operatorId, "DELETE_KEYWORD_FILTER", "KEYWORD_FILTER", id, null);
|
2026-04-28 17:29:17 +08:00
|
|
|
return ResponseEntity.ok(ApiResponse.ok());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@GetMapping("/global-mute")
|
|
|
|
|
public ResponseEntity<ApiResponse<ImGlobalMuteEntity>> getGlobalMute(@RequestParam String appId) {
|
|
|
|
|
return ResponseEntity.ok(ApiResponse.success(globalMuteService.get(appId)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@PutMapping("/global-mute")
|
|
|
|
|
public ResponseEntity<ApiResponse<ImGlobalMuteEntity>> setGlobalMute(
|
|
|
|
|
@RequestParam String appId,
|
2026-04-29 00:34:17 +08:00
|
|
|
@AuthenticationPrincipal String operatorId,
|
2026-04-28 17:29:17 +08:00
|
|
|
@RequestParam boolean enabled) {
|
2026-04-29 00:34:17 +08:00
|
|
|
ImGlobalMuteEntity saved = globalMuteService.setEnabled(appId, enabled);
|
|
|
|
|
operationLogService.record(appId, operatorId, "SET_GLOBAL_MUTE", "GLOBAL_MUTE", saved.getId(), String.valueOf(enabled));
|
|
|
|
|
return ResponseEntity.ok(ApiResponse.success(saved));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@GetMapping("/operation-logs")
|
|
|
|
|
public ResponseEntity<ApiResponse<Page<com.xuqm.im.entity.ImOperationLogEntity>>> operationLogs(
|
|
|
|
|
@RequestParam String appId,
|
|
|
|
|
@RequestParam(defaultValue = "0") int page,
|
|
|
|
|
@RequestParam(defaultValue = "20") int size) {
|
|
|
|
|
return ResponseEntity.ok(ApiResponse.success(
|
|
|
|
|
operationLogService.list(appId, PageRequest.of(page, size))));
|
2026-04-28 17:29:17 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-29 10:04:17 +08:00
|
|
|
public record RegisterUserRequest(
|
|
|
|
|
String userId,
|
|
|
|
|
String nickname,
|
|
|
|
|
String avatar,
|
|
|
|
|
ImAccountEntity.Gender gender,
|
|
|
|
|
ImAccountEntity.Status status) {}
|
|
|
|
|
public record UpdateUserRequest(
|
|
|
|
|
String nickname,
|
|
|
|
|
String avatar,
|
|
|
|
|
ImAccountEntity.Gender gender,
|
|
|
|
|
ImAccountEntity.Status status) {}
|
|
|
|
|
public record CreateGroupRequest(String name, String creatorId, List<String> memberIds, String groupType, String announcement) {}
|
|
|
|
|
public record UpdateGroupRequest(String name, String groupType, String announcement) {}
|
2026-04-28 17:29:17 +08:00
|
|
|
public record WebhookConfigRequest(String url, String secret, Boolean enabled) {}
|
|
|
|
|
public record KeywordFilterRequest(String pattern, String replacement, String action, Boolean enabled) {}
|
2026-04-24 16:16:33 +08:00
|
|
|
}
|