2026-04-21 22:07:29 +08:00
|
|
|
package com.xuqm.tenant.service;
|
|
|
|
|
|
2026-04-28 16:08:07 +08:00
|
|
|
import com.fasterxml.jackson.databind.JsonNode;
|
|
|
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
|
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
2026-04-21 22:07:29 +08:00
|
|
|
import com.xuqm.common.exception.BusinessException;
|
|
|
|
|
import com.xuqm.tenant.entity.FeatureServiceEntity;
|
2026-04-24 16:46:38 +08:00
|
|
|
import com.xuqm.tenant.entity.ServiceActivationRequestEntity;
|
|
|
|
|
import com.xuqm.tenant.entity.ServiceActivationRequestEntity.Status;
|
2026-04-21 22:07:29 +08:00
|
|
|
import com.xuqm.tenant.repository.FeatureServiceRepository;
|
2026-04-24 16:46:38 +08:00
|
|
|
import com.xuqm.tenant.repository.ServiceActivationRequestRepository;
|
2026-04-21 22:07:29 +08:00
|
|
|
import org.springframework.stereotype.Service;
|
2026-04-24 16:46:38 +08:00
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
2026-04-21 22:07:29 +08:00
|
|
|
|
|
|
|
|
import java.time.LocalDateTime;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.UUID;
|
|
|
|
|
|
|
|
|
|
@Service
|
|
|
|
|
public class FeatureServiceManager {
|
|
|
|
|
|
|
|
|
|
private final FeatureServiceRepository repository;
|
2026-04-24 16:46:38 +08:00
|
|
|
private final ServiceActivationRequestRepository requestRepository;
|
2026-04-28 16:08:07 +08:00
|
|
|
private final ObjectMapper objectMapper;
|
2026-04-21 22:07:29 +08:00
|
|
|
|
2026-04-24 16:46:38 +08:00
|
|
|
public FeatureServiceManager(FeatureServiceRepository repository,
|
2026-04-28 16:08:07 +08:00
|
|
|
ServiceActivationRequestRepository requestRepository,
|
|
|
|
|
ObjectMapper objectMapper) {
|
2026-04-21 22:07:29 +08:00
|
|
|
this.repository = repository;
|
2026-04-24 16:46:38 +08:00
|
|
|
this.requestRepository = requestRepository;
|
2026-04-28 16:08:07 +08:00
|
|
|
this.objectMapper = objectMapper;
|
2026-04-21 22:07:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public List<FeatureServiceEntity> listByApp(String appId) {
|
|
|
|
|
return repository.findByAppId(appId);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-24 16:46:38 +08:00
|
|
|
/**
|
|
|
|
|
* Submit an activation request. Disabling is immediate; enabling requires ops approval.
|
|
|
|
|
*/
|
|
|
|
|
@Transactional
|
|
|
|
|
public ServiceActivationRequestEntity submitActivationRequest(
|
|
|
|
|
String appId,
|
|
|
|
|
FeatureServiceEntity.Platform platform,
|
|
|
|
|
FeatureServiceEntity.ServiceType serviceType,
|
|
|
|
|
String applyReason) {
|
|
|
|
|
|
|
|
|
|
// Check if there's already a pending request
|
|
|
|
|
requestRepository.findFirstByAppIdAndPlatformAndServiceTypeOrderByCreatedAtDesc(appId, platform, serviceType)
|
|
|
|
|
.ifPresent(req -> {
|
|
|
|
|
if (req.getStatus() == Status.PENDING) {
|
|
|
|
|
throw new BusinessException(400, "已有待审核的开通申请,请等待运营人员处理");
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
ServiceActivationRequestEntity req = new ServiceActivationRequestEntity();
|
|
|
|
|
req.setId(UUID.randomUUID().toString());
|
|
|
|
|
req.setAppId(appId);
|
|
|
|
|
req.setPlatform(platform);
|
|
|
|
|
req.setServiceType(serviceType);
|
|
|
|
|
req.setStatus(Status.PENDING);
|
|
|
|
|
req.setApplyReason(applyReason);
|
|
|
|
|
req.setCreatedAt(LocalDateTime.now());
|
|
|
|
|
return requestRepository.save(req);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Disable a service immediately (no approval needed).
|
|
|
|
|
*/
|
|
|
|
|
@Transactional
|
|
|
|
|
public FeatureServiceEntity disable(String appId, FeatureServiceEntity.Platform platform,
|
|
|
|
|
FeatureServiceEntity.ServiceType serviceType) {
|
2026-04-21 22:07:29 +08:00
|
|
|
FeatureServiceEntity entity = repository
|
|
|
|
|
.findByAppIdAndPlatformAndServiceType(appId, platform, serviceType)
|
2026-04-24 16:46:38 +08:00
|
|
|
.orElseThrow(() -> new BusinessException(404, "服务未开通"));
|
|
|
|
|
entity.setEnabled(false);
|
|
|
|
|
return repository.save(entity);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Called by ops when approving an activation request.
|
|
|
|
|
*/
|
|
|
|
|
@Transactional
|
|
|
|
|
public ServiceActivationRequestEntity approveRequest(String requestId, String reviewNote) {
|
|
|
|
|
ServiceActivationRequestEntity req = requestRepository.findById(requestId)
|
|
|
|
|
.orElseThrow(() -> new BusinessException(404, "申请不存在"));
|
|
|
|
|
if (req.getStatus() != Status.PENDING) {
|
|
|
|
|
throw new BusinessException(400, "申请已处理");
|
|
|
|
|
}
|
|
|
|
|
req.setStatus(Status.APPROVED);
|
|
|
|
|
req.setReviewNote(reviewNote);
|
|
|
|
|
req.setReviewedAt(LocalDateTime.now());
|
|
|
|
|
requestRepository.save(req);
|
|
|
|
|
|
|
|
|
|
// Activate the service
|
|
|
|
|
FeatureServiceEntity entity = repository
|
|
|
|
|
.findByAppIdAndPlatformAndServiceType(req.getAppId(), req.getPlatform(), req.getServiceType())
|
2026-04-21 22:07:29 +08:00
|
|
|
.orElseGet(() -> {
|
|
|
|
|
FeatureServiceEntity e = new FeatureServiceEntity();
|
|
|
|
|
e.setId(UUID.randomUUID().toString());
|
2026-04-24 16:46:38 +08:00
|
|
|
e.setAppId(req.getAppId());
|
|
|
|
|
e.setPlatform(req.getPlatform());
|
|
|
|
|
e.setServiceType(req.getServiceType());
|
2026-04-21 22:07:29 +08:00
|
|
|
e.setCreatedAt(LocalDateTime.now());
|
|
|
|
|
return e;
|
|
|
|
|
});
|
2026-04-24 16:46:38 +08:00
|
|
|
entity.setEnabled(true);
|
|
|
|
|
repository.save(entity);
|
|
|
|
|
return req;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Called by ops when rejecting an activation request.
|
|
|
|
|
*/
|
|
|
|
|
@Transactional
|
|
|
|
|
public ServiceActivationRequestEntity rejectRequest(String requestId, String reviewNote) {
|
|
|
|
|
ServiceActivationRequestEntity req = requestRepository.findById(requestId)
|
|
|
|
|
.orElseThrow(() -> new BusinessException(404, "申请不存在"));
|
|
|
|
|
if (req.getStatus() != Status.PENDING) {
|
|
|
|
|
throw new BusinessException(400, "申请已处理");
|
|
|
|
|
}
|
|
|
|
|
req.setStatus(Status.REJECTED);
|
|
|
|
|
req.setReviewNote(reviewNote);
|
|
|
|
|
req.setReviewedAt(LocalDateTime.now());
|
|
|
|
|
return requestRepository.save(req);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public List<ServiceActivationRequestEntity> listRequestsByApp(String appId) {
|
|
|
|
|
return requestRepository.findByAppIdOrderByCreatedAtDesc(appId);
|
2026-04-21 22:07:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public FeatureServiceEntity getOrFail(String appId, FeatureServiceEntity.Platform platform,
|
|
|
|
|
FeatureServiceEntity.ServiceType serviceType) {
|
|
|
|
|
return repository.findByAppIdAndPlatformAndServiceType(appId, platform, serviceType)
|
|
|
|
|
.orElseThrow(() -> new BusinessException(404, "服务未配置"));
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-28 16:08:07 +08:00
|
|
|
@Transactional
|
|
|
|
|
public FeatureServiceEntity updateConfig(String appId,
|
|
|
|
|
FeatureServiceEntity.Platform platform,
|
|
|
|
|
FeatureServiceEntity.ServiceType serviceType,
|
|
|
|
|
String config) {
|
|
|
|
|
FeatureServiceEntity entity = getOrFail(appId, platform, serviceType);
|
|
|
|
|
entity.setConfig(config);
|
|
|
|
|
return repository.save(entity);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean allowStrangerMessage(String appId,
|
|
|
|
|
FeatureServiceEntity.Platform platform,
|
|
|
|
|
FeatureServiceEntity.ServiceType serviceType) {
|
|
|
|
|
FeatureServiceEntity entity = repository.findByAppIdAndPlatformAndServiceType(appId, platform, serviceType)
|
|
|
|
|
.orElse(null);
|
|
|
|
|
if (entity == null || entity.getConfig() == null || entity.getConfig().isBlank()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
JsonNode node = objectMapper.readTree(entity.getConfig());
|
|
|
|
|
return node.path("allowStrangerMessage").asBoolean(false);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public String buildAllowStrangerConfig(boolean allowStrangerMessage) {
|
|
|
|
|
ObjectNode node = objectMapper.createObjectNode();
|
|
|
|
|
node.put("allowStrangerMessage", allowStrangerMessage);
|
|
|
|
|
return node.toString();
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-21 22:07:29 +08:00
|
|
|
}
|