From 067f67869d9d965d09eedc56bc04ebe01310912b Mon Sep 17 00:00:00 2001 From: Florian Dewald Date: Fri, 24 Oct 2025 19:55:26 +0100 Subject: [PATCH] Move settings whether to generate thumbnails for S3 images to storage related settings --- proto/api/v1/attachment_service.proto | 3 ++ proto/api/v1/workspace_service.proto | 6 +-- proto/gen/api/v1/attachment_service.pb.go | 24 ++++++++--- proto/gen/api/v1/workspace_service.pb.go | 42 +++++++++---------- proto/gen/openapi.yaml | 10 +++-- proto/gen/store/workspace_setting.pb.go | 42 +++++++++---------- proto/store/workspace_setting.proto | 6 +-- server/router/api/v1/attachment_service.go | 25 +++++++---- .../router/api/v1/memo_attachment_service.go | 2 +- .../router/api/v1/memo_service_converter.go | 2 +- server/router/api/v1/workspace_service.go | 16 +++---- server/router/frontend/dist/index.html | 33 ++++++++++----- .../Settings/MemoRelatedSettings.tsx | 7 ---- .../components/Settings/StorageSection.tsx | 12 ++++++ .../types/proto/api/v1/attachment_service.ts | 22 +++++++++- .../types/proto/api/v1/workspace_service.ts | 40 +++++++++--------- web/src/utils/attachment.ts | 7 +--- 17 files changed, 181 insertions(+), 118 deletions(-) diff --git a/proto/api/v1/attachment_service.proto b/proto/api/v1/attachment_service.proto index 12fc9c1a3..d4d5976f0 100644 --- a/proto/api/v1/attachment_service.proto +++ b/proto/api/v1/attachment_service.proto @@ -84,6 +84,9 @@ message Attachment { // Optional. The related memo. Refer to `Memo.name`. // Format: memos/{memo} optional string memo = 8 [(google.api.field_behavior) = OPTIONAL]; + + // Optional. Output only. Whether to use thumbnails for this attachment when stored in S3. + optional bool use_thumbnail_for_s3_image = 9 [(google.api.field_behavior) = OUTPUT_ONLY]; } message CreateAttachmentRequest { diff --git a/proto/api/v1/workspace_service.proto b/proto/api/v1/workspace_service.proto index baac3567b..9dc4b3819 100644 --- a/proto/api/v1/workspace_service.proto +++ b/proto/api/v1/workspace_service.proto @@ -147,6 +147,9 @@ message WorkspaceSetting { } // The S3 config. S3Config s3_config = 4; + // use_thumbnails_for_s3_images enables thumbnail generation for images stored in S3. + // When false, images stored in S3 will not have thumbnails generated. + bool use_thumbnails_for_s3_images = 5; } // Memo-related workspace settings and policies. @@ -169,9 +172,6 @@ message WorkspaceSetting { bool enable_blur_nsfw_content = 9; // nsfw_tags is the list of tags that mark content as NSFW for blurring. repeated string nsfw_tags = 10; - // use_thumbnails_for_s3_images enables thumbnail generation for images stored in S3. - // When false, images stored in S3 will not have thumbnails generated. - bool use_thumbnails_for_s3_images = 11; } } diff --git a/proto/gen/api/v1/attachment_service.pb.go b/proto/gen/api/v1/attachment_service.pb.go index f471c3ebe..4121e684c 100644 --- a/proto/gen/api/v1/attachment_service.pb.go +++ b/proto/gen/api/v1/attachment_service.pb.go @@ -45,9 +45,12 @@ type Attachment struct { Size int64 `protobuf:"varint,7,opt,name=size,proto3" json:"size,omitempty"` // Optional. The related memo. Refer to `Memo.name`. // Format: memos/{memo} - Memo *string `protobuf:"bytes,8,opt,name=memo,proto3,oneof" json:"memo,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + Memo *string `protobuf:"bytes,8,opt,name=memo,proto3,oneof" json:"memo,omitempty"` + // Optional. Output only. Whether to use thumbnails for this attachment when stored in S3. + // This is determined by the workspace setting at the time of attachment creation. + UseThumbnailForS3Image *bool `protobuf:"varint,9,opt,name=use_thumbnail_for_s3_image,json=useThumbnailForS3Image,proto3,oneof" json:"use_thumbnail_for_s3_image,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Attachment) Reset() { @@ -136,6 +139,13 @@ func (x *Attachment) GetMemo() string { return "" } +func (x *Attachment) GetUseThumbnailForS3Image() bool { + if x != nil && x.UseThumbnailForS3Image != nil { + return *x.UseThumbnailForS3Image + } + return false +} + type CreateAttachmentRequest struct { state protoimpl.MessageState `protogen:"open.v1"` // Required. The attachment to create. @@ -549,7 +559,7 @@ var File_api_v1_attachment_service_proto protoreflect.FileDescriptor const file_api_v1_attachment_service_proto_rawDesc = "" + "\n" + - "\x1fapi/v1/attachment_service.proto\x12\fmemos.api.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x17google/api/client.proto\x1a\x1fgoogle/api/field_behavior.proto\x1a\x19google/api/httpbody.proto\x1a\x19google/api/resource.proto\x1a\x1bgoogle/protobuf/empty.proto\x1a google/protobuf/field_mask.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xfb\x02\n" + + "\x1fapi/v1/attachment_service.proto\x12\fmemos.api.v1\x1a\x1cgoogle/api/annotations.proto\x1a\x17google/api/client.proto\x1a\x1fgoogle/api/field_behavior.proto\x1a\x19google/api/httpbody.proto\x1a\x19google/api/resource.proto\x1a\x1bgoogle/protobuf/empty.proto\x1a google/protobuf/field_mask.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xe0\x03\n" + "\n" + "Attachment\x12\x17\n" + "\x04name\x18\x01 \x01(\tB\x03\xe0A\bR\x04name\x12@\n" + @@ -560,10 +570,12 @@ const file_api_v1_attachment_service_proto_rawDesc = "" + "\rexternal_link\x18\x05 \x01(\tB\x03\xe0A\x01R\fexternalLink\x12\x17\n" + "\x04type\x18\x06 \x01(\tB\x03\xe0A\x02R\x04type\x12\x17\n" + "\x04size\x18\a \x01(\x03B\x03\xe0A\x03R\x04size\x12\x1c\n" + - "\x04memo\x18\b \x01(\tB\x03\xe0A\x01H\x00R\x04memo\x88\x01\x01:O\xeaAL\n" + + "\x04memo\x18\b \x01(\tB\x03\xe0A\x01H\x00R\x04memo\x88\x01\x01\x12D\n" + + "\x1ause_thumbnail_for_s3_image\x18\t \x01(\bB\x03\xe0A\x03H\x01R\x16useThumbnailForS3Image\x88\x01\x01:O\xeaAL\n" + "\x17memos.api.v1/Attachment\x12\x18attachments/{attachment}*\vattachments2\n" + "attachmentB\a\n" + - "\x05_memo\"\x82\x01\n" + + "\x05_memoB\x1d\n" + + "\x1b_use_thumbnail_for_s3_image\"\x82\x01\n" + "\x17CreateAttachmentRequest\x12=\n" + "\n" + "attachment\x18\x01 \x01(\v2\x18.memos.api.v1.AttachmentB\x03\xe0A\x02R\n" + diff --git a/proto/gen/api/v1/workspace_service.pb.go b/proto/gen/api/v1/workspace_service.pb.go index 28c791887..088ca86ac 100644 --- a/proto/gen/api/v1/workspace_service.pb.go +++ b/proto/gen/api/v1/workspace_service.pb.go @@ -589,9 +589,12 @@ type WorkspaceSetting_StorageSetting struct { // The max upload size in megabytes. UploadSizeLimitMb int64 `protobuf:"varint,3,opt,name=upload_size_limit_mb,json=uploadSizeLimitMb,proto3" json:"upload_size_limit_mb,omitempty"` // The S3 config. - S3Config *WorkspaceSetting_StorageSetting_S3Config `protobuf:"bytes,4,opt,name=s3_config,json=s3Config,proto3" json:"s3_config,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + S3Config *WorkspaceSetting_StorageSetting_S3Config `protobuf:"bytes,4,opt,name=s3_config,json=s3Config,proto3" json:"s3_config,omitempty"` + // use_thumbnails_for_s3_images enables thumbnail generation for images stored in S3. + // When false, images stored in S3 will not have thumbnails generated. + UseThumbnailsForS3Images bool `protobuf:"varint,5,opt,name=use_thumbnails_for_s3_images,json=useThumbnailsForS3Images,proto3" json:"use_thumbnails_for_s3_images,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *WorkspaceSetting_StorageSetting) Reset() { @@ -652,6 +655,13 @@ func (x *WorkspaceSetting_StorageSetting) GetS3Config() *WorkspaceSetting_Storag return nil } +func (x *WorkspaceSetting_StorageSetting) GetUseThumbnailsForS3Images() bool { + if x != nil { + return x.UseThumbnailsForS3Images + } + return false +} + // Memo-related workspace settings and policies. type WorkspaceSetting_MemoRelatedSetting struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -672,12 +682,9 @@ type WorkspaceSetting_MemoRelatedSetting struct { // enable_blur_nsfw_content enables blurring of content marked as not safe for work (NSFW). EnableBlurNsfwContent bool `protobuf:"varint,9,opt,name=enable_blur_nsfw_content,json=enableBlurNsfwContent,proto3" json:"enable_blur_nsfw_content,omitempty"` // nsfw_tags is the list of tags that mark content as NSFW for blurring. - NsfwTags []string `protobuf:"bytes,10,rep,name=nsfw_tags,json=nsfwTags,proto3" json:"nsfw_tags,omitempty"` - // use_thumbnails_for_s3_images enables thumbnail generation for images stored in S3. - // When false, images stored in S3 will not have thumbnails generated. - UseThumbnailsForS3Images bool `protobuf:"varint,11,opt,name=use_thumbnails_for_s3_images,json=useThumbnailsForS3Images,proto3" json:"use_thumbnails_for_s3_images,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + NsfwTags []string `protobuf:"bytes,10,rep,name=nsfw_tags,json=nsfwTags,proto3" json:"nsfw_tags,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *WorkspaceSetting_MemoRelatedSetting) Reset() { @@ -773,13 +780,6 @@ func (x *WorkspaceSetting_MemoRelatedSetting) GetNsfwTags() []string { return nil } -func (x *WorkspaceSetting_MemoRelatedSetting) GetUseThumbnailsForS3Images() bool { - if x != nil { - return x.UseThumbnailsForS3Images - } - return false -} - // Custom profile configuration for workspace branding. type WorkspaceSetting_GeneralSetting_CustomProfile struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -965,12 +965,13 @@ const file_api_v1_workspace_service_proto_rawDesc = "" + "\x05title\x18\x01 \x01(\tR\x05title\x12 \n" + "\vdescription\x18\x02 \x01(\tR\vdescription\x12\x19\n" + "\blogo_url\x18\x03 \x01(\tR\alogoUrl\x12\x16\n" + - "\x06locale\x18\x04 \x01(\tR\x06locale\x1a\xbe\x04\n" + + "\x06locale\x18\x04 \x01(\tR\x06locale\x1a\xfe\x04\n" + "\x0eStorageSetting\x12\\\n" + "\fstorage_type\x18\x01 \x01(\x0e29.memos.api.v1.WorkspaceSetting.StorageSetting.StorageTypeR\vstorageType\x12+\n" + "\x11filepath_template\x18\x02 \x01(\tR\x10filepathTemplate\x12/\n" + "\x14upload_size_limit_mb\x18\x03 \x01(\x03R\x11uploadSizeLimitMb\x12S\n" + - "\ts3_config\x18\x04 \x01(\v26.memos.api.v1.WorkspaceSetting.StorageSetting.S3ConfigR\bs3Config\x1a\xcc\x01\n" + + "\ts3_config\x18\x04 \x01(\v26.memos.api.v1.WorkspaceSetting.StorageSetting.S3ConfigR\bs3Config\x12>\n" + + "\x1cuse_thumbnails_for_s3_images\x18\x05 \x01(\bR\x18useThumbnailsForS3Images\x1a\xcc\x01\n" + "\bS3Config\x12\"\n" + "\raccess_key_id\x18\x01 \x01(\tR\vaccessKeyId\x12*\n" + "\x11access_key_secret\x18\x02 \x01(\tR\x0faccessKeySecret\x12\x1a\n" + @@ -982,7 +983,7 @@ const file_api_v1_workspace_service_proto_rawDesc = "" + "\x18STORAGE_TYPE_UNSPECIFIED\x10\x00\x12\f\n" + "\bDATABASE\x10\x01\x12\t\n" + "\x05LOCAL\x10\x02\x12\x06\n" + - "\x02S3\x10\x03\x1a\x98\x04\n" + + "\x02S3\x10\x03\x1a\xd8\x03\n" + "\x12MemoRelatedSetting\x12<\n" + "\x1adisallow_public_visibility\x18\x01 \x01(\bR\x18disallowPublicVisibility\x127\n" + "\x18display_with_update_time\x18\x02 \x01(\bR\x15displayWithUpdateTime\x120\n" + @@ -993,8 +994,7 @@ const file_api_v1_workspace_service_proto_rawDesc = "" + "\x1adisable_markdown_shortcuts\x18\b \x01(\bR\x18disableMarkdownShortcuts\x127\n" + "\x18enable_blur_nsfw_content\x18\t \x01(\bR\x15enableBlurNsfwContent\x12\x1b\n" + "\tnsfw_tags\x18\n" + - " \x03(\tR\bnsfwTags\x12>\n" + - "\x1cuse_thumbnails_for_s3_images\x18\v \x01(\bR\x18useThumbnailsForS3Images\"F\n" + + " \x03(\tR\bnsfwTags\"F\n" + "\x03Key\x12\x13\n" + "\x0fKEY_UNSPECIFIED\x10\x00\x12\v\n" + "\aGENERAL\x10\x01\x12\v\n" + diff --git a/proto/gen/openapi.yaml b/proto/gen/openapi.yaml index 73ad960b0..650532c8f 100644 --- a/proto/gen/openapi.yaml +++ b/proto/gen/openapi.yaml @@ -2166,6 +2166,10 @@ components: memo: type: string description: "Optional. The related memo. Refer to `Memo.name`.\r\n Format: memos/{memo}" + useThumbnailForS3Image: + readOnly: true + type: boolean + description: Optional. Output only. Whether to use thumbnails for this attachment when stored in S3. CreateSessionRequest: type: object properties: @@ -3242,9 +3246,6 @@ components: items: type: string description: nsfw_tags is the list of tags that mark content as NSFW for blurring. - useThumbnailsForS3Images: - type: boolean - description: "use_thumbnails_for_s3_images enables thumbnail generation for images stored in S3.\r\n When false, images stored in S3 will not have thumbnails generated." description: Memo-related workspace settings and policies. WorkspaceSetting_StorageSetting: type: object @@ -3268,6 +3269,9 @@ components: allOf: - $ref: '#/components/schemas/StorageSetting_S3Config' description: The S3 config. + useThumbnailsForS3Images: + type: boolean + description: "use_thumbnails_for_s3_images enables thumbnail generation for images stored in S3.\r\n When false, images stored in S3 will not have thumbnails generated." description: Storage configuration settings for workspace attachments. tags: - name: ActivityService diff --git a/proto/gen/store/workspace_setting.pb.go b/proto/gen/store/workspace_setting.pb.go index 833c77a5f..8cc6c09ec 100644 --- a/proto/gen/store/workspace_setting.pb.go +++ b/proto/gen/store/workspace_setting.pb.go @@ -509,9 +509,12 @@ type WorkspaceStorageSetting struct { // The max upload size in megabytes. UploadSizeLimitMb int64 `protobuf:"varint,3,opt,name=upload_size_limit_mb,json=uploadSizeLimitMb,proto3" json:"upload_size_limit_mb,omitempty"` // The S3 config. - S3Config *StorageS3Config `protobuf:"bytes,4,opt,name=s3_config,json=s3Config,proto3" json:"s3_config,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + S3Config *StorageS3Config `protobuf:"bytes,4,opt,name=s3_config,json=s3Config,proto3" json:"s3_config,omitempty"` + // use_thumbnails_for_s3_images enables thumbnail generation for images stored in S3. + // When false, images stored in S3 will not have thumbnails generated. + UseThumbnailsForS3Images bool `protobuf:"varint,5,opt,name=use_thumbnails_for_s3_images,json=useThumbnailsForS3Images,proto3" json:"use_thumbnails_for_s3_images,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *WorkspaceStorageSetting) Reset() { @@ -572,6 +575,13 @@ func (x *WorkspaceStorageSetting) GetS3Config() *StorageS3Config { return nil } +func (x *WorkspaceStorageSetting) GetUseThumbnailsForS3Images() bool { + if x != nil { + return x.UseThumbnailsForS3Images + } + return false +} + // Reference: https://developers.cloudflare.com/r2/examples/aws/aws-sdk-go/ type StorageS3Config struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -676,12 +686,9 @@ type WorkspaceMemoRelatedSetting struct { // enable_blur_nsfw_content enables blurring of content marked as not safe for work (NSFW). EnableBlurNsfwContent bool `protobuf:"varint,9,opt,name=enable_blur_nsfw_content,json=enableBlurNsfwContent,proto3" json:"enable_blur_nsfw_content,omitempty"` // nsfw_tags is the list of tags that mark content as NSFW for blurring. - NsfwTags []string `protobuf:"bytes,10,rep,name=nsfw_tags,json=nsfwTags,proto3" json:"nsfw_tags,omitempty"` - // use_thumbnails_for_s3_images enables thumbnail generation for images stored in S3. - // When false, images stored in S3 will not have thumbnails generated. - UseThumbnailsForS3Images bool `protobuf:"varint,11,opt,name=use_thumbnails_for_s3_images,json=useThumbnailsForS3Images,proto3" json:"use_thumbnails_for_s3_images,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + NsfwTags []string `protobuf:"bytes,10,rep,name=nsfw_tags,json=nsfwTags,proto3" json:"nsfw_tags,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *WorkspaceMemoRelatedSetting) Reset() { @@ -777,13 +784,6 @@ func (x *WorkspaceMemoRelatedSetting) GetNsfwTags() []string { return nil } -func (x *WorkspaceMemoRelatedSetting) GetUseThumbnailsForS3Images() bool { - if x != nil { - return x.UseThumbnailsForS3Images - } - return false -} - var File_store_workspace_setting_proto protoreflect.FileDescriptor const file_store_workspace_setting_proto_rawDesc = "" + @@ -814,12 +814,13 @@ const file_store_workspace_setting_proto_rawDesc = "" + "\x05title\x18\x01 \x01(\tR\x05title\x12 \n" + "\vdescription\x18\x02 \x01(\tR\vdescription\x12\x19\n" + "\blogo_url\x18\x03 \x01(\tR\alogoUrl\x12\x16\n" + - "\x06locale\x18\x04 \x01(\tR\x06locale\"\xd5\x02\n" + + "\x06locale\x18\x04 \x01(\tR\x06locale\"\x95\x03\n" + "\x17WorkspaceStorageSetting\x12S\n" + "\fstorage_type\x18\x01 \x01(\x0e20.memos.store.WorkspaceStorageSetting.StorageTypeR\vstorageType\x12+\n" + "\x11filepath_template\x18\x02 \x01(\tR\x10filepathTemplate\x12/\n" + "\x14upload_size_limit_mb\x18\x03 \x01(\x03R\x11uploadSizeLimitMb\x129\n" + - "\ts3_config\x18\x04 \x01(\v2\x1c.memos.store.StorageS3ConfigR\bs3Config\"L\n" + + "\ts3_config\x18\x04 \x01(\v2\x1c.memos.store.StorageS3ConfigR\bs3Config\x12>\n" + + "\x1cuse_thumbnails_for_s3_images\x18\x05 \x01(\bR\x18useThumbnailsForS3Images\"L\n" + "\vStorageType\x12\x1c\n" + "\x18STORAGE_TYPE_UNSPECIFIED\x10\x00\x12\f\n" + "\bDATABASE\x10\x01\x12\t\n" + @@ -831,7 +832,7 @@ const file_store_workspace_setting_proto_rawDesc = "" + "\bendpoint\x18\x03 \x01(\tR\bendpoint\x12\x16\n" + "\x06region\x18\x04 \x01(\tR\x06region\x12\x16\n" + "\x06bucket\x18\x05 \x01(\tR\x06bucket\x12$\n" + - "\x0euse_path_style\x18\x06 \x01(\bR\fusePathStyle\"\xa1\x04\n" + + "\x0euse_path_style\x18\x06 \x01(\bR\fusePathStyle\"\xe1\x03\n" + "\x1bWorkspaceMemoRelatedSetting\x12<\n" + "\x1adisallow_public_visibility\x18\x01 \x01(\bR\x18disallowPublicVisibility\x127\n" + "\x18display_with_update_time\x18\x02 \x01(\bR\x15displayWithUpdateTime\x120\n" + @@ -842,8 +843,7 @@ const file_store_workspace_setting_proto_rawDesc = "" + "\x1adisable_markdown_shortcuts\x18\b \x01(\bR\x18disableMarkdownShortcuts\x127\n" + "\x18enable_blur_nsfw_content\x18\t \x01(\bR\x15enableBlurNsfwContent\x12\x1b\n" + "\tnsfw_tags\x18\n" + - " \x03(\tR\bnsfwTags\x12>\n" + - "\x1cuse_thumbnails_for_s3_images\x18\v \x01(\bR\x18useThumbnailsForS3Images*s\n" + + " \x03(\tR\bnsfwTags*s\n" + "\x13WorkspaceSettingKey\x12%\n" + "!WORKSPACE_SETTING_KEY_UNSPECIFIED\x10\x00\x12\t\n" + "\x05BASIC\x10\x01\x12\v\n" + diff --git a/proto/store/workspace_setting.proto b/proto/store/workspace_setting.proto index ed6af89c2..91a48b18a 100644 --- a/proto/store/workspace_setting.proto +++ b/proto/store/workspace_setting.proto @@ -83,6 +83,9 @@ message WorkspaceStorageSetting { int64 upload_size_limit_mb = 3; // The S3 config. StorageS3Config s3_config = 4; + // use_thumbnails_for_s3_images enables thumbnail generation for images stored in S3. + // When false, images stored in S3 will not have thumbnails generated. + bool use_thumbnails_for_s3_images = 5; } // Reference: https://developers.cloudflare.com/r2/examples/aws/aws-sdk-go/ @@ -114,7 +117,4 @@ message WorkspaceMemoRelatedSetting { bool enable_blur_nsfw_content = 9; // nsfw_tags is the list of tags that mark content as NSFW for blurring. repeated string nsfw_tags = 10; - // use_thumbnails_for_s3_images enables thumbnail generation for images stored in S3. - // When false, images stored in S3 will not have thumbnails generated. - bool use_thumbnails_for_s3_images = 11; } diff --git a/server/router/api/v1/attachment_service.go b/server/router/api/v1/attachment_service.go index f87d8f6fa..4ec4325e8 100644 --- a/server/router/api/v1/attachment_service.go +++ b/server/router/api/v1/attachment_service.go @@ -119,7 +119,7 @@ func (s *APIV1Service) CreateAttachment(ctx context.Context, request *v1pb.Creat return nil, status.Errorf(codes.Internal, "failed to create attachment: %v", err) } - return convertAttachmentFromStore(attachment), nil + return s.convertAttachmentFromStore(ctx, attachment), nil } func (s *APIV1Service) ListAttachments(ctx context.Context, request *v1pb.ListAttachmentsRequest) (*v1pb.ListAttachmentsResponse, error) { @@ -164,7 +164,7 @@ func (s *APIV1Service) ListAttachments(ctx context.Context, request *v1pb.ListAt response := &v1pb.ListAttachmentsResponse{} for _, attachment := range attachments { - response.Attachments = append(response.Attachments, convertAttachmentFromStore(attachment)) + response.Attachments = append(response.Attachments, s.convertAttachmentFromStore(ctx, attachment)) } // For simplicity, set total size to the number of returned attachments. @@ -191,7 +191,7 @@ func (s *APIV1Service) GetAttachment(ctx context.Context, request *v1pb.GetAttac if attachment == nil { return nil, status.Errorf(codes.NotFound, "attachment not found") } - return convertAttachmentFromStore(attachment), nil + return s.convertAttachmentFromStore(ctx, attachment), nil } func (s *APIV1Service) GetAttachmentBinary(ctx context.Context, request *v1pb.GetAttachmentBinaryRequest) (*httpbody.HttpBody, error) { @@ -235,10 +235,10 @@ func (s *APIV1Service) GetAttachmentBinary(ctx context.Context, request *v1pb.Ge // Check if we should generate thumbnails for S3 images shouldGenerateThumbnail := true if attachment.StorageType == storepb.AttachmentStorageType_S3 { - memoRelatedSetting, err := s.Store.GetWorkspaceMemoRelatedSetting(ctx) + storageSetting, err := s.Store.GetWorkspaceStorageSetting(ctx) if err != nil { - slog.Warn("failed to get workspace memo related setting", slog.Any("error", err)) - } else if !memoRelatedSetting.UseThumbnailsForS3Images { + slog.Warn("failed to get workspace storage setting", slog.Any("error", err)) + } else if !storageSetting.UseThumbnailsForS3Images { shouldGenerateThumbnail = false } } @@ -381,7 +381,7 @@ func (s *APIV1Service) DeleteAttachment(ctx context.Context, request *v1pb.Delet return &emptypb.Empty{}, nil } -func convertAttachmentFromStore(attachment *store.Attachment) *v1pb.Attachment { +func (s *APIV1Service) convertAttachmentFromStore(ctx context.Context, attachment *store.Attachment) *v1pb.Attachment { attachmentMessage := &v1pb.Attachment{ Name: fmt.Sprintf("%s%s", AttachmentNamePrefix, attachment.UID), CreateTime: timestamppb.New(time.Unix(attachment.CreatedTs, 0)), @@ -397,6 +397,17 @@ func convertAttachmentFromStore(attachment *store.Attachment) *v1pb.Attachment { attachmentMessage.ExternalLink = attachment.Reference } + // Populate use_thumbnail_for_s3_image based on workspace setting and storage type + if attachment.StorageType == storepb.AttachmentStorageType_S3 { + storageSetting, err := s.Store.GetWorkspaceStorageSetting(ctx) + if err != nil { + slog.Warn("failed to get workspace storage setting", slog.Any("error", err)) + } else { + useThumbnail := storageSetting.UseThumbnailsForS3Images + attachmentMessage.UseThumbnailForS3Image = &useThumbnail + } + } + return attachmentMessage } diff --git a/server/router/api/v1/memo_attachment_service.go b/server/router/api/v1/memo_attachment_service.go index e7c7f18ac..95e0d480b 100644 --- a/server/router/api/v1/memo_attachment_service.go +++ b/server/router/api/v1/memo_attachment_service.go @@ -96,7 +96,7 @@ func (s *APIV1Service) ListMemoAttachments(ctx context.Context, request *v1pb.Li Attachments: []*v1pb.Attachment{}, } for _, attachment := range attachments { - response.Attachments = append(response.Attachments, convertAttachmentFromStore(attachment)) + response.Attachments = append(response.Attachments, s.convertAttachmentFromStore(ctx, attachment)) } return response, nil } diff --git a/server/router/api/v1/memo_service_converter.go b/server/router/api/v1/memo_service_converter.go index de14e3954..412027181 100644 --- a/server/router/api/v1/memo_service_converter.go +++ b/server/router/api/v1/memo_service_converter.go @@ -62,7 +62,7 @@ func (s *APIV1Service) convertMemoFromStore(ctx context.Context, memo *store.Mem memoMessage.Attachments = []*v1pb.Attachment{} for _, attachment := range attachments { - attachmentResponse := convertAttachmentFromStore(attachment) + attachmentResponse := s.convertAttachmentFromStore(ctx, attachment) memoMessage.Attachments = append(memoMessage.Attachments, attachmentResponse) } diff --git a/server/router/api/v1/workspace_service.go b/server/router/api/v1/workspace_service.go index aaf828120..52cad2327 100644 --- a/server/router/api/v1/workspace_service.go +++ b/server/router/api/v1/workspace_service.go @@ -211,9 +211,10 @@ func convertWorkspaceStorageSettingFromStore(settingpb *storepb.WorkspaceStorage return nil } setting := &v1pb.WorkspaceSetting_StorageSetting{ - StorageType: v1pb.WorkspaceSetting_StorageSetting_StorageType(settingpb.StorageType), - FilepathTemplate: settingpb.FilepathTemplate, - UploadSizeLimitMb: settingpb.UploadSizeLimitMb, + StorageType: v1pb.WorkspaceSetting_StorageSetting_StorageType(settingpb.StorageType), + FilepathTemplate: settingpb.FilepathTemplate, + UploadSizeLimitMb: settingpb.UploadSizeLimitMb, + UseThumbnailsForS3Images: settingpb.UseThumbnailsForS3Images, } if settingpb.S3Config != nil { setting.S3Config = &v1pb.WorkspaceSetting_StorageSetting_S3Config{ @@ -233,9 +234,10 @@ func convertWorkspaceStorageSettingToStore(setting *v1pb.WorkspaceSetting_Storag return nil } settingpb := &storepb.WorkspaceStorageSetting{ - StorageType: storepb.WorkspaceStorageSetting_StorageType(setting.StorageType), - FilepathTemplate: setting.FilepathTemplate, - UploadSizeLimitMb: setting.UploadSizeLimitMb, + StorageType: storepb.WorkspaceStorageSetting_StorageType(setting.StorageType), + FilepathTemplate: setting.FilepathTemplate, + UploadSizeLimitMb: setting.UploadSizeLimitMb, + UseThumbnailsForS3Images: setting.UseThumbnailsForS3Images, } if setting.S3Config != nil { settingpb.S3Config = &storepb.StorageS3Config{ @@ -264,7 +266,6 @@ func convertWorkspaceMemoRelatedSettingFromStore(setting *storepb.WorkspaceMemoR DisableMarkdownShortcuts: setting.DisableMarkdownShortcuts, EnableBlurNsfwContent: setting.EnableBlurNsfwContent, NsfwTags: setting.NsfwTags, - UseThumbnailsForS3Images: setting.UseThumbnailsForS3Images, } } @@ -282,7 +283,6 @@ func convertWorkspaceMemoRelatedSettingToStore(setting *v1pb.WorkspaceSetting_Me DisableMarkdownShortcuts: setting.DisableMarkdownShortcuts, EnableBlurNsfwContent: setting.EnableBlurNsfwContent, NsfwTags: setting.NsfwTags, - UseThumbnailsForS3Images: setting.UseThumbnailsForS3Images, } } diff --git a/server/router/frontend/dist/index.html b/server/router/frontend/dist/index.html index a612ed1f7..476920fad 100644 --- a/server/router/frontend/dist/index.html +++ b/server/router/frontend/dist/index.html @@ -1,11 +1,22 @@ - - - - - - Memos - - - No embeddable frontend found. - - + + + + + + + + + + Memos + + + + + + + + +
+ + + diff --git a/web/src/components/Settings/MemoRelatedSettings.tsx b/web/src/components/Settings/MemoRelatedSettings.tsx index 025759b29..58f9938fc 100644 --- a/web/src/components/Settings/MemoRelatedSettings.tsx +++ b/web/src/components/Settings/MemoRelatedSettings.tsx @@ -175,13 +175,6 @@ const MemoRelatedSettings = observer(() => { -
- {t("setting.memo-related-settings.use-thumbnails-for-s3-images")} - updatePartialSetting({ useThumbnailsForS3Images: checked })} - /> -
)} +
+ {t("setting.memo-related-settings.use-thumbnails-for-s3-images")} + + setWorkspaceStorageSetting({ + ...workspaceStorageSetting, + useThumbnailsForS3Images: checked, + }) + } + /> +