refactor: 优化会议访问密码更新逻辑和屏保实体字段策略
- 在 `LegacyMeetingController` 和 `AndroidMeetingController` 中使用 `LambdaUpdateWrapper` 更新会议访问密码 - 更新 `ScreenSaver` 实体的 `ownerUserId` 字段策略为 `ALWAYS` - 添加相关测试用例以验证屏保实体字段策略和更新逻辑 - 优化 `AiModels.tsx` 中的提供商基础 URL 和表单占位符dev_na
parent
f6ffaddae1
commit
a295a3b15b
|
|
@ -1,6 +1,7 @@
|
|||
package com.imeeting.controller.android;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.imeeting.common.RedisKeys;
|
||||
|
|
@ -185,8 +186,9 @@ public class AndroidMeetingController {
|
|||
return ApiResponse.error("仅会议创建人可设置访问密码");
|
||||
}
|
||||
String password = normalizePassword(command == null ? null : command.getPassword());
|
||||
meeting.setAccessPassword(password);
|
||||
meetingService.updateById(meeting);
|
||||
meetingService.update(new LambdaUpdateWrapper<Meeting>()
|
||||
.eq(Meeting::getId,meeting.getId())
|
||||
.set(Meeting::getAccessPassword, password));
|
||||
return ApiResponse.ok(password);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.imeeting.controller.android.legacy;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.imeeting.common.RedisKeys;
|
||||
|
|
@ -205,8 +206,9 @@ public class LegacyMeetingController {
|
|||
return LegacyApiResponse.error("403", "仅会议创建人可设置访问密码");
|
||||
}
|
||||
String password = normalizePassword(request == null ? null : request.getPassword());
|
||||
meeting.setAccessPassword(password);
|
||||
meetingService.updateById(meeting);
|
||||
meetingService.update(new LambdaUpdateWrapper<Meeting>()
|
||||
.eq(Meeting::getId,meeting.getId())
|
||||
.set(Meeting::getAccessPassword, password));
|
||||
return LegacyApiResponse.ok(new LegacyMeetingAccessPasswordResponse(password));
|
||||
}
|
||||
|
||||
|
|
@ -235,16 +237,16 @@ public class LegacyMeetingController {
|
|||
: null;
|
||||
boolean hasSummary = detail != null && detail.getSummaryContent() != null && !detail.getSummaryContent().isBlank();
|
||||
|
||||
if (hasSummary) {
|
||||
if (summaryCompleted) {
|
||||
return new LegacyMeetingPreviewResult("200", "success", buildCompletedPreview(meeting, detail, summaryTask));
|
||||
}
|
||||
if (summaryCompleted) {
|
||||
return new LegacyMeetingPreviewResult(
|
||||
"504",
|
||||
"处理已完成,但摘要尚未同步,请稍后重试",
|
||||
buildProcessingPreview(meeting, summaryTask, processingStatus("摘要已生成,可扫码查看", 100, STAGE_COMPLETED))
|
||||
);
|
||||
}
|
||||
// if (summaryCompleted) {
|
||||
// return new LegacyMeetingPreviewResult(
|
||||
// "504",
|
||||
// "处理已完成,但摘要尚未同步,请稍后重试",
|
||||
// buildProcessingPreview(meeting, summaryTask, processingStatus("摘要已生成,可扫码查看", 100, STAGE_COMPLETED))
|
||||
// );
|
||||
// }
|
||||
if (isFailed(asrTask) || Integer.valueOf(4).equals(meeting.getStatus())) {
|
||||
return new LegacyMeetingPreviewResult(
|
||||
"503",
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ public class Meeting extends BaseEntity {
|
|||
private String audioSaveMessage;
|
||||
|
||||
@Schema(description = "访问密码")
|
||||
|
||||
private String accessPassword;
|
||||
|
||||
@Schema(description = "创建人ID")
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package com.imeeting.entity.biz;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldStrategy;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.unisbase.entity.BaseEntity;
|
||||
|
|
@ -21,6 +23,7 @@ public class ScreenSaver extends BaseEntity {
|
|||
private String scopeType;
|
||||
|
||||
@Schema(description = "所属用户ID")
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||
private Long ownerUserId;
|
||||
|
||||
@Schema(description = "屏保名称")
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
package com.imeeting.service.biz.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldStrategy;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.imeeting.dto.biz.ScreenSaverAdminVO;
|
||||
import com.imeeting.dto.biz.ScreenSaverDTO;
|
||||
import com.imeeting.dto.biz.ScreenSaverSelectionResult;
|
||||
import com.imeeting.dto.biz.ScreenSaverUserSettingsDTO;
|
||||
import com.imeeting.dto.biz.ScreenSaverUserSettingsVO;
|
||||
|
|
@ -18,6 +21,8 @@ import org.mockito.ArgumentCaptor;
|
|||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
|
|
@ -141,6 +146,38 @@ class ScreenSaverServiceImplTest {
|
|||
verify(userConfigMapper, never()).insert(any(ScreenSaverUserConfig.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateShouldClearOwnerWhenPromotingUserScopeToPlatformScope() {
|
||||
ScreenSaverUserConfigMapper userConfigMapper = mock(ScreenSaverUserConfigMapper.class);
|
||||
ScreenSaverUserSettingsMapper userSettingsMapper = mock(ScreenSaverUserSettingsMapper.class);
|
||||
SysUserMapper sysUserMapper = mock(SysUserMapper.class);
|
||||
|
||||
ScreenSaverServiceImpl service = spy(new ScreenSaverServiceImpl(userConfigMapper, userSettingsMapper, sysUserMapper));
|
||||
ScreenSaver existing = screenSaver(101L, "USER", 88L, 1, 1);
|
||||
doReturn(existing).when(service).getById(101L);
|
||||
doReturn(true).when(service).updateById(any(ScreenSaver.class));
|
||||
|
||||
ScreenSaverDTO dto = new ScreenSaverDTO();
|
||||
dto.setScopeType("PLATFORM");
|
||||
|
||||
ScreenSaver result = service.update(101L, dto, loginUser(88L, 9L, true));
|
||||
|
||||
ArgumentCaptor<ScreenSaver> captor = ArgumentCaptor.forClass(ScreenSaver.class);
|
||||
verify(service).updateById(captor.capture());
|
||||
assertEquals("PLATFORM", captor.getValue().getScopeType());
|
||||
assertNull(captor.getValue().getOwnerUserId());
|
||||
assertEquals("PLATFORM", result.getScopeType());
|
||||
assertNull(result.getOwnerUserId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void ownerUserIdShouldAlwaysParticipateInUpdateStatements() throws NoSuchFieldException {
|
||||
TableField tableField = ScreenSaver.class.getDeclaredField("ownerUserId").getAnnotation(TableField.class);
|
||||
|
||||
assertNotNull(tableField);
|
||||
assertEquals(FieldStrategy.ALWAYS, tableField.updateStrategy());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getMySettingsShouldFallbackToDefaultDuration() {
|
||||
ScreenSaverUserConfigMapper userConfigMapper = mock(ScreenSaverUserConfigMapper.class);
|
||||
|
|
|
|||
|
|
@ -31,14 +31,14 @@ const { Title } = Typography;
|
|||
type ModelType = "ASR" | "LLM";
|
||||
|
||||
const PROVIDER_BASE_URL_MAP: Record<string, string> = {
|
||||
openai: "https://api.openai.com/v1",
|
||||
openai: "https://api.openai.com",
|
||||
deepseek: "https://api.deepseek.com",
|
||||
aliyun: "https://dashscope.aliyuncs.com/compatible-mode/v1",
|
||||
qwen: "https://dashscope.aliyuncs.com/compatible-mode/v1",
|
||||
dashscope: "https://dashscope.aliyuncs.com/compatible-mode/v1",
|
||||
moonshot: "https://api.moonshot.cn/v1",
|
||||
kimi: "https://api.moonshot.cn/v1",
|
||||
groq: "https://api.groq.com/openai/v1",
|
||||
aliyun: "https://dashscope.aliyuncs.com/compatible-mode",
|
||||
qwen: "https://dashscope.aliyuncs.com/compatible-mode",
|
||||
dashscope: "https://dashscope.aliyuncs.com/compatible-mode",
|
||||
moonshot: "https://api.moonshot.cn",
|
||||
kimi: "https://api.moonshot.cn",
|
||||
groq: "https://api.groq.com/openai",
|
||||
};
|
||||
|
||||
const DEFAULT_LLM_TEST_MESSAGE = "请回复:LLM 连通性测试成功。";
|
||||
|
|
@ -526,7 +526,7 @@ const AiModels: React.FC = () => {
|
|||
</Row>
|
||||
|
||||
<Form.Item name="baseUrl" label="Base URL" rules={[{ required: true, message: "请输入 Base URL" }]}>
|
||||
<Input placeholder="https://api.example.com/v1" />
|
||||
<Input placeholder="https://api.example.com" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
|
|
|
|||
|
|
@ -740,9 +740,9 @@ export default function ScreenSaverManagement() {
|
|||
<Button icon={<ReloadOutlined />} onClick={() => void loadData()} loading={loading}>
|
||||
刷新
|
||||
</Button>
|
||||
<Button icon={<SettingOutlined />} onClick={openSettingsModal}>
|
||||
播放设置({mySettings.displayDurationSec} 秒/张)
|
||||
</Button>
|
||||
{/*<Button icon={<SettingOutlined />} onClick={openSettingsModal}>*/}
|
||||
{/* 播放设置({mySettings.displayDurationSec} 秒/张)*/}
|
||||
{/*</Button>*/}
|
||||
<Button type="primary" icon={<PlusOutlined />} onClick={openCreate}>
|
||||
新增屏保
|
||||
</Button>
|
||||
|
|
|
|||
Loading…
Reference in New Issue