比较提交

..

没有共同的提交。cf2013a52dd27c01b9171285598bea43847cf22e 和 0385b2010adbc557cdaeaa938f64e8016b4cc6fb 的历史完全不同。

共有 109 个文件被更改,包括 1014 次插入1534 次删除

查看文件

@ -1,10 +0,0 @@
.git
.idea
.gradle
**/target
**/build
**/dist
**/node_modules
**/.DS_Store
**/*.log
*.iml

查看文件

@ -1 +1 @@
21 17

查看文件

@ -1,4 +1,3 @@
# syntax=docker/dockerfile:1.7
ARG SERVICE_MODULE=tenant-service ARG SERVICE_MODULE=tenant-service
FROM maven:3.9.9-eclipse-temurin-21 AS build FROM maven:3.9.9-eclipse-temurin-21 AS build
@ -6,7 +5,6 @@ ARG SERVICE_MODULE
WORKDIR /workspace WORKDIR /workspace
COPY pom.xml ./pom.xml COPY pom.xml ./pom.xml
COPY maven-settings.xml ./maven-settings.xml
COPY common ./common COPY common ./common
COPY im-sdk ./im-sdk COPY im-sdk ./im-sdk
COPY tenant-service ./tenant-service COPY tenant-service ./tenant-service
@ -16,8 +14,7 @@ COPY update-service ./update-service
COPY demo-service ./demo-service COPY demo-service ./demo-service
COPY file-service ./file-service COPY file-service ./file-service
RUN --mount=type=cache,target=/root/.m2,sharing=locked \ RUN mvn -pl ${SERVICE_MODULE} -am -DskipTests package
mvn -s /workspace/maven-settings.xml -pl ${SERVICE_MODULE} -am -DskipTests package
FROM eclipse-temurin:21-jre-jammy FROM eclipse-temurin:21-jre-jammy
WORKDIR /app WORKDIR /app

4
Jenkinsfile vendored
查看文件

@ -15,7 +15,6 @@ pipeline {
PROD_HOST = '106.54.23.149' PROD_HOST = '106.54.23.149'
PROD_USER = 'ubuntu' PROD_USER = 'ubuntu'
COMPOSE_FILE = '/opt/xuqm/deploy/compose.production.yaml' COMPOSE_FILE = '/opt/xuqm/deploy/compose.production.yaml'
DOCKER_BUILDKIT = '1'
} }
stages { stages {
@ -30,8 +29,7 @@ pipeline {
def imageName = "${ACR_REGISTRY}/${ACR_NAMESPACE}/${params.SERVICE}:${params.IMAGE_TAG}" def imageName = "${ACR_REGISTRY}/${ACR_NAMESPACE}/${params.SERVICE}:${params.IMAGE_TAG}"
bat """ bat """
docker login ${ACR_REGISTRY} -u ${ACR_USERNAME} -p %ACR_PASS% docker login ${ACR_REGISTRY} -u ${ACR_USERNAME} -p %ACR_PASS%
docker pull ${imageName} || exit 0 docker build --build-arg SERVICE_MODULE=${params.SERVICE} -t ${imageName} .
docker build --build-arg SERVICE_MODULE=${params.SERVICE} --build-arg BUILDKIT_INLINE_CACHE=1 --cache-from ${imageName} -t ${imageName} .
docker push ${imageName} docker push ${imageName}
docker rmi ${imageName} docker rmi ${imageName}
""" """

查看文件

@ -138,15 +138,15 @@ cd update-service && mvn spring-boot:run &
} }
``` ```
> 说明SDK 和 demo 侧统一`appKey`。当前默认值是 `ak_demo_chat`,如果数据库里没有这条记录,tenant-service 会在启动时自动创建。 > 说明SDK 和 demo 侧传入的 `appId` 实际按 `appKey` 解析。当前默认值是 `ak_demo_chat`,如果数据库里没有这条记录,tenant-service 会在启动时自动创建。
#### 功能服务(需 Token #### 功能服务(需 Token
| 方法 | 路径 | 说明 | | 方法 | 路径 | 说明 |
|------|------|------| |------|------|------|
| GET | `/api/apps/{appKey}/services` | 获取应用下所有功能服务 | | GET | `/api/apps/{appId}/services` | 获取应用下所有功能服务 |
| POST | `/api/apps/{appKey}/services/toggle?platform=&serviceType=&enable=` | 开启/关闭功能服务 | | POST | `/api/apps/{appId}/services/toggle?platform=&serviceType=&enable=` | 开启/关闭功能服务 |
| POST | `/api/apps/{appKey}/services/{id}/regenerate-key` | 重新生成 secretKey | | POST | `/api/apps/{appId}/services/{id}/regenerate-key` | 重新生成 secretKey |
**platform 枚举**`ANDROID` / `IOS` / `HARMONY` **platform 枚举**`ANDROID` / `IOS` / `HARMONY`
**serviceType 枚举**`IM` / `PUSH` / `UPDATE` **serviceType 枚举**`IM` / `PUSH` / `UPDATE`
@ -216,7 +216,7 @@ cd update-service && mvn spring-boot:run &
``` ```
POST /api/im/auth/login POST /api/im/auth/login
?appKey=ak_xxx ?appId=ak_xxx
&userId=user_001 &userId=user_001
&nickname=张三 (可选,仅首次注册时存入外部系统) &nickname=张三 (可选,仅首次注册时存入外部系统)
&avatar=https://... (可选) &avatar=https://... (可选)
@ -230,9 +230,9 @@ POST /api/im/auth/login
| 方法 | 路径 | 说明 | | 方法 | 路径 | 说明 |
|------|------|------| |------|------|------|
| POST | `/api/im/messages/send?appKey=` | 发送消息 | | POST | `/api/im/messages/send?appId=` | 发送消息 |
| POST | `/api/im/messages/{id}/revoke?appKey=` | 撤回消息 | | POST | `/api/im/messages/{id}/revoke?appId=` | 撤回消息 |
| GET | `/api/im/messages/history/{toId}?appKey=&page=&size=` | 查询历史消息 | | GET | `/api/im/messages/history/{toId}?appId=&page=&size=` | 查询历史消息 |
**发送消息请求体** **发送消息请求体**
```json ```json
@ -276,7 +276,7 @@ ws://localhost:8082/ws/im?token=<im_jwt>
{ {
"destination": "/app/chat.send", "destination": "/app/chat.send",
"payload": { "payload": {
"appKey": "ak_xxx", "appId": "ak_xxx",
"toId": "user_002", "toId": "user_002",
"chatType": "SINGLE", "chatType": "SINGLE",
"msgType": "TEXT", "msgType": "TEXT",
@ -310,7 +310,7 @@ Frame 格式:
```json ```json
{ {
"destination": "/app/chat.revoke", "destination": "/app/chat.revoke",
"payload": { "appKey": "ak_xxx", "messageId": "msg-uuid" } "payload": { "appId": "ak_xxx", "messageId": "msg-uuid" }
} }
``` ```
@ -332,7 +332,7 @@ Frame 格式:
```json ```json
{ {
"event": "message", "event": "message",
"appKey": "ak_xxx", "appId": "ak_xxx",
"message": { ...消息对象... } "message": { ...消息对象... }
} }
``` ```
@ -345,11 +345,11 @@ Frame 格式:
| 表名 | 说明 | | 表名 | 说明 |
|------|------| |------|------|
| `push_device_token` | 设备推送 tokenappKey + userId + vendor 唯一) | | `push_device_token` | 设备推送 tokenappId + userId + vendor 唯一) |
### 支持厂商 ### 支持厂商
`HUAWEI` / `XIAOMI` / `OPPO` / `VIVO` / `HONOR` / `APNS`iOS `HUAWEI` / `XIAOMI` / `OPPO` / `VIVO` / `HONOR` / `APNS`iOS/ `FCM`
### 接口 ### 接口
@ -366,7 +366,7 @@ Frame 格式:
**注册 token** **注册 token**
``` ```
POST /api/push/register POST /api/push/register
?appKey=ak_xxx ?appId=ak_xxx
&userId=user_001 &userId=user_001
&vendor=HUAWEI &vendor=HUAWEI
&token=device_push_token &token=device_push_token
@ -375,7 +375,7 @@ POST /api/push/register
**发送推送** **发送推送**
``` ```
POST /api/push/send POST /api/push/send
?appKey=ak_xxx ?appId=ak_xxx
&userId=user_001 &userId=user_001
&title=新消息 &title=新消息
&body=张三: Hello! &body=张三: Hello!
@ -385,7 +385,7 @@ POST /api/push/send
**开关接收推送** **开关接收推送**
``` ```
POST /api/push/receive-push POST /api/push/receive-push
?appKey=ak_xxx ?appId=ak_xxx
&userId=user_001 &userId=user_001
&enabled=false &enabled=false
``` ```
@ -393,7 +393,7 @@ POST /api/push/receive-push
**内部通知** **内部通知**
```json ```json
{ {
"appKey": "ak_xxx", "appId": "ak_xxx",
"userIds": ["user_001", "user_002"], "userIds": ["user_001", "user_002"],
"title": "群聊消息", "title": "群聊消息",
"body": "张三: Hello!", "body": "张三: Hello!",
@ -437,12 +437,11 @@ push:
| POST | `/api/v1/updates/app/upload` | 上传版本(先传 file-service,再把 `apkUrl` 交给 update-service | | POST | `/api/v1/updates/app/upload` | 上传版本(先传 file-service,再把 `apkUrl` 交给 update-service |
| POST | `/api/v1/updates/app/{id}/publish` | 发布版本 | | POST | `/api/v1/updates/app/{id}/publish` | 发布版本 |
| GET | `/api/v1/updates/app/list` | 版本列表 | | GET | `/api/v1/updates/app/list` | 版本列表 |
| POST | `/api/v1/updates/store/app/{id}/execute-submit` | 批量提交应用市场,过程会写入批次日志与逐市场状态 |
**检查更新** **检查更新**
``` ```
GET /api/v1/updates/app/check GET /api/v1/updates/app/check
?appKey=ak_xxx ?appId=ak_xxx
&platform=ANDROID &platform=ANDROID
&currentVersionCode=10 &currentVersionCode=10
``` ```
@ -465,8 +464,6 @@ GET /api/v1/updates/app/check
**platform 枚举**`ANDROID` / `IOS` / `HARMONY` **platform 枚举**`ANDROID` / `IOS` / `HARMONY`
**市场提审状态**`PENDING` / `SUBMITTING` / `UNDER_REVIEW` / `APPROVED` / `REJECTED`
**上传 APK两段式** **上传 APK两段式**
``` ```
POST /api/file/upload POST /api/file/upload
@ -477,7 +474,7 @@ POST /api/file/upload
``` ```
POST /api/v1/updates/app/upload POST /api/v1/updates/app/upload
appKey=ak_xxx appId=ak_xxx
platform=ANDROID platform=ANDROID
versionName=1.1.0 versionName=1.1.0
versionCode=11 versionCode=11
@ -497,7 +494,7 @@ POST /api/v1/updates/app/upload
**检查 RN 更新** **检查 RN 更新**
``` ```
GET /api/v1/rn/update/check GET /api/v1/rn/update/check
?appKey=ak_xxx ?appId=ak_xxx
&moduleId=main &moduleId=main
&platform=android &platform=android
&currentVersion=1.0.0 &currentVersion=1.0.0
@ -520,7 +517,7 @@ GET /api/v1/rn/update/check
**上传 Bundlemultipart/form-data** **上传 Bundlemultipart/form-data**
``` ```
POST /api/v1/rn/upload POST /api/v1/rn/upload
appKey=ak_xxx appId=ak_xxx
moduleId=main moduleId=main
platform=ANDROID platform=ANDROID
version=1.1.0 version=1.1.0
@ -529,7 +526,7 @@ POST /api/v1/rn/upload
bundle=<binary .bundle 文件> bundle=<binary .bundle 文件>
``` ```
服务端自动计算 MD5,存储至 `{upload-dir}/rn/{appKey}/{platform}/{moduleId}/`。 服务端自动计算 MD5,存储至 `{upload-dir}/rn/{appId}/{platform}/{moduleId}/`。
### 环境变量配置 ### 环境变量配置

查看文件

@ -6,7 +6,7 @@ import java.time.Instant;
@Entity @Entity
@Table( @Table(
name = "demo_user", name = "demo_user",
uniqueConstraints = @UniqueConstraint(name = "uq_demo_user_appkey_userid", columnNames = {"app_key", "user_id"}) uniqueConstraints = @UniqueConstraint(name = "uq_demo_user_appid_userid", columnNames = {"app_id", "user_id"})
) )
public class DemoUserEntity { public class DemoUserEntity {
@ -18,8 +18,8 @@ public class DemoUserEntity {
@Column(name = "id", length = 36, nullable = false, updatable = false) @Column(name = "id", length = 36, nullable = false, updatable = false)
private String id; private String id;
@Column(name = "app_key", length = 64, nullable = false) @Column(name = "app_id", length = 64, nullable = false)
private String appKey; private String appId;
@Column(name = "user_id", length = 128, nullable = false) @Column(name = "user_id", length = 128, nullable = false)
private String userId; private String userId;
@ -43,8 +43,8 @@ public class DemoUserEntity {
public String getId() { return id; } public String getId() { return id; }
public void setId(String id) { this.id = id; } public void setId(String id) { this.id = id; }
public String getAppKey() { return appKey; } public String getAppId() { return appId; }
public void setAppKey(String appKey) { this.appKey = appKey; } public void setAppId(String appId) { this.appId = appId; }
public String getUserId() { return userId; } public String getUserId() { return userId; }
public void setUserId(String userId) { this.userId = userId; } public void setUserId(String userId) { this.userId = userId; }

查看文件

@ -10,14 +10,14 @@ import java.util.Optional;
public interface DemoUserRepository extends JpaRepository<DemoUserEntity, String> { public interface DemoUserRepository extends JpaRepository<DemoUserEntity, String> {
Optional<DemoUserEntity> findByAppKeyAndUserId(String appKey, String userId); Optional<DemoUserEntity> findByAppIdAndUserId(String appId, String userId);
boolean existsByAppKeyAndUserId(String appKey, String userId); boolean existsByAppIdAndUserId(String appId, String userId);
@Query("SELECT u FROM DemoUserEntity u WHERE u.appKey = :appKey AND " + @Query("SELECT u FROM DemoUserEntity u WHERE u.appId = :appId AND " +
"(LOWER(u.userId) LIKE LOWER(CONCAT('%', :keyword, '%')) OR " + "(LOWER(u.userId) LIKE LOWER(CONCAT('%', :keyword, '%')) OR " +
"LOWER(u.nickname) LIKE LOWER(CONCAT('%', :keyword, '%')))") "LOWER(u.nickname) LIKE LOWER(CONCAT('%', :keyword, '%')))")
List<DemoUserEntity> searchByKeyword(@Param("appKey") String appKey, @Param("keyword") String keyword); List<DemoUserEntity> searchByKeyword(@Param("appId") String appId, @Param("keyword") String keyword);
List<DemoUserEntity> findAllByAppKeyOrderByCreatedAtAsc(String appKey); List<DemoUserEntity> findAllByAppIdOrderByCreatedAtAsc(String appId);
} }

查看文件

@ -58,13 +58,13 @@ public class DemoAuthService {
@Transactional @Transactional
public AuthResult register(String appKey, String userId, String password, String nickname) { public AuthResult register(String appKey, String userId, String password, String nickname) {
if (userRepository.existsByAppKeyAndUserId(appKey, userId)) { if (userRepository.existsByAppIdAndUserId(appKey, userId)) {
throw new BusinessException(409, "User already exists: " + userId); throw new BusinessException(409, "User already exists: " + userId);
} }
DemoUserEntity user = new DemoUserEntity(); DemoUserEntity user = new DemoUserEntity();
user.setId(UUID.randomUUID().toString()); user.setId(UUID.randomUUID().toString());
user.setAppKey(appKey); user.setAppId(appKey);
user.setUserId(userId); user.setUserId(userId);
user.setPasswordHash(passwordEncoder.encode(password)); user.setPasswordHash(passwordEncoder.encode(password));
user.setNickname(nickname != null ? nickname : userId); user.setNickname(nickname != null ? nickname : userId);
@ -84,7 +84,7 @@ public class DemoAuthService {
@Transactional(readOnly = true) @Transactional(readOnly = true)
public AuthResult login(String appKey, String userId, String password) { public AuthResult login(String appKey, String userId, String password) {
DemoUserEntity user = userRepository.findByAppKeyAndUserId(appKey, userId) DemoUserEntity user = userRepository.findByAppIdAndUserId(appKey, userId)
.orElseThrow(() -> new BusinessException(401, "Invalid credentials")); .orElseThrow(() -> new BusinessException(401, "Invalid credentials"));
if (!passwordEncoder.matches(password, user.getPasswordHash())) { if (!passwordEncoder.matches(password, user.getPasswordHash())) {
@ -103,7 +103,7 @@ public class DemoAuthService {
@Transactional @Transactional
public void resetPassword(String appKey, String userId, String newPassword) { public void resetPassword(String appKey, String userId, String newPassword) {
DemoUserEntity user = userRepository.findByAppKeyAndUserId(appKey, userId) DemoUserEntity user = userRepository.findByAppIdAndUserId(appKey, userId)
.orElseThrow(() -> new BusinessException(404, "User not found: " + userId)); .orElseThrow(() -> new BusinessException(404, "User not found: " + userId));
user.setPasswordHash(passwordEncoder.encode(newPassword)); user.setPasswordHash(passwordEncoder.encode(newPassword));
userRepository.save(user); userRepository.save(user);
@ -161,7 +161,7 @@ public class DemoAuthService {
private UserProfile toProfile(DemoUserEntity user) { private UserProfile toProfile(DemoUserEntity user) {
return new UserProfile( return new UserProfile(
user.getAppKey(), user.getAppId(),
user.getUserId(), user.getUserId(),
user.getNickname(), user.getNickname(),
user.getAvatar(), user.getAvatar(),

查看文件

@ -24,14 +24,14 @@ public class DemoUserService {
@Transactional(readOnly = true) @Transactional(readOnly = true)
public UserProfile getProfile(String appKey, String userId) { public UserProfile getProfile(String appKey, String userId) {
DemoUserEntity user = userRepository.findByAppKeyAndUserId(appKey, userId) DemoUserEntity user = userRepository.findByAppIdAndUserId(appKey, userId)
.orElseThrow(() -> new BusinessException(404, "User not found")); .orElseThrow(() -> new BusinessException(404, "User not found"));
return toProfile(user); return toProfile(user);
} }
@Transactional @Transactional
public UserProfile updateProfile(String appKey, String userId, String nickname, String avatar, String gender) { public UserProfile updateProfile(String appKey, String userId, String nickname, String avatar, String gender) {
DemoUserEntity user = userRepository.findByAppKeyAndUserId(appKey, userId) DemoUserEntity user = userRepository.findByAppIdAndUserId(appKey, userId)
.orElseThrow(() -> new BusinessException(404, "User not found")); .orElseThrow(() -> new BusinessException(404, "User not found"));
if (nickname != null && !nickname.isBlank()) { if (nickname != null && !nickname.isBlank()) {
@ -54,7 +54,7 @@ public class DemoUserService {
@Transactional @Transactional
public void resetPassword(String appKey, String userId, String oldPassword, String newPassword) { public void resetPassword(String appKey, String userId, String oldPassword, String newPassword) {
DemoUserEntity user = userRepository.findByAppKeyAndUserId(appKey, userId) DemoUserEntity user = userRepository.findByAppIdAndUserId(appKey, userId)
.orElseThrow(() -> new BusinessException(404, "User not found")); .orElseThrow(() -> new BusinessException(404, "User not found"));
if (!passwordEncoder.matches(oldPassword, user.getPasswordHash())) { if (!passwordEncoder.matches(oldPassword, user.getPasswordHash())) {
@ -81,7 +81,7 @@ public class DemoUserService {
@Transactional(readOnly = true) @Transactional(readOnly = true)
public List<UserProfile> listMembers(String appKey) { public List<UserProfile> listMembers(String appKey) {
return userRepository.findAllByAppKeyOrderByCreatedAtAsc(appKey) return userRepository.findAllByAppIdOrderByCreatedAtAsc(appKey)
.stream() .stream()
.map(this::toProfile) .map(this::toProfile)
.toList(); .toList();
@ -89,7 +89,7 @@ public class DemoUserService {
private UserProfile toProfile(DemoUserEntity user) { private UserProfile toProfile(DemoUserEntity user) {
return new UserProfile( return new UserProfile(
user.getAppKey(), user.getAppId(),
user.getUserId(), user.getUserId(),
user.getNickname(), user.getNickname(),
user.getAvatar(), user.getAvatar(),

查看文件

@ -20,14 +20,14 @@
| 名称 | 含义 | 常见位置 | | 名称 | 含义 | 常见位置 |
|------|------|----------| |------|------|----------|
| `tenant appKey` | 租户平台应用唯一标识,`tenant-service` 的 `/api/apps/{appKey}`、`/api/apps/{appKey}/services` 使用它 | 租户平台、服务配置页 | | `tenant appKey` | 租户平台应用唯一标识,`tenant-service` 的 `/api/apps/{appKey}`、`/api/apps/{appKey}/services` 使用它 | 租户平台、服务配置页 |
| `IM appKey` | IM 业务域作用域标识,`im-service` 的管理接口和消息接口统一使用它 | IM 管理页、IM HTTP 接口 | | `IM appKey` | IM 业务域作用域标识,`im-service` 的管理接口和消息接口虽然历史参数名仍叫 `appId`,但实际传的是这个值 | IM 管理页、IM HTTP 接口 |
结论: 结论:
- `tenant-platform` 的“服务配置”只认租户 `appKey` - `tenant-platform` 的“服务配置”只认租户 `appKey`
- `tenant-platform` 的“IM 管理”必须带 `appKey` - `tenant-platform` 的“IM 管理”必须带 `appKey`
- `tenant-platform` 的“离线推送 / 版本管理”只需要一次开通,平台差异配置在各自的管理页里维护,不再按 Android / iOS / 鸿蒙分别申请开通 - `tenant-platform` 的“离线推送 / 版本管理”只需要一次开通,平台差异配置在各自的管理页里维护,不再按 Android / iOS / 鸿蒙分别申请开通
- `im-service` 的对外协议统一使用 `appKey` - `im-service` 代码里沿用旧参数名 `appId`,但这是历史命名,调用方传的是 `appKey`
## 初始化管理员账号 ## 初始化管理员账号
@ -184,8 +184,6 @@
- RN bundle 建议打成 zip 后再上传,zip 内至少包含 `rn-manifest.json`、bundle 文件和资源文件;update-service 会优先从 manifest 自动读取 `moduleId`、`version` / `bundleVersion`、`minCommonVersion` 和 `packageName` - RN bundle 建议打成 zip 后再上传,zip 内至少包含 `rn-manifest.json`、bundle 文件和资源文件;update-service 会优先从 manifest 自动读取 `moduleId`、`version` / `bundleVersion`、`minCommonVersion` 和 `packageName`
- 租户平台里的“发布配置”标签页保存灰度默认模式、成员目录同步回调和成员选择回调;当默认模式切到成员灰度时,至少要配置一个回调才允许保存,保存前也会做连通性校验。 - 租户平台里的“发布配置”标签页保存灰度默认模式、成员目录同步回调和成员选择回调;当默认模式切到成员灰度时,至少要配置一个回调才允许保存,保存前也会做连通性校验。
- 上下架、上传、发布、灰度、市场提交、商店配置变更都会写入 `update_operation_log`,可通过 `GET /api/v1/updates/ops/logs?appKey=...` 查询。 - 上下架、上传、发布、灰度、市场提交、商店配置变更都会写入 `update_operation_log`,可通过 `GET /api/v1/updates/ops/logs?appKey=...` 查询。
- 市场提交增加了批次级日志和逐市场阶段日志,常见 action 包括 `STORE_SUBMIT_REQUEST`、`STORE_SUBMIT_BATCH_START`、`STORE_SUBMIT_STORE_START`、`STORE_SUBMIT_STORE_STAGE`、`STORE_SUBMIT_STORE_SUCCESS`、`STORE_SUBMIT_STORE_FAILED`、`STORE_SUBMIT_BATCH_END`。
- `storeReviewStatus` 的单市场状态除了 `PENDING / UNDER_REVIEW / APPROVED / REJECTED` 之外,还会出现 `SUBMITTING`,表示当前已经进入提审流程但尚未返回最终结果;详情页会额外显示阶段、提交时间和批次 ID。
- 提交应用市场会真实调用已实现的厂商接口。小米、OPPO、vivo 和华为/荣耀当前支持服务端提交;App Store、Google Play、鸿蒙仍以跳转页和人工流程为主。 - 提交应用市场会真实调用已实现的厂商接口。小米、OPPO、vivo 和华为/荣耀当前支持服务端提交;App Store、Google Play、鸿蒙仍以跳转页和人工流程为主。
- 租户平台控制台新增 `GET /api/dashboard/stats`,返回当前租户的应用数、已开通服务数和子账号数,同时会写一条 `CONSOLE / DASHBOARD / VIEW_DASHBOARD` 操作日志。 - 租户平台控制台新增 `GET /api/dashboard/stats`,返回当前租户的应用数、已开通服务数和子账号数,同时会写一条 `CONSOLE / DASHBOARD / VIEW_DASHBOARD` 操作日志。
- 租户平台“操作日志”菜单现在集中查看租户平台与版本管理两类日志;版本管理日志继续按 `appKey` 查询,控制台访问日志则落在 `t_operation_log` - 租户平台“操作日志”菜单现在集中查看租户平台与版本管理两类日志;版本管理日志继续按 `appKey` 查询,控制台访问日志则落在 `t_operation_log`
@ -345,7 +343,7 @@ IM 服务会在消息、好友和已读等事件发生后,以 `POST` 方式向
请求头: 请求头:
- `Content-Type: application/json` - `Content-Type: application/json`
- `X-App-Key`: 应用 `appKey` - `X-App-Id`: 应用 `appId`
- `X-App-Timestamp`: 请求时间戳 - `X-App-Timestamp`: 请求时间戳
- `X-App-Nonce`: 随机串 - `X-App-Nonce`: 随机串
- `X-App-Signature`: 签名结果 - `X-App-Signature`: 签名结果
@ -353,7 +351,7 @@ IM 服务会在消息、好友和已读等事件发生后,以 `POST` 方式向
签名规则: 签名规则:
```text ```text
HMAC-SHA256(appSecret, appKey + "\n" + timestamp + "\n" + nonce + "\n" + sha256(body)) HMAC-SHA256(appSecret, appId + "\n" + timestamp + "\n" + nonce + "\n" + sha256(body))
``` ```
统一请求体结构: 统一请求体结构:
@ -366,7 +364,7 @@ HMAC-SHA256(appSecret, appKey + "\n" + timestamp + "\n" + nonce + "\n" + sha256(
"requestTime": 1714360000000, "requestTime": 1714360000000,
"payload": {}, "payload": {},
"signature": null, "signature": null,
"appKey": "ak_demo_chat" "appId": "ak_demo_chat"
} }
``` ```
@ -380,7 +378,7 @@ HMAC-SHA256(appSecret, appKey + "\n" + timestamp + "\n" + nonce + "\n" + sha256(
| `requestTime` | 毫秒时间戳 | | `requestTime` | 毫秒时间戳 |
| `payload` | 事件数据,结构随事件变化 | | `payload` | 事件数据,结构随事件变化 |
| `signature` | 预留字段,当前由请求头承载 | | `signature` | 预留字段,当前由请求头承载 |
| `appKey` | 回调所属应用唯一标识 | | `appId` | 回调所属应用 ID |
`payload` 会根据事件类型变化: `payload` 会根据事件类型变化:
@ -405,7 +403,7 @@ HMAC-SHA256(appSecret, appKey + "\n" + timestamp + "\n" + nonce + "\n" + sha256(
```json ```json
{ {
"appKey": "ak_demo_chat", "appId": "ak_demo_chat",
"readerId": "user_001", "readerId": "user_001",
"peerId": "user_002", "peerId": "user_002",
"groupId": null, "groupId": null,
@ -419,7 +417,7 @@ HMAC-SHA256(appSecret, appKey + "\n" + timestamp + "\n" + nonce + "\n" + sha256(
```json ```json
{ {
"appKey": "ak_demo_chat", "appId": "ak_demo_chat",
"requestId": "req_001", "requestId": "req_001",
"fromUserId": "user_001", "fromUserId": "user_001",
"toUserId": "user_002", "toUserId": "user_002",
@ -433,7 +431,7 @@ HMAC-SHA256(appSecret, appKey + "\n" + timestamp + "\n" + nonce + "\n" + sha256(
```json ```json
{ {
"appKey": "ak_demo_chat", "appId": "ak_demo_chat",
"requestId": "req_001", "requestId": "req_001",
"groupId": "group_001", "groupId": "group_001",
"groupName": "技术群", "groupName": "技术群",
@ -448,7 +446,7 @@ HMAC-SHA256(appSecret, appKey + "\n" + timestamp + "\n" + nonce + "\n" + sha256(
```json ```json
{ {
"appKey": "ak_demo_chat", "appId": "ak_demo_chat",
"id": "blk_001", "id": "blk_001",
"userId": "user_001", "userId": "user_001",
"blockedUserId": "user_002", "blockedUserId": "user_002",
@ -471,14 +469,14 @@ HMAC-SHA256(appSecret, appKey + "\n" + timestamp + "\n" + nonce + "\n" + sha256(
import crypto from 'crypto' import crypto from 'crypto'
export function verifyWebhook({ export function verifyWebhook({
appKey, appId,
timestamp, timestamp,
nonce, nonce,
body, body,
signature, signature,
appSecret, appSecret,
}: { }: {
appKey: string appId: string
timestamp: string timestamp: string
nonce: string nonce: string
body: string body: string
@ -486,7 +484,7 @@ export function verifyWebhook({
appSecret: string appSecret: string
}) { }) {
const bodyHash = crypto.createHash('sha256').update(body, 'utf8').digest('hex') const bodyHash = crypto.createHash('sha256').update(body, 'utf8').digest('hex')
const payload = `${appKey}\n${timestamp}\n${nonce}\n${bodyHash}` const payload = `${appId}\n${timestamp}\n${nonce}\n${bodyHash}`
const expected = crypto.createHmac('sha256', appSecret).update(payload, 'utf8').digest('hex') const expected = crypto.createHmac('sha256', appSecret).update(payload, 'utf8').digest('hex')
return expected === signature return expected === signature
} }

查看文件

@ -33,7 +33,7 @@ public class FriendController {
public ResponseEntity<ApiResponse<List<String>>> listFriends( public ResponseEntity<ApiResponse<List<String>>> listFriends(
@AuthenticationPrincipal String userId, @AuthenticationPrincipal String userId,
@RequestParam String appKey) { @RequestParam String appKey) {
List<String> friendIds = friendRepository.findByAppKeyAndUserId(appKey, userId) List<String> friendIds = friendRepository.findByAppIdAndUserId(appKey, userId)
.stream() .stream()
.map(ImFriendEntity::getFriendId) .map(ImFriendEntity::getFriendId)
.toList(); .toList();
@ -68,8 +68,8 @@ public class FriendController {
@AuthenticationPrincipal String userId, @AuthenticationPrincipal String userId,
@PathVariable String friendId, @PathVariable String friendId,
@RequestParam String appKey) { @RequestParam String appKey) {
friendRepository.deleteByAppKeyAndUserIdAndFriendId(appKey, userId, friendId); friendRepository.deleteByAppIdAndUserIdAndFriendId(appKey, userId, friendId);
friendRepository.deleteByAppKeyAndUserIdAndFriendId(appKey, friendId, userId); friendRepository.deleteByAppIdAndUserIdAndFriendId(appKey, friendId, userId);
return ResponseEntity.ok(ApiResponse.success(null)); return ResponseEntity.ok(ApiResponse.success(null));
} }
@ -77,8 +77,8 @@ public class FriendController {
public ResponseEntity<ApiResponse<Void>> removeAllFriends( public ResponseEntity<ApiResponse<Void>> removeAllFriends(
@AuthenticationPrincipal String userId, @AuthenticationPrincipal String userId,
@RequestParam String appKey) { @RequestParam String appKey) {
friendRepository.deleteByAppKeyAndUserId(appKey, userId); friendRepository.deleteByAppIdAndUserId(appKey, userId);
friendRepository.deleteByAppKeyAndFriendId(appKey, userId); friendRepository.deleteByAppIdAndFriendId(appKey, userId);
return ResponseEntity.ok(ApiResponse.ok()); return ResponseEntity.ok(ApiResponse.ok());
} }
@ -91,8 +91,8 @@ public class FriendController {
if (friendId == null || friendId.isBlank() || userId.equals(friendId)) { if (friendId == null || friendId.isBlank() || userId.equals(friendId)) {
continue; continue;
} }
friendRepository.deleteByAppKeyAndUserIdAndFriendId(appKey, userId, friendId); friendRepository.deleteByAppIdAndUserIdAndFriendId(appKey, userId, friendId);
friendRepository.deleteByAppKeyAndUserIdAndFriendId(appKey, friendId, userId); friendRepository.deleteByAppIdAndUserIdAndFriendId(appKey, friendId, userId);
} }
return ResponseEntity.ok(ApiResponse.success(null)); return ResponseEntity.ok(ApiResponse.success(null));
} }
@ -103,7 +103,7 @@ public class FriendController {
@PathVariable String friendId, @PathVariable String friendId,
@RequestParam String appKey, @RequestParam String appKey,
@RequestParam(required = false) String groupName) { @RequestParam(required = false) String groupName) {
ImFriendEntity link = friendRepository.findByAppKeyAndUserIdAndFriendId(appKey, userId, friendId) ImFriendEntity link = friendRepository.findByAppIdAndUserIdAndFriendId(appKey, userId, friendId)
.orElseGet(() -> addFriendLink(appKey, userId, friendId)); .orElseGet(() -> addFriendLink(appKey, userId, friendId));
link.setFriendGroup(normalizeGroup(groupName)); link.setFriendGroup(normalizeGroup(groupName));
return ResponseEntity.ok(ApiResponse.success(friendRepository.save(link))); return ResponseEntity.ok(ApiResponse.success(friendRepository.save(link)));
@ -113,7 +113,7 @@ public class FriendController {
public ResponseEntity<ApiResponse<List<String>>> listFriendGroups( public ResponseEntity<ApiResponse<List<String>>> listFriendGroups(
@AuthenticationPrincipal String userId, @AuthenticationPrincipal String userId,
@RequestParam String appKey) { @RequestParam String appKey) {
List<String> groups = friendRepository.findByAppKeyAndUserId(appKey, userId).stream() List<String> groups = friendRepository.findByAppIdAndUserId(appKey, userId).stream()
.map(ImFriendEntity::getFriendGroup) .map(ImFriendEntity::getFriendGroup)
.filter(group -> group != null && !group.isBlank()) .filter(group -> group != null && !group.isBlank())
.distinct() .distinct()
@ -128,7 +128,7 @@ public class FriendController {
@RequestParam String appKey, @RequestParam String appKey,
@PathVariable String groupName) { @PathVariable String groupName) {
List<String> friendIds = friendRepository List<String> friendIds = friendRepository
.findByAppKeyAndUserIdAndFriendGroup(appKey, userId, normalizeGroup(groupName)) .findByAppIdAndUserIdAndFriendGroup(appKey, userId, normalizeGroup(groupName))
.stream() .stream()
.map(ImFriendEntity::getFriendId) .map(ImFriendEntity::getFriendId)
.toList(); .toList();
@ -137,19 +137,19 @@ public class FriendController {
private ImFriendEntity addFriendLink(String appKey, String userId, String friendId) { private ImFriendEntity addFriendLink(String appKey, String userId, String friendId) {
ImFriendEntity forward = friendRepository ImFriendEntity forward = friendRepository
.findByAppKeyAndUserIdAndFriendId(appKey, userId, friendId) .findByAppIdAndUserIdAndFriendId(appKey, userId, friendId)
.orElseGet(() -> { .orElseGet(() -> {
ImFriendEntity e = new ImFriendEntity(); ImFriendEntity e = new ImFriendEntity();
e.setAppKey(appKey); e.setAppId(appKey);
e.setUserId(userId); e.setUserId(userId);
e.setFriendId(friendId); e.setFriendId(friendId);
return friendRepository.save(e); return friendRepository.save(e);
}); });
friendRepository.findByAppKeyAndUserIdAndFriendId(appKey, friendId, userId) friendRepository.findByAppIdAndUserIdAndFriendId(appKey, friendId, userId)
.orElseGet(() -> { .orElseGet(() -> {
ImFriendEntity e = new ImFriendEntity(); ImFriendEntity e = new ImFriendEntity();
e.setAppKey(appKey); e.setAppId(appKey);
e.setUserId(friendId); e.setUserId(friendId);
e.setFriendId(userId); e.setFriendId(userId);
return friendRepository.save(e); return friendRepository.save(e);
@ -172,8 +172,8 @@ public class FriendController {
@RequestBody FriendCheckRequest req) { @RequestBody FriendCheckRequest req) {
List<FriendCheckResult> results = new ArrayList<>(); List<FriendCheckResult> results = new ArrayList<>();
for (String friendId : req.friendIds() == null ? List.<String>of() : req.friendIds()) { for (String friendId : req.friendIds() == null ? List.<String>of() : req.friendIds()) {
boolean isFriend = friendRepository.existsByAppKeyAndUserIdAndFriendId(appKey, userId, friendId) boolean isFriend = friendRepository.existsByAppIdAndUserIdAndFriendId(appKey, userId, friendId)
|| friendRepository.existsByAppKeyAndUserIdAndFriendId(appKey, friendId, userId); || friendRepository.existsByAppIdAndUserIdAndFriendId(appKey, friendId, userId);
results.add(new FriendCheckResult(friendId, isFriend)); results.add(new FriendCheckResult(friendId, isFriend));
} }
return ResponseEntity.ok(ApiResponse.success(results)); return ResponseEntity.ok(ApiResponse.success(results));

查看文件

@ -109,7 +109,7 @@ public class ImAdminController {
@RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size) { @RequestParam(defaultValue = "20") int size) {
return ResponseEntity.ok(ApiResponse.success( return ResponseEntity.ok(ApiResponse.success(
accountRepository.findByAppKey(appKey, PageRequest.of(page, size)))); accountRepository.findByAppId(appKey, PageRequest.of(page, size))));
} }
/** Ban or unban a user. */ /** Ban or unban a user. */
@ -119,7 +119,7 @@ public class ImAdminController {
@PathVariable String userId, @PathVariable String userId,
@AuthenticationPrincipal String operatorId, @AuthenticationPrincipal String operatorId,
@RequestBody Map<String, String> body) { @RequestBody Map<String, String> body) {
ImAccountEntity account = accountRepository.findByAppKeyAndUserId(appKey, userId) ImAccountEntity account = accountRepository.findByAppIdAndUserId(appKey, userId)
.orElseThrow(() -> new BusinessException(404, "账号不存在")); .orElseThrow(() -> new BusinessException(404, "账号不存在"));
String status = body.get("status"); String status = body.get("status");
if (status == null || status.isBlank()) { if (status == null || status.isBlank()) {
@ -152,7 +152,7 @@ public class ImAdminController {
/** List all groups for the given appKey. */ /** List all groups for the given appKey. */
@GetMapping("/groups") @GetMapping("/groups")
public ResponseEntity<ApiResponse<List<ImGroupEntity>>> listGroups(@RequestParam String appKey) { public ResponseEntity<ApiResponse<List<ImGroupEntity>>> listGroups(@RequestParam String appKey) {
return ResponseEntity.ok(ApiResponse.success(groupRepository.findByAppKey(appKey))); return ResponseEntity.ok(ApiResponse.success(groupRepository.findByAppId(appKey)));
} }
/** Admin registers a new IM user (or returns existing). */ /** Admin registers a new IM user (or returns existing). */
@ -253,10 +253,10 @@ public class ImAdminController {
public ResponseEntity<ApiResponse<Map<String, Object>>> stats( public ResponseEntity<ApiResponse<Map<String, Object>>> stats(
@RequestParam String appKey, @RequestParam String appKey,
@AuthenticationPrincipal String operatorId) { @AuthenticationPrincipal String operatorId) {
long totalMessages = messageRepository.countByAppKey(appKey); long totalMessages = messageRepository.countByAppId(appKey);
long totalUsers = accountRepository.countByAppKey(appKey); long totalUsers = accountRepository.countByAppId(appKey);
long totalGroups = groupRepository.countByAppKey(appKey); long totalGroups = groupRepository.countByAppId(appKey);
long todayMessages = messageRepository.countTodayByAppKey(appKey); long todayMessages = messageRepository.countTodayByAppId(appKey);
operationLogService.record(appKey, operatorId, "VIEW_STATS", "STATS", null, "summary"); operationLogService.record(appKey, operatorId, "VIEW_STATS", "STATS", null, "summary");
return ResponseEntity.ok(ApiResponse.success(Map.of( return ResponseEntity.ok(ApiResponse.success(Map.of(
@ -551,11 +551,11 @@ public class ImAdminController {
Page<WebhookDeliveryEntity> result; Page<WebhookDeliveryEntity> result;
PageRequest pageable = PageRequest.of(page, size); PageRequest pageable = PageRequest.of(page, size);
if (callbackEvent != null && !callbackEvent.isBlank()) { if (callbackEvent != null && !callbackEvent.isBlank()) {
result = webhookDeliveryRepository.findByAppKeyAndCallbackEvent(appKey, callbackEvent, pageable); result = webhookDeliveryRepository.findByAppIdAndCallbackEvent(appKey, callbackEvent, pageable);
} else if (success != null) { } else if (success != null) {
result = webhookDeliveryRepository.findByAppKeyAndSuccess(appKey, success, pageable); result = webhookDeliveryRepository.findByAppIdAndSuccess(appKey, success, pageable);
} else { } else {
result = webhookDeliveryRepository.findByAppKey(appKey, pageable); result = webhookDeliveryRepository.findByAppId(appKey, pageable);
} }
return ResponseEntity.ok(ApiResponse.success(result)); return ResponseEntity.ok(ApiResponse.success(result));
} }
@ -569,9 +569,9 @@ public class ImAdminController {
Page<WebhookAlertEntity> result; Page<WebhookAlertEntity> result;
PageRequest pageable = PageRequest.of(page, size); PageRequest pageable = PageRequest.of(page, size);
if (acknowledged != null) { if (acknowledged != null) {
result = webhookAlertRepository.findByAppKeyAndAcknowledged(appKey, acknowledged, pageable); result = webhookAlertRepository.findByAppIdAndAcknowledged(appKey, acknowledged, pageable);
} else { } else {
result = webhookAlertRepository.findByAppKey(appKey, pageable); result = webhookAlertRepository.findByAppId(appKey, pageable);
} }
return ResponseEntity.ok(ApiResponse.success(result)); return ResponseEntity.ok(ApiResponse.success(result));
} }
@ -583,7 +583,7 @@ public class ImAdminController {
@AuthenticationPrincipal String operatorId) { @AuthenticationPrincipal String operatorId) {
WebhookAlertEntity alert = webhookAlertRepository.findById(id) WebhookAlertEntity alert = webhookAlertRepository.findById(id)
.orElseThrow(() -> new BusinessException(404, "告警不存在")); .orElseThrow(() -> new BusinessException(404, "告警不存在"));
if (!alert.getAppKey().equals(appKey)) { if (!alert.getAppId().equals(appKey)) {
throw new BusinessException(403, "无权操作"); throw new BusinessException(403, "无权操作");
} }
alert.setAcknowledged(true); alert.setAcknowledged(true);
@ -604,7 +604,7 @@ public class ImAdminController {
health.put("enabled", webhook.isEnabled()); health.put("enabled", webhook.isEnabled());
health.put("consecutiveFailures", webhook.getConsecutiveFailures()); health.put("consecutiveFailures", webhook.getConsecutiveFailures());
health.put("lastFailureAt", webhook.getLastFailureAt()); health.put("lastFailureAt", webhook.getLastFailureAt());
long unacknowledgedAlerts = webhookAlertRepository.countUnacknowledgedByAppKey(appKey); long unacknowledgedAlerts = webhookAlertRepository.countUnacknowledgedByAppId(appKey);
health.put("unacknowledgedAlerts", unacknowledgedAlerts); health.put("unacknowledgedAlerts", unacknowledgedAlerts);
return ResponseEntity.ok(ApiResponse.success(health)); return ResponseEntity.ok(ApiResponse.success(health));
} }

查看文件

@ -27,10 +27,10 @@ public class StatisticsController {
@RequestParam(required = false) Integer days) { @RequestParam(required = false) Integer days) {
int d = days == null ? 7 : days; int d = days == null ? 7 : days;
LocalDateTime since = LocalDateTime.now().minusDays(d); LocalDateTime since = LocalDateTime.now().minusDays(d);
long total = messageRepository.countByAppKeyAndCreatedAtAfter(appKey, since); long total = messageRepository.countByAppIdAndCreatedAtAfter(appKey, since);
long single = messageRepository.countByAppKeyAndChatTypeAndCreatedAtAfter( long single = messageRepository.countByAppIdAndChatTypeAndCreatedAtAfter(
appKey, com.xuqm.im.entity.ImMessageEntity.ChatType.SINGLE, since); appKey, com.xuqm.im.entity.ImMessageEntity.ChatType.SINGLE, since);
long group = messageRepository.countByAppKeyAndChatTypeAndCreatedAtAfter( long group = messageRepository.countByAppIdAndChatTypeAndCreatedAtAfter(
appKey, com.xuqm.im.entity.ImMessageEntity.ChatType.GROUP, since); appKey, com.xuqm.im.entity.ImMessageEntity.ChatType.GROUP, since);
return ApiResponse.success(Map.of( return ApiResponse.success(Map.of(
"totalMessages", total, "totalMessages", total,
@ -46,9 +46,9 @@ public class StatisticsController {
@RequestParam(required = false) Integer days) { @RequestParam(required = false) Integer days) {
int d = days == null ? 7 : days; int d = days == null ? 7 : days;
LocalDateTime since = LocalDateTime.now().minusDays(d); LocalDateTime since = LocalDateTime.now().minusDays(d);
long success = webhookDeliveryRepository.countSuccessfulByAppKeySince(appKey, since); long success = webhookDeliveryRepository.countSuccessfulByAppIdSince(appKey, since);
long failed = webhookDeliveryRepository.countFailedByAppKeySince(appKey, since); long failed = webhookDeliveryRepository.countFailedByAppIdSince(appKey, since);
List<Object[]> raw = webhookDeliveryRepository.statsByAppKeySince(appKey, since); List<Object[]> raw = webhookDeliveryRepository.statsByAppIdSince(appKey, since);
List<Map<String, Object>> eventStats = new ArrayList<>(); List<Map<String, Object>> eventStats = new ArrayList<>();
for (Object[] row : raw) { for (Object[] row : raw) {
eventStats.add(Map.of( eventStats.add(Map.of(

查看文件

@ -13,7 +13,7 @@ import java.time.LocalDateTime;
@Entity @Entity
@Table(name = "im_account", @Table(name = "im_account",
uniqueConstraints = @UniqueConstraint(columnNames = {"appKey", "userId"})) uniqueConstraints = @UniqueConstraint(columnNames = {"appId", "userId"}))
public class ImAccountEntity { public class ImAccountEntity {
public enum Gender { UNKNOWN, MALE, FEMALE } public enum Gender { UNKNOWN, MALE, FEMALE }
@ -23,7 +23,7 @@ public class ImAccountEntity {
private String id; private String id;
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String appKey; private String appId;
@Column(nullable = false, length = 128) @Column(nullable = false, length = 128)
private String userId; private String userId;
@ -49,8 +49,8 @@ public class ImAccountEntity {
public String getId() { return id; } public String getId() { return id; }
public void setId(String id) { this.id = id; } public void setId(String id) { this.id = id; }
public String getAppKey() { return appKey; } public String getAppId() { return appId; }
public void setAppKey(String appKey) { this.appKey = appKey; } public void setAppId(String appId) { this.appId = appId; }
public String getUserId() { return userId; } public String getUserId() { return userId; }
public void setUserId(String userId) { this.userId = userId; } public void setUserId(String userId) { this.userId = userId; }

查看文件

@ -11,13 +11,13 @@ import java.time.LocalDateTime;
@Entity @Entity
@Table( @Table(
name = "im_blacklist", name = "im_blacklist",
uniqueConstraints = @UniqueConstraint(columnNames = {"appKey", "userId", "blockedUserId"}), uniqueConstraints = @UniqueConstraint(columnNames = {"appId", "userId", "blockedUserId"}),
indexes = @Index(name = "idx_blacklist_app_user", columnList = "appKey,userId") indexes = @Index(name = "idx_blacklist_app_user", columnList = "appId,userId")
) )
public class ImBlacklistEntity extends BaseIdEntity { public class ImBlacklistEntity extends BaseIdEntity {
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String appKey; private String appId;
@Column(nullable = false, length = 128) @Column(nullable = false, length = 128)
private String userId; private String userId;
@ -28,8 +28,8 @@ public class ImBlacklistEntity extends BaseIdEntity {
@Column(nullable = false) @Column(nullable = false)
private LocalDateTime createdAt; private LocalDateTime createdAt;
public String getAppKey() { return appKey; } public String getAppId() { return appId; }
public void setAppKey(String appKey) { this.appKey = appKey; } public void setAppId(String appId) { this.appId = appId; }
public String getUserId() { return userId; } public String getUserId() { return userId; }
public void setUserId(String userId) { this.userId = userId; } public void setUserId(String userId) { this.userId = userId; }

查看文件

@ -10,16 +10,16 @@ import java.time.LocalDateTime;
@Entity @Entity
@Table( @Table(
name = "im_conversation_state", name = "im_conversation_state",
uniqueConstraints = @UniqueConstraint(columnNames = {"appKey", "userId", "targetId", "chatType"}), uniqueConstraints = @UniqueConstraint(columnNames = {"appId", "userId", "targetId", "chatType"}),
indexes = { indexes = {
@Index(name = "idx_conv_state_app_user", columnList = "appKey,userId"), @Index(name = "idx_conv_state_app_user", columnList = "appId,userId"),
@Index(name = "idx_conv_state_app_target", columnList = "appKey,targetId") @Index(name = "idx_conv_state_app_target", columnList = "appId,targetId")
} }
) )
public class ImConversationStateEntity extends BaseIdEntity { public class ImConversationStateEntity extends BaseIdEntity {
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String appKey; private String appId;
@Column(nullable = false, length = 128) @Column(nullable = false, length = 128)
private String userId; private String userId;
@ -53,8 +53,8 @@ public class ImConversationStateEntity extends BaseIdEntity {
@Column(nullable = false) @Column(nullable = false)
private LocalDateTime updatedAt; private LocalDateTime updatedAt;
public String getAppKey() { return appKey; } public String getAppId() { return appId; }
public void setAppKey(String appKey) { this.appKey = appKey; } public void setAppId(String appId) { this.appId = appId; }
public String getUserId() { return userId; } public String getUserId() { return userId; }
public void setUserId(String userId) { this.userId = userId; } public void setUserId(String userId) { this.userId = userId; }

查看文件

@ -13,7 +13,7 @@ import java.time.Instant;
@Entity @Entity
@Table(name = "im_friends", @Table(name = "im_friends",
uniqueConstraints = @UniqueConstraint(columnNames = {"appKey", "userId", "friendId"})) uniqueConstraints = @UniqueConstraint(columnNames = {"appId", "userId", "friendId"}))
public class ImFriendEntity { public class ImFriendEntity {
@Id @Id
@ -21,7 +21,7 @@ public class ImFriendEntity {
private Long id; private Long id;
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String appKey; private String appId;
@Column(nullable = false, length = 128) @Column(nullable = false, length = 128)
private String userId; private String userId;
@ -39,8 +39,8 @@ public class ImFriendEntity {
public Long getId() { return id; } public Long getId() { return id; }
public void setId(Long id) { this.id = id; } public void setId(Long id) { this.id = id; }
public String getAppKey() { return appKey; } public String getAppId() { return appId; }
public void setAppKey(String appKey) { this.appKey = appKey; } public void setAppId(String appId) { this.appId = appId; }
public String getUserId() { return userId; } public String getUserId() { return userId; }
public void setUserId(String userId) { this.userId = userId; } public void setUserId(String userId) { this.userId = userId; }

查看文件

@ -13,15 +13,15 @@ import java.time.LocalDateTime;
@Entity @Entity
@Table( @Table(
name = "im_friend_request", name = "im_friend_request",
uniqueConstraints = @UniqueConstraint(columnNames = {"appKey", "fromUserId", "toUserId"}), uniqueConstraints = @UniqueConstraint(columnNames = {"appId", "fromUserId", "toUserId"}),
indexes = @Index(name = "idx_friend_request_app_to", columnList = "appKey,toUserId") indexes = @Index(name = "idx_friend_request_app_to", columnList = "appId,toUserId")
) )
public class ImFriendRequestEntity extends BaseIdEntity { public class ImFriendRequestEntity extends BaseIdEntity {
public enum Status { PENDING, ACCEPTED, REJECTED } public enum Status { PENDING, ACCEPTED, REJECTED }
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String appKey; private String appId;
@Column(nullable = false, length = 128) @Column(nullable = false, length = 128)
private String fromUserId; private String fromUserId;
@ -40,8 +40,8 @@ public class ImFriendRequestEntity extends BaseIdEntity {
private LocalDateTime reviewedAt; private LocalDateTime reviewedAt;
public String getAppKey() { return appKey; } public String getAppId() { return appId; }
public void setAppKey(String appKey) { this.appKey = appKey; } public void setAppId(String appId) { this.appId = appId; }
public String getFromUserId() { return fromUserId; } public String getFromUserId() { return fromUserId; }
public void setFromUserId(String fromUserId) { this.fromUserId = fromUserId; } public void setFromUserId(String fromUserId) { this.fromUserId = fromUserId; }

查看文件

@ -17,7 +17,7 @@ public class ImGlobalMuteEntity {
private String id; private String id;
@Column(nullable = false, length = 64, unique = true) @Column(nullable = false, length = 64, unique = true)
private String appKey; private String appId;
@Column(nullable = false) @Column(nullable = false)
private boolean enabled; private boolean enabled;
@ -33,8 +33,8 @@ public class ImGlobalMuteEntity {
public String getId() { return id; } public String getId() { return id; }
public void setId(String id) { this.id = id; } public void setId(String id) { this.id = id; }
public String getAppKey() { return appKey; } public String getAppId() { return appId; }
public void setAppKey(String appKey) { this.appKey = appKey; } public void setAppId(String appId) { this.appId = appId; }
public boolean isEnabled() { return enabled; } public boolean isEnabled() { return enabled; }
public void setEnabled(boolean enabled) { this.enabled = enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; }

查看文件

@ -16,7 +16,7 @@ public class ImGroupEntity {
private String id; private String id;
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String appKey; private String appId;
@Column(nullable = false, length = 128) @Column(nullable = false, length = 128)
private String name; private String name;
@ -49,8 +49,8 @@ public class ImGroupEntity {
public String getId() { return id; } public String getId() { return id; }
public void setId(String id) { this.id = id; } public void setId(String id) { this.id = id; }
public String getAppKey() { return appKey; } public String getAppId() { return appId; }
public void setAppKey(String appKey) { this.appKey = appKey; } public void setAppId(String appId) { this.appId = appId; }
public String getName() { return name; } public String getName() { return name; }
public void setName(String name) { this.name = name; } public void setName(String name) { this.name = name; }

查看文件

@ -12,14 +12,14 @@ import java.time.LocalDateTime;
@Entity @Entity
@Table( @Table(
name = "im_group_join_request", name = "im_group_join_request",
indexes = @Index(name = "idx_group_join_request_app_group", columnList = "appKey,groupId") indexes = @Index(name = "idx_group_join_request_app_group", columnList = "appId,groupId")
) )
public class ImGroupJoinRequestEntity extends BaseIdEntity { public class ImGroupJoinRequestEntity extends BaseIdEntity {
public enum Status { PENDING, ACCEPTED, REJECTED } public enum Status { PENDING, ACCEPTED, REJECTED }
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String appKey; private String appId;
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String groupId; private String groupId;
@ -38,8 +38,8 @@ public class ImGroupJoinRequestEntity extends BaseIdEntity {
private LocalDateTime reviewedAt; private LocalDateTime reviewedAt;
public String getAppKey() { return appKey; } public String getAppId() { return appId; }
public void setAppKey(String appKey) { this.appKey = appKey; } public void setAppId(String appId) { this.appId = appId; }
public String getGroupId() { return groupId; } public String getGroupId() { return groupId; }
public void setGroupId(String groupId) { this.groupId = groupId; } public void setGroupId(String groupId) { this.groupId = groupId; }

查看文件

@ -16,8 +16,8 @@ import java.time.LocalDateTime;
@Entity @Entity
@Table(name = "im_message", indexes = { @Table(name = "im_message", indexes = {
@Index(name = "idx_app_from", columnList = "appKey,fromUserId"), @Index(name = "idx_app_from", columnList = "appId,fromUserId"),
@Index(name = "idx_app_to", columnList = "appKey,toId") @Index(name = "idx_app_to", columnList = "appId,toId")
}) })
public class ImMessageEntity { public class ImMessageEntity {
@ -32,7 +32,7 @@ public class ImMessageEntity {
private String id; private String id;
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String appKey; private String appId;
@Column(nullable = false, length = 128) @Column(nullable = false, length = 128)
private String fromUserId; private String fromUserId;
@ -74,8 +74,8 @@ public class ImMessageEntity {
public String getId() { return id; } public String getId() { return id; }
public void setId(String id) { this.id = id; } public void setId(String id) { this.id = id; }
public String getAppKey() { return appKey; } public String getAppId() { return appId; }
public void setAppKey(String appKey) { this.appKey = appKey; } public void setAppId(String appId) { this.appId = appId; }
public String getFromUserId() { return fromUserId; } public String getFromUserId() { return fromUserId; }
public void setFromUserId(String fromUserId) { this.fromUserId = fromUserId; } public void setFromUserId(String fromUserId) { this.fromUserId = fromUserId; }

查看文件

@ -14,7 +14,7 @@ public class ImOfflineMessageEntity {
private String id; private String id;
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String appKey; private String appId;
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String userId; private String userId;
@ -31,8 +31,8 @@ public class ImOfflineMessageEntity {
public String getId() { return id; } public String getId() { return id; }
public void setId(String id) { this.id = id; } public void setId(String id) { this.id = id; }
public String getAppKey() { return appKey; } public String getAppId() { return appId; }
public void setAppKey(String appKey) { this.appKey = appKey; } public void setAppId(String appId) { this.appId = appId; }
public String getUserId() { return userId; } public String getUserId() { return userId; }
public void setUserId(String userId) { this.userId = userId; } public void setUserId(String userId) { this.userId = userId; }

查看文件

@ -11,13 +11,13 @@ import java.time.LocalDateTime;
@Entity @Entity
@Table(name = "im_operation_log", indexes = { @Table(name = "im_operation_log", indexes = {
@Index(name = "idx_op_log_app_time", columnList = "appKey,createdAt"), @Index(name = "idx_op_log_app_time", columnList = "appId,createdAt"),
@Index(name = "idx_op_log_app_operator", columnList = "appKey,operatorId") @Index(name = "idx_op_log_app_operator", columnList = "appId,operatorId")
}) })
public class ImOperationLogEntity extends BaseIdEntity { public class ImOperationLogEntity extends BaseIdEntity {
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String appKey; private String appId;
@Column(nullable = false, length = 128) @Column(nullable = false, length = 128)
private String operatorId; private String operatorId;
@ -38,8 +38,8 @@ public class ImOperationLogEntity extends BaseIdEntity {
@JsonSerialize(using = EpochMillisLocalDateTimeSerializer.class) @JsonSerialize(using = EpochMillisLocalDateTimeSerializer.class)
private LocalDateTime createdAt; private LocalDateTime createdAt;
public String getAppKey() { return appKey; } public String getAppId() { return appId; }
public void setAppKey(String appKey) { this.appKey = appKey; } public void setAppId(String appId) { this.appId = appId; }
public String getOperatorId() { return operatorId; } public String getOperatorId() { return operatorId; }
public void setOperatorId(String operatorId) { this.operatorId = operatorId; } public void setOperatorId(String operatorId) { this.operatorId = operatorId; }

查看文件

@ -18,7 +18,7 @@ public class KeywordFilterEntity {
private String id; private String id;
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String appKey; private String appId;
@Column(nullable = false, length = 512) @Column(nullable = false, length = 512)
private String pattern; private String pattern;
@ -39,8 +39,8 @@ public class KeywordFilterEntity {
public String getId() { return id; } public String getId() { return id; }
public void setId(String id) { this.id = id; } public void setId(String id) { this.id = id; }
public String getAppKey() { return appKey; } public String getAppId() { return appId; }
public void setAppKey(String appKey) { this.appKey = appKey; } public void setAppId(String appId) { this.appId = appId; }
public String getPattern() { return pattern; } public String getPattern() { return pattern; }
public void setPattern(String pattern) { this.pattern = pattern; } public void setPattern(String pattern) { this.pattern = pattern; }

查看文件

@ -16,7 +16,7 @@ public class WebhookAlertEntity {
private String id; private String id;
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String appKey; private String appId;
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String webhookId; private String webhookId;
@ -43,8 +43,8 @@ public class WebhookAlertEntity {
public String getId() { return id; } public String getId() { return id; }
public void setId(String id) { this.id = id; } public void setId(String id) { this.id = id; }
public String getAppKey() { return appKey; } public String getAppId() { return appId; }
public void setAppKey(String appKey) { this.appKey = appKey; } public void setAppId(String appId) { this.appId = appId; }
public String getWebhookId() { return webhookId; } public String getWebhookId() { return webhookId; }
public void setWebhookId(String webhookId) { this.webhookId = webhookId; } public void setWebhookId(String webhookId) { this.webhookId = webhookId; }

查看文件

@ -16,7 +16,7 @@ public class WebhookConfigEntity {
private String id; private String id;
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String appKey; private String appId;
@Column(nullable = false, length = 512) @Column(nullable = false, length = 512)
private String url; private String url;
@ -40,8 +40,8 @@ public class WebhookConfigEntity {
public String getId() { return id; } public String getId() { return id; }
public void setId(String id) { this.id = id; } public void setId(String id) { this.id = id; }
public String getAppKey() { return appKey; } public String getAppId() { return appId; }
public void setAppKey(String appKey) { this.appKey = appKey; } public void setAppId(String appId) { this.appId = appId; }
public String getUrl() { return url; } public String getUrl() { return url; }
public void setUrl(String url) { this.url = url; } public void setUrl(String url) { this.url = url; }

查看文件

@ -14,7 +14,7 @@ public class WebhookDeliveryEntity {
private String id; private String id;
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String appKey; private String appId;
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String callbackId; private String callbackId;
@ -46,8 +46,8 @@ public class WebhookDeliveryEntity {
public String getId() { return id; } public String getId() { return id; }
public void setId(String id) { this.id = id; } public void setId(String id) { this.id = id; }
public String getAppKey() { return appKey; } public String getAppId() { return appId; }
public void setAppKey(String appKey) { this.appKey = appKey; } public void setAppId(String appId) { this.appId = appId; }
public String getCallbackId() { return callbackId; } public String getCallbackId() { return callbackId; }
public void setCallbackId(String callbackId) { this.callbackId = callbackId; } public void setCallbackId(String callbackId) { this.callbackId = callbackId; }

查看文件

@ -10,12 +10,12 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
public interface ImAccountRepository extends JpaRepository<ImAccountEntity, String> { public interface ImAccountRepository extends JpaRepository<ImAccountEntity, String> {
Optional<ImAccountEntity> findByAppKeyAndUserId(String appKey, String userId); Optional<ImAccountEntity> findByAppIdAndUserId(String appId, String userId);
boolean existsByAppKeyAndUserId(String appKey, String userId); boolean existsByAppIdAndUserId(String appId, String userId);
Page<ImAccountEntity> findByAppKey(String appKey, Pageable pageable); Page<ImAccountEntity> findByAppId(String appId, Pageable pageable);
long countByAppKey(String appKey); long countByAppId(String appId);
@Query("SELECT a FROM ImAccountEntity a WHERE a.appKey = :appKey AND a.status = 'ACTIVE' AND " + @Query("SELECT a FROM ImAccountEntity a WHERE a.appId = :appId AND a.status = 'ACTIVE' AND " +
"(LOWER(a.userId) LIKE LOWER(CONCAT('%',:kw,'%')) OR LOWER(a.nickname) LIKE LOWER(CONCAT('%',:kw,'%')))") "(LOWER(a.userId) LIKE LOWER(CONCAT('%',:kw,'%')) OR LOWER(a.nickname) LIKE LOWER(CONCAT('%',:kw,'%')))")
List<ImAccountEntity> searchByKeyword(@Param("appKey") String appKey, @Param("kw") String keyword, Pageable pageable); List<ImAccountEntity> searchByKeyword(@Param("appId") String appId, @Param("kw") String keyword, Pageable pageable);
} }

查看文件

@ -7,13 +7,13 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
public interface ImBlacklistRepository extends JpaRepository<ImBlacklistEntity, String> { public interface ImBlacklistRepository extends JpaRepository<ImBlacklistEntity, String> {
List<ImBlacklistEntity> findByAppKey(String appKey); List<ImBlacklistEntity> findByAppId(String appId);
List<ImBlacklistEntity> findByAppKeyAndUserId(String appKey, String userId); List<ImBlacklistEntity> findByAppIdAndUserId(String appId, String userId);
Optional<ImBlacklistEntity> findByAppKeyAndUserIdAndBlockedUserId( Optional<ImBlacklistEntity> findByAppIdAndUserIdAndBlockedUserId(
String appKey, String userId, String blockedUserId); String appId, String userId, String blockedUserId);
boolean existsByAppKeyAndUserIdAndBlockedUserId(String appKey, String userId, String blockedUserId); boolean existsByAppIdAndUserIdAndBlockedUserId(String appId, String userId, String blockedUserId);
void deleteByAppKeyAndUserIdAndBlockedUserId(String appKey, String userId, String blockedUserId); void deleteByAppIdAndUserIdAndBlockedUserId(String appId, String userId, String blockedUserId);
} }

查看文件

@ -7,16 +7,16 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
public interface ImConversationStateRepository extends JpaRepository<ImConversationStateEntity, String> { public interface ImConversationStateRepository extends JpaRepository<ImConversationStateEntity, String> {
Optional<ImConversationStateEntity> findByAppKeyAndUserIdAndTargetIdAndChatType( Optional<ImConversationStateEntity> findByAppIdAndUserIdAndTargetIdAndChatType(
String appKey, String userId, String targetId, String chatType); String appId, String userId, String targetId, String chatType);
List<ImConversationStateEntity> findByAppKeyAndUserId(String appKey, String userId); List<ImConversationStateEntity> findByAppIdAndUserId(String appId, String userId);
List<ImConversationStateEntity> findByAppKeyAndUserIdAndHiddenFalse(String appKey, String userId); List<ImConversationStateEntity> findByAppIdAndUserIdAndHiddenFalse(String appId, String userId);
List<ImConversationStateEntity> findByAppKeyAndUserIdAndConversationGroup( List<ImConversationStateEntity> findByAppIdAndUserIdAndConversationGroup(
String appKey, String userId, String conversationGroup); String appId, String userId, String conversationGroup);
void deleteByAppKeyAndUserIdAndTargetIdAndChatType( void deleteByAppIdAndUserIdAndTargetIdAndChatType(
String appKey, String userId, String targetId, String chatType); String appId, String userId, String targetId, String chatType);
} }

查看文件

@ -9,20 +9,20 @@ import java.util.Optional;
public interface ImFriendRepository extends JpaRepository<ImFriendEntity, Long> { public interface ImFriendRepository extends JpaRepository<ImFriendEntity, Long> {
List<ImFriendEntity> findByAppKeyAndUserId(String appKey, String userId); List<ImFriendEntity> findByAppIdAndUserId(String appId, String userId);
List<ImFriendEntity> findByAppKeyAndUserIdAndFriendGroup(String appKey, String userId, String friendGroup); List<ImFriendEntity> findByAppIdAndUserIdAndFriendGroup(String appId, String userId, String friendGroup);
Optional<ImFriendEntity> findByAppKeyAndUserIdAndFriendId(String appKey, String userId, String friendId); Optional<ImFriendEntity> findByAppIdAndUserIdAndFriendId(String appId, String userId, String friendId);
boolean existsByAppKeyAndUserIdAndFriendId(String appKey, String userId, String friendId); boolean existsByAppIdAndUserIdAndFriendId(String appId, String userId, String friendId);
@Transactional @Transactional
void deleteByAppKeyAndUserIdAndFriendId(String appKey, String userId, String friendId); void deleteByAppIdAndUserIdAndFriendId(String appId, String userId, String friendId);
@Transactional @Transactional
void deleteByAppKeyAndUserId(String appKey, String userId); void deleteByAppIdAndUserId(String appId, String userId);
@Transactional @Transactional
void deleteByAppKeyAndFriendId(String appKey, String friendId); void deleteByAppIdAndFriendId(String appId, String friendId);
} }

查看文件

@ -7,10 +7,10 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
public interface ImFriendRequestRepository extends JpaRepository<ImFriendRequestEntity, String> { public interface ImFriendRequestRepository extends JpaRepository<ImFriendRequestEntity, String> {
List<ImFriendRequestEntity> findByAppKey(String appKey); List<ImFriendRequestEntity> findByAppId(String appId);
Optional<ImFriendRequestEntity> findByAppKeyAndFromUserIdAndToUserId( Optional<ImFriendRequestEntity> findByAppIdAndFromUserIdAndToUserId(
String appKey, String fromUserId, String toUserId); String appId, String fromUserId, String toUserId);
List<ImFriendRequestEntity> findByAppKeyAndToUserId(String appKey, String toUserId); List<ImFriendRequestEntity> findByAppIdAndToUserId(String appId, String toUserId);
List<ImFriendRequestEntity> findByAppKeyAndFromUserId(String appKey, String fromUserId); List<ImFriendRequestEntity> findByAppIdAndFromUserId(String appId, String fromUserId);
} }

查看文件

@ -6,5 +6,5 @@ import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional; import java.util.Optional;
public interface ImGlobalMuteRepository extends JpaRepository<ImGlobalMuteEntity, String> { public interface ImGlobalMuteRepository extends JpaRepository<ImGlobalMuteEntity, String> {
Optional<ImGlobalMuteEntity> findByAppKey(String appKey); Optional<ImGlobalMuteEntity> findByAppId(String appId);
} }

查看文件

@ -7,10 +7,10 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
public interface ImGroupJoinRequestRepository extends JpaRepository<ImGroupJoinRequestEntity, String> { public interface ImGroupJoinRequestRepository extends JpaRepository<ImGroupJoinRequestEntity, String> {
List<ImGroupJoinRequestEntity> findByAppKey(String appKey); List<ImGroupJoinRequestEntity> findByAppId(String appId);
Optional<ImGroupJoinRequestEntity> findByAppKeyAndGroupIdAndRequesterId( Optional<ImGroupJoinRequestEntity> findByAppIdAndGroupIdAndRequesterId(
String appKey, String groupId, String requesterId); String appId, String groupId, String requesterId);
List<ImGroupJoinRequestEntity> findByAppKeyAndGroupId(String appKey, String groupId); List<ImGroupJoinRequestEntity> findByAppIdAndGroupId(String appId, String groupId);
List<ImGroupJoinRequestEntity> findByAppKeyAndRequesterId(String appKey, String requesterId); List<ImGroupJoinRequestEntity> findByAppIdAndRequesterId(String appId, String requesterId);
} }

查看文件

@ -8,22 +8,22 @@ import org.springframework.data.repository.query.Param;
import java.util.List; import java.util.List;
public interface ImGroupRepository extends JpaRepository<ImGroupEntity, String> { public interface ImGroupRepository extends JpaRepository<ImGroupEntity, String> {
List<ImGroupEntity> findByAppKey(String appKey); List<ImGroupEntity> findByAppId(String appId);
long countByAppKey(String appKey); long countByAppId(String appId);
@Query(value = """ @Query(value = """
SELECT * FROM im_group SELECT * FROM im_group
WHERE app_key = :appKey WHERE app_id = :appId
AND JSON_CONTAINS(member_ids, JSON_QUOTE(:userId)) AND JSON_CONTAINS(member_ids, JSON_QUOTE(:userId))
ORDER BY created_at DESC ORDER BY created_at DESC
""", nativeQuery = true) """, nativeQuery = true)
List<ImGroupEntity> findUserGroups( List<ImGroupEntity> findUserGroups(
@Param("appKey") String appKey, @Param("appId") String appId,
@Param("userId") String userId); @Param("userId") String userId);
@Query(""" @Query("""
select g from ImGroupEntity g select g from ImGroupEntity g
where g.appKey = :appKey where g.appId = :appId
and (:keyword is null or :keyword = '' or and (:keyword is null or :keyword = '' or
lower(g.id) like lower(concat('%', :keyword, '%')) or lower(g.id) like lower(concat('%', :keyword, '%')) or
lower(g.name) like lower(concat('%', :keyword, '%')) or lower(g.name) like lower(concat('%', :keyword, '%')) or
@ -32,7 +32,7 @@ public interface ImGroupRepository extends JpaRepository<ImGroupEntity, String>
order by g.createdAt desc order by g.createdAt desc
""") """)
List<ImGroupEntity> searchByKeyword( List<ImGroupEntity> searchByKeyword(
@Param("appKey") String appKey, @Param("appId") String appId,
@Param("keyword") String keyword, @Param("keyword") String keyword,
Pageable pageable); Pageable pageable);
} }

查看文件

@ -25,16 +25,16 @@ public interface ImMessageRepository extends JpaRepository<ImMessageEntity, Stri
chat_type, chat_type,
MAX(created_at) AS last_time MAX(created_at) AS last_time
FROM im_message FROM im_message
WHERE app_key = :appKey AND chat_type = 'SINGLE' WHERE app_id = :appId AND chat_type = 'SINGLE'
AND (from_user_id = :userId OR to_id = :userId) AND (from_user_id = :userId OR to_id = :userId)
GROUP BY target_id, chat_type GROUP BY target_id, chat_type
UNION ALL UNION ALL
SELECT to_id AS target_id, chat_type, MAX(created_at) AS last_time SELECT to_id AS target_id, chat_type, MAX(created_at) AS last_time
FROM im_message FROM im_message
WHERE app_key = :appKey AND chat_type = 'GROUP' WHERE app_id = :appId AND chat_type = 'GROUP'
AND to_id IN ( AND to_id IN (
SELECT id FROM im_group SELECT id FROM im_group
WHERE app_key = :appKey AND JSON_CONTAINS(member_ids, JSON_QUOTE(:userId)) WHERE app_id = :appId AND JSON_CONTAINS(member_ids, JSON_QUOTE(:userId))
) )
GROUP BY to_id, chat_type GROUP BY to_id, chat_type
) combined ) combined
@ -42,31 +42,31 @@ public interface ImMessageRepository extends JpaRepository<ImMessageEntity, Stri
LIMIT :size LIMIT :size
""", nativeQuery = true) """, nativeQuery = true)
List<ConversationSummary> findConversations( List<ConversationSummary> findConversations(
@Param("appKey") String appKey, @Param("appId") String appId,
@Param("userId") String userId, @Param("userId") String userId,
@Param("size") int size); @Param("size") int size);
Page<ImMessageEntity> findByAppKeyAndToIdOrderByCreatedAtDesc( Page<ImMessageEntity> findByAppIdAndToIdOrderByCreatedAtDesc(
String appKey, String toId, Pageable pageable); String appId, String toId, Pageable pageable);
Page<ImMessageEntity> findByAppKeyAndFromUserIdAndToIdOrderByCreatedAtDesc( Page<ImMessageEntity> findByAppIdAndFromUserIdAndToIdOrderByCreatedAtDesc(
String appKey, String fromUserId, String toId, Pageable pageable); String appId, String fromUserId, String toId, Pageable pageable);
@Query(""" @Query("""
select m from ImMessageEntity m select m from ImMessageEntity m
where m.appKey = :appKey where m.appId = :appId
and m.chatType = com.xuqm.im.entity.ImMessageEntity$ChatType.SINGLE and m.chatType = com.xuqm.im.entity.ImMessageEntity$ChatType.SINGLE
and ((m.fromUserId = :userId and m.toId = :peerId) and ((m.fromUserId = :userId and m.toId = :peerId)
or (m.fromUserId = :peerId and m.toId = :userId)) or (m.fromUserId = :peerId and m.toId = :userId))
order by m.createdAt desc order by m.createdAt desc
""") """)
Page<ImMessageEntity> findSingleConversation( Page<ImMessageEntity> findSingleConversation(
@Param("appKey") String appKey, @Param("appId") String appId,
@Param("userId") String userId, @Param("userId") String userId,
@Param("peerId") String peerId, @Param("peerId") String peerId,
Pageable pageable); Pageable pageable);
@Query(""" @Query("""
select m from ImMessageEntity m select m from ImMessageEntity m
where m.appKey = :appKey where m.appId = :appId
and m.chatType = com.xuqm.im.entity.ImMessageEntity$ChatType.SINGLE and m.chatType = com.xuqm.im.entity.ImMessageEntity$ChatType.SINGLE
and ((m.fromUserId = :userId and m.toId = :peerId) and ((m.fromUserId = :userId and m.toId = :peerId)
or (m.fromUserId = :peerId and m.toId = :userId)) or (m.fromUserId = :peerId and m.toId = :userId))
@ -81,7 +81,7 @@ public interface ImMessageRepository extends JpaRepository<ImMessageEntity, Stri
order by m.createdAt desc order by m.createdAt desc
""") """)
Page<ImMessageEntity> findSingleConversationFiltered( Page<ImMessageEntity> findSingleConversationFiltered(
@Param("appKey") String appKey, @Param("appId") String appId,
@Param("userId") String userId, @Param("userId") String userId,
@Param("peerId") String peerId, @Param("peerId") String peerId,
@Param("msgType") ImMessageEntity.MsgType msgType, @Param("msgType") ImMessageEntity.MsgType msgType,
@ -90,33 +90,33 @@ public interface ImMessageRepository extends JpaRepository<ImMessageEntity, Stri
@Param("endTime") LocalDateTime endTime, @Param("endTime") LocalDateTime endTime,
Pageable pageable); Pageable pageable);
List<ImMessageEntity> findByAppKeyAndFromUserIdAndToIdAndCreatedAtLessThanEqualOrderByCreatedAtAsc( List<ImMessageEntity> findByAppIdAndFromUserIdAndToIdAndCreatedAtLessThanEqualOrderByCreatedAtAsc(
String appKey, String appId,
String fromUserId, String fromUserId,
String toId, String toId,
LocalDateTime createdAt); LocalDateTime createdAt);
List<ImMessageEntity> findByAppKeyAndToIdAndChatTypeAndCreatedAtLessThanEqualOrderByCreatedAtAsc( List<ImMessageEntity> findByAppIdAndToIdAndChatTypeAndCreatedAtLessThanEqualOrderByCreatedAtAsc(
String appKey, String appId,
String toId, String toId,
ImMessageEntity.ChatType chatType, ImMessageEntity.ChatType chatType,
LocalDateTime createdAt); LocalDateTime createdAt);
@Query(""" @Query("""
select m from ImMessageEntity m select m from ImMessageEntity m
where m.appKey = :appKey where m.appId = :appId
and m.chatType = com.xuqm.im.entity.ImMessageEntity$ChatType.GROUP and m.chatType = com.xuqm.im.entity.ImMessageEntity$ChatType.GROUP
and m.toId = :groupId and m.toId = :groupId
order by m.createdAt desc order by m.createdAt desc
""") """)
Page<ImMessageEntity> findGroupHistory( Page<ImMessageEntity> findGroupHistory(
@Param("appKey") String appKey, @Param("appId") String appId,
@Param("groupId") String groupId, @Param("groupId") String groupId,
Pageable pageable); Pageable pageable);
@Query(""" @Query("""
select m from ImMessageEntity m select m from ImMessageEntity m
where m.appKey = :appKey where m.appId = :appId
and m.chatType = com.xuqm.im.entity.ImMessageEntity$ChatType.GROUP and m.chatType = com.xuqm.im.entity.ImMessageEntity$ChatType.GROUP
and m.toId = :groupId and m.toId = :groupId
and (:msgType is null or m.msgType = :msgType) and (:msgType is null or m.msgType = :msgType)
@ -129,7 +129,7 @@ public interface ImMessageRepository extends JpaRepository<ImMessageEntity, Stri
order by m.createdAt desc order by m.createdAt desc
""") """)
Page<ImMessageEntity> findGroupHistoryFiltered( Page<ImMessageEntity> findGroupHistoryFiltered(
@Param("appKey") String appKey, @Param("appId") String appId,
@Param("groupId") String groupId, @Param("groupId") String groupId,
@Param("msgType") ImMessageEntity.MsgType msgType, @Param("msgType") ImMessageEntity.MsgType msgType,
@Param("keyword") String keyword, @Param("keyword") String keyword,
@ -139,7 +139,7 @@ public interface ImMessageRepository extends JpaRepository<ImMessageEntity, Stri
@Query(""" @Query("""
select m from ImMessageEntity m select m from ImMessageEntity m
where m.appKey = :appKey where m.appId = :appId
and (:chatType is null or m.chatType = :chatType) and (:chatType is null or m.chatType = :chatType)
and (:msgType is null or m.msgType = :msgType) and (:msgType is null or m.msgType = :msgType)
and (:keyword is null or :keyword = '' or and (:keyword is null or :keyword = '' or
@ -152,7 +152,7 @@ public interface ImMessageRepository extends JpaRepository<ImMessageEntity, Stri
order by m.createdAt desc order by m.createdAt desc
""") """)
Page<ImMessageEntity> searchByKeyword( Page<ImMessageEntity> searchByKeyword(
@Param("appKey") String appKey, @Param("appId") String appId,
@Param("chatType") ImMessageEntity.ChatType chatType, @Param("chatType") ImMessageEntity.ChatType chatType,
@Param("msgType") ImMessageEntity.MsgType msgType, @Param("msgType") ImMessageEntity.MsgType msgType,
@Param("keyword") String keyword, @Param("keyword") String keyword,
@ -162,7 +162,7 @@ public interface ImMessageRepository extends JpaRepository<ImMessageEntity, Stri
@Query(""" @Query("""
select m from ImMessageEntity m select m from ImMessageEntity m
where m.appKey = :appKey where m.appId = :appId
and (:chatType is null or m.chatType = :chatType) and (:chatType is null or m.chatType = :chatType)
and (:msgType is null or m.msgType = :msgType) and (:msgType is null or m.msgType = :msgType)
and (:keyword is null or :keyword = '' or and (:keyword is null or :keyword = '' or
@ -178,7 +178,7 @@ public interface ImMessageRepository extends JpaRepository<ImMessageEntity, Stri
or (m.chatType = com.xuqm.im.entity.ImMessageEntity$ChatType.GROUP or (m.chatType = com.xuqm.im.entity.ImMessageEntity$ChatType.GROUP
and m.toId in ( and m.toId in (
select g.id from ImGroupEntity g select g.id from ImGroupEntity g
where g.appKey = :appKey where g.appId = :appId
and function('JSON_CONTAINS', g.memberIds, function('JSON_QUOTE', :userId)) = 1 and function('JSON_CONTAINS', g.memberIds, function('JSON_QUOTE', :userId)) = 1
) )
) )
@ -186,7 +186,7 @@ public interface ImMessageRepository extends JpaRepository<ImMessageEntity, Stri
order by m.createdAt desc order by m.createdAt desc
""") """)
Page<ImMessageEntity> searchByKeywordForUser( Page<ImMessageEntity> searchByKeywordForUser(
@Param("appKey") String appKey, @Param("appId") String appId,
@Param("userId") String userId, @Param("userId") String userId,
@Param("chatType") ImMessageEntity.ChatType chatType, @Param("chatType") ImMessageEntity.ChatType chatType,
@Param("msgType") ImMessageEntity.MsgType msgType, @Param("msgType") ImMessageEntity.MsgType msgType,
@ -197,7 +197,7 @@ public interface ImMessageRepository extends JpaRepository<ImMessageEntity, Stri
@Query(""" @Query("""
select count(m) from ImMessageEntity m select count(m) from ImMessageEntity m
where m.appKey = :appKey where m.appId = :appId
and m.chatType = com.xuqm.im.entity.ImMessageEntity$ChatType.SINGLE and m.chatType = com.xuqm.im.entity.ImMessageEntity$ChatType.SINGLE
and ((m.fromUserId = :userId and m.toId = :peerId) and ((m.fromUserId = :userId and m.toId = :peerId)
or (m.fromUserId = :peerId and m.toId = :userId)) or (m.fromUserId = :peerId and m.toId = :userId))
@ -205,48 +205,48 @@ public interface ImMessageRepository extends JpaRepository<ImMessageEntity, Stri
and (:since is null or m.createdAt > :since) and (:since is null or m.createdAt > :since)
""") """)
long countUnreadSingleConversation( long countUnreadSingleConversation(
@Param("appKey") String appKey, @Param("appId") String appId,
@Param("userId") String userId, @Param("userId") String userId,
@Param("peerId") String peerId, @Param("peerId") String peerId,
@Param("since") LocalDateTime since); @Param("since") LocalDateTime since);
@Query(""" @Query("""
select count(m) from ImMessageEntity m select count(m) from ImMessageEntity m
where m.appKey = :appKey where m.appId = :appId
and m.chatType = com.xuqm.im.entity.ImMessageEntity$ChatType.GROUP and m.chatType = com.xuqm.im.entity.ImMessageEntity$ChatType.GROUP
and m.toId = :groupId and m.toId = :groupId
and m.fromUserId <> :userId and m.fromUserId <> :userId
and (:since is null or m.createdAt > :since) and (:since is null or m.createdAt > :since)
""") """)
long countUnreadGroupConversation( long countUnreadGroupConversation(
@Param("appKey") String appKey, @Param("appId") String appId,
@Param("userId") String userId, @Param("userId") String userId,
@Param("groupId") String groupId, @Param("groupId") String groupId,
@Param("since") LocalDateTime since); @Param("since") LocalDateTime since);
long countByAppKey(String appKey); long countByAppId(String appId);
@Query("select count(m) from ImMessageEntity m where m.appKey = :appKey and m.createdAt >= :since") @Query("select count(m) from ImMessageEntity m where m.appId = :appId and m.createdAt >= :since")
long countByAppKeyAndCreatedAtAfter(@Param("appKey") String appKey, @Param("since") LocalDateTime since); long countByAppIdAndCreatedAtAfter(@Param("appId") String appId, @Param("since") LocalDateTime since);
@Query("select count(m) from ImMessageEntity m where m.appKey = :appKey and m.chatType = :chatType and m.createdAt >= :since") @Query("select count(m) from ImMessageEntity m where m.appId = :appId and m.chatType = :chatType and m.createdAt >= :since")
long countByAppKeyAndChatTypeAndCreatedAtAfter( long countByAppIdAndChatTypeAndCreatedAtAfter(
@Param("appKey") String appKey, @Param("appId") String appId,
@Param("chatType") ImMessageEntity.ChatType chatType, @Param("chatType") ImMessageEntity.ChatType chatType,
@Param("since") LocalDateTime since); @Param("since") LocalDateTime since);
default long countTodayByAppKey(String appKey) { default long countTodayByAppId(String appId) {
return countByAppKeyAndCreatedAtAfter(appKey, LocalDateTime.now().toLocalDate().atStartOfDay()); return countByAppIdAndCreatedAtAfter(appId, LocalDateTime.now().toLocalDate().atStartOfDay());
} }
@Query(""" @Query("""
select m from ImMessageEntity m select m from ImMessageEntity m
where m.appKey = :appKey where m.appId = :appId
and m.chatType = com.xuqm.im.entity.ImMessageEntity$ChatType.SINGLE and m.chatType = com.xuqm.im.entity.ImMessageEntity$ChatType.SINGLE
and m.toId = :userId and m.toId = :userId
and m.status <> com.xuqm.im.entity.ImMessageEntity$MsgStatus.READ and m.status <> com.xuqm.im.entity.ImMessageEntity$MsgStatus.READ
""") """)
List<ImMessageEntity> findUnreadByAppKeyAndToId( List<ImMessageEntity> findUnreadByAppIdAndToId(
@Param("appKey") String appKey, @Param("appId") String appId,
@Param("userId") String userId); @Param("userId") String userId);
} }

查看文件

@ -11,14 +11,14 @@ import java.util.List;
@Repository @Repository
public interface ImOfflineMessageRepository extends JpaRepository<ImOfflineMessageEntity, String> { public interface ImOfflineMessageRepository extends JpaRepository<ImOfflineMessageEntity, String> {
List<ImOfflineMessageEntity> findByAppKeyAndUserIdAndDeliveredFalse(String appKey, String userId); List<ImOfflineMessageEntity> findByAppIdAndUserIdAndDeliveredFalse(String appId, String userId);
@Modifying @Modifying
@Query("UPDATE ImOfflineMessageEntity o SET o.delivered = true WHERE o.id IN ?1") @Query("UPDATE ImOfflineMessageEntity o SET o.delivered = true WHERE o.id IN ?1")
void markDeliveredByIds(List<String> ids); void markDeliveredByIds(List<String> ids);
@Query("SELECT COUNT(o) FROM ImOfflineMessageEntity o WHERE o.appKey = ?1 AND o.userId = ?2 AND o.delivered = false") @Query("SELECT COUNT(o) FROM ImOfflineMessageEntity o WHERE o.appId = ?1 AND o.userId = ?2 AND o.delivered = false")
long countUndeliveredByAppKeyAndUserId(String appKey, String userId); long countUndeliveredByAppIdAndUserId(String appId, String userId);
void deleteByAppKeyAndUserIdAndDeliveredTrue(String appKey, String userId); void deleteByAppIdAndUserIdAndDeliveredTrue(String appId, String userId);
} }

查看文件

@ -6,5 +6,5 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
public interface ImOperationLogRepository extends JpaRepository<ImOperationLogEntity, String> { public interface ImOperationLogRepository extends JpaRepository<ImOperationLogEntity, String> {
Page<ImOperationLogEntity> findByAppKeyOrderByCreatedAtDesc(String appKey, Pageable pageable); Page<ImOperationLogEntity> findByAppIdOrderByCreatedAtDesc(String appId, Pageable pageable);
} }

查看文件

@ -5,7 +5,7 @@ import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List; import java.util.List;
public interface KeywordFilterRepository extends JpaRepository<KeywordFilterEntity, String> { public interface KeywordFilterRepository extends JpaRepository<KeywordFilterEntity, String> {
List<KeywordFilterEntity> findByAppKeyAndEnabledTrue(String appKey); List<KeywordFilterEntity> findByAppIdAndEnabledTrue(String appId);
List<KeywordFilterEntity> findByAppKey(String appKey); List<KeywordFilterEntity> findByAppId(String appId);
java.util.Optional<KeywordFilterEntity> findByIdAndAppId(String id, String appKey); java.util.Optional<KeywordFilterEntity> findByIdAndAppId(String id, String appId);
} }

查看文件

@ -8,10 +8,10 @@ import org.springframework.data.jpa.repository.Query;
public interface WebhookAlertRepository extends JpaRepository<WebhookAlertEntity, String> { public interface WebhookAlertRepository extends JpaRepository<WebhookAlertEntity, String> {
Page<WebhookAlertEntity> findByAppKey(String appKey, Pageable pageable); Page<WebhookAlertEntity> findByAppId(String appId, Pageable pageable);
Page<WebhookAlertEntity> findByAppKeyAndAcknowledged(String appKey, boolean acknowledged, Pageable pageable); Page<WebhookAlertEntity> findByAppIdAndAcknowledged(String appId, boolean acknowledged, Pageable pageable);
@Query("SELECT COUNT(a) FROM WebhookAlertEntity a WHERE a.appKey = ?1 AND a.acknowledged = false") @Query("SELECT COUNT(a) FROM WebhookAlertEntity a WHERE a.appId = ?1 AND a.acknowledged = false")
long countUnacknowledgedByAppKey(String appKey); long countUnacknowledgedByAppId(String appId);
} }

查看文件

@ -5,7 +5,7 @@ import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List; import java.util.List;
public interface WebhookConfigRepository extends JpaRepository<WebhookConfigEntity, String> { public interface WebhookConfigRepository extends JpaRepository<WebhookConfigEntity, String> {
List<WebhookConfigEntity> findByAppKeyAndEnabledTrue(String appKey); List<WebhookConfigEntity> findByAppIdAndEnabledTrue(String appId);
List<WebhookConfigEntity> findByAppKey(String appKey); List<WebhookConfigEntity> findByAppId(String appId);
java.util.Optional<WebhookConfigEntity> findByIdAndAppId(String id, String appKey); java.util.Optional<WebhookConfigEntity> findByIdAndAppId(String id, String appId);
} }

查看文件

@ -10,21 +10,21 @@ import java.util.List;
public interface WebhookDeliveryRepository extends JpaRepository<WebhookDeliveryEntity, String> { public interface WebhookDeliveryRepository extends JpaRepository<WebhookDeliveryEntity, String> {
Page<WebhookDeliveryEntity> findByAppKeyAndCallbackEvent(String appKey, String callbackEvent, Pageable pageable); Page<WebhookDeliveryEntity> findByAppIdAndCallbackEvent(String appId, String callbackEvent, Pageable pageable);
Page<WebhookDeliveryEntity> findByAppKey(String appKey, Pageable pageable); Page<WebhookDeliveryEntity> findByAppId(String appId, Pageable pageable);
Page<WebhookDeliveryEntity> findByAppKeyAndSuccess(String appKey, boolean success, Pageable pageable); Page<WebhookDeliveryEntity> findByAppIdAndSuccess(String appId, boolean success, Pageable pageable);
List<WebhookDeliveryEntity> findByCallbackId(String callbackId); List<WebhookDeliveryEntity> findByCallbackId(String callbackId);
@Query("SELECT COUNT(d) FROM WebhookDeliveryEntity d WHERE d.appKey = ?1 AND d.success = true AND d.createdAt >= ?2") @Query("SELECT COUNT(d) FROM WebhookDeliveryEntity d WHERE d.appId = ?1 AND d.success = true AND d.createdAt >= ?2")
long countSuccessfulByAppKeySince(String appKey, LocalDateTime since); long countSuccessfulByAppIdSince(String appId, LocalDateTime since);
@Query("SELECT COUNT(d) FROM WebhookDeliveryEntity d WHERE d.appKey = ?1 AND d.success = false AND d.createdAt >= ?2") @Query("SELECT COUNT(d) FROM WebhookDeliveryEntity d WHERE d.appId = ?1 AND d.success = false AND d.createdAt >= ?2")
long countFailedByAppKeySince(String appKey, LocalDateTime since); long countFailedByAppIdSince(String appId, LocalDateTime since);
@Query("SELECT d.callbackEvent, COUNT(d), SUM(CASE WHEN d.success = true THEN 1 ELSE 0 END) " + @Query("SELECT d.callbackEvent, COUNT(d), SUM(CASE WHEN d.success = true THEN 1 ELSE 0 END) " +
"FROM WebhookDeliveryEntity d WHERE d.appKey = ?1 AND d.createdAt >= ?2 GROUP BY d.callbackEvent") "FROM WebhookDeliveryEntity d WHERE d.appId = ?1 AND d.createdAt >= ?2 GROUP BY d.callbackEvent")
List<Object[]> statsByAppKeySince(String appKey, LocalDateTime since); List<Object[]> statsByAppIdSince(String appId, LocalDateTime since);
} }

查看文件

@ -23,11 +23,11 @@ public class BlacklistService {
@Transactional @Transactional
public ImBlacklistEntity add(String appKey, String userId, String blockedUserId) { public ImBlacklistEntity add(String appKey, String userId, String blockedUserId) {
return repository.findByAppKeyAndUserIdAndBlockedUserId(appKey, userId, blockedUserId) return repository.findByAppIdAndUserIdAndBlockedUserId(appKey, userId, blockedUserId)
.orElseGet(() -> { .orElseGet(() -> {
ImBlacklistEntity entity = new ImBlacklistEntity(); ImBlacklistEntity entity = new ImBlacklistEntity();
entity.setId(UUID.randomUUID().toString()); entity.setId(UUID.randomUUID().toString());
entity.setAppKey(appKey); entity.setAppId(appKey);
entity.setUserId(userId); entity.setUserId(userId);
entity.setBlockedUserId(blockedUserId); entity.setBlockedUserId(blockedUserId);
entity.setCreatedAt(LocalDateTime.now()); entity.setCreatedAt(LocalDateTime.now());
@ -39,24 +39,24 @@ public class BlacklistService {
@Transactional @Transactional
public void remove(String appKey, String userId, String blockedUserId) { public void remove(String appKey, String userId, String blockedUserId) {
ImBlacklistEntity entity = repository.findByAppKeyAndUserIdAndBlockedUserId(appKey, userId, blockedUserId) ImBlacklistEntity entity = repository.findByAppIdAndUserIdAndBlockedUserId(appKey, userId, blockedUserId)
.orElse(null); .orElse(null);
repository.deleteByAppKeyAndUserIdAndBlockedUserId(appKey, userId, blockedUserId); repository.deleteByAppIdAndUserIdAndBlockedUserId(appKey, userId, blockedUserId);
if (entity != null) { if (entity != null) {
dispatchWebhook(entity, "blacklist.removed"); dispatchWebhook(entity, "blacklist.removed");
} }
} }
public List<ImBlacklistEntity> list(String appKey, String userId) { public List<ImBlacklistEntity> list(String appKey, String userId) {
return repository.findByAppKeyAndUserId(appKey, userId); return repository.findByAppIdAndUserId(appKey, userId);
} }
public List<ImBlacklistEntity> listByApp(String appKey) { public List<ImBlacklistEntity> listByApp(String appKey) {
return repository.findByAppKey(appKey); return repository.findByAppId(appKey);
} }
public boolean isBlocked(String appKey, String userId, String blockedUserId) { public boolean isBlocked(String appKey, String userId, String blockedUserId) {
return repository.existsByAppKeyAndUserIdAndBlockedUserId(appKey, userId, blockedUserId); return repository.existsByAppIdAndUserIdAndBlockedUserId(appKey, userId, blockedUserId);
} }
public boolean isEitherBlocked(String appKey, String userId, String targetUserId) { public boolean isEitherBlocked(String appKey, String userId, String targetUserId) {
@ -65,11 +65,11 @@ public class BlacklistService {
private void dispatchWebhook(ImBlacklistEntity entity, String callbackEvent) { private void dispatchWebhook(ImBlacklistEntity entity, String callbackEvent) {
webhookDispatchService.dispatch( webhookDispatchService.dispatch(
entity.getAppKey(), entity.getAppId(),
"blacklist", "blacklist",
callbackEvent, callbackEvent,
new BlacklistCallbackPayload( new BlacklistCallbackPayload(
entity.getAppKey(), entity.getAppId(),
entity.getId(), entity.getId(),
entity.getUserId(), entity.getUserId(),
entity.getBlockedUserId(), entity.getBlockedUserId(),

查看文件

@ -87,7 +87,7 @@ public class ConversationStateService {
@Transactional @Transactional
public void deleteConversationState(String appKey, String userId, String targetId, String chatType) { public void deleteConversationState(String appKey, String userId, String targetId, String chatType) {
repository.deleteByAppKeyAndUserIdAndTargetIdAndChatType(appKey, userId, targetId, chatType); repository.deleteByAppIdAndUserIdAndTargetIdAndChatType(appKey, userId, targetId, chatType);
} }
@Transactional @Transactional
@ -107,7 +107,7 @@ public class ConversationStateService {
public void clearHiddenForUsers(String appKey, String targetId, String chatType, Collection<String> userIds) { public void clearHiddenForUsers(String appKey, String targetId, String chatType, Collection<String> userIds) {
for (String userId : userIds) { for (String userId : userIds) {
ImConversationStateEntity state = repository ImConversationStateEntity state = repository
.findByAppKeyAndUserIdAndTargetIdAndChatType(appKey, userId, targetId, chatType) .findByAppIdAndUserIdAndTargetIdAndChatType(appKey, userId, targetId, chatType)
.orElse(null); .orElse(null);
if (state != null && state.isHidden()) { if (state != null && state.isHidden()) {
state.setHidden(false); state.setHidden(false);
@ -118,11 +118,11 @@ public class ConversationStateService {
} }
public ImConversationStateEntity getOrCreate(String appKey, String userId, String targetId, String chatType) { public ImConversationStateEntity getOrCreate(String appKey, String userId, String targetId, String chatType) {
return repository.findByAppKeyAndUserIdAndTargetIdAndChatType(appKey, userId, targetId, chatType) return repository.findByAppIdAndUserIdAndTargetIdAndChatType(appKey, userId, targetId, chatType)
.orElseGet(() -> { .orElseGet(() -> {
ImConversationStateEntity entity = new ImConversationStateEntity(); ImConversationStateEntity entity = new ImConversationStateEntity();
entity.setId(UUID.randomUUID().toString()); entity.setId(UUID.randomUUID().toString());
entity.setAppKey(appKey); entity.setAppId(appKey);
entity.setUserId(userId); entity.setUserId(userId);
entity.setTargetId(targetId); entity.setTargetId(targetId);
entity.setChatType(chatType); entity.setChatType(chatType);
@ -139,16 +139,16 @@ public class ConversationStateService {
} }
public ImConversationStateEntity find(String appKey, String userId, String targetId, String chatType) { public ImConversationStateEntity find(String appKey, String userId, String targetId, String chatType) {
return repository.findByAppKeyAndUserIdAndTargetIdAndChatType(appKey, userId, targetId, chatType) return repository.findByAppIdAndUserIdAndTargetIdAndChatType(appKey, userId, targetId, chatType)
.orElse(null); .orElse(null);
} }
public List<ImConversationStateEntity> listVisible(String appKey, String userId) { public List<ImConversationStateEntity> listVisible(String appKey, String userId) {
return repository.findByAppKeyAndUserIdAndHiddenFalse(appKey, userId); return repository.findByAppIdAndUserIdAndHiddenFalse(appKey, userId);
} }
public List<String> listConversationGroups(String appKey, String userId) { public List<String> listConversationGroups(String appKey, String userId) {
return repository.findByAppKeyAndUserId(appKey, userId).stream() return repository.findByAppIdAndUserId(appKey, userId).stream()
.map(ImConversationStateEntity::getConversationGroup) .map(ImConversationStateEntity::getConversationGroup)
.filter(group -> group != null && !group.isBlank()) .filter(group -> group != null && !group.isBlank())
.distinct() .distinct()
@ -157,7 +157,7 @@ public class ConversationStateService {
} }
public List<ImConversationStateEntity> listByConversationGroup(String appKey, String userId, String conversationGroup) { public List<ImConversationStateEntity> listByConversationGroup(String appKey, String userId, String conversationGroup) {
return repository.findByAppKeyAndUserIdAndConversationGroup(appKey, userId, normalizeGroup(conversationGroup)); return repository.findByAppIdAndUserIdAndConversationGroup(appKey, userId, normalizeGroup(conversationGroup));
} }
private void touch(ImConversationStateEntity entity) { private void touch(ImConversationStateEntity entity) {

查看文件

@ -51,12 +51,12 @@ public class FriendRequestService {
throw new BusinessException(403, "当前应用未开放好友申请"); throw new BusinessException(403, "当前应用未开放好友申请");
} }
final boolean[] created = {false}; final boolean[] created = {false};
ImFriendRequestEntity saved = requestRepository.findByAppKeyAndFromUserIdAndToUserId(appKey, fromUserId, toUserId) ImFriendRequestEntity saved = requestRepository.findByAppIdAndFromUserIdAndToUserId(appKey, fromUserId, toUserId)
.orElseGet(() -> { .orElseGet(() -> {
created[0] = true; created[0] = true;
ImFriendRequestEntity entity = new ImFriendRequestEntity(); ImFriendRequestEntity entity = new ImFriendRequestEntity();
entity.setId(UUID.randomUUID().toString()); entity.setId(UUID.randomUUID().toString());
entity.setAppKey(appKey); entity.setAppId(appKey);
entity.setFromUserId(fromUserId); entity.setFromUserId(fromUserId);
entity.setToUserId(toUserId); entity.setToUserId(toUserId);
entity.setRemark(remark); entity.setRemark(remark);
@ -94,10 +94,10 @@ public class FriendRequestService {
request.setReviewedAt(LocalDateTime.now()); request.setReviewedAt(LocalDateTime.now());
requestRepository.save(request); requestRepository.save(request);
friendRepository friendRepository
.findByAppKeyAndUserIdAndFriendId(appKey, request.getFromUserId(), request.getToUserId()) .findByAppIdAndUserIdAndFriendId(appKey, request.getFromUserId(), request.getToUserId())
.orElseGet(() -> friendEntity(appKey, request.getFromUserId(), request.getToUserId())); .orElseGet(() -> friendEntity(appKey, request.getFromUserId(), request.getToUserId()));
friendRepository friendRepository
.findByAppKeyAndUserIdAndFriendId(appKey, request.getToUserId(), request.getFromUserId()) .findByAppIdAndUserIdAndFriendId(appKey, request.getToUserId(), request.getFromUserId())
.orElseGet(() -> friendEntity(appKey, request.getToUserId(), request.getFromUserId())); .orElseGet(() -> friendEntity(appKey, request.getToUserId(), request.getFromUserId()));
dispatchWebhook(request, "friend.request.accepted"); dispatchWebhook(request, "friend.request.accepted");
publishNotification( publishNotification(
@ -148,17 +148,17 @@ public class FriendRequestService {
} }
public List<ImFriendRequestEntity> incoming(String appKey, String userId) { public List<ImFriendRequestEntity> incoming(String appKey, String userId) {
return requestRepository.findByAppKeyAndToUserId(appKey, userId).stream() return requestRepository.findByAppIdAndToUserId(appKey, userId).stream()
.filter(request -> ImFriendRequestEntity.Status.PENDING.name().equals(request.getStatus())) .filter(request -> ImFriendRequestEntity.Status.PENDING.name().equals(request.getStatus()))
.toList(); .toList();
} }
public List<ImFriendRequestEntity> outgoing(String appKey, String userId) { public List<ImFriendRequestEntity> outgoing(String appKey, String userId) {
return requestRepository.findByAppKeyAndFromUserId(appKey, userId); return requestRepository.findByAppIdAndFromUserId(appKey, userId);
} }
public List<ImFriendRequestEntity> listByApp(String appKey) { public List<ImFriendRequestEntity> listByApp(String appKey) {
return requestRepository.findByAppKey(appKey); return requestRepository.findByAppId(appKey);
} }
@Transactional @Transactional
@ -176,7 +176,7 @@ public class FriendRequestService {
private ImFriendRequestEntity getRequest(String appKey, String requestId, String operatorId) { private ImFriendRequestEntity getRequest(String appKey, String requestId, String operatorId) {
ImFriendRequestEntity request = requestRepository.findById(requestId) ImFriendRequestEntity request = requestRepository.findById(requestId)
.orElseThrow(() -> new BusinessException(404, "好友申请不存在")); .orElseThrow(() -> new BusinessException(404, "好友申请不存在"));
if (!request.getAppKey().equals(appKey) || !request.getToUserId().equals(operatorId)) { if (!request.getAppId().equals(appKey) || !request.getToUserId().equals(operatorId)) {
throw new BusinessException(403, "无权操作"); throw new BusinessException(403, "无权操作");
} }
return request; return request;
@ -185,7 +185,7 @@ public class FriendRequestService {
private ImFriendRequestEntity getRequest(String appKey, String requestId) { private ImFriendRequestEntity getRequest(String appKey, String requestId) {
ImFriendRequestEntity request = requestRepository.findById(requestId) ImFriendRequestEntity request = requestRepository.findById(requestId)
.orElseThrow(() -> new BusinessException(404, "好友申请不存在")); .orElseThrow(() -> new BusinessException(404, "好友申请不存在"));
if (!request.getAppKey().equals(appKey)) { if (!request.getAppId().equals(appKey)) {
throw new BusinessException(403, "无权操作"); throw new BusinessException(403, "无权操作");
} }
return request; return request;
@ -201,11 +201,11 @@ public class FriendRequestService {
request.setReviewedAt(LocalDateTime.now()); request.setReviewedAt(LocalDateTime.now());
ImFriendRequestEntity saved = requestRepository.save(request); ImFriendRequestEntity saved = requestRepository.save(request);
friendRepository friendRepository
.findByAppKeyAndUserIdAndFriendId(request.getAppKey(), request.getFromUserId(), request.getToUserId()) .findByAppIdAndUserIdAndFriendId(request.getAppId(), request.getFromUserId(), request.getToUserId())
.orElseGet(() -> friendEntity(request.getAppKey(), request.getFromUserId(), request.getToUserId())); .orElseGet(() -> friendEntity(request.getAppId(), request.getFromUserId(), request.getToUserId()));
friendRepository friendRepository
.findByAppKeyAndUserIdAndFriendId(request.getAppKey(), request.getToUserId(), request.getFromUserId()) .findByAppIdAndUserIdAndFriendId(request.getAppId(), request.getToUserId(), request.getFromUserId())
.orElseGet(() -> friendEntity(request.getAppKey(), request.getToUserId(), request.getFromUserId())); .orElseGet(() -> friendEntity(request.getAppId(), request.getToUserId(), request.getFromUserId()));
dispatchWebhook(saved, "friend.request.accepted"); dispatchWebhook(saved, "friend.request.accepted");
publishNotification( publishNotification(
request, request,
@ -225,7 +225,7 @@ public class FriendRequestService {
private com.xuqm.im.entity.ImFriendEntity friendEntity(String appKey, String userId, String friendId) { private com.xuqm.im.entity.ImFriendEntity friendEntity(String appKey, String userId, String friendId) {
com.xuqm.im.entity.ImFriendEntity entity = new com.xuqm.im.entity.ImFriendEntity(); com.xuqm.im.entity.ImFriendEntity entity = new com.xuqm.im.entity.ImFriendEntity();
entity.setAppKey(appKey); entity.setAppId(appKey);
entity.setUserId(userId); entity.setUserId(userId);
entity.setFriendId(friendId); entity.setFriendId(friendId);
return friendRepository.save(entity); return friendRepository.save(entity);
@ -245,7 +245,7 @@ public class FriendRequestService {
) { ) {
ImMessageEntity message = new ImMessageEntity(); ImMessageEntity message = new ImMessageEntity();
message.setId(UUID.randomUUID().toString()); message.setId(UUID.randomUUID().toString());
message.setAppKey(request.getAppKey()); message.setAppId(request.getAppId());
message.setFromUserId(fromUserId); message.setFromUserId(fromUserId);
message.setToId(toUserId); message.setToId(toUserId);
message.setChatType(ImMessageEntity.ChatType.SINGLE); message.setChatType(ImMessageEntity.ChatType.SINGLE);
@ -302,11 +302,11 @@ public class FriendRequestService {
private void dispatchWebhook(ImFriendRequestEntity request, String callbackEvent) { private void dispatchWebhook(ImFriendRequestEntity request, String callbackEvent) {
webhookDispatchService.dispatch( webhookDispatchService.dispatch(
request.getAppKey(), request.getAppId(),
"friend_request", "friend_request",
callbackEvent, callbackEvent,
new FriendRequestCallbackPayload( new FriendRequestCallbackPayload(
request.getAppKey(), request.getAppId(),
request.getId(), request.getId(),
request.getFromUserId(), request.getFromUserId(),
request.getToUserId(), request.getToUserId(),

查看文件

@ -17,14 +17,14 @@ public class GlobalMuteService {
} }
public boolean isEnabled(String appKey) { public boolean isEnabled(String appKey) {
return repository.findByAppKey(appKey).map(ImGlobalMuteEntity::isEnabled).orElse(false); return repository.findByAppId(appKey).map(ImGlobalMuteEntity::isEnabled).orElse(false);
} }
public ImGlobalMuteEntity get(String appKey) { public ImGlobalMuteEntity get(String appKey) {
return repository.findByAppKey(appKey).orElseGet(() -> { return repository.findByAppId(appKey).orElseGet(() -> {
ImGlobalMuteEntity entity = new ImGlobalMuteEntity(); ImGlobalMuteEntity entity = new ImGlobalMuteEntity();
entity.setId(UUID.randomUUID().toString()); entity.setId(UUID.randomUUID().toString());
entity.setAppKey(appKey); entity.setAppId(appKey);
entity.setEnabled(false); entity.setEnabled(false);
entity.setCreatedAt(LocalDateTime.now()); entity.setCreatedAt(LocalDateTime.now());
entity.setUpdatedAt(LocalDateTime.now()); entity.setUpdatedAt(LocalDateTime.now());
@ -33,10 +33,10 @@ public class GlobalMuteService {
} }
public ImGlobalMuteEntity setEnabled(String appKey, boolean enabled) { public ImGlobalMuteEntity setEnabled(String appKey, boolean enabled) {
ImGlobalMuteEntity entity = repository.findByAppKey(appKey).orElseGet(() -> { ImGlobalMuteEntity entity = repository.findByAppId(appKey).orElseGet(() -> {
ImGlobalMuteEntity created = new ImGlobalMuteEntity(); ImGlobalMuteEntity created = new ImGlobalMuteEntity();
created.setId(UUID.randomUUID().toString()); created.setId(UUID.randomUUID().toString());
created.setAppKey(appKey); created.setAppId(appKey);
created.setCreatedAt(LocalDateTime.now()); created.setCreatedAt(LocalDateTime.now());
return created; return created;
}); });

查看文件

@ -47,11 +47,11 @@ public class ImAccountService {
} }
public LoginResult loginOrRegister(String appKey, String userId) { public LoginResult loginOrRegister(String appKey, String userId) {
ImAccountEntity account = accountRepository.findByAppKeyAndUserId(appKey, userId) ImAccountEntity account = accountRepository.findByAppIdAndUserId(appKey, userId)
.orElseGet(() -> { .orElseGet(() -> {
ImAccountEntity e = new ImAccountEntity(); ImAccountEntity e = new ImAccountEntity();
e.setId(UUID.randomUUID().toString()); e.setId(UUID.randomUUID().toString());
e.setAppKey(appKey); e.setAppId(appKey);
e.setUserId(userId); e.setUserId(userId);
e.setGender(ImAccountEntity.Gender.UNKNOWN); e.setGender(ImAccountEntity.Gender.UNKNOWN);
e.setStatus(ImAccountEntity.Status.ACTIVE); e.setStatus(ImAccountEntity.Status.ACTIVE);
@ -67,7 +67,7 @@ public class ImAccountService {
} }
public ImAccountEntity getAccount(String appKey, String userId) { public ImAccountEntity getAccount(String appKey, String userId) {
return accountRepository.findByAppKeyAndUserId(appKey, userId) return accountRepository.findByAppIdAndUserId(appKey, userId)
.orElseThrow(() -> new BusinessException(404, "账号不存在")); .orElseThrow(() -> new BusinessException(404, "账号不存在"));
} }
@ -98,11 +98,11 @@ public class ImAccountService {
public ImAccountEntity importAccount(String appKey, String userId, String nickname, public ImAccountEntity importAccount(String appKey, String userId, String nickname,
String avatar, ImAccountEntity.Gender gender, String avatar, ImAccountEntity.Gender gender,
ImAccountEntity.Status status) { ImAccountEntity.Status status) {
ImAccountEntity account = accountRepository.findByAppKeyAndUserId(appKey, userId) ImAccountEntity account = accountRepository.findByAppIdAndUserId(appKey, userId)
.orElseGet(() -> { .orElseGet(() -> {
ImAccountEntity entity = new ImAccountEntity(); ImAccountEntity entity = new ImAccountEntity();
entity.setId(UUID.randomUUID().toString()); entity.setId(UUID.randomUUID().toString());
entity.setAppKey(appKey); entity.setAppId(appKey);
entity.setUserId(userId); entity.setUserId(userId);
entity.setCreatedAt(LocalDateTime.now()); entity.setCreatedAt(LocalDateTime.now());
return entity; return entity;
@ -122,12 +122,12 @@ public class ImAccountService {
} }
public void deleteAccount(String appKey, String userId) { public void deleteAccount(String appKey, String userId) {
accountRepository.findByAppKeyAndUserId(appKey, userId) accountRepository.findByAppIdAndUserId(appKey, userId)
.ifPresent(accountRepository::delete); .ifPresent(accountRepository::delete);
} }
public boolean exists(String appKey, String userId) { public boolean exists(String appKey, String userId) {
return accountRepository.existsByAppKeyAndUserId(appKey, userId); return accountRepository.existsByAppIdAndUserId(appKey, userId);
} }
public List<ImAccountEntity> searchAccounts(String appKey, String keyword, int size) { public List<ImAccountEntity> searchAccounts(String appKey, String keyword, int size) {

查看文件

@ -75,7 +75,7 @@ public class ImGroupService {
ImGroupEntity group = new ImGroupEntity(); ImGroupEntity group = new ImGroupEntity();
group.setId(UUID.randomUUID().toString()); group.setId(UUID.randomUUID().toString());
group.setAppKey(appKey); group.setAppId(appKey);
group.setName(name); group.setName(name);
group.setGroupType(normalizeGroupType(groupType)); group.setGroupType(normalizeGroupType(groupType));
group.setCreatorId(creatorId); group.setCreatorId(creatorId);
@ -135,7 +135,7 @@ public class ImGroupService {
if (changed) { if (changed) {
group.setMemberIds(toJson(members)); group.setMemberIds(toJson(members));
ImGroupEntity saved = groupRepository.save(group); ImGroupEntity saved = groupRepository.save(group);
webhookDispatchService.dispatch(saved.getAppKey(), "group", "group.member_added", webhookDispatchService.dispatch(saved.getAppId(), "group", "group.member_added",
java.util.Map.of("groupId", saved.getId(), "addedUserIds", userIds, "operatorId", operatorId)); java.util.Map.of("groupId", saved.getId(), "addedUserIds", userIds, "operatorId", operatorId));
return saved; return saved;
} }
@ -153,7 +153,7 @@ public class ImGroupService {
members.remove(userId); members.remove(userId);
group.setMemberIds(toJson(members)); group.setMemberIds(toJson(members));
ImGroupEntity saved = groupRepository.save(group); ImGroupEntity saved = groupRepository.save(group);
webhookDispatchService.dispatch(saved.getAppKey(), "group", "group.member_removed", webhookDispatchService.dispatch(saved.getAppId(), "group", "group.member_removed",
java.util.Map.of("groupId", saved.getId(), "removedUserId", userId, "operatorId", operatorId)); java.util.Map.of("groupId", saved.getId(), "removedUserId", userId, "operatorId", operatorId));
return saved; return saved;
} }
@ -176,7 +176,7 @@ public class ImGroupService {
if (changed) { if (changed) {
group.setMemberIds(toJson(members)); group.setMemberIds(toJson(members));
ImGroupEntity saved = groupRepository.save(group); ImGroupEntity saved = groupRepository.save(group);
webhookDispatchService.dispatch(saved.getAppKey(), "group", "group.member_removed", webhookDispatchService.dispatch(saved.getAppId(), "group", "group.member_removed",
java.util.Map.of("groupId", saved.getId(), "removedUserIds", userIds, "operatorId", operatorId)); java.util.Map.of("groupId", saved.getId(), "removedUserIds", userIds, "operatorId", operatorId));
return saved; return saved;
} }
@ -197,7 +197,7 @@ public class ImGroupService {
group.setAnnouncement(announcement); group.setAnnouncement(announcement);
} }
ImGroupEntity saved = groupRepository.save(group); ImGroupEntity saved = groupRepository.save(group);
webhookDispatchService.dispatch(saved.getAppKey(), "group", "group.updated", webhookDispatchService.dispatch(saved.getAppId(), "group", "group.updated",
java.util.Map.of("groupId", saved.getId(), "name", saved.getName(), "operatorId", operatorId)); java.util.Map.of("groupId", saved.getId(), "name", saved.getName(), "operatorId", operatorId));
return saved; return saved;
} }
@ -268,7 +268,7 @@ public class ImGroupService {
} }
public List<ImGroupEntity> listByApp(String appKey) { public List<ImGroupEntity> listByApp(String appKey) {
return groupRepository.findByAppKey(appKey); return groupRepository.findByAppId(appKey);
} }
public List<ImGroupEntity> listUserGroups(String appKey, String userId) { public List<ImGroupEntity> listUserGroups(String appKey, String userId) {
@ -277,7 +277,7 @@ public class ImGroupService {
public List<ImGroupEntity> listPublicGroups(String appKey, String keyword) { public List<ImGroupEntity> listPublicGroups(String appKey, String keyword) {
String normalizedKeyword = keyword == null ? "" : keyword.trim().toLowerCase(); String normalizedKeyword = keyword == null ? "" : keyword.trim().toLowerCase();
return groupRepository.findByAppKey(appKey).stream() return groupRepository.findByAppId(appKey).stream()
.filter(group -> "PUBLIC".equalsIgnoreCase(normalizeGroupType(group.getGroupType()))) .filter(group -> "PUBLIC".equalsIgnoreCase(normalizeGroupType(group.getGroupType())))
.filter(group -> normalizedKeyword.isBlank() .filter(group -> normalizedKeyword.isBlank()
|| group.getName().toLowerCase().contains(normalizedKeyword) || group.getName().toLowerCase().contains(normalizedKeyword)
@ -313,7 +313,7 @@ public class ImGroupService {
throw new BusinessException(403, "当前应用未开放群加入申请"); throw new BusinessException(403, "当前应用未开放群加入申请");
} }
ImGroupEntity group = get(groupId); ImGroupEntity group = get(groupId);
if (!group.getAppKey().equals(appKey)) { if (!group.getAppId().equals(appKey)) {
throw new BusinessException(403, "无权操作"); throw new BusinessException(403, "无权操作");
} }
if (!"PUBLIC".equalsIgnoreCase(normalizeGroupType(group.getGroupType()))) { if (!"PUBLIC".equalsIgnoreCase(normalizeGroupType(group.getGroupType()))) {
@ -322,11 +322,11 @@ public class ImGroupService {
if (memberIds(group).contains(requesterId)) { if (memberIds(group).contains(requesterId)) {
throw new BusinessException(400, "已经在群内"); throw new BusinessException(400, "已经在群内");
} }
return joinRequestRepository.findByAppKeyAndGroupIdAndRequesterId(appKey, groupId, requesterId) return joinRequestRepository.findByAppIdAndGroupIdAndRequesterId(appKey, groupId, requesterId)
.orElseGet(() -> { .orElseGet(() -> {
ImGroupJoinRequestEntity entity = new ImGroupJoinRequestEntity(); ImGroupJoinRequestEntity entity = new ImGroupJoinRequestEntity();
entity.setId(UUID.randomUUID().toString()); entity.setId(UUID.randomUUID().toString());
entity.setAppKey(appKey); entity.setAppId(appKey);
entity.setGroupId(groupId); entity.setGroupId(groupId);
entity.setRequesterId(requesterId); entity.setRequesterId(requesterId);
entity.setRemark(remark); entity.setRemark(remark);
@ -350,7 +350,7 @@ public class ImGroupService {
public List<ImGroupJoinRequestEntity> listJoinRequests(String appKey, String groupId, String operatorId) { public List<ImGroupJoinRequestEntity> listJoinRequests(String appKey, String groupId, String operatorId) {
ImGroupEntity group = get(groupId); ImGroupEntity group = get(groupId);
ensureCanManage(group, operatorId); ensureCanManage(group, operatorId);
return joinRequestRepository.findByAppKeyAndGroupId(appKey, groupId); return joinRequestRepository.findByAppIdAndGroupId(appKey, groupId);
} }
@Transactional @Transactional
@ -442,7 +442,7 @@ public class ImGroupService {
} }
private void ensureAppMatches(ImGroupEntity group, String appKey) { private void ensureAppMatches(ImGroupEntity group, String appKey) {
if (!group.getAppKey().equals(appKey)) { if (!group.getAppId().equals(appKey)) {
throw new BusinessException(403, "无权操作"); throw new BusinessException(403, "无权操作");
} }
} }
@ -614,7 +614,7 @@ public class ImGroupService {
public List<ImGroupJoinRequestEntity> adminListJoinRequests(String appKey, String groupId) { public List<ImGroupJoinRequestEntity> adminListJoinRequests(String appKey, String groupId) {
ImGroupEntity group = get(groupId); ImGroupEntity group = get(groupId);
ensureAppMatches(group, appKey); ensureAppMatches(group, appKey);
return joinRequestRepository.findByAppKeyAndGroupId(appKey, groupId); return joinRequestRepository.findByAppIdAndGroupId(appKey, groupId);
} }
@Transactional @Transactional
@ -667,7 +667,7 @@ public class ImGroupService {
group.setCreatorId(newOwnerId); group.setCreatorId(newOwnerId);
group.setAdminIds(toJson(admins)); group.setAdminIds(toJson(admins));
ImGroupEntity saved = groupRepository.save(group); ImGroupEntity saved = groupRepository.save(group);
webhookDispatchService.dispatch(saved.getAppKey(), "group", "group.owner_transferred", webhookDispatchService.dispatch(saved.getAppId(), "group", "group.owner_transferred",
java.util.Map.of("groupId", saved.getId(), "newOwnerId", newOwnerId)); java.util.Map.of("groupId", saved.getId(), "newOwnerId", newOwnerId));
return saved; return saved;
} }
@ -683,7 +683,7 @@ public class ImGroupService {
} }
group.setExtAttributes(toJson(current)); group.setExtAttributes(toJson(current));
ImGroupEntity saved = groupRepository.save(group); ImGroupEntity saved = groupRepository.save(group);
webhookDispatchService.dispatch(saved.getAppKey(), "group", "group.attributes_updated", webhookDispatchService.dispatch(saved.getAppId(), "group", "group.attributes_updated",
java.util.Map.of("groupId", saved.getId(), "attributes", current)); java.util.Map.of("groupId", saved.getId(), "attributes", current));
return saved; return saved;
} }
@ -760,7 +760,7 @@ public class ImGroupService {
if (recipient == null || recipient.isBlank() || recipient.equals(fromUserId)) continue; if (recipient == null || recipient.isBlank() || recipient.equals(fromUserId)) continue;
ImMessageEntity message = new ImMessageEntity(); ImMessageEntity message = new ImMessageEntity();
message.setId(UUID.randomUUID().toString()); message.setId(UUID.randomUUID().toString());
message.setAppKey(group.getAppKey()); message.setAppId(group.getAppId());
message.setFromUserId(fromUserId); message.setFromUserId(fromUserId);
message.setToId(recipient); message.setToId(recipient);
message.setChatType(ImMessageEntity.ChatType.SINGLE); message.setChatType(ImMessageEntity.ChatType.SINGLE);
@ -775,11 +775,11 @@ public class ImGroupService {
private void dispatchJoinRequestWebhook(ImGroupEntity group, ImGroupJoinRequestEntity request, String callbackEvent) { private void dispatchJoinRequestWebhook(ImGroupEntity group, ImGroupJoinRequestEntity request, String callbackEvent) {
webhookDispatchService.dispatch( webhookDispatchService.dispatch(
group.getAppKey(), group.getAppId(),
"group_join_request", "group_join_request",
callbackEvent, callbackEvent,
new GroupJoinRequestCallbackPayload( new GroupJoinRequestCallbackPayload(
group.getAppKey(), group.getAppId(),
request.getId(), request.getId(),
request.getGroupId(), request.getGroupId(),
group.getName(), group.getName(),
@ -832,7 +832,7 @@ public class ImGroupService {
private ImGroupJoinRequestEntity getJoinRequest(String appKey, String requestId) { private ImGroupJoinRequestEntity getJoinRequest(String appKey, String requestId) {
ImGroupJoinRequestEntity request = joinRequestRepository.findById(requestId) ImGroupJoinRequestEntity request = joinRequestRepository.findById(requestId)
.orElseThrow(() -> new BusinessException(404, "加群申请不存在")); .orElseThrow(() -> new BusinessException(404, "加群申请不存在"));
if (!request.getAppKey().equals(appKey)) { if (!request.getAppId().equals(appKey)) {
throw new BusinessException(403, "无权操作"); throw new BusinessException(403, "无权操作");
} }
return request; return request;
@ -894,7 +894,7 @@ public class ImGroupService {
private List<ImAccountEntity> resolveMembers(String appKey, List<String> ids) { private List<ImAccountEntity> resolveMembers(String appKey, List<String> ids) {
List<ImAccountEntity> members = new ArrayList<>(); List<ImAccountEntity> members = new ArrayList<>();
for (String userId : ids == null ? List.<String>of() : ids) { for (String userId : ids == null ? List.<String>of() : ids) {
accountRepository.findByAppKeyAndUserId(appKey, userId).ifPresent(members::add); accountRepository.findByAppIdAndUserId(appKey, userId).ifPresent(members::add);
} }
return members; return members;
} }

查看文件

@ -20,7 +20,7 @@ public class KeywordFilterService {
} }
public String filter(String appKey, String content) { public String filter(String appKey, String content) {
List<KeywordFilterEntity> filters = repository.findByAppKeyAndEnabledTrue(appKey); List<KeywordFilterEntity> filters = repository.findByAppIdAndEnabledTrue(appKey);
String result = content; String result = content;
for (KeywordFilterEntity f : filters) { for (KeywordFilterEntity f : filters) {
try { try {
@ -42,7 +42,7 @@ public class KeywordFilterService {
public KeywordFilterEntity add(String appKey, String pattern, String replacement, String action) { public KeywordFilterEntity add(String appKey, String pattern, String replacement, String action) {
KeywordFilterEntity entity = new KeywordFilterEntity(); KeywordFilterEntity entity = new KeywordFilterEntity();
entity.setId(UUID.randomUUID().toString()); entity.setId(UUID.randomUUID().toString());
entity.setAppKey(appKey); entity.setAppId(appKey);
entity.setPattern(pattern); entity.setPattern(pattern);
entity.setReplacement(replacement); entity.setReplacement(replacement);
entity.setAction(action); entity.setAction(action);
@ -52,7 +52,7 @@ public class KeywordFilterService {
} }
public List<KeywordFilterEntity> list(String appKey) { public List<KeywordFilterEntity> list(String appKey) {
return repository.findByAppKey(appKey); return repository.findByAppId(appKey);
} }
public KeywordFilterEntity update(String appKey, String id, String pattern, String replacement, String action, Boolean enabled) { public KeywordFilterEntity update(String appKey, String id, String pattern, String replacement, String action, Boolean enabled) {

查看文件

@ -116,7 +116,7 @@ public class MessageService {
message.setId(req.messageId() != null && !req.messageId().isBlank() message.setId(req.messageId() != null && !req.messageId().isBlank()
? req.messageId() ? req.messageId()
: UUID.randomUUID().toString()); : UUID.randomUUID().toString());
message.setAppKey(appKey); message.setAppId(appKey);
message.setFromUserId(fromUserId); message.setFromUserId(fromUserId);
message.setToId(req.toId()); message.setToId(req.toId());
message.setChatType(req.chatType()); message.setChatType(req.chatType());
@ -184,14 +184,14 @@ public class MessageService {
} }
private boolean isFriend(String appKey, String userId, String friendId) { private boolean isFriend(String appKey, String userId, String friendId) {
return friendRepository.existsByAppKeyAndUserIdAndFriendId(appKey, userId, friendId) return friendRepository.existsByAppIdAndUserIdAndFriendId(appKey, userId, friendId)
|| friendRepository.existsByAppKeyAndUserIdAndFriendId(appKey, friendId, userId); || friendRepository.existsByAppIdAndUserIdAndFriendId(appKey, friendId, userId);
} }
public ImMessageEntity revoke(String appKey, String messageId, String requestUserId) { public ImMessageEntity revoke(String appKey, String messageId, String requestUserId) {
ImMessageEntity message = messageRepository.findById(messageId) ImMessageEntity message = messageRepository.findById(messageId)
.orElseThrow(() -> new BusinessException(404, "消息不存在")); .orElseThrow(() -> new BusinessException(404, "消息不存在"));
if (!message.getAppKey().equals(appKey)) { if (!message.getAppId().equals(appKey)) {
throw new BusinessException(403, "无权操作"); throw new BusinessException(403, "无权操作");
} }
if (!message.getFromUserId().equals(requestUserId)) { if (!message.getFromUserId().equals(requestUserId)) {
@ -223,7 +223,7 @@ public class MessageService {
public ImMessageEntity edit(String appKey, String messageId, String requestUserId, EditMessageRequest req) { public ImMessageEntity edit(String appKey, String messageId, String requestUserId, EditMessageRequest req) {
ImMessageEntity message = messageRepository.findById(messageId) ImMessageEntity message = messageRepository.findById(messageId)
.orElseThrow(() -> new BusinessException(404, "消息不存在")); .orElseThrow(() -> new BusinessException(404, "消息不存在"));
if (!message.getAppKey().equals(appKey)) { if (!message.getAppId().equals(appKey)) {
throw new BusinessException(403, "无权操作"); throw new BusinessException(403, "无权操作");
} }
if (!message.getFromUserId().equals(requestUserId)) { if (!message.getFromUserId().equals(requestUserId)) {
@ -278,7 +278,7 @@ public class MessageService {
public ImMessageEntity adminRevoke(String appKey, String messageId) { public ImMessageEntity adminRevoke(String appKey, String messageId) {
ImMessageEntity message = messageRepository.findById(messageId) ImMessageEntity message = messageRepository.findById(messageId)
.orElseThrow(() -> new BusinessException(404, "消息不存在")); .orElseThrow(() -> new BusinessException(404, "消息不存在"));
if (!message.getAppKey().equals(appKey)) { if (!message.getAppId().equals(appKey)) {
throw new BusinessException(403, "无权操作"); throw new BusinessException(403, "无权操作");
} }
message.setStatus(ImMessageEntity.MsgStatus.REVOKED); message.setStatus(ImMessageEntity.MsgStatus.REVOKED);
@ -341,7 +341,7 @@ public class MessageService {
return; return;
} }
List<ImMessageEntity> messages = messageRepository List<ImMessageEntity> messages = messageRepository
.findByAppKeyAndFromUserIdAndToIdAndCreatedAtLessThanEqualOrderByCreatedAtAsc( .findByAppIdAndFromUserIdAndToIdAndCreatedAtLessThanEqualOrderByCreatedAtAsc(
appKey, peerId, readerId, readAt); appKey, peerId, readerId, readAt);
if (messages.isEmpty()) { if (messages.isEmpty()) {
return; return;
@ -374,7 +374,7 @@ public class MessageService {
return; return;
} }
List<ImMessageEntity> messages = messageRepository List<ImMessageEntity> messages = messageRepository
.findByAppKeyAndToIdAndChatTypeAndCreatedAtLessThanEqualOrderByCreatedAtAsc( .findByAppIdAndToIdAndChatTypeAndCreatedAtLessThanEqualOrderByCreatedAtAsc(
appKey, groupId, ImMessageEntity.ChatType.GROUP, readAt); appKey, groupId, ImMessageEntity.ChatType.GROUP, readAt);
if (messages.isEmpty()) { if (messages.isEmpty()) {
return; return;
@ -491,12 +491,12 @@ public class MessageService {
public List<GroupReadReceiptSummary> groupReadReceipts(String appKey, String groupId, List<String> messageIds) { public List<GroupReadReceiptSummary> groupReadReceipts(String appKey, String groupId, List<String> messageIds) {
ImGroupEntity group = groupService.get(groupId); ImGroupEntity group = groupService.get(groupId);
if (!group.getAppKey().equals(appKey)) { if (!group.getAppId().equals(appKey)) {
throw new BusinessException(403, "无权操作"); throw new BusinessException(403, "无权操作");
} }
List<String> members = groupService.memberIds(group); List<String> members = groupService.memberIds(group);
return messageRepository.findAllById(messageIds == null ? List.of() : messageIds).stream() return messageRepository.findAllById(messageIds == null ? List.of() : messageIds).stream()
.filter(message -> appKey.equals(message.getAppKey())) .filter(message -> appKey.equals(message.getAppId()))
.filter(message -> groupId.equals(message.getToId())) .filter(message -> groupId.equals(message.getToId()))
.filter(message -> message.getChatType() == ImMessageEntity.ChatType.GROUP) .filter(message -> message.getChatType() == ImMessageEntity.ChatType.GROUP)
.map(message -> { .map(message -> {
@ -520,7 +520,7 @@ public class MessageService {
try { try {
Map<String, Object> payload = new java.util.LinkedHashMap<>(); Map<String, Object> payload = new java.util.LinkedHashMap<>();
payload.put("messageId", message.getId()); payload.put("messageId", message.getId());
payload.put("appKey", message.getAppKey()); payload.put("appKey", message.getAppId());
payload.put("fromUserId", message.getFromUserId()); payload.put("fromUserId", message.getFromUserId());
payload.put("toId", message.getToId()); payload.put("toId", message.getToId());
payload.put("chatType", message.getChatType().name()); payload.put("chatType", message.getChatType().name());
@ -598,7 +598,7 @@ public class MessageService {
public ImMessageEntity adminSend(String appKey, String fromUserId, String toId, ImMessageEntity.MsgType msgType, String content) { public ImMessageEntity adminSend(String appKey, String fromUserId, String toId, ImMessageEntity.MsgType msgType, String content) {
ImMessageEntity message = new ImMessageEntity(); ImMessageEntity message = new ImMessageEntity();
message.setId(UUID.randomUUID().toString()); message.setId(UUID.randomUUID().toString());
message.setAppKey(appKey); message.setAppId(appKey);
message.setFromUserId(fromUserId); message.setFromUserId(fromUserId);
message.setToId(toId); message.setToId(toId);
message.setChatType(ImMessageEntity.ChatType.SINGLE); message.setChatType(ImMessageEntity.ChatType.SINGLE);
@ -624,7 +624,7 @@ public class MessageService {
} }
public void adminSetMsgRead(String appKey, String userId) { public void adminSetMsgRead(String appKey, String userId) {
List<ImMessageEntity> messages = messageRepository.findUnreadByAppKeyAndToId(appKey, userId); List<ImMessageEntity> messages = messageRepository.findUnreadByAppIdAndToId(appKey, userId);
for (ImMessageEntity message : messages) { for (ImMessageEntity message : messages) {
message.setStatus(ImMessageEntity.MsgStatus.READ); message.setStatus(ImMessageEntity.MsgStatus.READ);
messageRepository.save(message); messageRepository.save(message);
@ -642,7 +642,7 @@ public class MessageService {
message.setId(req.messageId() != null && !req.messageId().isBlank() message.setId(req.messageId() != null && !req.messageId().isBlank()
? req.messageId() ? req.messageId()
: UUID.randomUUID().toString()); : UUID.randomUUID().toString());
message.setAppKey(appKey); message.setAppId(appKey);
message.setFromUserId(req.fromUserId()); message.setFromUserId(req.fromUserId());
message.setToId(req.toId()); message.setToId(req.toId());
message.setChatType(req.chatType() != null ? req.chatType() : ImMessageEntity.ChatType.SINGLE); message.setChatType(req.chatType() != null ? req.chatType() : ImMessageEntity.ChatType.SINGLE);

查看文件

@ -36,7 +36,7 @@ public class OfflineMessageSyncService {
public void storeOfflineMessage(String appKey, String userId, String messageId) { public void storeOfflineMessage(String appKey, String userId, String messageId) {
ImOfflineMessageEntity entity = new ImOfflineMessageEntity(); ImOfflineMessageEntity entity = new ImOfflineMessageEntity();
entity.setId(UUID.randomUUID().toString()); entity.setId(UUID.randomUUID().toString());
entity.setAppKey(appKey); entity.setAppId(appKey);
entity.setUserId(userId); entity.setUserId(userId);
entity.setMessageId(messageId); entity.setMessageId(messageId);
entity.setDelivered(false); entity.setDelivered(false);
@ -48,7 +48,7 @@ public class OfflineMessageSyncService {
@Transactional @Transactional
public void syncAndDeliver(String appKey, String userId) { public void syncAndDeliver(String appKey, String userId) {
List<ImOfflineMessageEntity> offlineMessages = offlineMessageRepository List<ImOfflineMessageEntity> offlineMessages = offlineMessageRepository
.findByAppKeyAndUserIdAndDeliveredFalse(appKey, userId); .findByAppIdAndUserIdAndDeliveredFalse(appKey, userId);
if (offlineMessages.isEmpty()) { if (offlineMessages.isEmpty()) {
return; return;
} }
@ -68,17 +68,17 @@ public class OfflineMessageSyncService {
log.info("Synced {} offline messages for appKey={} userId={}", deliveredIds.size(), appKey, userId); log.info("Synced {} offline messages for appKey={} userId={}", deliveredIds.size(), appKey, userId);
} }
offlineMessageRepository.deleteByAppKeyAndUserIdAndDeliveredTrue(appKey, userId); offlineMessageRepository.deleteByAppIdAndUserIdAndDeliveredTrue(appKey, userId);
} }
public long countUndelivered(String appKey, String userId) { public long countUndelivered(String appKey, String userId) {
return offlineMessageRepository.countUndeliveredByAppKeyAndUserId(appKey, userId); return offlineMessageRepository.countUndeliveredByAppIdAndUserId(appKey, userId);
} }
@Transactional @Transactional
public List<ImMessageEntity> syncAndReturn(String appKey, String userId) { public List<ImMessageEntity> syncAndReturn(String appKey, String userId) {
List<ImOfflineMessageEntity> offlineMessages = offlineMessageRepository List<ImOfflineMessageEntity> offlineMessages = offlineMessageRepository
.findByAppKeyAndUserIdAndDeliveredFalse(appKey, userId); .findByAppIdAndUserIdAndDeliveredFalse(appKey, userId);
List<ImMessageEntity> result = new ArrayList<>(); List<ImMessageEntity> result = new ArrayList<>();
List<String> deliveredIds = new ArrayList<>(); List<String> deliveredIds = new ArrayList<>();
for (ImOfflineMessageEntity offline : offlineMessages) { for (ImOfflineMessageEntity offline : offlineMessages) {
@ -91,7 +91,7 @@ public class OfflineMessageSyncService {
if (!deliveredIds.isEmpty()) { if (!deliveredIds.isEmpty()) {
offlineMessageRepository.markDeliveredByIds(deliveredIds); offlineMessageRepository.markDeliveredByIds(deliveredIds);
} }
offlineMessageRepository.deleteByAppKeyAndUserIdAndDeliveredTrue(appKey, userId); offlineMessageRepository.deleteByAppIdAndUserIdAndDeliveredTrue(appKey, userId);
return result; return result;
} }
} }

查看文件

@ -27,7 +27,7 @@ public class OperationLogService {
String detail) { String detail) {
ImOperationLogEntity entity = new ImOperationLogEntity(); ImOperationLogEntity entity = new ImOperationLogEntity();
entity.setId(UUID.randomUUID().toString()); entity.setId(UUID.randomUUID().toString());
entity.setAppKey(appKey); entity.setAppId(appKey);
entity.setOperatorId(operatorId == null || operatorId.isBlank() ? "system" : operatorId); entity.setOperatorId(operatorId == null || operatorId.isBlank() ? "system" : operatorId);
entity.setAction(action); entity.setAction(action);
entity.setResourceType(resourceType); entity.setResourceType(resourceType);
@ -38,6 +38,6 @@ public class OperationLogService {
} }
public Page<ImOperationLogEntity> list(String appKey, Pageable pageable) { public Page<ImOperationLogEntity> list(String appKey, Pageable pageable) {
return repository.findByAppKeyOrderByCreatedAtDesc(appKey, pageable); return repository.findByAppIdOrderByCreatedAtDesc(appKey, pageable);
} }
} }

查看文件

@ -19,7 +19,7 @@ public class WebhookConfigService {
} }
public List<WebhookConfigEntity> list(String appKey) { public List<WebhookConfigEntity> list(String appKey) {
return repository.findByAppKey(appKey); return repository.findByAppId(appKey);
} }
public WebhookConfigEntity get(String appKey, String id) { public WebhookConfigEntity get(String appKey, String id) {
@ -30,7 +30,7 @@ public class WebhookConfigService {
public WebhookConfigEntity create(String appKey, String url, String secret, Boolean enabled) { public WebhookConfigEntity create(String appKey, String url, String secret, Boolean enabled) {
WebhookConfigEntity entity = new WebhookConfigEntity(); WebhookConfigEntity entity = new WebhookConfigEntity();
entity.setId(UUID.randomUUID().toString()); entity.setId(UUID.randomUUID().toString());
entity.setAppKey(appKey); entity.setAppId(appKey);
entity.setUrl(url); entity.setUrl(url);
entity.setSecret(secret); entity.setSecret(secret);
entity.setEnabled(enabled == null || enabled); entity.setEnabled(enabled == null || enabled);

查看文件

@ -61,7 +61,7 @@ public class WebhookDispatchService {
@Async @Async
public void dispatch(String appKey, String callbackType, String callbackEvent, Object payload) { public void dispatch(String appKey, String callbackType, String callbackEvent, Object payload) {
List<WebhookConfigEntity> webhooks = webhookRepository.findByAppKeyAndEnabledTrue(appKey); List<WebhookConfigEntity> webhooks = webhookRepository.findByAppIdAndEnabledTrue(appKey);
if (webhooks.isEmpty()) { if (webhooks.isEmpty()) {
return; return;
} }
@ -100,7 +100,7 @@ public class WebhookDispatchService {
for (int attempt = 1; attempt <= MAX_RETRIES; attempt++) { for (int attempt = 1; attempt <= MAX_RETRIES; attempt++) {
WebhookDeliveryEntity delivery = new WebhookDeliveryEntity(); WebhookDeliveryEntity delivery = new WebhookDeliveryEntity();
delivery.setId(UUID.randomUUID().toString()); delivery.setId(UUID.randomUUID().toString());
delivery.setAppKey(appKey); delivery.setAppId(appKey);
delivery.setCallbackId(callbackId); delivery.setCallbackId(callbackId);
delivery.setCallbackEvent(callbackEvent); delivery.setCallbackEvent(callbackEvent);
delivery.setUrl(webhook.getUrl()); delivery.setUrl(webhook.getUrl());
@ -112,7 +112,7 @@ public class WebhookDispatchService {
.uri(URI.create(webhook.getUrl())) .uri(URI.create(webhook.getUrl()))
.timeout(Duration.ofMillis(webhookTimeoutMs)) .timeout(Duration.ofMillis(webhookTimeoutMs))
.header("Content-Type", "application/json") .header("Content-Type", "application/json")
.header("X-App-Key", appKey) .header("X-App-Id", appKey)
.header("X-App-Timestamp", String.valueOf(requestTime)) .header("X-App-Timestamp", String.valueOf(requestTime))
.header("X-App-Nonce", nonce) .header("X-App-Nonce", nonce)
.header("X-App-Signature", signature) .header("X-App-Signature", signature)
@ -182,7 +182,7 @@ public class WebhookDispatchService {
WebhookAlertEntity alert = new WebhookAlertEntity(); WebhookAlertEntity alert = new WebhookAlertEntity();
alert.setId(UUID.randomUUID().toString()); alert.setId(UUID.randomUUID().toString());
alert.setAppKey(appKey); alert.setAppId(appKey);
alert.setWebhookId(webhook.getId()); alert.setWebhookId(webhook.getId());
alert.setWebhookUrl(webhook.getUrl()); alert.setWebhookUrl(webhook.getUrl());
alert.setAlertType("AUTO_DISABLED"); alert.setAlertType("AUTO_DISABLED");

查看文件

@ -1,48 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0
https://maven.apache.org/xsd/settings-1.2.0.xsd">
<profiles>
<profile>
<id>xuqm-nexus</id>
<repositories>
<repository>
<id>xuqm-maven-public</id>
<url>https://nexus.xuqinmin.com/repository/maven-public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>xuqm-maven-snapshots</id>
<url>https://nexus.xuqinmin.com/repository/maven-snapshots/</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>xuqm-maven-public</id>
<url>https://nexus.xuqinmin.com/repository/maven-public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</profile>
</profiles>
<activeProfiles>
<activeProfile>xuqm-nexus</activeProfile>
</activeProfiles>
</settings>

查看文件

@ -15,6 +15,7 @@
<module>common</module> <module>common</module>
<module>tenant-service</module> <module>tenant-service</module>
<module>im-service</module> <module>im-service</module>
<module>im-sdk</module>
<module>push-service</module> <module>push-service</module>
<module>update-service</module> <module>update-service</module>
<module>demo-service</module> <module>demo-service</module>

查看文件

@ -11,7 +11,7 @@ import java.time.LocalDateTime;
@Entity @Entity
@Table(name = "push_device_login_log", indexes = { @Table(name = "push_device_login_log", indexes = {
@Index(name = "idx_push_device_log_user_time", columnList = "appKey,userId,createdAt"), @Index(name = "idx_push_device_log_user_time", columnList = "appId,userId,createdAt"),
@Index(name = "idx_push_device_log_token", columnList = "tokenHash") @Index(name = "idx_push_device_log_token", columnList = "tokenHash")
}) })
public class DeviceLoginLogEntity { public class DeviceLoginLogEntity {
@ -24,7 +24,7 @@ public class DeviceLoginLogEntity {
private String id; private String id;
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String appKey; private String appId;
@Column(nullable = false, length = 128) @Column(nullable = false, length = 128)
private String userId; private String userId;
@ -70,8 +70,8 @@ public class DeviceLoginLogEntity {
public String getId() { return id; } public String getId() { return id; }
public void setId(String id) { this.id = id; } public void setId(String id) { this.id = id; }
public String getAppKey() { return appKey; } public String getAppId() { return appId; }
public void setAppKey(String appKey) { this.appKey = appKey; } public void setAppId(String appId) { this.appId = appId; }
public String getUserId() { return userId; } public String getUserId() { return userId; }
public void setUserId(String userId) { this.userId = userId; } public void setUserId(String userId) { this.userId = userId; }

查看文件

@ -11,18 +11,18 @@ import java.time.LocalDateTime;
@Entity @Entity
@Table(name = "push_device_token", @Table(name = "push_device_token",
uniqueConstraints = @UniqueConstraint(columnNames = {"appKey", "userId", "deviceId"})) uniqueConstraints = @UniqueConstraint(columnNames = {"appId", "userId", "deviceId"}))
public class DeviceTokenEntity { public class DeviceTokenEntity {
public enum Vendor { public enum Vendor {
HUAWEI, XIAOMI, OPPO, VIVO, HONOR, HARMONY, APNS HUAWEI, XIAOMI, OPPO, VIVO, HONOR, HARMONY, FCM, APNS
} }
@Id @Id
private String id; private String id;
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String appKey; private String appId;
@Column(nullable = false, length = 128) @Column(nullable = false, length = 128)
private String userId; private String userId;
@ -67,8 +67,8 @@ public class DeviceTokenEntity {
public String getId() { return id; } public String getId() { return id; }
public void setId(String id) { this.id = id; } public void setId(String id) { this.id = id; }
public String getAppKey() { return appKey; } public String getAppId() { return appId; }
public void setAppKey(String appKey) { this.appKey = appKey; } public void setAppId(String appId) { this.appId = appId; }
public String getUserId() { return userId; } public String getUserId() { return userId; }
public void setUserId(String userId) { this.userId = userId; } public void setUserId(String userId) { this.userId = userId; }

查看文件

@ -6,5 +6,5 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
public interface DeviceLoginLogRepository extends JpaRepository<DeviceLoginLogEntity, String> { public interface DeviceLoginLogRepository extends JpaRepository<DeviceLoginLogEntity, String> {
Page<DeviceLoginLogEntity> findByAppKeyAndUserIdOrderByCreatedAtDesc(String appKey, String userId, Pageable pageable); Page<DeviceLoginLogEntity> findByAppIdAndUserIdOrderByCreatedAtDesc(String appId, String userId, Pageable pageable);
} }

查看文件

@ -7,16 +7,16 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
public interface DeviceTokenRepository extends JpaRepository<DeviceTokenEntity, String> { public interface DeviceTokenRepository extends JpaRepository<DeviceTokenEntity, String> {
List<DeviceTokenEntity> findByAppKeyAndUserIdAndReceivePushTrue(String appKey, String userId); List<DeviceTokenEntity> findByAppIdAndUserIdAndReceivePushTrue(String appId, String userId);
Optional<DeviceTokenEntity> findFirstByAppKeyAndUserIdAndReceivePushTrueOrderByLastLoginAtDescUpdatedAtDesc( Optional<DeviceTokenEntity> findFirstByAppIdAndUserIdAndReceivePushTrueOrderByLastLoginAtDescUpdatedAtDesc(
String appKey, String userId); String appId, String userId);
List<DeviceTokenEntity> findByAppKeyAndUserIdAndReceivePushTrueOrderByLastLoginAtDescUpdatedAtDesc(String appKey, String userId); List<DeviceTokenEntity> findByAppIdAndUserIdAndReceivePushTrueOrderByLastLoginAtDescUpdatedAtDesc(String appId, String userId);
Optional<DeviceTokenEntity> findByAppKeyAndUserIdAndVendor( Optional<DeviceTokenEntity> findByAppIdAndUserIdAndVendor(
String appKey, String userId, DeviceTokenEntity.Vendor vendor); String appId, String userId, DeviceTokenEntity.Vendor vendor);
Optional<DeviceTokenEntity> findByAppKeyAndUserIdAndDeviceId(String appKey, String userId, String deviceId); Optional<DeviceTokenEntity> findByAppIdAndUserIdAndDeviceId(String appId, String userId, String deviceId);
Optional<DeviceTokenEntity> findFirstByToken(String token); Optional<DeviceTokenEntity> findFirstByToken(String token);
List<DeviceTokenEntity> findByAppKeyAndUserId(String appKey, String userId); List<DeviceTokenEntity> findByAppIdAndUserId(String appId, String userId);
List<DeviceTokenEntity> findByAppKeyAndUserIdOrderByLastLoginAtDescUpdatedAtDesc(String appKey, String userId); List<DeviceTokenEntity> findByAppIdAndUserIdOrderByLastLoginAtDescUpdatedAtDesc(String appId, String userId);
void deleteByAppKeyAndUserIdAndVendor(String appKey, String userId, DeviceTokenEntity.Vendor vendor); void deleteByAppIdAndUserIdAndVendor(String appId, String userId, DeviceTokenEntity.Vendor vendor);
void deleteByAppKeyAndUserIdAndDeviceId(String appKey, String userId, String deviceId); void deleteByAppIdAndUserIdAndDeviceId(String appId, String userId, String deviceId);
} }

查看文件

@ -35,15 +35,15 @@ public class PushDiagnosticsService {
this.jwtUtil = jwtUtil; this.jwtUtil = jwtUtil;
} }
public PushTokenDiagnostics searchByToken(String token, String appKeyHint) { public PushTokenDiagnostics searchByToken(String token, String appIdHint) {
Optional<DeviceTokenEntity> tokenMatch = tokenRepository.findFirstByToken(token); Optional<DeviceTokenEntity> tokenMatch = tokenRepository.findFirstByToken(token);
String appKey = appKeyHint; String appKey = appIdHint;
String userId = null; String userId = null;
String tokenType = "UNKNOWN"; String tokenType = "UNKNOWN";
if (tokenMatch.isPresent()) { if (tokenMatch.isPresent()) {
DeviceTokenEntity device = tokenMatch.get(); DeviceTokenEntity device = tokenMatch.get();
appKey = device.getAppKey(); appKey = device.getAppId();
userId = device.getUserId(); userId = device.getUserId();
tokenType = "PUSH"; tokenType = "PUSH";
} else { } else {
@ -56,8 +56,8 @@ public class PushDiagnosticsService {
try { try {
Claims claims = jwtUtil.parse(token); Claims claims = jwtUtil.parse(token);
userId = claims.getSubject(); userId = claims.getSubject();
String claimAppKey = claims.get("appKey", String.class); String claimAppId = claims.get("appKey", String.class);
appKey = claimAppKey == null || claimAppKey.isBlank() ? appKeyHint : claimAppKey; appKey = claimAppId == null || claimAppId.isBlank() ? appIdHint : claimAppId;
tokenType = "IM"; tokenType = "IM";
} catch (Exception ignored) { } catch (Exception ignored) {
// Keep UNKNOWN and return an empty diagnostic. // Keep UNKNOWN and return an empty diagnostic.
@ -71,7 +71,7 @@ public class PushDiagnosticsService {
ImPresenceClient.PresenceStatus presence = presenceClient.userStatus(appKey, userId) ImPresenceClient.PresenceStatus presence = presenceClient.userStatus(appKey, userId)
.orElse(new ImPresenceClient.PresenceStatus(appKey, userId, false, 0L)); .orElse(new ImPresenceClient.PresenceStatus(appKey, userId, false, 0L));
List<DeviceTokenEntity> devices = tokenRepository.findByAppKeyAndUserIdOrderByLastLoginAtDescUpdatedAtDesc(appKey, userId); List<DeviceTokenEntity> devices = tokenRepository.findByAppIdAndUserIdOrderByLastLoginAtDescUpdatedAtDesc(appKey, userId);
List<DeviceInfo> deliverableDevices = pushDispatcher.selectedPushTargets(appKey, userId) List<DeviceInfo> deliverableDevices = pushDispatcher.selectedPushTargets(appKey, userId)
.stream() .stream()
.map(DeviceInfo::from) .map(DeviceInfo::from)
@ -93,7 +93,7 @@ public class PushDiagnosticsService {
public PushTokenDiagnostics searchByUserId(String appKey, String userId) { public PushTokenDiagnostics searchByUserId(String appKey, String userId) {
ImPresenceClient.PresenceStatus presence = presenceClient.userStatus(appKey, userId) ImPresenceClient.PresenceStatus presence = presenceClient.userStatus(appKey, userId)
.orElse(new ImPresenceClient.PresenceStatus(appKey, userId, false, 0L)); .orElse(new ImPresenceClient.PresenceStatus(appKey, userId, false, 0L));
List<DeviceTokenEntity> devices = tokenRepository.findByAppKeyAndUserIdOrderByLastLoginAtDescUpdatedAtDesc(appKey, userId); List<DeviceTokenEntity> devices = tokenRepository.findByAppIdAndUserIdOrderByLastLoginAtDescUpdatedAtDesc(appKey, userId);
List<DeviceInfo> deliverableDevices = pushDispatcher.selectedPushTargets(appKey, userId) List<DeviceInfo> deliverableDevices = pushDispatcher.selectedPushTargets(appKey, userId)
.stream() .stream()
.map(DeviceInfo::from) .map(DeviceInfo::from)
@ -126,7 +126,7 @@ public class PushDiagnosticsService {
public Page<DeviceLoginLogEntity> deviceLogs(String appKey, String userId, int page, int size) { public Page<DeviceLoginLogEntity> deviceLogs(String appKey, String userId, int page, int size) {
int safePage = Math.max(page, 0); int safePage = Math.max(page, 0);
int safeSize = Math.min(Math.max(size, 1), 200); int safeSize = Math.min(Math.max(size, 1), 200);
return logRepository.findByAppKeyAndUserIdOrderByCreatedAtDesc(appKey, userId, PageRequest.of(safePage, safeSize)); return logRepository.findByAppIdAndUserIdOrderByCreatedAtDesc(appKey, userId, PageRequest.of(safePage, safeSize));
} }
public record PushTokenDiagnostics( public record PushTokenDiagnostics(

查看文件

@ -68,22 +68,17 @@ public class PushDispatcher {
String routeType = routeType(payload); String routeType = routeType(payload);
String platform = platformForVendor(vendor, payload); String platform = platformForVendor(vendor, payload);
return pushConfigClient.loadServiceConfig(appKey, platform, "PUSH") return pushConfigClient.loadServiceConfig(appKey, platform, "PUSH")
.map(config -> profileFor(config, vendor.name(), routeType) .map(config -> {
.map(profile -> new PushSendOptions( JsonNode route = config.path("routing").path(routeType);
profile.path("key").asText(""), String channelKey = route.path("channel").asText("");
String channelId = effectiveChannelId(config.path("channels"), channelKey);
return new PushSendOptions(
routeType, routeType,
profile.path("channelId").asText(""), channelId,
profile.path("category").asText(""), route.path("category").asText(""),
profile.path("threadIdentifier").asText(""), route.path("priority").asText(""));
profile.path("interruptionLevel").asText(""), })
profile.path("importance").asText(""), .orElseGet(() -> new PushSendOptions(routeType, "", "", ""));
readBoolean(profile, "badge"),
readBoolean(profile, "sound"),
readBoolean(profile, "vibration"),
readInteger(profile, "notifyType"),
mapPriority(profile.path("importance").asText(""))))
.orElseGet(() -> new PushSendOptions("", routeType, "", "", "", "", "", null, null, null, null, "")))
.orElseGet(() -> new PushSendOptions("", routeType, "", "", "", "", "", null, null, null, null, ""));
} }
private String platformForVendor(DeviceTokenEntity.Vendor vendor, String payload) { private String platformForVendor(DeviceTokenEntity.Vendor vendor, String payload) {
@ -126,73 +121,18 @@ public class PushDispatcher {
} }
} }
private java.util.Optional<JsonNode> profileFor(JsonNode config, String vendor, String routeType) { private String effectiveChannelId(JsonNode channels, String channelKey) {
JsonNode profiles = config.path("profiles"); if (channels == null || !channels.isArray() || channelKey == null || channelKey.isBlank()) {
if (profiles == null || !profiles.isArray()) { return "";
return java.util.Optional.empty();
} }
JsonNode fallback = null; for (JsonNode channel : channels) {
for (JsonNode profile : profiles) { if (channelKey.equals(channel.path("key").asText(""))) {
if (!profile.path("enabled").asBoolean(true)) { String base = channel.path("channelId").asText(channelKey);
continue; int version = Math.max(channel.path("version").asInt(1), 1);
} return base + "_v" + version;
if (!vendor.equalsIgnoreCase(profile.path("vendor").asText(""))) {
continue;
}
String profileRouteType = profile.path("routeType").asText("");
if (profileRouteType.isBlank() || "DEFAULT".equalsIgnoreCase(profileRouteType)) {
if (fallback == null) {
fallback = profile;
}
continue;
}
if (!routeType.equalsIgnoreCase(profileRouteType)) {
continue;
}
return java.util.Optional.of(profile);
}
return java.util.Optional.ofNullable(fallback);
}
private Boolean readBoolean(JsonNode node, String key) {
if (node == null || node.isNull()) {
return null;
}
JsonNode value = node.get(key);
if (value == null || value.isNull()) {
return null;
}
return value.asBoolean();
}
private Integer readInteger(JsonNode node, String key) {
if (node == null || node.isNull()) {
return null;
}
JsonNode value = node.get(key);
if (value == null || value.isNull()) {
return null;
}
if (value.isInt() || value.isLong() || value.isNumber()) {
return value.asInt();
}
String text = value.asText("");
if (text.isBlank()) {
return null;
}
try {
return Integer.parseInt(text.trim());
} catch (NumberFormatException e) {
return null;
} }
} }
return "";
private String mapPriority(String importance) {
return switch (importance == null ? "" : importance.trim().toUpperCase()) {
case "HIGH", "MAX" -> "HIGH";
case "LOW", "MIN" -> "LOW";
default -> "DEFAULT";
};
} }
public List<DeviceTokenEntity> selectedPushTargets(String appKey, String userId) { public List<DeviceTokenEntity> selectedPushTargets(String appKey, String userId) {
@ -210,7 +150,7 @@ public class PushDispatcher {
private List<DeviceTokenEntity> selectTargets(String appKey, String userId) { private List<DeviceTokenEntity> selectTargets(String appKey, String userId) {
List<DeviceTokenEntity> devices = tokenRepository List<DeviceTokenEntity> devices = tokenRepository
.findByAppKeyAndUserIdAndReceivePushTrueOrderByLastLoginAtDescUpdatedAtDesc(appKey, userId); .findByAppIdAndUserIdAndReceivePushTrueOrderByLastLoginAtDescUpdatedAtDesc(appKey, userId);
if (devices.isEmpty()) { if (devices.isEmpty()) {
return List.of(); return List.of();
} }
@ -245,15 +185,15 @@ public class PushDispatcher {
String osVersion, String osVersion,
String appVersion) { String appVersion) {
String resolvedDeviceId = normalizeDeviceId(deviceId, vendor, token); String resolvedDeviceId = normalizeDeviceId(deviceId, vendor, token);
Optional<DeviceTokenEntity> existing = tokenRepository.findByAppKeyAndUserIdAndDeviceId(appKey, userId, resolvedDeviceId); Optional<DeviceTokenEntity> existing = tokenRepository.findByAppIdAndUserIdAndDeviceId(appKey, userId, resolvedDeviceId);
if (existing.isEmpty() && (deviceId == null || deviceId.isBlank())) { if (existing.isEmpty() && (deviceId == null || deviceId.isBlank())) {
existing = tokenRepository.findByAppKeyAndUserIdAndVendor(appKey, userId, vendor); existing = tokenRepository.findByAppIdAndUserIdAndVendor(appKey, userId, vendor);
} }
LocalDateTime now = LocalDateTime.now(); LocalDateTime now = LocalDateTime.now();
DeviceTokenEntity entity = existing.orElseGet(() -> { DeviceTokenEntity entity = existing.orElseGet(() -> {
DeviceTokenEntity e = new DeviceTokenEntity(); DeviceTokenEntity e = new DeviceTokenEntity();
e.setId(UUID.randomUUID().toString()); e.setId(UUID.randomUUID().toString());
e.setAppKey(appKey); e.setAppId(appKey);
e.setUserId(userId); e.setUserId(userId);
e.setVendor(vendor); e.setVendor(vendor);
e.setCreatedAt(now); e.setCreatedAt(now);
@ -276,8 +216,8 @@ public class PushDispatcher {
public void setReceivePush(String appKey, String userId, String deviceId, boolean enabled) { public void setReceivePush(String appKey, String userId, String deviceId, boolean enabled) {
List<DeviceTokenEntity> tokens = deviceId == null || deviceId.isBlank() List<DeviceTokenEntity> tokens = deviceId == null || deviceId.isBlank()
? tokenRepository.findByAppKeyAndUserId(appKey, userId) ? tokenRepository.findByAppIdAndUserId(appKey, userId)
: tokenRepository.findByAppKeyAndUserIdAndDeviceId(appKey, userId, deviceId).stream().toList(); : tokenRepository.findByAppIdAndUserIdAndDeviceId(appKey, userId, deviceId).stream().toList();
for (DeviceTokenEntity token : tokens) { for (DeviceTokenEntity token : tokens) {
token.setReceivePush(enabled); token.setReceivePush(enabled);
token.setUpdatedAt(LocalDateTime.now()); token.setUpdatedAt(LocalDateTime.now());
@ -288,20 +228,20 @@ public class PushDispatcher {
public void unregisterToken(String appKey, String userId, DeviceTokenEntity.Vendor vendor, String deviceId) { public void unregisterToken(String appKey, String userId, DeviceTokenEntity.Vendor vendor, String deviceId) {
if (deviceId != null && !deviceId.isBlank()) { if (deviceId != null && !deviceId.isBlank()) {
tokenRepository.findByAppKeyAndUserIdAndDeviceId(appKey, userId, deviceId) tokenRepository.findByAppIdAndUserIdAndDeviceId(appKey, userId, deviceId)
.ifPresent(entity -> recordLog(entity, DeviceLoginLogEntity.EventType.UNREGISTER)); .ifPresent(entity -> recordLog(entity, DeviceLoginLogEntity.EventType.UNREGISTER));
tokenRepository.deleteByAppKeyAndUserIdAndDeviceId(appKey, userId, deviceId); tokenRepository.deleteByAppIdAndUserIdAndDeviceId(appKey, userId, deviceId);
return; return;
} }
tokenRepository.findByAppKeyAndUserIdAndVendor(appKey, userId, vendor) tokenRepository.findByAppIdAndUserIdAndVendor(appKey, userId, vendor)
.ifPresent(entity -> recordLog(entity, DeviceLoginLogEntity.EventType.UNREGISTER)); .ifPresent(entity -> recordLog(entity, DeviceLoginLogEntity.EventType.UNREGISTER));
tokenRepository.deleteByAppKeyAndUserIdAndVendor(appKey, userId, vendor); tokenRepository.deleteByAppIdAndUserIdAndVendor(appKey, userId, vendor);
} }
private void recordLog(DeviceTokenEntity token, DeviceLoginLogEntity.EventType eventType) { private void recordLog(DeviceTokenEntity token, DeviceLoginLogEntity.EventType eventType) {
DeviceLoginLogEntity entity = new DeviceLoginLogEntity(); DeviceLoginLogEntity entity = new DeviceLoginLogEntity();
entity.setId(UUID.randomUUID().toString()); entity.setId(UUID.randomUUID().toString());
entity.setAppKey(token.getAppKey()); entity.setAppId(token.getAppId());
entity.setUserId(token.getUserId()); entity.setUserId(token.getUserId());
entity.setVendor(token.getVendor()); entity.setVendor(token.getVendor());
entity.setTokenHash(hashToken(token.getToken())); entity.setTokenHash(hashToken(token.getToken()));

查看文件

@ -82,31 +82,16 @@ public class ApnsPushProvider implements PushProvider {
String url = (production ? productionPushUrl : sandboxPushUrl).replace("{token}", token); String url = (production ? productionPushUrl : sandboxPushUrl).replace("{token}", token);
Map<String, Object> aps = new java.util.LinkedHashMap<>(); Map<String, Object> aps = new java.util.LinkedHashMap<>();
aps.put("alert", Map.of("title", title, "body", body)); aps.put("alert", Map.of("title", title, "body", body));
if (options == null || options.sound() == null || options.sound()) {
aps.put("sound", "default"); aps.put("sound", "default");
}
if (options != null) { if (options != null) {
if (options.category() != null && !options.category().isBlank()) { if (options.category() != null && !options.category().isBlank()) {
aps.put("category", options.category()); aps.put("category", options.category());
} }
if (options.threadIdentifier() != null && !options.threadIdentifier().isBlank()) { if (options.routeType() != null && !options.routeType().isBlank()) {
aps.put("thread-id", options.threadIdentifier());
} else if (options.routeType() != null && !options.routeType().isBlank()) {
aps.put("thread-id", options.routeType()); aps.put("thread-id", options.routeType());
} }
if ("HIGH".equalsIgnoreCase(options.priority()) || "HIGH".equalsIgnoreCase(options.interruptionLevel())) { if ("HIGH".equalsIgnoreCase(options.priority())) {
aps.put("interruption-level", "time-sensitive"); aps.put("interruption-level", "time-sensitive");
} else if ("CRITICAL".equalsIgnoreCase(options.interruptionLevel())) {
aps.put("interruption-level", "critical");
} else if ("PASSIVE".equalsIgnoreCase(options.interruptionLevel())) {
aps.put("interruption-level", "passive");
} else if ("ACTIVE".equalsIgnoreCase(options.interruptionLevel())) {
aps.put("interruption-level", "active");
}
if (options.badge() != null) {
if (Boolean.TRUE.equals(options.badge())) {
aps.put("badge", 1);
}
} }
} }
Map<String, Object> message = new java.util.LinkedHashMap<>(); Map<String, Object> message = new java.util.LinkedHashMap<>();
@ -168,7 +153,7 @@ public class ApnsPushProvider implements PushProvider {
private String resolveConfig(String appKey, String key, String fallback) { private String resolveConfig(String appKey, String key, String fallback) {
JsonNode config = configClient.loadServiceConfig(appKey, "IOS", "PUSH") JsonNode config = configClient.loadServiceConfig(appKey, "IOS", "PUSH")
.map(node -> node.path("vendors").path("apns")) .map(node -> node.path("apns"))
.orElse(null); .orElse(null);
if (config == null) { if (config == null) {
return fallback == null ? "" : fallback; return fallback == null ? "" : fallback;

查看文件

@ -0,0 +1,159 @@
package com.xuqm.push.service.provider;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xuqm.push.service.TenantPushConfigClient;
import io.jsonwebtoken.Jwts;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Component
public class FcmPushProvider implements PushProvider {
private static final Logger log = LoggerFactory.getLogger(FcmPushProvider.class);
@Value("${push.fcm.project-id:}")
private String envProjectId;
@Value("${push.fcm.service-account-json:}")
private String envServiceAccountJson;
@Value("${push.fcm.token-url:https://oauth2.googleapis.com/token}")
private String tokenUrl;
@Value("${push.fcm.push-url:https://fcm.googleapis.com/v1/projects/{projectId}/messages:send}")
private String pushUrl;
private final TenantPushConfigClient configClient;
private final HttpClient httpClient = HttpClient.newHttpClient();
private final ObjectMapper objectMapper = new ObjectMapper();
private final Map<String, TokenCache> tokenCache = new ConcurrentHashMap<>();
public FcmPushProvider(TenantPushConfigClient configClient) {
this.configClient = configClient;
}
@Override
public String vendorName() {
return "FCM";
}
@Override
public boolean send(String appKey, String token, String title, String body, String payload) {
return send(appKey, token, title, body, payload, PushSendOptions.empty());
}
@Override
public boolean send(String appKey, String token, String title, String body, String payload, PushSendOptions options) {
String projectId = resolveConfig(appKey, "projectId", envProjectId);
String serviceAccountJson = resolveConfig(appKey, "serviceAccountJson", envServiceAccountJson);
if (projectId.isBlank() || serviceAccountJson.isBlank()) {
log.warn("FCM push not configured");
return false;
}
try {
String accessToken = getAccessToken(projectId, serviceAccountJson);
String url = pushUrl.replace("{projectId}", projectId);
Map<String, Object> bodyMap = new LinkedHashMap<>();
bodyMap.put("token", token);
bodyMap.put("notification", Map.of("title", title, "body", body));
bodyMap.put("data", payload != null ? Map.of("payload", payload) : Map.of());
if (options != null && options.channelId() != null && !options.channelId().isBlank()) {
bodyMap.put("android", Map.of("notification", Map.of("channel_id", options.channelId())));
}
Map<String, Object> message = Map.of("message", bodyMap);
String requestBody = objectMapper.writeValueAsString(message);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + accessToken)
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
return response.statusCode() == 200;
} catch (Exception e) {
log.error("FCM push failed: {}", e.getMessage());
return false;
}
}
private String getAccessToken(String projectId, String serviceAccountJson) throws Exception {
TokenCache cache = tokenCache.get(projectId);
if (cache != null && cache.expiresAt > System.currentTimeMillis() + 60_000) {
return cache.token;
}
JsonNode sa = objectMapper.readTree(serviceAccountJson);
String clientEmail = sa.path("client_email").asText();
String privateKeyPem = sa.path("private_key").asText();
PrivateKey privateKey = parseRsaPrivateKey(privateKeyPem);
long now = System.currentTimeMillis();
String jwt = Jwts.builder()
.subject(clientEmail)
.issuer(clientEmail)
.claim("aud", tokenUrl)
.claim("scope", "https://www.googleapis.com/auth/firebase.messaging")
.issuedAt(new Date(now))
.expiration(new Date(now + 3600_000))
.signWith(privateKey)
.compact();
String form = "grant_type=" + URLEncoder.encode("urn:ietf:params:oauth:grant-type:jwt-bearer", StandardCharsets.UTF_8)
+ "&assertion=" + jwt;
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(tokenUrl))
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(form))
.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
Map<?, ?> json = objectMapper.readValue(response.body(), Map.class);
String accessToken = (String) json.get("access_token");
Integer expiresIn = (Integer) json.get("expires_in");
long expiresAt = System.currentTimeMillis() + (expiresIn != null ? expiresIn : 3600) * 1000L;
tokenCache.put(projectId, new TokenCache(accessToken, expiresAt));
return accessToken;
}
private PrivateKey parseRsaPrivateKey(String pem) throws Exception {
String clean = pem.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s", "");
byte[] decoded = Base64.getDecoder().decode(clean);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decoded);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(spec);
}
private String resolveConfig(String appKey, String key, String fallback) {
JsonNode config = configClient.loadServiceConfig(appKey, "ANDROID", "PUSH")
.map(node -> node.path("fcm"))
.orElse(null);
if (config == null) {
return fallback == null ? "" : fallback;
}
String value = config.path(key).asText("");
return value.isBlank() ? (fallback == null ? "" : fallback) : value;
}
private record TokenCache(String token, long expiresAt) {}
}

查看文件

@ -78,9 +78,6 @@ public class HarmonyPushProvider implements PushProvider {
if (options.channelId() != null && !options.channelId().isBlank()) { if (options.channelId() != null && !options.channelId().isBlank()) {
notification.put("channel_id", options.channelId()); notification.put("channel_id", options.channelId());
} }
if (options.badge() != null && options.badge()) {
notification.put("badge", 1);
}
} }
Map<String, Object> message = Map.of( Map<String, Object> message = Map.of(
"message", Map.of( "message", Map.of(
@ -118,7 +115,7 @@ public class HarmonyPushProvider implements PushProvider {
private String resolveConfig(String appKey, String key, String fallback) { private String resolveConfig(String appKey, String key, String fallback) {
JsonNode config = configClient.loadServiceConfig(appKey, "HARMONY", "PUSH") JsonNode config = configClient.loadServiceConfig(appKey, "HARMONY", "PUSH")
.map(node -> node.path("vendors").path("harmony")) .map(node -> node.path("harmony"))
.orElse(null); .orElse(null);
if (config == null) { if (config == null) {
return fallback == null ? "" : fallback; return fallback == null ? "" : fallback;

查看文件

@ -46,11 +46,6 @@ public class HonorPushProvider implements PushProvider {
@Override @Override
public boolean send(String appKey, String token, String title, String body, String payload) { public boolean send(String appKey, String token, String title, String body, String payload) {
return send(appKey, token, title, body, payload, PushSendOptions.empty());
}
@Override
public boolean send(String appKey, String token, String title, String body, String payload, PushSendOptions options) {
String resolvedAppId = resolveConfig(appKey, "appId", envAppId); String resolvedAppId = resolveConfig(appKey, "appId", envAppId);
String resolvedAppSecret = resolveConfig(appKey, "clientSecret", envAppSecret); String resolvedAppSecret = resolveConfig(appKey, "clientSecret", envAppSecret);
if (resolvedAppId.isBlank() || resolvedAppSecret.isBlank()) { if (resolvedAppId.isBlank() || resolvedAppSecret.isBlank()) {
@ -63,21 +58,10 @@ public class HonorPushProvider implements PushProvider {
try { try {
String accessToken = getAccessToken(resolvedAppId, resolvedAppSecret); String accessToken = getAccessToken(resolvedAppId, resolvedAppSecret);
String url = pushUrl.replace("{appId}", resolvedAppId); String url = pushUrl.replace("{appId}", resolvedAppId);
java.util.Map<String, Object> notification = new java.util.LinkedHashMap<>();
notification.put("title", title);
notification.put("body", body);
if (options != null) {
if (options.channelId() != null && !options.channelId().isBlank()) {
notification.put("channel_id", options.channelId());
}
if (options.category() != null && !options.category().isBlank()) {
notification.put("category", options.category());
}
}
Map<String, Object> message = Map.of( Map<String, Object> message = Map.of(
"message", Map.of( "message", Map.of(
"token", new String[]{token}, "token", new String[]{token},
"notification", notification, "notification", Map.of("title", title, "body", body),
"data", payload != null ? payload : "{}" "data", payload != null ? payload : "{}"
) )
); );
@ -110,7 +94,7 @@ public class HonorPushProvider implements PushProvider {
private String resolveConfig(String appKey, String key, String fallback) { private String resolveConfig(String appKey, String key, String fallback) {
JsonNode config = configClient.loadServiceConfig(appKey, "ANDROID", "PUSH") JsonNode config = configClient.loadServiceConfig(appKey, "ANDROID", "PUSH")
.map(node -> node.path("vendors").path("honor")) .map(node -> node.path("honor"))
.orElse(null); .orElse(null);
if (config == null) { if (config == null) {
return fallback == null ? "" : fallback; return fallback == null ? "" : fallback;

查看文件

@ -68,9 +68,7 @@ public class HuaweiPushProvider implements PushProvider {
Map<String, Object> androidNotification = new LinkedHashMap<>(); Map<String, Object> androidNotification = new LinkedHashMap<>();
String channelId = options != null && options.channelId() != null && !options.channelId().isBlank() String channelId = options != null && options.channelId() != null && !options.channelId().isBlank()
? options.channelId() : ""; ? options.channelId() : "";
String category = options != null && options.category() != null && !options.category().isBlank() String category = resolveConfig(appKey, "category", "");
? options.category()
: resolveConfig(appKey, "category", "");
if (!channelId.isBlank()) androidNotification.put("channel_id", channelId); if (!channelId.isBlank()) androidNotification.put("channel_id", channelId);
if (!category.isBlank()) androidNotification.put("category", category); if (!category.isBlank()) androidNotification.put("category", category);
if (!androidNotification.isEmpty()) { if (!androidNotification.isEmpty()) {
@ -106,7 +104,7 @@ public class HuaweiPushProvider implements PushProvider {
private String resolveConfig(String appKey, String key, String fallback) { private String resolveConfig(String appKey, String key, String fallback) {
JsonNode config = configClient.loadServiceConfig(appKey, "ANDROID", "PUSH") JsonNode config = configClient.loadServiceConfig(appKey, "ANDROID", "PUSH")
.map(node -> node.path("vendors").path("huawei")) .map(node -> node.path("huawei"))
.orElse(null); .orElse(null);
if (config == null) { if (config == null) {
return fallback == null ? "" : fallback; return fallback == null ? "" : fallback;

查看文件

@ -40,11 +40,6 @@ public class OppoPushProvider implements PushProvider {
@Override @Override
public boolean send(String appKey, String token, String title, String body, String payload) { public boolean send(String appKey, String token, String title, String body, String payload) {
return send(appKey, token, title, body, payload, PushSendOptions.empty());
}
@Override
public boolean send(String appKey, String token, String title, String body, String payload, PushSendOptions options) {
String vendorAppKey = resolveConfig(appKey, "appKey"); String vendorAppKey = resolveConfig(appKey, "appKey");
String masterSecret = resolveConfig(appKey, "masterSecret"); String masterSecret = resolveConfig(appKey, "masterSecret");
if (vendorAppKey.isBlank() || masterSecret.isBlank()) { if (vendorAppKey.isBlank() || masterSecret.isBlank()) {
@ -60,9 +55,7 @@ public class OppoPushProvider implements PushProvider {
inner.put("content", body); inner.put("content", body);
inner.put("target_type", 2); inner.put("target_type", 2);
inner.put("target_value", token); inner.put("target_value", token);
String channelId = options != null && options.channelId() != null && !options.channelId().isBlank() String channelId = resolveConfig(appKey, "channelId");
? options.channelId()
: resolveConfig(appKey, "channelId");
if (!channelId.isBlank()) inner.put("channel_id", channelId); if (!channelId.isBlank()) inner.put("channel_id", channelId);
Map<String, Object> message = Map.of("message", inner); Map<String, Object> message = Map.of("message", inner);
String requestBody = objectMapper.writeValueAsString(message); String requestBody = objectMapper.writeValueAsString(message);
@ -105,7 +98,7 @@ public class OppoPushProvider implements PushProvider {
private String resolveConfig(String appKey, String key) { private String resolveConfig(String appKey, String key) {
JsonNode config = configClient.loadServiceConfig(appKey, "ANDROID", "PUSH") JsonNode config = configClient.loadServiceConfig(appKey, "ANDROID", "PUSH")
.map(node -> node.path("vendors").path("oppo")) .map(node -> node.path("oppo"))
.orElse(null); .orElse(null);
if (config == null) { if (config == null) {
return ""; return "";

查看文件

@ -1,20 +1,12 @@
package com.xuqm.push.service.provider; package com.xuqm.push.service.provider;
public record PushSendOptions( public record PushSendOptions(
String profileKey,
String routeType, String routeType,
String channelId, String channelId,
String category, String category,
String threadIdentifier,
String interruptionLevel,
String importance,
Boolean badge,
Boolean sound,
Boolean vibration,
Integer notifyType,
String priority String priority
) { ) {
public static PushSendOptions empty() { public static PushSendOptions empty() {
return new PushSendOptions("", "", "", "", "", "", "", null, null, null, null, ""); return new PushSendOptions("", "", "", "");
} }
} }

查看文件

@ -40,11 +40,6 @@ public class VivoPushProvider implements PushProvider {
@Override @Override
public boolean send(String appKey, String token, String title, String body, String payload) { public boolean send(String appKey, String token, String title, String body, String payload) {
return send(appKey, token, title, body, payload, PushSendOptions.empty());
}
@Override
public boolean send(String appKey, String token, String title, String body, String payload, PushSendOptions options) {
String vendorAppKey = resolveConfig(appKey, "appKey"); String vendorAppKey = resolveConfig(appKey, "appKey");
String appIdConfig = resolveConfig(appKey, "appId"); String appIdConfig = resolveConfig(appKey, "appId");
if (vendorAppKey.isBlank() || appIdConfig.isBlank()) { if (vendorAppKey.isBlank() || appIdConfig.isBlank()) {
@ -58,17 +53,11 @@ public class VivoPushProvider implements PushProvider {
message.put("title", title); message.put("title", title);
message.put("content", body); message.put("content", body);
message.put("notifyType", 1); message.put("notifyType", 1);
String category = options != null && options.category() != null && !options.category().isBlank() String category = resolveConfig(appKey, "category");
? options.category()
: resolveConfig(appKey, "category");
String receiptId = resolveConfig(appKey, "receiptId"); String receiptId = resolveConfig(appKey, "receiptId");
if (!category.isBlank()) { if (!category.isBlank()) {
message.put("classification", switch (category.toUpperCase()) { // vivo classification: 0=operation, 1=IM/system
case "MESSAGE", "IM" -> 1; message.put("classification", "IM".equalsIgnoreCase(category) ? 1 : 0);
case "SOCIAL" -> 2;
case "SYSTEM" -> 3;
default -> 0;
});
} }
if (!receiptId.isBlank()) { if (!receiptId.isBlank()) {
message.put("requestId", receiptId + "_" + System.currentTimeMillis()); message.put("requestId", receiptId + "_" + System.currentTimeMillis());
@ -113,7 +102,7 @@ public class VivoPushProvider implements PushProvider {
private String resolveConfig(String appKey, String key) { private String resolveConfig(String appKey, String key) {
JsonNode config = configClient.loadServiceConfig(appKey, "ANDROID", "PUSH") JsonNode config = configClient.loadServiceConfig(appKey, "ANDROID", "PUSH")
.map(node -> node.path("vendors").path("vivo")) .map(node -> node.path("vivo"))
.orElse(null); .orElse(null);
if (config == null) { if (config == null) {
return ""; return "";

查看文件

@ -70,9 +70,8 @@ public class XiaomiPushProvider implements PushProvider {
.append("&title=").append(URLEncoder.encode(title, StandardCharsets.UTF_8)) .append("&title=").append(URLEncoder.encode(title, StandardCharsets.UTF_8))
.append("&description=").append(URLEncoder.encode(body, StandardCharsets.UTF_8)) .append("&description=").append(URLEncoder.encode(body, StandardCharsets.UTF_8))
.append("&restricted_package_name=").append(URLEncoder.encode(packageName, StandardCharsets.UTF_8)) .append("&restricted_package_name=").append(URLEncoder.encode(packageName, StandardCharsets.UTF_8))
.append("&notify_type=1")
.append("&extra.notify_foreground=1"); .append("&extra.notify_foreground=1");
Integer notifyType = options != null ? options.notifyType() : null;
form.append("&notify_type=").append(notifyType == null ? 1 : Math.max(notifyType, 0));
if (!channelId.isBlank()) { if (!channelId.isBlank()) {
form.append("&channel_id=").append(URLEncoder.encode(channelId, StandardCharsets.UTF_8)); form.append("&channel_id=").append(URLEncoder.encode(channelId, StandardCharsets.UTF_8));
} }
@ -111,7 +110,7 @@ public class XiaomiPushProvider implements PushProvider {
private String resolveVendorConfig(String appKey, String key, String fallback) { private String resolveVendorConfig(String appKey, String key, String fallback) {
JsonNode config = configClient.loadServiceConfig(appKey, "ANDROID", "PUSH") JsonNode config = configClient.loadServiceConfig(appKey, "ANDROID", "PUSH")
.map(node -> node.path("vendors").path("xiaomi")) .map(node -> node.path("xiaomi"))
.orElse(null); .orElse(null);
if (config == null) { if (config == null) {
return fallback == null ? "" : fallback; return fallback == null ? "" : fallback;

查看文件

@ -34,6 +34,11 @@ push:
xiaomi: xiaomi:
app-secret: ${XIAOMI_APP_SECRET:} app-secret: ${XIAOMI_APP_SECRET:}
push-url: https://api.xmpush.xiaomi.com/v3/message/regid push-url: https://api.xmpush.xiaomi.com/v3/message/regid
fcm:
project-id: ${FCM_PROJECT_ID:}
service-account-json: ${FCM_SERVICE_ACCOUNT_JSON:}
token-url: https://oauth2.googleapis.com/token
push-url: https://fcm.googleapis.com/v1/projects/{projectId}/messages:send
apns: apns:
team-id: ${APNS_TEAM_ID:} team-id: ${APNS_TEAM_ID:}
key-id: ${APNS_KEY_ID:} key-id: ${APNS_KEY_ID:}

查看文件

@ -20,11 +20,6 @@
<groupId>com.xuqm</groupId> <groupId>com.xuqm</groupId>
<artifactId>common</artifactId> <artifactId>common</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.xuqm</groupId>
<artifactId>im-sdk</artifactId>
<version>0.1.0-SNAPSHOT</version>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>

查看文件

@ -112,7 +112,35 @@ public class FeatureServiceController {
case PUSH -> featureServiceManager.buildPushConfig( case PUSH -> featureServiceManager.buildPushConfig(
appKey, appKey,
platform, platform,
req == null ? null : req.pushConfig()); req == null ? null : req.huaweiAppIdValue(),
req == null ? null : req.huaweiAppSecretValue(),
req == null ? null : req.huaweiCategoryValue(),
req == null ? null : req.xiaomiAppIdValue(),
req == null ? null : req.xiaomiAppKeyValue(),
req == null ? null : req.xiaomiAppSecretValue(),
req == null ? null : req.xiaomiChannelIdValue(),
req == null ? null : req.oppoAppIdValue(),
req == null ? null : req.oppoAppKeyValue(),
req == null ? null : req.oppoMasterSecretValue(),
req == null ? null : req.oppoChannelIdValue(),
req == null ? null : req.vivoAppIdValue(),
req == null ? null : req.vivoAppKeyValue(),
req == null ? null : req.vivoAppSecretValue(),
req == null ? null : req.vivoCategoryValue(),
req == null ? null : req.vivoReceiptIdValue(),
req == null ? null : req.honorAppIdValue(),
req == null ? null : req.honorClientIdValue(),
req == null ? null : req.honorClientSecretValue(),
req == null ? null : req.harmonyAppIdValue(),
req == null ? null : req.harmonyAppSecretValue(),
req == null ? null : req.apnsTeamIdValue(),
req == null ? null : req.apnsKeyIdValue(),
req == null ? null : req.apnsBundleIdValue(),
req == null ? null : req.apnsKeyPathValue(),
req != null && req.apnsSandboxValue(),
req == null ? null : req.fcmServiceAccountJsonValue(),
req == null ? null : req.channels(),
req == null ? null : req.routing());
}; };
FeatureServiceEntity saved = featureServiceManager.updateConfig( FeatureServiceEntity saved = featureServiceManager.updateConfig(
appKey, platform, serviceType, config); appKey, platform, serviceType, config);
@ -187,7 +215,102 @@ public class FeatureServiceController {
String defaultPackageName, String defaultPackageName,
String defaultAppStoreUrl, String defaultAppStoreUrl,
String defaultMarketUrl, String defaultMarketUrl,
JsonNode pushConfig String huaweiAppId,
String huaweiAppSecret,
String huaweiCategory,
String xiaomiAppId,
String xiaomiAppKey,
String xiaomiAppSecret,
String xiaomiChannelId,
String oppoAppId,
String oppoAppKey,
String oppoMasterSecret,
String oppoChannelId,
String vivoAppId,
String vivoAppKey,
String vivoAppSecret,
String vivoCategory,
String vivoReceiptId,
String honorAppId,
String honorClientId,
String honorClientSecret,
String harmonyAppId,
String harmonyAppSecret,
String apnsTeamId,
String apnsKeyId,
String apnsBundleId,
String apnsKeyPath,
Boolean apnsSandbox,
String fcmServiceAccountJson,
PushVendorConfig huawei,
PushVendorConfig xiaomi,
PushVendorConfig oppo,
PushVendorConfig vivo,
PushVendorConfig honor,
PushVendorConfig harmony,
PushVendorConfig apns,
PushVendorConfig fcm,
JsonNode channels,
JsonNode routing
) { ) {
public String huaweiAppIdValue() { return firstText(huaweiAppId, huawei == null ? null : huawei.appId()); }
public String huaweiAppSecretValue() { return firstText(huaweiAppSecret, huawei == null ? null : huawei.appSecret()); }
public String huaweiCategoryValue() { return firstText(huaweiCategory, huawei == null ? null : huawei.category()); }
public String xiaomiAppIdValue() { return firstText(xiaomiAppId, xiaomi == null ? null : xiaomi.appId()); }
public String xiaomiAppKeyValue() { return firstText(xiaomiAppKey, xiaomi == null ? null : xiaomi.appKey()); }
public String xiaomiAppSecretValue() { return firstText(xiaomiAppSecret, xiaomi == null ? null : xiaomi.appSecret()); }
public String xiaomiChannelIdValue() { return firstText(xiaomiChannelId, xiaomi == null ? null : xiaomi.channelId()); }
public String oppoAppIdValue() { return firstText(oppoAppId, oppo == null ? null : oppo.appId()); }
public String oppoAppKeyValue() { return firstText(oppoAppKey, oppo == null ? null : oppo.appKey()); }
public String oppoMasterSecretValue() { return firstText(oppoMasterSecret, oppo == null ? null : oppo.masterSecret()); }
public String oppoChannelIdValue() { return firstText(oppoChannelId, oppo == null ? null : oppo.channelId()); }
public String vivoAppIdValue() { return firstText(vivoAppId, vivo == null ? null : vivo.appId()); }
public String vivoAppKeyValue() { return firstText(vivoAppKey, vivo == null ? null : vivo.appKey()); }
public String vivoAppSecretValue() { return firstText(vivoAppSecret, vivo == null ? null : vivo.appSecret()); }
public String vivoCategoryValue() { return firstText(vivoCategory, vivo == null ? null : vivo.category()); }
public String vivoReceiptIdValue() { return firstText(vivoReceiptId, vivo == null ? null : vivo.receiptId()); }
public String honorAppIdValue() { return firstText(honorAppId, honor == null ? null : honor.appId()); }
public String honorClientIdValue() { return firstText(honorClientId, honor == null ? null : honor.clientId()); }
public String honorClientSecretValue() { return firstText(honorClientSecret, honor == null ? null : honor.clientSecret()); }
public String harmonyAppIdValue() { return firstText(harmonyAppId, harmony == null ? null : harmony.appId()); }
public String harmonyAppSecretValue() { return firstText(harmonyAppSecret, harmony == null ? null : harmony.appSecret()); }
public String apnsTeamIdValue() { return firstText(apnsTeamId, apns == null ? null : apns.teamId()); }
public String apnsKeyIdValue() { return firstText(apnsKeyId, apns == null ? null : apns.keyId()); }
public String apnsBundleIdValue() { return firstText(apnsBundleId, apns == null ? null : apns.bundleId()); }
public String apnsKeyPathValue() { return firstText(apnsKeyPath, apns == null ? null : apns.keyPath()); }
public boolean apnsSandboxValue() {
if (apnsSandbox != null) {
return apnsSandbox;
} }
return apns != null && Boolean.TRUE.equals(apns.sandbox());
}
public String fcmServiceAccountJsonValue() {
return firstText(fcmServiceAccountJson, fcm == null ? null : fcm.serviceAccountJson());
}
private static String firstText(String first, String second) {
if (first != null) {
return first;
}
return second;
}
}
public record PushVendorConfig(
String appId,
String appKey,
String appSecret,
String masterSecret,
String clientId,
String clientSecret,
String teamId,
String keyId,
String bundleId,
String keyPath,
Boolean sandbox,
String serviceAccountJson,
String channelId,
String category,
String receiptId
) {}
} }

查看文件

@ -1,44 +0,0 @@
package com.xuqm.tenant.controller;
import com.xuqm.common.model.ApiResponse;
import com.xuqm.tenant.entity.AppEntity;
import com.xuqm.tenant.service.ImPlatformEventService;
import com.xuqm.tenant.service.SdkAppProvisioningService;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
@RequestMapping("/api/im/platform-events")
public class ImPlatformEventController {
private final SdkAppProvisioningService provisioningService;
private final ImPlatformEventService platformEventService;
public ImPlatformEventController(SdkAppProvisioningService provisioningService,
ImPlatformEventService platformEventService) {
this.provisioningService = provisioningService;
this.platformEventService = platformEventService;
}
@GetMapping("/token")
public ResponseEntity<ApiResponse<Map<String, String>>> token(
@AuthenticationPrincipal String tenantId,
@RequestParam String appKey) {
try {
AppEntity app = provisioningService.resolveApp(appKey);
if (tenantId == null || tenantId.isBlank() || !tenantId.equals(app.getTenantId())) {
return ResponseEntity.status(403).body(ApiResponse.error(403, "Forbidden"));
}
return ResponseEntity.ok(ApiResponse.success(platformEventService.issueToken(appKey)));
} catch (Exception e) {
return ResponseEntity.status(500)
.body(ApiResponse.error(500, e.getMessage()));
}
}
}

查看文件

@ -1,42 +0,0 @@
package com.xuqm.tenant.controller;
import com.xuqm.common.model.ApiResponse;
import com.xuqm.tenant.service.ImPlatformEventService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
@RequestMapping("/api/internal/im/platform-events")
public class InternalImPlatformEventController {
private final ImPlatformEventService platformEventService;
@Value("${sdk.internal-token:xuqm-internal-token}")
private String internalToken;
public InternalImPlatformEventController(ImPlatformEventService platformEventService) {
this.platformEventService = platformEventService;
}
@PostMapping("/notify")
public ResponseEntity<ApiResponse<Map<String, String>>> notify(
@RequestHeader(value = "X-Internal-Token", required = false) String token,
@RequestBody ImPlatformEventService.StoreReviewEventRequest request) {
if (token == null || !internalToken.equals(token)) {
return ResponseEntity.status(403).body(ApiResponse.error(403, "Forbidden"));
}
try {
return ResponseEntity.ok(ApiResponse.success(platformEventService.notifyStoreReviewChange(request)));
} catch (Exception e) {
return ResponseEntity.status(500)
.body(ApiResponse.error(500, e.getMessage()));
}
}
}

查看文件

@ -56,22 +56,22 @@ public class SdkConfigController {
@RequestParam(required = false, defaultValue = "ANDROID") FeatureServiceEntity.Platform platform) { @RequestParam(required = false, defaultValue = "ANDROID") FeatureServiceEntity.Platform platform) {
AppEntity app = sdkAppProvisioningService.resolveApp(appKey); AppEntity app = sdkAppProvisioningService.resolveApp(appKey);
List<FeatureServiceEntity> features = featureServiceRepository.findByAppKey(app.getAppKey()); List<FeatureServiceEntity> features = featureServiceRepository.findByAppId(app.getAppKey());
boolean imEnabled = features.stream() boolean imEnabled = features.stream()
.anyMatch(f -> f.getServiceType() == FeatureServiceEntity.ServiceType.IM && f.isEnabled()); .anyMatch(f -> f.getServiceType() == FeatureServiceEntity.ServiceType.IM && f.isEnabled());
boolean pushEnabled = features.stream() boolean pushEnabled = features.stream()
.anyMatch(f -> f.getServiceType() == FeatureServiceEntity.ServiceType.PUSH && f.isEnabled()); .anyMatch(f -> f.getServiceType() == FeatureServiceEntity.ServiceType.PUSH && f.isEnabled());
JsonNode updateConfig = featureServiceRepository JsonNode updateConfig = featureServiceRepository
.findByAppKeyAndPlatformAndServiceType(app.getAppKey(), platform, FeatureServiceEntity.ServiceType.UPDATE) .findByAppIdAndPlatformAndServiceType(app.getAppKey(), platform, FeatureServiceEntity.ServiceType.UPDATE)
.map(feature -> parseConfig(feature.getConfig())) .map(feature -> parseConfig(feature.getConfig()))
.orElseGet(objectMapper::createObjectNode); .orElseGet(objectMapper::createObjectNode);
JsonNode pushConfig = featureServiceRepository JsonNode pushConfig = featureServiceRepository
.findByAppKeyAndPlatformAndServiceType(app.getAppKey(), platform, FeatureServiceEntity.ServiceType.PUSH) .findByAppIdAndPlatformAndServiceType(app.getAppKey(), platform, FeatureServiceEntity.ServiceType.PUSH)
.map(feature -> parseConfig(feature.getConfig())) .map(feature -> parseConfig(feature.getConfig()))
.orElseGet(objectMapper::createObjectNode); .orElseGet(objectMapper::createObjectNode);
boolean updateEnabled = featureServiceRepository boolean updateEnabled = featureServiceRepository
.findByAppKeyAndPlatformAndServiceType(app.getAppKey(), platform, FeatureServiceEntity.ServiceType.UPDATE) .findByAppIdAndPlatformAndServiceType(app.getAppKey(), platform, FeatureServiceEntity.ServiceType.UPDATE)
.map(FeatureServiceEntity::isEnabled) .map(FeatureServiceEntity::isEnabled)
.orElse(false); .orElse(false);

查看文件

@ -26,7 +26,7 @@ public class FeatureServiceEntity {
private String id; private String id;
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String appKey; private String appId;
@Enumerated(EnumType.STRING) @Enumerated(EnumType.STRING)
@Column(nullable = false, length = 16) @Column(nullable = false, length = 16)
@ -52,8 +52,8 @@ public class FeatureServiceEntity {
public String getId() { return id; } public String getId() { return id; }
public void setId(String id) { this.id = id; } public void setId(String id) { this.id = id; }
public String getAppKey() { return appKey; } public String getAppId() { return appId; }
public void setAppKey(String appKey) { this.appKey = appKey; } public void setAppId(String appId) { this.appId = appId; }
public Platform getPlatform() { return platform; } public Platform getPlatform() { return platform; }
public void setPlatform(Platform platform) { this.platform = platform; } public void setPlatform(Platform platform) { this.platform = platform; }

查看文件

@ -19,7 +19,7 @@ public class ServiceActivationRequestEntity {
private String id; private String id;
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String appKey; private String appId;
@Enumerated(EnumType.STRING) @Enumerated(EnumType.STRING)
@Column(nullable = false, length = 16) @Column(nullable = false, length = 16)
@ -47,11 +47,14 @@ public class ServiceActivationRequestEntity {
public String getId() { return id; } public String getId() { return id; }
public void setId(String id) { this.id = id; } public void setId(String id) { this.id = id; }
@JsonProperty("appKey") public String getAppId() { return appId; }
public String getAppKey() { return appKey; } public void setAppId(String appId) { this.appId = appId; }
@JsonProperty("appKey") @JsonProperty("appKey")
public void setAppKey(String appKey) { this.appKey = appKey; } public String getAppKey() { return appId; }
@JsonProperty("appKey")
public void setAppKey(String appKey) { this.appId = appKey; }
public FeatureServiceEntity.Platform getPlatform() { return platform; } public FeatureServiceEntity.Platform getPlatform() { return platform; }
public void setPlatform(FeatureServiceEntity.Platform platform) { this.platform = platform; } public void setPlatform(FeatureServiceEntity.Platform platform) { this.platform = platform; }

查看文件

@ -7,10 +7,10 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
public interface FeatureServiceRepository extends JpaRepository<FeatureServiceEntity, String> { public interface FeatureServiceRepository extends JpaRepository<FeatureServiceEntity, String> {
List<FeatureServiceEntity> findByAppKey(String appKey); List<FeatureServiceEntity> findByAppId(String appId);
List<FeatureServiceEntity> findByAppKeyAndServiceType(String appKey, FeatureServiceEntity.ServiceType serviceType); List<FeatureServiceEntity> findByAppIdAndServiceType(String appId, FeatureServiceEntity.ServiceType serviceType);
Optional<FeatureServiceEntity> findByAppKeyAndPlatformAndServiceType( Optional<FeatureServiceEntity> findByAppIdAndPlatformAndServiceType(
String appKey, String appId,
FeatureServiceEntity.Platform platform, FeatureServiceEntity.Platform platform,
FeatureServiceEntity.ServiceType serviceType); FeatureServiceEntity.ServiceType serviceType);

查看文件

@ -12,13 +12,13 @@ import java.util.Optional;
public interface ServiceActivationRequestRepository extends JpaRepository<ServiceActivationRequestEntity, String> { public interface ServiceActivationRequestRepository extends JpaRepository<ServiceActivationRequestEntity, String> {
Optional<ServiceActivationRequestEntity> findFirstByAppKeyAndPlatformAndServiceTypeOrderByCreatedAtDesc( Optional<ServiceActivationRequestEntity> findFirstByAppIdAndPlatformAndServiceTypeOrderByCreatedAtDesc(
String appKey, FeatureServiceEntity.Platform platform, FeatureServiceEntity.ServiceType serviceType); String appId, FeatureServiceEntity.Platform platform, FeatureServiceEntity.ServiceType serviceType);
Optional<ServiceActivationRequestEntity> findFirstByAppKeyAndServiceTypeOrderByCreatedAtDesc( Optional<ServiceActivationRequestEntity> findFirstByAppIdAndServiceTypeOrderByCreatedAtDesc(
String appKey, FeatureServiceEntity.ServiceType serviceType); String appId, FeatureServiceEntity.ServiceType serviceType);
List<ServiceActivationRequestEntity> findByAppKeyOrderByCreatedAtDesc(String appKey); List<ServiceActivationRequestEntity> findByAppIdOrderByCreatedAtDesc(String appId);
Page<ServiceActivationRequestEntity> findByStatusOrderByCreatedAtDesc(Status status, Pageable pageable); Page<ServiceActivationRequestEntity> findByStatusOrderByCreatedAtDesc(Status status, Pageable pageable);

查看文件

@ -33,7 +33,7 @@ public class DashboardService {
List<AppEntity> apps = appRepository.findByTenantId(tenantId); List<AppEntity> apps = appRepository.findByTenantId(tenantId);
long serviceCount = 0; long serviceCount = 0;
for (AppEntity app : apps) { for (AppEntity app : apps) {
serviceCount += featureServiceRepository.findByAppKey(app.getId()).stream() serviceCount += featureServiceRepository.findByAppId(app.getId()).stream()
.filter(FeatureServiceEntity::isEnabled) .filter(FeatureServiceEntity::isEnabled)
.count(); .count();
} }

查看文件

@ -38,7 +38,7 @@ public class FeatureServiceManager {
} }
public List<FeatureServiceEntity> listByApp(String appKey) { public List<FeatureServiceEntity> listByApp(String appKey) {
List<FeatureServiceEntity> services = repository.findByAppKey(appKey); List<FeatureServiceEntity> services = repository.findByAppId(appKey);
if (services.isEmpty()) { if (services.isEmpty()) {
return services; return services;
} }
@ -68,7 +68,7 @@ public class FeatureServiceManager {
String applyReason) { String applyReason) {
if (isAppWideService(serviceType)) { if (isAppWideService(serviceType)) {
requestRepository.findFirstByAppKeyAndServiceTypeOrderByCreatedAtDesc(appKey, serviceType) requestRepository.findFirstByAppIdAndServiceTypeOrderByCreatedAtDesc(appKey, serviceType)
.ifPresent(req -> { .ifPresent(req -> {
if (req.getStatus() == Status.PENDING) { if (req.getStatus() == Status.PENDING) {
throw new BusinessException(400, "已有待审核的开通申请,请等待运营人员处理"); throw new BusinessException(400, "已有待审核的开通申请,请等待运营人员处理");
@ -78,7 +78,7 @@ public class FeatureServiceManager {
ServiceActivationRequestEntity req = new ServiceActivationRequestEntity(); ServiceActivationRequestEntity req = new ServiceActivationRequestEntity();
req.setId(UUID.randomUUID().toString()); req.setId(UUID.randomUUID().toString());
req.setAppKey(appKey); req.setAppId(appKey);
req.setPlatform(platform); req.setPlatform(platform);
req.setServiceType(serviceType); req.setServiceType(serviceType);
req.setStatus(Status.PENDING); req.setStatus(Status.PENDING);
@ -94,7 +94,7 @@ public class FeatureServiceManager {
public FeatureServiceEntity disable(String appKey, FeatureServiceEntity.Platform platform, public FeatureServiceEntity disable(String appKey, FeatureServiceEntity.Platform platform,
FeatureServiceEntity.ServiceType serviceType) { FeatureServiceEntity.ServiceType serviceType) {
if (isAppWideService(serviceType)) { if (isAppWideService(serviceType)) {
List<FeatureServiceEntity> services = repository.findByAppKeyAndServiceType(appKey, serviceType); List<FeatureServiceEntity> services = repository.findByAppIdAndServiceType(appKey, serviceType);
if (services.isEmpty()) { if (services.isEmpty()) {
throw new BusinessException(404, "服务未开通"); throw new BusinessException(404, "服务未开通");
} }
@ -104,7 +104,7 @@ public class FeatureServiceManager {
} }
FeatureServiceEntity entity = repository FeatureServiceEntity entity = repository
.findByAppKeyAndPlatformAndServiceType(appKey, platform, serviceType) .findByAppIdAndPlatformAndServiceType(appKey, platform, serviceType)
.orElseThrow(() -> new BusinessException(404, "服务未开通")); .orElseThrow(() -> new BusinessException(404, "服务未开通"));
entity.setEnabled(false); entity.setEnabled(false);
return repository.save(entity); return repository.save(entity);
@ -126,17 +126,17 @@ public class FeatureServiceManager {
requestRepository.save(req); requestRepository.save(req);
// Normalize to appKey so SdkConfigController queries are consistent // Normalize to appKey so SdkConfigController queries are consistent
String normalizedAppId = appRepository.findById(req.getAppKey()) String normalizedAppId = appRepository.findById(req.getAppId())
.map(app -> app.getAppKey()) .map(app -> app.getAppKey())
.orElse(req.getAppKey()); .orElse(req.getAppId());
if (isAppWideService(req.getServiceType())) { if (isAppWideService(req.getServiceType())) {
List<FeatureServiceEntity> services = repository.findByAppKeyAndServiceType(normalizedAppId, req.getServiceType()); List<FeatureServiceEntity> services = repository.findByAppIdAndServiceType(normalizedAppId, req.getServiceType());
if (services.isEmpty()) { if (services.isEmpty()) {
for (FeatureServiceEntity.Platform platform : FeatureServiceEntity.Platform.values()) { for (FeatureServiceEntity.Platform platform : FeatureServiceEntity.Platform.values()) {
FeatureServiceEntity created = new FeatureServiceEntity(); FeatureServiceEntity created = new FeatureServiceEntity();
created.setId(UUID.randomUUID().toString()); created.setId(UUID.randomUUID().toString());
created.setAppKey(normalizedAppId); created.setAppId(normalizedAppId);
created.setPlatform(platform); created.setPlatform(platform);
created.setServiceType(req.getServiceType()); created.setServiceType(req.getServiceType());
created.setEnabled(true); created.setEnabled(true);
@ -151,11 +151,11 @@ public class FeatureServiceManager {
} }
FeatureServiceEntity entity = repository FeatureServiceEntity entity = repository
.findByAppKeyAndPlatformAndServiceType(normalizedAppId, req.getPlatform(), req.getServiceType()) .findByAppIdAndPlatformAndServiceType(normalizedAppId, req.getPlatform(), req.getServiceType())
.orElseGet(() -> { .orElseGet(() -> {
FeatureServiceEntity e = new FeatureServiceEntity(); FeatureServiceEntity e = new FeatureServiceEntity();
e.setId(UUID.randomUUID().toString()); e.setId(UUID.randomUUID().toString());
e.setAppKey(normalizedAppId); e.setAppId(normalizedAppId);
e.setPlatform(req.getPlatform()); e.setPlatform(req.getPlatform());
e.setServiceType(req.getServiceType()); e.setServiceType(req.getServiceType());
e.setCreatedAt(LocalDateTime.now()); e.setCreatedAt(LocalDateTime.now());
@ -183,18 +183,18 @@ public class FeatureServiceManager {
} }
public List<ServiceActivationRequestEntity> listRequestsByApp(String appKey) { public List<ServiceActivationRequestEntity> listRequestsByApp(String appKey) {
return requestRepository.findByAppKeyOrderByCreatedAtDesc(appKey); return requestRepository.findByAppIdOrderByCreatedAtDesc(appKey);
} }
public FeatureServiceEntity getOrFail(String appKey, FeatureServiceEntity.Platform platform, public FeatureServiceEntity getOrFail(String appKey, FeatureServiceEntity.Platform platform,
FeatureServiceEntity.ServiceType serviceType) { FeatureServiceEntity.ServiceType serviceType) {
if (serviceType == FeatureServiceEntity.ServiceType.IM) { if (serviceType == FeatureServiceEntity.ServiceType.IM) {
return repository.findByAppKeyAndServiceType(appKey, serviceType) return repository.findByAppIdAndServiceType(appKey, serviceType)
.stream() .stream()
.findFirst() .findFirst()
.orElseThrow(() -> new BusinessException(404, "服务未配置")); .orElseThrow(() -> new BusinessException(404, "服务未配置"));
} }
return repository.findByAppKeyAndPlatformAndServiceType(appKey, platform, serviceType) return repository.findByAppIdAndPlatformAndServiceType(appKey, platform, serviceType)
.orElseThrow(() -> new BusinessException(404, "服务未配置")); .orElseThrow(() -> new BusinessException(404, "服务未配置"));
} }
@ -204,7 +204,7 @@ public class FeatureServiceManager {
FeatureServiceEntity.ServiceType serviceType, FeatureServiceEntity.ServiceType serviceType,
String config) { String config) {
if (serviceType == FeatureServiceEntity.ServiceType.IM) { if (serviceType == FeatureServiceEntity.ServiceType.IM) {
List<FeatureServiceEntity> services = repository.findByAppKeyAndServiceType(appKey, serviceType); List<FeatureServiceEntity> services = repository.findByAppIdAndServiceType(appKey, serviceType);
if (services.isEmpty()) { if (services.isEmpty()) {
throw new BusinessException(404, "服务未配置"); throw new BusinessException(404, "服务未配置");
} }
@ -477,25 +477,127 @@ public class FeatureServiceManager {
public String buildPushConfig(String appKey, public String buildPushConfig(String appKey,
FeatureServiceEntity.Platform platform, FeatureServiceEntity.Platform platform,
JsonNode pushConfig) { String huaweiAppId,
ObjectNode root = objectMapper.createObjectNode(); String huaweiAppSecret,
root.put("schemaVersion", 2); String huaweiCategory,
root.put("updatedAt", java.time.LocalDateTime.now().toString()); String xiaomiAppId,
ObjectNode vendors = objectMapper.createObjectNode(); String xiaomiAppKey,
ArrayNode profiles = objectMapper.createArrayNode(); String xiaomiAppSecret,
if (pushConfig != null && pushConfig.isObject()) { String xiaomiChannelId,
JsonNode inputVendors = pushConfig.path("vendors"); String oppoAppId,
if (inputVendors != null && inputVendors.isObject()) { String oppoAppKey,
vendors.setAll((ObjectNode) inputVendors); String oppoMasterSecret,
String oppoChannelId,
String vivoAppId,
String vivoAppKey,
String vivoAppSecret,
String vivoCategory,
String vivoReceiptId,
String honorAppId,
String honorClientId,
String honorClientSecret,
String harmonyAppId,
String harmonyAppSecret,
String apnsTeamId,
String apnsKeyId,
String apnsBundleId,
String apnsKeyPath,
boolean apnsSandbox,
String fcmServiceAccountJson,
JsonNode channels,
JsonNode routing) {
ObjectNode node = readConfigNode(appKey, platform, FeatureServiceEntity.ServiceType.PUSH).deepCopy();
ensureObjectNode(node, "huawei");
ensureObjectNode(node, "xiaomi");
ensureObjectNode(node, "oppo");
ensureObjectNode(node, "vivo");
ensureObjectNode(node, "honor");
ensureObjectNode(node, "harmony");
ensureObjectNode(node, "apns");
ensureObjectNode(node, "fcm");
putText(node.with("huawei"), "appId", huaweiAppId);
putText(node.with("huawei"), "appSecret", huaweiAppSecret);
putText(node.with("huawei"), "category", huaweiCategory);
putText(node.with("xiaomi"), "appId", xiaomiAppId);
putText(node.with("xiaomi"), "appKey", xiaomiAppKey);
putText(node.with("xiaomi"), "appSecret", xiaomiAppSecret);
putText(node.with("xiaomi"), "channelId", xiaomiChannelId);
putText(node.with("oppo"), "appId", oppoAppId);
putText(node.with("oppo"), "appKey", oppoAppKey);
putText(node.with("oppo"), "masterSecret", oppoMasterSecret);
putText(node.with("oppo"), "channelId", oppoChannelId);
putText(node.with("vivo"), "appId", vivoAppId);
putText(node.with("vivo"), "appKey", vivoAppKey);
putText(node.with("vivo"), "appSecret", vivoAppSecret);
putText(node.with("vivo"), "category", vivoCategory);
putText(node.with("vivo"), "receiptId", vivoReceiptId);
putText(node.with("honor"), "appId", honorAppId);
putText(node.with("honor"), "clientId", honorClientId);
putText(node.with("honor"), "clientSecret", honorClientSecret);
putText(node.with("harmony"), "appId", harmonyAppId);
putText(node.with("harmony"), "appSecret", harmonyAppSecret);
putText(node.with("apns"), "teamId", apnsTeamId);
putText(node.with("apns"), "keyId", apnsKeyId);
putText(node.with("apns"), "bundleId", apnsBundleId);
putText(node.with("apns"), "keyPath", apnsKeyPath);
node.with("apns").put("sandbox", apnsSandbox);
putText(node.with("fcm"), "serviceAccountJson", fcmServiceAccountJson);
if (channels != null && channels.isArray()) {
node.set("channels", channels);
} else if (!node.has("channels")) {
node.set("channels", defaultPushChannels());
} }
JsonNode inputProfiles = pushConfig.path("profiles"); if (routing != null && routing.isObject()) {
if (inputProfiles != null && inputProfiles.isArray()) { node.set("routing", routing);
inputProfiles.forEach(profile -> profiles.add(profile.deepCopy())); } else if (!node.has("routing")) {
node.set("routing", defaultPushRouting());
} }
return node.toString();
} }
root.set("vendors", vendors);
root.set("profiles", profiles); private ArrayNode defaultPushChannels() {
return root.toString(); ArrayNode channels = objectMapper.createArrayNode();
channels.add(defaultPushChannel("im_message", "xuqm_im_message", "聊天消息", "单聊、群聊和好友消息", "HIGH"));
channels.add(defaultPushChannel("system_notice", "xuqm_system_notice", "系统通知", "系统通知和业务提醒", "DEFAULT"));
return channels;
}
private ObjectNode defaultPushChannel(String key, String channelId, String name, String description, String importance) {
ObjectNode channel = objectMapper.createObjectNode();
channel.put("key", key);
channel.put("channelId", channelId);
channel.put("version", 1);
channel.put("name", name);
channel.put("description", description);
channel.put("importance", importance);
channel.put("sound", true);
channel.put("vibration", true);
channel.put("badge", true);
return channel;
}
private ObjectNode defaultPushRouting() {
ObjectNode routing = objectMapper.createObjectNode();
routing.set("IM_MESSAGE", defaultPushRoute("im_message", "MESSAGE", "HIGH"));
routing.set("FRIEND_REQUEST", defaultPushRoute("im_message", "SOCIAL", "HIGH"));
routing.set("SYSTEM_NOTICE", defaultPushRoute("system_notice", "SYSTEM", "DEFAULT"));
return routing;
}
private ObjectNode defaultPushRoute(String channel, String category, String priority) {
ObjectNode route = objectMapper.createObjectNode();
route.put("channel", channel);
route.put("category", category);
route.put("priority", priority);
return route;
} }
@Transactional @Transactional
@ -547,12 +649,12 @@ public class FeatureServiceManager {
FeatureServiceEntity.ServiceType serviceType) { FeatureServiceEntity.ServiceType serviceType) {
FeatureServiceEntity entity; FeatureServiceEntity entity;
if (serviceType == FeatureServiceEntity.ServiceType.IM) { if (serviceType == FeatureServiceEntity.ServiceType.IM) {
entity = repository.findByAppKeyAndServiceType(appKey, serviceType) entity = repository.findByAppIdAndServiceType(appKey, serviceType)
.stream() .stream()
.findFirst() .findFirst()
.orElse(null); .orElse(null);
} else { } else {
entity = repository.findByAppKeyAndPlatformAndServiceType(appKey, platform, serviceType) entity = repository.findByAppIdAndPlatformAndServiceType(appKey, platform, serviceType)
.orElse(null); .orElse(null);
} }
if (entity == null || entity.getConfig() == null || entity.getConfig().isBlank()) { if (entity == null || entity.getConfig() == null || entity.getConfig().isBlank()) {

查看文件

@ -1,165 +0,0 @@
package com.xuqm.tenant.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xuqm.common.security.AppRequestSignatureUtil;
import com.xuqm.im.sdk.XuqmImServerSdk;
import com.xuqm.tenant.entity.AppEntity;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
@Service
public class ImPlatformEventService {
private final HttpClient httpClient = HttpClient.newHttpClient();
private final SdkAppProvisioningService provisioningService;
private final ObjectMapper objectMapper;
@Value("${sdk.im-api-url:https://im.dev.xuqinmin.com}")
private String imApiUrl;
@Value("${sdk.im-platform-events-user-prefix:platform-events:}")
private String platformEventsUserPrefix;
@Value("${sdk.im-platform-events-system-user:platform-events-system}")
private String platformEventsSystemUser;
public ImPlatformEventService(SdkAppProvisioningService provisioningService,
ObjectMapper objectMapper) {
this.provisioningService = provisioningService;
this.objectMapper = objectMapper;
}
public Map<String, String> issueToken(String appKey) throws Exception {
AppEntity app = provisioningService.resolveApp(appKey);
XuqmImServerSdk sdk = sdk(app);
String userId = platformEventsUserId(appKey);
ensureAccount(sdk, app, userId, "平台通知");
String token = requestImToken(app, userId);
Map<String, String> result = new LinkedHashMap<>();
result.put("appKey", app.getAppKey());
result.put("userId", userId);
result.put("token", token);
return result;
}
public Map<String, String> notifyStoreReviewChange(StoreReviewEventRequest request) throws Exception {
AppEntity app = provisioningService.resolveApp(request.appKey());
XuqmImServerSdk sdk = sdk(app);
String recipientUserId = platformEventsUserId(request.appKey());
String senderUserId = platformEventsSystemUserId();
ensureAccount(sdk, app, recipientUserId, "平台通知");
ensureAccount(sdk, app, senderUserId, "系统通知");
Map<String, Object> contentPayload = new LinkedHashMap<>();
contentPayload.put("event", request.event() == null || request.event().isBlank() ? "store_review_update" : request.event());
contentPayload.put("appKey", request.appKey());
contentPayload.put("versionId", request.versionId() == null ? "" : request.versionId());
contentPayload.put("storeType", request.storeType() == null ? "" : request.storeType());
contentPayload.put("reviewState", request.reviewState() == null ? "" : request.reviewState());
contentPayload.put("reviewReason", request.reviewReason() == null ? "" : request.reviewReason());
contentPayload.put("stage", request.stage() == null ? "" : request.stage());
contentPayload.put("batchId", request.batchId() == null ? "" : request.batchId());
contentPayload.put("publishStatus", request.publishStatus() == null ? "" : request.publishStatus());
contentPayload.put("source", request.source() == null ? "update-service" : request.source());
contentPayload.put("timestamp", System.currentTimeMillis());
String content = objectMapper.writeValueAsString(contentPayload);
var message = sdk.sendMessage(new XuqmImServerSdk.SendMessageRequest(
UUID.randomUUID().toString(),
recipientUserId,
"SINGLE",
"NOTIFY",
content,
null
));
Map<String, String> result = new LinkedHashMap<>();
result.put("appKey", app.getAppKey());
result.put("userId", recipientUserId);
result.put("messageId", message.id());
return result;
}
private void ensureAccount(XuqmImServerSdk sdk, AppEntity app, String userId, String suffix) {
sdk.importAccount(
userId,
app.getName() + " " + suffix,
app.getIconUrl(),
"UNKNOWN",
"ACTIVE"
);
}
private XuqmImServerSdk sdk(AppEntity app) {
return XuqmImServerSdk.builder()
.baseUrl(imApiUrl)
.appKey(app.getAppKey())
.appSecret(app.getAppSecret())
.build();
}
private String requestImToken(AppEntity app, String userId) throws Exception {
long timestamp = System.currentTimeMillis();
String nonce = UUID.randomUUID().toString();
String payload = AppRequestSignatureUtil.payload(app.getAppKey(), userId, timestamp, nonce);
String signature = AppRequestSignatureUtil.sign(app.getAppSecret(), payload);
URI uri = URI.create(imApiUrl + "/api/im/auth/login?appKey="
+ encodeQuery(app.getAppKey())
+ "&userId="
+ encodeQuery(userId));
HttpRequest request = HttpRequest.newBuilder(uri)
.header("Content-Type", "application/x-www-form-urlencoded")
.header("X-App-Timestamp", String.valueOf(timestamp))
.header("X-App-Nonce", nonce)
.header("X-App-Signature", signature)
.POST(HttpRequest.BodyPublishers.noBody())
.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() < 200 || response.statusCode() >= 300) {
throw new IllegalStateException("Failed to issue IM token: HTTP " + response.statusCode());
}
var root = objectMapper.readTree(response.body());
if (root.path("code").asInt() != 200) {
throw new IllegalStateException("Failed to issue IM token: " + root.path("message").asText("unknown error"));
}
String token = root.path("data").path("token").asText(null);
if (token == null || token.isBlank()) {
throw new IllegalStateException("Failed to issue IM token: empty token");
}
return token;
}
private String encodeQuery(String value) {
return java.net.URLEncoder.encode(value == null ? "" : value, java.nio.charset.StandardCharsets.UTF_8);
}
private String platformEventsUserId(String appKey) {
return platformEventsUserPrefix + appKey;
}
private String platformEventsSystemUserId() {
return platformEventsUserPrefix + platformEventsSystemUser;
}
public record StoreReviewEventRequest(
String appKey,
String versionId,
String storeType,
String reviewState,
String reviewReason,
String stage,
String batchId,
String publishStatus,
String event,
String source
) {}
}

查看文件

@ -80,7 +80,7 @@ public class OpsService {
List<AppEntity> apps = appRepository.findByTenantId(tenantId); List<AppEntity> apps = appRepository.findByTenantId(tenantId);
long subAccountCount = tenantRepository.countByParentId(tenantId); long subAccountCount = tenantRepository.countByParentId(tenantId);
long activeServiceCount = apps.stream() long activeServiceCount = apps.stream()
.flatMap(app -> featureServiceRepository.findByAppKey(app.getAppKey()).stream()) .flatMap(app -> featureServiceRepository.findByAppId(app.getAppKey()).stream())
.filter(FeatureServiceEntity::isEnabled) .filter(FeatureServiceEntity::isEnabled)
.count(); .count();
@ -207,7 +207,7 @@ public class OpsService {
public Map<String, Object> getAppDetail(String appKey) { public Map<String, Object> getAppDetail(String appKey) {
AppEntity app = appRepository.findByAppKey(appKey) AppEntity app = appRepository.findByAppKey(appKey)
.orElseThrow(() -> new IllegalArgumentException("应用不存在")); .orElseThrow(() -> new IllegalArgumentException("应用不存在"));
List<FeatureServiceEntity> services = featureServiceRepository.findByAppKey(app.getAppKey()); List<FeatureServiceEntity> services = featureServiceRepository.findByAppId(app.getAppKey());
long enabledCount = services.stream().filter(FeatureServiceEntity::isEnabled).count(); long enabledCount = services.stream().filter(FeatureServiceEntity::isEnabled).count();
Map<String, Object> result = new LinkedHashMap<>(); Map<String, Object> result = new LinkedHashMap<>();
result.put("app", app); result.put("app", app);
@ -221,7 +221,7 @@ public class OpsService {
public List<FeatureServiceEntity> listAppServices(String appKey) { public List<FeatureServiceEntity> listAppServices(String appKey) {
appRepository.findByAppKey(appKey) appRepository.findByAppKey(appKey)
.orElseThrow(() -> new IllegalArgumentException("应用不存在")); .orElseThrow(() -> new IllegalArgumentException("应用不存在"));
return featureServiceRepository.findByAppKey(appKey); return featureServiceRepository.findByAppId(appKey);
} }
public Page<OperationLogEntity> listOperationLogs(int page, int size) { public Page<OperationLogEntity> listOperationLogs(int page, int size) {

查看文件

@ -117,13 +117,13 @@ public class SdkAppProvisioningService {
} }
private void ensureFeatureDefaults(AppEntity app) { private void ensureFeatureDefaults(AppEntity app) {
featureServiceRepository.findByAppKeyAndServiceType(app.getAppKey(), FeatureServiceEntity.ServiceType.IM) featureServiceRepository.findByAppIdAndServiceType(app.getAppKey(), FeatureServiceEntity.ServiceType.IM)
.stream() .stream()
.findFirst() .findFirst()
.orElseGet(() -> { .orElseGet(() -> {
FeatureServiceEntity feature = new FeatureServiceEntity(); FeatureServiceEntity feature = new FeatureServiceEntity();
feature.setId(UUID.randomUUID().toString()); feature.setId(UUID.randomUUID().toString());
feature.setAppKey(app.getAppKey()); feature.setAppId(app.getAppKey());
feature.setPlatform(FeatureServiceEntity.Platform.ANDROID); feature.setPlatform(FeatureServiceEntity.Platform.ANDROID);
feature.setServiceType(FeatureServiceEntity.ServiceType.IM); feature.setServiceType(FeatureServiceEntity.ServiceType.IM);
feature.setEnabled(true); feature.setEnabled(true);
@ -141,11 +141,11 @@ public class SdkAppProvisioningService {
for (FeatureServiceEntity.ServiceType serviceType : List.of( for (FeatureServiceEntity.ServiceType serviceType : List.of(
FeatureServiceEntity.ServiceType.PUSH, FeatureServiceEntity.ServiceType.PUSH,
FeatureServiceEntity.ServiceType.UPDATE)) { FeatureServiceEntity.ServiceType.UPDATE)) {
featureServiceRepository.findByAppKeyAndPlatformAndServiceType(app.getAppKey(), platform, serviceType) featureServiceRepository.findByAppIdAndPlatformAndServiceType(app.getAppKey(), platform, serviceType)
.orElseGet(() -> { .orElseGet(() -> {
FeatureServiceEntity feature = new FeatureServiceEntity(); FeatureServiceEntity feature = new FeatureServiceEntity();
feature.setId(UUID.randomUUID().toString()); feature.setId(UUID.randomUUID().toString());
feature.setAppKey(app.getAppKey()); feature.setAppId(app.getAppKey());
feature.setPlatform(platform); feature.setPlatform(platform);
feature.setServiceType(serviceType); feature.setServiceType(serviceType);
feature.setEnabled(true); feature.setEnabled(true);

查看文件

@ -88,4 +88,3 @@ sdk:
im-ws-url: ${SDK_IM_WS_URL:wss://im.dev.xuqinmin.com/ws/im} im-ws-url: ${SDK_IM_WS_URL:wss://im.dev.xuqinmin.com/ws/im}
file-service-url: ${SDK_FILE_SERVICE_URL:https://file.dev.xuqinmin.com} file-service-url: ${SDK_FILE_SERVICE_URL:https://file.dev.xuqinmin.com}
im-api-url: ${SDK_IM_API_URL:https://im.dev.xuqinmin.com} im-api-url: ${SDK_IM_API_URL:https://im.dev.xuqinmin.com}
im-platform-events-user-prefix: ${SDK_IM_PLATFORM_EVENTS_USER_PREFIX:platform-events:}

查看文件

@ -58,10 +58,10 @@ public class AppVersionController {
} }
Optional<AppVersionEntity> latest = versionRepository Optional<AppVersionEntity> latest = versionRepository
.findTopByAppKeyAndPlatformAndPublishStatusAndVersionCodeGreaterThanOrderByVersionCodeDesc( .findTopByAppIdAndPlatformAndPublishStatusAndVersionCodeGreaterThanOrderByVersionCodeDesc(
appKey, platform, AppVersionEntity.PublishStatus.PUBLISHED, currentVersionCode); appKey, platform, AppVersionEntity.PublishStatus.PUBLISHED, currentVersionCode);
Optional<AppVersionEntity> forcedHigher = versionRepository Optional<AppVersionEntity> forcedHigher = versionRepository
.findTopByAppKeyAndPlatformAndPublishStatusAndVersionCodeGreaterThanAndForceUpdateTrueOrderByVersionCodeDesc( .findTopByAppIdAndPlatformAndPublishStatusAndVersionCodeGreaterThanAndForceUpdateTrueOrderByVersionCodeDesc(
appKey, platform, AppVersionEntity.PublishStatus.PUBLISHED, currentVersionCode); appKey, platform, AppVersionEntity.PublishStatus.PUBLISHED, currentVersionCode);
if (latest.isEmpty()) { if (latest.isEmpty()) {
@ -146,7 +146,7 @@ public class AppVersionController {
} }
AppVersionEntity entity = new AppVersionEntity(); AppVersionEntity entity = new AppVersionEntity();
entity.setId(UUID.randomUUID().toString()); entity.setId(UUID.randomUUID().toString());
entity.setAppKey(appKey); entity.setAppId(appKey);
entity.setPlatform(platform); entity.setPlatform(platform);
entity.setVersionName(resolvedVersionName); entity.setVersionName(resolvedVersionName);
entity.setVersionCode(resolvedVersionCode); entity.setVersionCode(resolvedVersionCode);
@ -189,7 +189,7 @@ public class AppVersionController {
} }
AppVersionEntity saved = versionRepository.save(entity); AppVersionEntity saved = versionRepository.save(entity);
operationLogService.record( operationLogService.record(
saved.getAppKey(), saved.getAppId(),
"APP_VERSION", "APP_VERSION",
saved.getId(), saved.getId(),
"UPLOAD", "UPLOAD",
@ -246,7 +246,7 @@ public class AppVersionController {
entity.setGrayMemberIds(null); entity.setGrayMemberIds(null);
AppVersionEntity saved = versionRepository.save(entity); AppVersionEntity saved = versionRepository.save(entity);
operationLogService.record( operationLogService.record(
saved.getAppKey(), saved.getAppId(),
"APP_VERSION", "APP_VERSION",
saved.getId(), saved.getId(),
publishAction(previousStatus, saved.getPublishStatus(), publishImmediately), publishAction(previousStatus, saved.getPublishStatus(), publishImmediately),
@ -273,7 +273,7 @@ public class AppVersionController {
entity.setPublishStatus(AppVersionEntity.PublishStatus.DEPRECATED); entity.setPublishStatus(AppVersionEntity.PublishStatus.DEPRECATED);
AppVersionEntity saved = versionRepository.save(entity); AppVersionEntity saved = versionRepository.save(entity);
operationLogService.record( operationLogService.record(
saved.getAppKey(), saved.getAppId(),
"APP_VERSION", "APP_VERSION",
saved.getId(), saved.getId(),
"UNPUBLISH", "UNPUBLISH",
@ -290,7 +290,7 @@ public class AppVersionController {
@PathVariable String id, @PathVariable String id,
@RequestBody Map<String, Object> body) throws Exception { @RequestBody Map<String, Object> body) throws Exception {
AppVersionEntity entity = versionRepository.findById(id).orElseThrow(); AppVersionEntity entity = versionRepository.findById(id).orElseThrow();
if (publishConfigService.allowAnonymousUpdateCheck(entity.getAppKey())) { if (publishConfigService.allowAnonymousUpdateCheck(entity.getAppId())) {
throw new com.xuqm.common.exception.BusinessException(400, "允许免登录检查更新的应用不支持灰度发布"); throw new com.xuqm.common.exception.BusinessException(400, "允许免登录检查更新的应用不支持灰度发布");
} }
boolean enabled = Boolean.TRUE.equals(body.get("enabled")); boolean enabled = Boolean.TRUE.equals(body.get("enabled"));
@ -305,7 +305,7 @@ public class AppVersionController {
String selectionSource = body.get("selectionSource") == null ? "LOCAL" String selectionSource = body.get("selectionSource") == null ? "LOCAL"
: body.get("selectionSource").toString().trim().toUpperCase(); : body.get("selectionSource").toString().trim().toUpperCase();
if (memberIds.isEmpty() && "CALLBACK".equals(selectionSource)) { if (memberIds.isEmpty() && "CALLBACK".equals(selectionSource)) {
memberIds = publishConfigService.resolveGrayMembers(entity.getAppKey(), body); memberIds = publishConfigService.resolveGrayMembers(entity.getAppId(), body);
} }
entity.setGrayMode("MEMBERS"); entity.setGrayMode("MEMBERS");
entity.setGrayMemberIds(toJson(memberIds)); entity.setGrayMemberIds(toJson(memberIds));
@ -318,7 +318,7 @@ public class AppVersionController {
entity.setPublishStatus(AppVersionEntity.PublishStatus.PUBLISHED); entity.setPublishStatus(AppVersionEntity.PublishStatus.PUBLISHED);
AppVersionEntity saved = versionRepository.save(entity); AppVersionEntity saved = versionRepository.save(entity);
operationLogService.record( operationLogService.record(
saved.getAppKey(), saved.getAppId(),
"APP_VERSION", "APP_VERSION",
saved.getId(), saved.getId(),
"GRAY_UPDATE", "GRAY_UPDATE",
@ -336,7 +336,7 @@ public class AppVersionController {
public ResponseEntity<ApiResponse<List<AppVersionEntity>>> list( public ResponseEntity<ApiResponse<List<AppVersionEntity>>> list(
@RequestParam String appKey, @RequestParam AppVersionEntity.Platform platform) { @RequestParam String appKey, @RequestParam AppVersionEntity.Platform platform) {
return ResponseEntity.ok(ApiResponse.success( return ResponseEntity.ok(ApiResponse.success(
versionRepository.findByAppKeyAndPlatformOrderByVersionCodeDesc(appKey, platform))); versionRepository.findByAppIdAndPlatformOrderByVersionCodeDesc(appKey, platform)));
} }
private String publishAction(AppVersionEntity.PublishStatus previousStatus, private String publishAction(AppVersionEntity.PublishStatus previousStatus,

查看文件

@ -56,7 +56,7 @@ public class RnBundleController {
RnBundleEntity.Platform p = RnBundleEntity.Platform.valueOf(platform.toUpperCase()); RnBundleEntity.Platform p = RnBundleEntity.Platform.valueOf(platform.toUpperCase());
Optional<RnBundleEntity> latest = bundleRepository Optional<RnBundleEntity> latest = bundleRepository
.findTopByAppKeyAndModuleIdAndPlatformAndPublishStatusOrderByCreatedAtDesc( .findTopByAppIdAndModuleIdAndPlatformAndPublishStatusOrderByCreatedAtDesc(
appKey, moduleId, p, RnBundleEntity.PublishStatus.PUBLISHED); appKey, moduleId, p, RnBundleEntity.PublishStatus.PUBLISHED);
if (latest.isEmpty()) { if (latest.isEmpty()) {
@ -115,7 +115,7 @@ public class RnBundleController {
RnBundleEntity entity = new RnBundleEntity(); RnBundleEntity entity = new RnBundleEntity();
entity.setId(UUID.randomUUID().toString()); entity.setId(UUID.randomUUID().toString());
entity.setAppKey(appKey); entity.setAppId(appKey);
entity.setModuleId(resolvedModuleId); entity.setModuleId(resolvedModuleId);
entity.setPlatform(resolvedPlatform); entity.setPlatform(resolvedPlatform);
entity.setVersion(resolvedVersion); entity.setVersion(resolvedVersion);
@ -132,7 +132,7 @@ public class RnBundleController {
entity.setCreatedAt(LocalDateTime.now()); entity.setCreatedAt(LocalDateTime.now());
RnBundleEntity saved = bundleRepository.save(entity); RnBundleEntity saved = bundleRepository.save(entity);
operationLogService.record( operationLogService.record(
saved.getAppKey(), saved.getAppId(),
"RN_BUNDLE", "RN_BUNDLE",
saved.getId(), saved.getId(),
"UPLOAD", "UPLOAD",
@ -160,11 +160,11 @@ public class RnBundleController {
List<RnBundleEntity> result; List<RnBundleEntity> result;
if (moduleId != null && platform != null) { if (moduleId != null && platform != null) {
RnBundleEntity.Platform p = RnBundleEntity.Platform.valueOf(platform.toUpperCase()); RnBundleEntity.Platform p = RnBundleEntity.Platform.valueOf(platform.toUpperCase());
result = bundleRepository.findByAppKeyAndModuleIdAndPlatformOrderByCreatedAtDesc(appKey, moduleId, p); result = bundleRepository.findByAppIdAndModuleIdAndPlatformOrderByCreatedAtDesc(appKey, moduleId, p);
} else if (moduleId != null) { } else if (moduleId != null) {
result = bundleRepository.findByAppKeyAndModuleIdOrderByCreatedAtDesc(appKey, moduleId); result = bundleRepository.findByAppIdAndModuleIdOrderByCreatedAtDesc(appKey, moduleId);
} else { } else {
result = bundleRepository.findByAppKeyOrderByCreatedAtDesc(appKey); result = bundleRepository.findByAppIdOrderByCreatedAtDesc(appKey);
} }
return ResponseEntity.ok(ApiResponse.success(result)); return ResponseEntity.ok(ApiResponse.success(result));
} }
@ -194,7 +194,7 @@ public class RnBundleController {
entity.setGrayMemberIds(null); entity.setGrayMemberIds(null);
RnBundleEntity saved = bundleRepository.save(entity); RnBundleEntity saved = bundleRepository.save(entity);
operationLogService.record( operationLogService.record(
saved.getAppKey(), saved.getAppId(),
"RN_BUNDLE", "RN_BUNDLE",
saved.getId(), saved.getId(),
publishImmediately && (scheduledPublishAt == null || scheduledPublishAt.isBlank()) ? "PUBLISH" : "SCHEDULE_PUBLISH", publishImmediately && (scheduledPublishAt == null || scheduledPublishAt.isBlank()) ? "PUBLISH" : "SCHEDULE_PUBLISH",
@ -220,7 +220,7 @@ public class RnBundleController {
entity.setPublishStatus(RnBundleEntity.PublishStatus.DEPRECATED); entity.setPublishStatus(RnBundleEntity.PublishStatus.DEPRECATED);
RnBundleEntity saved = bundleRepository.save(entity); RnBundleEntity saved = bundleRepository.save(entity);
operationLogService.record( operationLogService.record(
saved.getAppKey(), saved.getAppId(),
"RN_BUNDLE", "RN_BUNDLE",
saved.getId(), saved.getId(),
"UNPUBLISH", "UNPUBLISH",
@ -237,7 +237,7 @@ public class RnBundleController {
@PathVariable String id, @PathVariable String id,
@RequestBody Map<String, Object> body) throws Exception { @RequestBody Map<String, Object> body) throws Exception {
RnBundleEntity entity = bundleRepository.findById(id).orElseThrow(); RnBundleEntity entity = bundleRepository.findById(id).orElseThrow();
if (publishConfigService.allowAnonymousUpdateCheck(entity.getAppKey())) { if (publishConfigService.allowAnonymousUpdateCheck(entity.getAppId())) {
throw new com.xuqm.common.exception.BusinessException(400, "允许免登录检查更新的应用不支持灰度发布"); throw new com.xuqm.common.exception.BusinessException(400, "允许免登录检查更新的应用不支持灰度发布");
} }
boolean enabled = Boolean.TRUE.equals(body.get("enabled")); boolean enabled = Boolean.TRUE.equals(body.get("enabled"));
@ -252,7 +252,7 @@ public class RnBundleController {
String selectionSource = body.get("selectionSource") == null ? "LOCAL" String selectionSource = body.get("selectionSource") == null ? "LOCAL"
: body.get("selectionSource").toString().trim().toUpperCase(); : body.get("selectionSource").toString().trim().toUpperCase();
if (memberIds.isEmpty() && "CALLBACK".equals(selectionSource)) { if (memberIds.isEmpty() && "CALLBACK".equals(selectionSource)) {
memberIds = publishConfigService.resolveGrayMembers(entity.getAppKey(), body); memberIds = publishConfigService.resolveGrayMembers(entity.getAppId(), body);
} }
entity.setGrayMode("MEMBERS"); entity.setGrayMode("MEMBERS");
entity.setGrayMemberIds(toJson(memberIds)); entity.setGrayMemberIds(toJson(memberIds));
@ -265,7 +265,7 @@ public class RnBundleController {
entity.setPublishStatus(RnBundleEntity.PublishStatus.PUBLISHED); entity.setPublishStatus(RnBundleEntity.PublishStatus.PUBLISHED);
RnBundleEntity saved = bundleRepository.save(entity); RnBundleEntity saved = bundleRepository.save(entity);
operationLogService.record( operationLogService.record(
saved.getAppKey(), saved.getAppId(),
"RN_BUNDLE", "RN_BUNDLE",
saved.getId(), saved.getId(),
"GRAY_UPDATE", "GRAY_UPDATE",

查看文件

@ -69,7 +69,7 @@ public class UnifiedReleaseController {
} }
AppVersionEntity entity = new AppVersionEntity(); AppVersionEntity entity = new AppVersionEntity();
entity.setId(UUID.randomUUID().toString()); entity.setId(UUID.randomUUID().toString());
entity.setAppKey(appKey); entity.setAppId(appKey);
entity.setPlatform(item.platform()); entity.setPlatform(item.platform());
entity.setVersionName(item.versionName()); entity.setVersionName(item.versionName());
entity.setVersionCode(item.versionCode()); entity.setVersionCode(item.versionCode());
@ -90,7 +90,7 @@ public class UnifiedReleaseController {
} }
AppVersionEntity saved = appVersionRepository.save(entity); AppVersionEntity saved = appVersionRepository.save(entity);
operationLogService.record( operationLogService.record(
saved.getAppKey(), saved.getAppId(),
"APP_VERSION", "APP_VERSION",
saved.getId(), saved.getId(),
"UPLOAD", "UPLOAD",
@ -117,7 +117,7 @@ public class UnifiedReleaseController {
RnBundleEntity entity = new RnBundleEntity(); RnBundleEntity entity = new RnBundleEntity();
entity.setId(UUID.randomUUID().toString()); entity.setId(UUID.randomUUID().toString());
entity.setAppKey(appKey); entity.setAppId(appKey);
entity.setModuleId(item.moduleId()); entity.setModuleId(item.moduleId());
entity.setPlatform(item.platform()); entity.setPlatform(item.platform());
entity.setVersion(item.version()); entity.setVersion(item.version());
@ -130,7 +130,7 @@ public class UnifiedReleaseController {
entity.setCreatedAt(LocalDateTime.now()); entity.setCreatedAt(LocalDateTime.now());
RnBundleEntity saved = rnBundleRepository.save(entity); RnBundleEntity saved = rnBundleRepository.save(entity);
operationLogService.record( operationLogService.record(
saved.getAppKey(), saved.getAppId(),
"RN_BUNDLE", "RN_BUNDLE",
saved.getId(), saved.getId(),
"UPLOAD", "UPLOAD",

查看文件

@ -9,7 +9,7 @@ import java.time.LocalDateTime;
@Entity @Entity
@Table(name = "update_gray_member", uniqueConstraints = { @Table(name = "update_gray_member", uniqueConstraints = {
@jakarta.persistence.UniqueConstraint(columnNames = {"appKey", "groupName", "userId"}) @jakarta.persistence.UniqueConstraint(columnNames = {"appId", "groupName", "userId"})
}) })
public class AppGrayMemberEntity { public class AppGrayMemberEntity {
@ -17,7 +17,7 @@ public class AppGrayMemberEntity {
private String id; private String id;
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String appKey; private String appId;
@Column(length = 64) @Column(length = 64)
private String groupName; private String groupName;
@ -37,8 +37,8 @@ public class AppGrayMemberEntity {
public String getId() { return id; } public String getId() { return id; }
public void setId(String id) { this.id = id; } public void setId(String id) { this.id = id; }
public String getAppKey() { return appKey; } public String getAppId() { return appId; }
public void setAppKey(String appKey) { this.appKey = appKey; } public void setAppId(String appId) { this.appId = appId; }
public String getGroupName() { return groupName; } public String getGroupName() { return groupName; }
public void setGroupName(String groupName) { this.groupName = groupName; } public void setGroupName(String groupName) { this.groupName = groupName; }

查看文件

@ -9,7 +9,7 @@ import java.time.LocalDateTime;
@Entity @Entity
@Table(name = "update_publish_config", uniqueConstraints = { @Table(name = "update_publish_config", uniqueConstraints = {
@jakarta.persistence.UniqueConstraint(columnNames = {"appKey"}) @jakarta.persistence.UniqueConstraint(columnNames = {"appId"})
}) })
public class AppPublishConfigEntity { public class AppPublishConfigEntity {
@ -17,7 +17,7 @@ public class AppPublishConfigEntity {
private String id; private String id;
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String appKey; private String appId;
@Column(columnDefinition = "TEXT") @Column(columnDefinition = "TEXT")
private String configJson; private String configJson;
@ -28,8 +28,8 @@ public class AppPublishConfigEntity {
public String getId() { return id; } public String getId() { return id; }
public void setId(String id) { this.id = id; } public void setId(String id) { this.id = id; }
public String getAppKey() { return appKey; } public String getAppId() { return appId; }
public void setAppKey(String appKey) { this.appKey = appKey; } public void setAppId(String appId) { this.appId = appId; }
public String getConfigJson() { return configJson; } public String getConfigJson() { return configJson; }
public void setConfigJson(String configJson) { this.configJson = configJson; } public void setConfigJson(String configJson) { this.configJson = configJson; }

查看文件

@ -5,7 +5,7 @@ import java.time.LocalDateTime;
@Entity @Entity
@Table(name = "update_store_config", uniqueConstraints = { @Table(name = "update_store_config", uniqueConstraints = {
@UniqueConstraint(columnNames = {"appKey", "storeType"}) @UniqueConstraint(columnNames = {"appId", "storeType"})
}) })
public class AppStoreConfigEntity { public class AppStoreConfigEntity {
@ -27,7 +27,7 @@ public class AppStoreConfigEntity {
private String id; private String id;
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String appKey; private String appId;
@Enumerated(EnumType.STRING) @Enumerated(EnumType.STRING)
@Column(nullable = false, length = 16) @Column(nullable = false, length = 16)
@ -58,8 +58,8 @@ public class AppStoreConfigEntity {
public String getId() { return id; } public String getId() { return id; }
public void setId(String id) { this.id = id; } public void setId(String id) { this.id = id; }
public String getAppKey() { return appKey; } public String getAppId() { return appId; }
public void setAppKey(String appKey) { this.appKey = appKey; } public void setAppId(String appId) { this.appId = appId; }
public StoreType getStoreType() { return storeType; } public StoreType getStoreType() { return storeType; }
public void setStoreType(StoreType storeType) { this.storeType = storeType; } public void setStoreType(StoreType storeType) { this.storeType = storeType; }

查看文件

@ -15,13 +15,13 @@ public class AppVersionEntity {
public enum Platform { ANDROID, IOS, HARMONY } public enum Platform { ANDROID, IOS, HARMONY }
public enum PublishStatus { DRAFT, PUBLISHED, DEPRECATED } public enum PublishStatus { DRAFT, PUBLISHED, DEPRECATED }
/** Per-store review state used in storeReviewStatus JSON values. */ /** Per-store review state used in storeReviewStatus JSON values. */
public enum StoreReviewState { PENDING, SUBMITTING, UNDER_REVIEW, APPROVED, REJECTED } public enum StoreReviewState { PENDING, UNDER_REVIEW, APPROVED, REJECTED }
@Id @Id
private String id; private String id;
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String appKey; private String appId;
@Enumerated(EnumType.STRING) @Enumerated(EnumType.STRING)
@Column(nullable = false, length = 16) @Column(nullable = false, length = 16)
@ -107,8 +107,8 @@ public class AppVersionEntity {
public String getId() { return id; } public String getId() { return id; }
public void setId(String id) { this.id = id; } public void setId(String id) { this.id = id; }
public String getAppKey() { return appKey; } public String getAppId() { return appId; }
public void setAppKey(String appKey) { this.appKey = appKey; } public void setAppId(String appId) { this.appId = appId; }
public Platform getPlatform() { return platform; } public Platform getPlatform() { return platform; }
public void setPlatform(Platform platform) { this.platform = platform; } public void setPlatform(Platform platform) { this.platform = platform; }

查看文件

@ -19,7 +19,7 @@ public class RnBundleEntity {
private String id; private String id;
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String appKey; private String appId;
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String moduleId; private String moduleId;
@ -73,8 +73,8 @@ public class RnBundleEntity {
public String getId() { return id; } public String getId() { return id; }
public void setId(String id) { this.id = id; } public void setId(String id) { this.id = id; }
public String getAppKey() { return appKey; } public String getAppId() { return appId; }
public void setAppKey(String appKey) { this.appKey = appKey; } public void setAppId(String appId) { this.appId = appId; }
public String getModuleId() { return moduleId; } public String getModuleId() { return moduleId; }
public void setModuleId(String moduleId) { this.moduleId = moduleId; } public void setModuleId(String moduleId) { this.moduleId = moduleId; }

查看文件

@ -15,7 +15,7 @@ public class UpdateOperationLogEntity {
private String id; private String id;
@Column(nullable = false, length = 64) @Column(nullable = false, length = 64)
private String appKey; private String appId;
@Column(nullable = false, length = 32) @Column(nullable = false, length = 32)
private String resourceType; private String resourceType;
@ -41,8 +41,8 @@ public class UpdateOperationLogEntity {
public String getId() { return id; } public String getId() { return id; }
public void setId(String id) { this.id = id; } public void setId(String id) { this.id = id; }
public String getAppKey() { return appKey; } public String getAppId() { return appId; }
public void setAppKey(String appKey) { this.appKey = appKey; } public void setAppId(String appId) { this.appId = appId; }
public String getResourceType() { return resourceType; } public String getResourceType() { return resourceType; }
public void setResourceType(String resourceType) { this.resourceType = resourceType; } public void setResourceType(String resourceType) { this.resourceType = resourceType; }

查看文件

@ -6,5 +6,5 @@ import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List; import java.util.List;
public interface AppGrayMemberRepository extends JpaRepository<AppGrayMemberEntity, String> { public interface AppGrayMemberRepository extends JpaRepository<AppGrayMemberEntity, String> {
List<AppGrayMemberEntity> findByAppKeyOrderByGroupNameAscNameAscUserIdAsc(String appKey); List<AppGrayMemberEntity> findByAppIdOrderByGroupNameAscNameAscUserIdAsc(String appId);
} }

查看文件

@ -6,5 +6,5 @@ import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional; import java.util.Optional;
public interface AppPublishConfigRepository extends JpaRepository<AppPublishConfigEntity, String> { public interface AppPublishConfigRepository extends JpaRepository<AppPublishConfigEntity, String> {
Optional<AppPublishConfigEntity> findByAppKey(String appKey); Optional<AppPublishConfigEntity> findByAppId(String appId);
} }

查看文件

@ -8,9 +8,9 @@ import java.util.Optional;
public interface AppStoreConfigRepository extends JpaRepository<AppStoreConfigEntity, String> { public interface AppStoreConfigRepository extends JpaRepository<AppStoreConfigEntity, String> {
List<AppStoreConfigEntity> findByAppKey(String appKey); List<AppStoreConfigEntity> findByAppId(String appId);
List<AppStoreConfigEntity> findByAppKeyAndEnabled(String appKey, boolean enabled); List<AppStoreConfigEntity> findByAppIdAndEnabled(String appId, boolean enabled);
Optional<AppStoreConfigEntity> findByAppKeyAndStoreType(String appKey, AppStoreConfigEntity.StoreType storeType); Optional<AppStoreConfigEntity> findByAppIdAndStoreType(String appId, AppStoreConfigEntity.StoreType storeType);
} }

某些文件未显示,因为此 diff 中更改的文件太多 显示更多