You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
49 lines
3.8 KiB
49 lines
3.8 KiB
package com.mydreamjob.messaging;
|
|
|
|
import com.mydreamjob.common.api.ApiResponse;
|
|
import com.mydreamjob.messaging.dto.MessageResponse;
|
|
import com.mydreamjob.security.CurrentUserAccessor;
|
|
import com.mydreamjob.common.logging.RequestIdAccessor;
|
|
import jakarta.servlet.http.HttpServletRequest;
|
|
import lombok.RequiredArgsConstructor;
|
|
import org.springframework.http.*;
|
|
import org.springframework.web.bind.annotation.*;
|
|
import org.springframework.web.multipart.MultipartFile;
|
|
import io.swagger.v3.oas.annotations.Operation;
|
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
|
|
@RestController @RequestMapping("/conversations") @RequiredArgsConstructor @Tag(name="消息")
|
|
public class ChatAttachmentController {
|
|
private final ChatAttachmentService service;
|
|
private final CurrentUserAccessor current;
|
|
private final RequestIdAccessor requestIds;
|
|
@Operation(summary="上传并发送图片或文件消息",description="仅有当前沟通权限的 DIRECT 成员。multipart 字段 file、kind=IMAGE/FILE、clientMessageId 必填;同一重试必须保持三者不变。单文件 10 MiB;IMAGE 支持 JPEG/PNG、最多 1600 万像素且边长≤8192,去除元数据并生成最长边320的JPEG缩略图;FILE支持 PDF/DOC/DOCX/UTF-8 TXT。默认会话有效附件总量100 MiB。成功原子提交消息与字节,复用 MESSAGE_CREATED 推送和游标补拉;不返回公开URL。")
|
|
@PostMapping(value="/{id}/attachment-messages",consumes=MediaType.MULTIPART_FORM_DATA_VALUE)
|
|
public ApiResponse<MessageResponse> send(@PathVariable Long id,@RequestParam String kind,
|
|
@RequestParam String clientMessageId,@RequestPart MultipartFile file,HttpServletRequest request) {
|
|
return ApiResponse.ok(service.send(id,current.requireUserId(),kind,clientMessageId,file),requestIds.get(request));
|
|
}
|
|
@Operation(summary="鉴权下载消息附件",description="每次重新校验成员、企业认证、有效投递和屏蔽,撤回或发送者禁用后不可下载;返回 no-store/nosniff/attachment,不支持公开URL或Token查询参数。")
|
|
@GetMapping("/{conversationId}/messages/{messageId}/attachment")
|
|
public ResponseEntity<byte[]> download(@PathVariable Long conversationId,@PathVariable Long messageId) {
|
|
return response(service.download(conversationId,messageId,current.requireUserId(),"download"),false);
|
|
}
|
|
@Operation(summary="鉴权读取图片预览",description="仅IMAGE,返回已重新编码去除元数据的图片;鉴权与下载相同。")
|
|
@GetMapping("/{conversationId}/messages/{messageId}/attachment/preview")
|
|
public ResponseEntity<byte[]> preview(@PathVariable Long conversationId,@PathVariable Long messageId) {
|
|
return response(service.download(conversationId,messageId,current.requireUserId(),"preview"),true);
|
|
}
|
|
@Operation(summary="鉴权读取图片缩略图",description="仅IMAGE,最长边320的JPEG,鉴权与下载相同。")
|
|
@GetMapping("/{conversationId}/messages/{messageId}/attachment/thumbnail")
|
|
public ResponseEntity<byte[]> thumbnail(@PathVariable Long conversationId,@PathVariable Long messageId) {
|
|
return response(service.download(conversationId,messageId,current.requireUserId(),"thumbnail"),true);
|
|
}
|
|
private ResponseEntity<byte[]> response(ChatAttachmentService.Download file,boolean inline) {
|
|
return ResponseEntity.ok().contentType(MediaType.parseMediaType(file.type()))
|
|
.header(HttpHeaders.CONTENT_DISPOSITION,(inline?ContentDisposition.inline():ContentDisposition.attachment())
|
|
.filename(file.name(),java.nio.charset.StandardCharsets.UTF_8).build().toString())
|
|
.header(HttpHeaders.CACHE_CONTROL,"no-store").header("X-Content-Type-Options","nosniff")
|
|
.header("Content-Security-Policy","default-src 'none'; sandbox")
|
|
.contentLength(file.content().length).body(file.content());
|
|
}
|
|
}
|
|
|