diff --git a/docs/apidocs.swagger.yaml b/docs/apidocs.swagger.yaml index 09722cfb2aa75..59e0c6075edd3 100644 --- a/docs/apidocs.swagger.yaml +++ b/docs/apidocs.swagger.yaml @@ -2150,6 +2150,9 @@ definitions: enableLinkPreview: type: boolean description: enable_link_preview enables links preview. + enableMembersEdit: + type: boolean + title: enable_members_edit any member can edit workspace memos apiv1WorkspaceSetting: type: object properties: diff --git a/proto/api/v1/workspace_setting_service.proto b/proto/api/v1/workspace_setting_service.proto index dc490421990a3..7e32a0350175e 100644 --- a/proto/api/v1/workspace_setting_service.proto +++ b/proto/api/v1/workspace_setting_service.proto @@ -94,6 +94,8 @@ message WorkspaceMemoRelatedSetting { bool enable_double_click_edit = 5; // enable_link_preview enables links preview. bool enable_link_preview = 6; + // enable_members_edit any member can edit workspace memos + bool enable_members_edit = 7; } message GetWorkspaceSettingRequest { diff --git a/proto/gen/api/v1/workspace_setting_service.pb.go b/proto/gen/api/v1/workspace_setting_service.pb.go index 1d48b2ac46945..19f5468ac16e1 100644 --- a/proto/gen/api/v1/workspace_setting_service.pb.go +++ b/proto/gen/api/v1/workspace_setting_service.pb.go @@ -419,6 +419,8 @@ type WorkspaceMemoRelatedSetting struct { EnableDoubleClickEdit bool `protobuf:"varint,5,opt,name=enable_double_click_edit,json=enableDoubleClickEdit,proto3" json:"enable_double_click_edit,omitempty"` // enable_link_preview enables links preview. EnableLinkPreview bool `protobuf:"varint,6,opt,name=enable_link_preview,json=enableLinkPreview,proto3" json:"enable_link_preview,omitempty"` + // enable_members_edit any member can edit workspace memos + EnableMembersEdit bool `protobuf:"varint,7,opt,name=enable_members_edit,json=enableMembersEdit,proto3" json:"enable_members_edit,omitempty"` } func (x *WorkspaceMemoRelatedSetting) Reset() { @@ -495,6 +497,13 @@ func (x *WorkspaceMemoRelatedSetting) GetEnableLinkPreview() bool { return false } +func (x *WorkspaceMemoRelatedSetting) GetEnableMembersEdit() bool { + if x != nil { + return x.EnableMembersEdit + } + return false +} + type GetWorkspaceSettingRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -758,8 +767,8 @@ var file_api_v1_workspace_setting_service_proto_rawDesc = []byte{ 0x1c, 0x0a, 0x18, 0x53, 0x54, 0x4f, 0x52, 0x41, 0x47, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x41, 0x54, 0x41, 0x42, 0x41, 0x53, 0x45, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x4c, - 0x4f, 0x43, 0x41, 0x4c, 0x10, 0x02, 0x12, 0x06, 0x0a, 0x02, 0x53, 0x33, 0x10, 0x03, 0x22, 0xd9, - 0x02, 0x0a, 0x1b, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4d, 0x65, 0x6d, 0x6f, + 0x4f, 0x43, 0x41, 0x4c, 0x10, 0x02, 0x12, 0x06, 0x0a, 0x02, 0x53, 0x33, 0x10, 0x03, 0x22, 0x89, + 0x03, 0x0a, 0x1b, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4d, 0x65, 0x6d, 0x6f, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x36, 0x0a, 0x17, 0x64, 0x69, 0x73, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, @@ -780,7 +789,10 @@ var file_api_v1_workspace_setting_service_proto_rawDesc = []byte{ 0x65, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x45, 0x64, 0x69, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4c, - 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x22, 0x36, 0x0a, 0x1a, 0x47, 0x65, + 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6e, + 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x5f, 0x65, 0x64, 0x69, + 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x4d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x64, 0x69, 0x74, 0x22, 0x36, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0xe2, 0x41, 0x01, 0x02, 0x52, 0x04, 0x6e, 0x61, diff --git a/proto/gen/store/workspace_setting.pb.go b/proto/gen/store/workspace_setting.pb.go index 3c6ffa0d36f95..78b420996a1a0 100644 --- a/proto/gen/store/workspace_setting.pb.go +++ b/proto/gen/store/workspace_setting.pb.go @@ -616,6 +616,8 @@ type WorkspaceMemoRelatedSetting struct { EnableDoubleClickEdit bool `protobuf:"varint,5,opt,name=enable_double_click_edit,json=enableDoubleClickEdit,proto3" json:"enable_double_click_edit,omitempty"` // enable_link_preview enables links preview. EnableLinkPreview bool `protobuf:"varint,6,opt,name=enable_link_preview,json=enableLinkPreview,proto3" json:"enable_link_preview,omitempty"` + // enable_members_edit any member can edit workspace memos + EnableMembersEdit bool `protobuf:"varint,7,opt,name=enable_members_edit,json=enableMembersEdit,proto3" json:"enable_members_edit,omitempty"` } func (x *WorkspaceMemoRelatedSetting) Reset() { @@ -692,6 +694,13 @@ func (x *WorkspaceMemoRelatedSetting) GetEnableLinkPreview() bool { return false } +func (x *WorkspaceMemoRelatedSetting) GetEnableMembersEdit() bool { + if x != nil { + return x.EnableMembersEdit + } + return false +} + var File_store_workspace_setting_proto protoreflect.FileDescriptor var file_store_workspace_setting_proto_rawDesc = []byte{ @@ -782,7 +791,7 @@ var file_store_workspace_setting_proto_rawDesc = []byte{ 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x22, - 0xd9, 0x02, 0x0a, 0x1b, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4d, 0x65, 0x6d, + 0x89, 0x03, 0x0a, 0x1b, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4d, 0x65, 0x6d, 0x6f, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x36, 0x0a, 0x17, 0x64, 0x69, 0x73, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, @@ -803,7 +812,10 @@ var file_store_workspace_setting_proto_rawDesc = []byte{ 0x6c, 0x65, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x45, 0x64, 0x69, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x70, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, - 0x4c, 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x2a, 0x73, 0x0a, 0x13, 0x57, + 0x4c, 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x12, 0x2e, 0x0a, 0x13, 0x65, + 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x5f, 0x65, 0x64, + 0x69, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, + 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x45, 0x64, 0x69, 0x74, 0x2a, 0x73, 0x0a, 0x13, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x12, 0x25, 0x0a, 0x21, 0x57, 0x4f, 0x52, 0x4b, 0x53, 0x50, 0x41, 0x43, 0x45, 0x5f, 0x53, 0x45, 0x54, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x55, 0x4e, 0x53, 0x50, diff --git a/proto/store/workspace_setting.proto b/proto/store/workspace_setting.proto index 267532ea5748e..7d2121d4bf65a 100644 --- a/proto/store/workspace_setting.proto +++ b/proto/store/workspace_setting.proto @@ -90,4 +90,6 @@ message WorkspaceMemoRelatedSetting { bool enable_double_click_edit = 5; // enable_link_preview enables links preview. bool enable_link_preview = 6; + // enable_members_edit any member can edit workspace memos + bool enable_members_edit = 7; } diff --git a/server/router/api/v1/memo_service.go b/server/router/api/v1/memo_service.go index 11549dc62ebf4..74d79056dc8a0 100644 --- a/server/router/api/v1/memo_service.go +++ b/server/router/api/v1/memo_service.go @@ -257,7 +257,14 @@ func (s *APIV1Service) UpdateMemo(ctx context.Context, request *v1pb.UpdateMemoR if err != nil { return nil, status.Errorf(codes.Internal, "failed to get current user") } - if memo.CreatorID != user.ID { + + workspaceMemoRelatedSetting, err := s.Store.GetWorkspaceMemoRelatedSetting(ctx) + if err != nil { + return nil, status.Errorf(codes.Internal, "failed to get workspace memo related setting") + } + + membersCanEdit := memo.Visibility == store.Protected && workspaceMemoRelatedSetting.EnableMembersEdit + if !membersCanEdit && memo.CreatorID != user.ID { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } diff --git a/server/router/api/v1/workspace_setting_service.go b/server/router/api/v1/workspace_setting_service.go index 1e5997fc20171..07daffbd01489 100644 --- a/server/router/api/v1/workspace_setting_service.go +++ b/server/router/api/v1/workspace_setting_service.go @@ -220,6 +220,7 @@ func convertWorkspaceMemoRelatedSettingFromStore(setting *storepb.WorkspaceMemoR EnableAutoCompact: setting.EnableAutoCompact, EnableDoubleClickEdit: setting.EnableDoubleClickEdit, EnableLinkPreview: setting.EnableLinkPreview, + EnableMembersEdit: setting.EnableMembersEdit, } } @@ -234,5 +235,6 @@ func convertWorkspaceMemoRelatedSettingToStore(setting *v1pb.WorkspaceMemoRelate EnableAutoCompact: setting.EnableAutoCompact, EnableDoubleClickEdit: setting.EnableDoubleClickEdit, EnableLinkPreview: setting.EnableLinkPreview, + EnableMembersEdit: setting.EnableMembersEdit, } } diff --git a/web/src/components/MemoContent/index.tsx b/web/src/components/MemoContent/index.tsx index f08a382851ce5..2d226cdfbd56d 100644 --- a/web/src/components/MemoContent/index.tsx +++ b/web/src/components/MemoContent/index.tsx @@ -1,8 +1,9 @@ import clsx from "clsx"; import { memo, useEffect, useRef, useState } from "react"; import useCurrentUser from "@/hooks/useCurrentUser"; -import { useMemoStore } from "@/store/v1"; +import { useMemoStore, useWorkspaceSettingStore } from "@/store/v1"; import { Node, NodeType } from "@/types/proto/api/v1/markdown_service"; +import { WorkspaceMemoRelatedSetting, WorkspaceSettingKey } from "@/types/proto/store/workspace_setting"; import { useTranslate } from "@/utils/i18n"; import Renderer from "./Renderer"; import { RendererContext } from "./types"; @@ -30,10 +31,15 @@ const MemoContent: React.FC = (props: Props) => { const t = useTranslate(); const currentUser = useCurrentUser(); const memoStore = useMemoStore(); + const workspaceSettingStore = useWorkspaceSettingStore(); + const workspaceMemoRelatedSetting = + workspaceSettingStore.getWorkspaceSettingByKey(WorkspaceSettingKey.MEMO_RELATED).memoRelatedSetting || + WorkspaceMemoRelatedSetting.fromPartial({}); const memoContentContainerRef = useRef(null); const [showCompactMode, setShowCompactMode] = useState(false); const memo = memoName ? memoStore.getMemoByName(memoName) : null; - const allowEdit = !props.readonly && memo && currentUser?.name === memo.creator; + const membersCanEdit = memo?.visibility === "PROTECTED" && workspaceMemoRelatedSetting.enableMembersEdit; + const allowEdit = !props.readonly && memo && (membersCanEdit || memo.creator === currentUser?.name); // Initial compact mode. useEffect(() => { diff --git a/web/src/components/MemoView.tsx b/web/src/components/MemoView.tsx index 0ba4e064c7ad1..dbb291e5fc11f 100644 --- a/web/src/components/MemoView.tsx +++ b/web/src/components/MemoView.tsx @@ -52,7 +52,8 @@ const MemoView: React.FC = (props: Props) => { (relation) => relation.type === MemoRelation_Type.COMMENT && relation.relatedMemo === memo.name, ).length; const relativeTimeFormat = Date.now() - memo.displayTime!.getTime() > 1000 * 60 * 60 * 24 ? "datetime" : "auto"; - const readonly = memo.creator !== user?.name; + const membersCanEdit = memo?.visibility === "PROTECTED" && workspaceMemoRelatedSetting.enableMembersEdit; + const readonly = !user || (!membersCanEdit && memo.creator !== user.name); const isInMemoDetailPage = location.pathname.startsWith(`/m/${memo.uid}`); // Initial related data: creator. diff --git a/web/src/components/Settings/MemoRelatedSettings.tsx b/web/src/components/Settings/MemoRelatedSettings.tsx index ee6270c9513b9..9d36dd7f5b5ce 100644 --- a/web/src/components/Settings/MemoRelatedSettings.tsx +++ b/web/src/components/Settings/MemoRelatedSettings.tsx @@ -67,6 +67,13 @@ const MemoRelatedSettings = () => { onChange={(event) => updatePartialSetting({ enableDoubleClickEdit: event.target.checked })} /> +
+ {t("setting.system-section.enable-members-edit")} + updatePartialSetting({ enableMembersEdit: event.target.checked })} + /> +
Content length limit(Byte)