- 单用户资料接口补上距离:此前只有推荐/附近列表会算距离,资料页和 聊天头部因此无内容可显示。沿用同一套 haversine 与隐私开关。 - 语音/图片消息可限定会员发送,两个开关在管理端「运营配置」中修改 (迁移 032)。校验放在 persistMessageContext,HTTP 与 WebSocket 两条发送路径都覆盖;文本消息永不受限。 - 短信服务关闭时注册不再要求验证码:关掉之后没人能拿到验证码,继续 要求就等于关闭注册通道。重置密码不做同样放宽,那里缺验证码等于 凭手机号夺号。app/config 增加 smsVerification 供客户端决定表单形态。 - 修复 AI 托管账号之间不回复:原规则按「发送方是否托管账号」拦截, 把真人操作测试号的正常对话也挡了。改为标记 worker 自己写入的回复, 只对 AI 生成的消息跳过入队。 - ai.default_model_id 同时接受模型 ID 与名称,填名称时不再被 MySQL 静默转成 0 而使配置失效。 - 聊天媒体留存管理与清理任务(迁移 033,两台线上均已应用)。 新增集成测试均针对真实 MySQL:会员限制、免短信注册、AI 入队规则、 默认模型解析、资料距离。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
66 lines
2.8 KiB
SQL
66 lines
2.8 KiB
SQL
SET NAMES utf8mb4;
|
|
|
|
CREATE TABLE IF NOT EXISTS im_message_media (
|
|
message_id BIGINT UNSIGNED NOT NULL,
|
|
media_asset_id BIGINT UNSIGNED NULL,
|
|
media_type VARCHAR(20) NOT NULL,
|
|
public_url VARCHAR(500) NOT NULL DEFAULT '',
|
|
duration_ms INT UNSIGNED NULL,
|
|
status TINYINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '0 deleted, 1 active, 2 deleting, 3 cleanup failed',
|
|
delete_reason VARCHAR(255) NOT NULL DEFAULT '',
|
|
cleanup_error VARCHAR(500) NOT NULL DEFAULT '',
|
|
deleted_at DATETIME(3) NULL,
|
|
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
|
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
|
PRIMARY KEY (message_id),
|
|
KEY idx_im_message_media_cleanup (status, created_at),
|
|
KEY idx_im_message_media_asset (media_asset_id),
|
|
KEY idx_im_message_media_type_created (media_type, created_at)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
|
|
-- Associate media messages that predate this table with their immutable upload
|
|
-- record. A nullable asset id keeps the audit row visible even if historical
|
|
-- data was imported without a matching media_assets entry.
|
|
INSERT IGNORE INTO im_message_media (
|
|
message_id,
|
|
media_asset_id,
|
|
media_type,
|
|
public_url,
|
|
duration_ms,
|
|
status,
|
|
created_at
|
|
)
|
|
SELECT
|
|
m.id,
|
|
(
|
|
SELECT ma.id
|
|
FROM media_assets ma
|
|
WHERE ma.owner_user_id=m.sender_id
|
|
AND ma.public_url=JSON_UNQUOTE(JSON_EXTRACT(IF(JSON_VALID(CONVERT(m.body USING utf8mb4)),CONVERT(m.body USING utf8mb4),'{}'), '$.url'))
|
|
AND ma.media_type=IF(m.message_type=2, 'image', 'audio')
|
|
ORDER BY ma.id DESC
|
|
LIMIT 1
|
|
),
|
|
IF(m.message_type=2, 'image', 'voice'),
|
|
JSON_UNQUOTE(JSON_EXTRACT(IF(JSON_VALID(CONVERT(m.body USING utf8mb4)),CONVERT(m.body USING utf8mb4),'{}'), '$.url')),
|
|
IF(
|
|
m.message_type=3,
|
|
CAST(JSON_UNQUOTE(JSON_EXTRACT(IF(JSON_VALID(CONVERT(m.body USING utf8mb4)),CONVERT(m.body USING utf8mb4),'{}'), '$.duration')) AS UNSIGNED) * 1000,
|
|
NULL
|
|
),
|
|
1,
|
|
m.created_at
|
|
FROM im_messages m
|
|
WHERE m.message_type IN (2,3)
|
|
AND JSON_VALID(CONVERT(m.body USING utf8mb4))
|
|
AND JSON_UNQUOTE(JSON_EXTRACT(IF(JSON_VALID(CONVERT(m.body USING utf8mb4)),CONVERT(m.body USING utf8mb4),'{}'), '$.url')) IS NOT NULL;
|
|
|
|
INSERT INTO system_configs (config_key, config_value, value_type, description) VALUES
|
|
('im.chat_media_retention_enabled', 'false', 'boolean', '是否按保留天数自动清理聊天图片和语音文件'),
|
|
('im.chat_media_retention_days', '90', 'number', '聊天图片和语音文件保留天数(1-3650)'),
|
|
('im.chat_media_cleanup_last_at', '', 'string', '聊天媒体最近一次定期清理时间'),
|
|
('im.chat_media_cleanup_last_result', '', 'string', '聊天媒体最近一次定期清理结果')
|
|
ON DUPLICATE KEY UPDATE
|
|
value_type=VALUES(value_type),
|
|
description=VALUES(description);
|