From 91cc84b224e4b908116bb30c30d4cbbf45f2f6af Mon Sep 17 00:00:00 2001 From: Iziram Date: Tue, 9 Jul 2024 11:21:30 +0200 Subject: [PATCH 1/3] =?UTF-8?q?=E2=9C=A8=20feat(Web):=20setting=20members?= =?UTF-8?q?=20edit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add new setting Members edit. Enable all members to edit workspace's memos. --- web/src/components/MemoContent/index.tsx | 10 ++++++++-- web/src/components/MemoView.tsx | 2 +- web/src/components/Settings/MemoRelatedSettings.tsx | 7 +++++++ web/src/locales/en.json | 3 ++- web/src/locales/fr.json | 3 ++- 5 files changed, 20 insertions(+), 5 deletions(-) diff --git a/web/src/components/MemoContent/index.tsx b/web/src/components/MemoContent/index.tsx index f08a382851ce5..0c0ddcc7dd56d 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 readonly = !currentUser || (!workspaceMemoRelatedSetting.enableMembersEdit && currentUser.name !== memo?.name); + const allowEdit = !props.readonly && memo && !readonly; // Initial compact mode. useEffect(() => { diff --git a/web/src/components/MemoView.tsx b/web/src/components/MemoView.tsx index 0ba4e064c7ad1..e6448e9cc8700 100644 --- a/web/src/components/MemoView.tsx +++ b/web/src/components/MemoView.tsx @@ -52,7 +52,7 @@ 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 readonly = !user || (!workspaceMemoRelatedSetting.enableMembersEdit && 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) Date: Tue, 9 Jul 2024 12:30:07 +0200 Subject: [PATCH 2/3] =?UTF-8?q?=E2=9C=A8=20feat(Server):=20setting=20membe?= =?UTF-8?q?rs=20edit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit add setting to enable edit for any member on workspace's memos --- docs/apidocs.swagger.yaml | 268 +++++++++++++----- proto/api/v1/workspace_setting_service.proto | 2 + .../api/v1/workspace_setting_service.pb.go | 18 +- proto/gen/store/workspace_setting.pb.go | 16 +- proto/store/workspace_setting.proto | 2 + server/router/api/v1/memo_service.go | 8 +- .../api/v1/workspace_setting_service.go | 2 + 7 files changed, 246 insertions(+), 70 deletions(-) diff --git a/docs/apidocs.swagger.yaml b/docs/apidocs.swagger.yaml index ca605c407a13d..983136ffa45ce 100644 --- a/docs/apidocs.swagger.yaml +++ b/docs/apidocs.swagger.yaml @@ -301,12 +301,16 @@ paths: type: integer format: int32 - name: pageToken - description: "A page token, received from a previous `ListMemos` call.\r\nProvide this to retrieve the subsequent page." + description: |- + A page token, received from a previous `ListMemos` call. + Provide this to retrieve the subsequent page. in: query required: false type: string - name: filter - description: "Filter is used to filter memos returned in the list.\r\nFormat: \"creator == 'users/{uid}' && visibilities == ['PUBLIC', 'PROTECTED']\"" + description: |- + Filter is used to filter memos returned in the list. + Format: "creator == 'users/{uid}' && visibilities == ['PUBLIC', 'PROTECTED']" in: query required: false type: string @@ -347,12 +351,17 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: name - description: "name is the name of the user to get stats for.\r\nFormat: users/{id}" + description: |- + name is the name of the user to get stats for. + Format: users/{id} in: query required: false type: string - name: timezone - description: "timezone location\r\nFormat: uses tz identifier\r\nhttps://en.wikipedia.org/wiki/List_of_tz_database_time_zones" + description: |- + timezone location + Format: uses tz identifier + https://en.wikipedia.org/wiki/List_of_tz_database_time_zones in: query required: false type: string @@ -399,7 +408,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: filter - description: "Filter is used to filter memos returned.\r\nFormat: \"creator == 'users/{uid}' && visibilities == ['PUBLIC', 'PROTECTED']\"" + description: |- + Filter is used to filter memos returned. + Format: "creator == 'users/{uid}' && visibilities == ['PUBLIC', 'PROTECTED']" in: query required: false type: string @@ -532,7 +543,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: filter - description: "Filter is used to filter users returned in the list.\r\nFormat: \"username == 'frank'\"" + description: |- + Filter is used to filter users returned in the list. + Format: "username == 'frank'" in: query required: false type: string @@ -693,7 +706,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: name - description: "The resource name of the workspace setting.\r\nFormat: settings/{setting}" + description: |- + The resource name of the workspace setting. + Format: settings/{setting} in: path required: true type: string @@ -715,7 +730,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: setting.name - description: "name is the name of the setting.\r\nFormat: settings/{setting}" + description: |- + name is the name of the setting. + Format: settings/{setting} in: path required: true type: string @@ -751,7 +768,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: identityProvider.name - description: "The name of the identityProvider.\r\nFormat: identityProviders/{id}" + description: |- + The name of the identityProvider. + Format: identityProviders/{id} in: path required: true type: string @@ -789,7 +808,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: inbox.name - description: "The name of the inbox.\r\nFormat: inboxes/{id}" + description: |- + The name of the inbox. + Format: inboxes/{id} in: path required: true type: string @@ -833,7 +854,10 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: memo.name - description: "The name of the memo.\r\nFormat: memos/{id}\r\nid is the system generated id." + description: |- + The name of the memo. + Format: memos/{id} + id is the system generated id. in: path required: true type: string @@ -851,7 +875,9 @@ paths: $ref: '#/definitions/v1RowStatus' creator: type: string - title: "The name of the creator.\r\nFormat: users/{id}" + title: |- + The name of the creator. + Format: users/{id} createTime: type: string format: date-time @@ -904,7 +930,9 @@ paths: readOnly: true parent: type: string - title: "The name of the parent memo.\r\nFormat: memos/{id}" + title: |- + The name of the parent memo. + Format: memos/{id} readOnly: true tags: - MemoService @@ -923,7 +951,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: name_1 - description: "The name of the identityProvider to get.\r\nFormat: identityProviders/{id}" + description: |- + The name of the identityProvider to get. + Format: identityProviders/{id} in: path required: true type: string @@ -945,7 +975,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: name_1 - description: "The name of the identityProvider to delete.\r\nFormat: identityProviders/{id}" + description: |- + The name of the identityProvider to delete. + Format: identityProviders/{id} in: path required: true type: string @@ -967,7 +999,10 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: name_2 - description: "The name of the resource.\r\nFormat: resources/{id}\r\nid is the system generated unique identifier." + description: |- + The name of the resource. + Format: resources/{id} + id is the system generated unique identifier. in: path required: true type: string @@ -989,7 +1024,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: name_2 - description: "The name of the inbox to delete.\r\nFormat: inboxes/{id}" + description: |- + The name of the inbox to delete. + Format: inboxes/{id} in: path required: true type: string @@ -1011,7 +1048,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: name_3 - description: "The name of the memo.\r\nFormat: memos/{id}" + description: |- + The name of the memo. + Format: memos/{id} in: path required: true type: string @@ -1033,7 +1072,10 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: name_3 - description: "The name of the resource.\r\nFormat: resources/{id}\r\nid is the system generated unique identifier." + description: |- + The name of the resource. + Format: resources/{id} + id is the system generated unique identifier. in: path required: true type: string @@ -1056,7 +1098,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: name_4 - description: "The name of the memo.\r\nFormat: memos/{id}" + description: |- + The name of the memo. + Format: memos/{id} in: path required: true type: string @@ -1078,7 +1122,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: name - description: "The name of the user.\r\nFormat: users/{id}" + description: |- + The name of the user. + Format: users/{id} in: path required: true type: string @@ -1100,7 +1146,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: name - description: "The name of the user.\r\nFormat: users/{id}" + description: |- + The name of the user. + Format: users/{id} in: path required: true type: string @@ -1122,7 +1170,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: name - description: "The name of the user.\r\nFormat: users/{id}" + description: |- + The name of the user. + Format: users/{id} in: path required: true type: string @@ -1143,7 +1193,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: name - description: "The name of the user.\r\nFormat: users/{id}" + description: |- + The name of the user. + Format: users/{id} in: path required: true type: string @@ -1171,7 +1223,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: name - description: "The name of the user.\r\nFormat: users/{id}" + description: |- + The name of the user. + Format: users/{id} in: path required: true type: string @@ -1198,7 +1252,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: name - description: "The name of the memo.\r\nFormat: memos/{id}" + description: |- + The name of the memo. + Format: memos/{id} in: path required: true type: string @@ -1219,7 +1275,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: name - description: "The name of the memo.\r\nFormat: memos/{id}" + description: |- + The name of the memo. + Format: memos/{id} in: path required: true type: string @@ -1246,7 +1304,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: name - description: "The name of the memo.\r\nFormat: memos/{id}. Use \"memos/-\" to list all properties." + description: |- + The name of the memo. + Format: memos/{id}. Use "memos/-" to list all properties. in: path required: true type: string @@ -1269,7 +1329,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: name - description: "The name of the memo.\r\nFormat: memos/{id}. Use \"memos/-\" to rebuild all memos." + description: |- + The name of the memo. + Format: memos/{id}. Use "memos/-" to rebuild all memos. in: path required: true type: string @@ -1296,7 +1358,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: name - description: "The name of the memo.\r\nFormat: memos/{id}" + description: |- + The name of the memo. + Format: memos/{id} in: path required: true type: string @@ -1317,7 +1381,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: name - description: "The name of the memo.\r\nFormat: memos/{id}" + description: |- + The name of the memo. + Format: memos/{id} in: path required: true type: string @@ -1344,7 +1410,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: name - description: "The name of the memo.\r\nFormat: memos/{id}" + description: |- + The name of the memo. + Format: memos/{id} in: path required: true type: string @@ -1366,7 +1434,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: name - description: "The name of the memo.\r\nFormat: memos/{id}" + description: |- + The name of the memo. + Format: memos/{id} in: path required: true type: string @@ -1393,7 +1463,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: name - description: "The name of the memo.\r\nFormat: memos/{id}" + description: |- + The name of the memo. + Format: memos/{id} in: path required: true type: string @@ -1415,7 +1487,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: name - description: "The name of the memo.\r\nFormat: memos/{id}" + description: |- + The name of the memo. + Format: memos/{id} in: path required: true type: string @@ -1442,7 +1516,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: name - description: "The name of the user.\r\nFormat: users/{id}" + description: |- + The name of the user. + Format: users/{id} in: path required: true type: string @@ -1464,13 +1540,17 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: parent - description: "The parent, who owns the tags.\r\nFormat: memos/{id}. Use \"memos/-\" to list all tags." + description: |- + The parent, who owns the tags. + Format: memos/{id}. Use "memos/-" to list all tags. in: path required: true type: string pattern: memos/[^/]+ - name: filter - description: "Filter is used to filter memos.\r\nFormat: \"creator == 'users/{uid}' && visibilities == ['PUBLIC', 'PROTECTED']\"" + description: |- + Filter is used to filter memos. + Format: "creator == 'users/{uid}' && visibilities == ['PUBLIC', 'PROTECTED']" in: query required: false type: string @@ -1492,7 +1572,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: parent - description: "The parent, who owns the tags.\r\nFormat: memos/{id}. Use \"memos/-\" to delete all tags." + description: |- + The parent, who owns the tags. + Format: memos/{id}. Use "memos/-" to delete all tags. in: path required: true type: string @@ -1523,7 +1605,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: parent - description: "The parent, who owns the tags.\r\nFormat: memos/{id}. Use \"memos/-\" to rename all tags." + description: |- + The parent, who owns the tags. + Format: memos/{id}. Use "memos/-" to rename all tags. in: path required: true type: string @@ -1550,7 +1634,10 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: resource.name - description: "The name of the resource.\r\nFormat: resources/{id}\r\nid is the system generated unique identifier." + description: |- + The name of the resource. + Format: resources/{id} + id is the system generated unique identifier. in: path required: true type: string @@ -1582,7 +1669,9 @@ paths: format: int64 memo: type: string - title: "The related memo.\r\nFormat: memos/{id}" + title: |- + The related memo. + Format: memos/{id} tags: - ResourceService /api/v1/{setting.name}: @@ -1600,7 +1689,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: setting.name - description: "The name of the user.\r\nFormat: users/{id}" + description: |- + The name of the user. + Format: users/{id} in: path required: true type: string @@ -1637,7 +1728,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: user.name - description: "The name of the user.\r\nFormat: users/{id}" + description: |- + The name of the user. + Format: users/{id} in: path required: true type: string @@ -1691,7 +1784,9 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: name - description: "The name of the user.\r\nFormat: users/{id}" + description: |- + The name of the user. + Format: users/{id} in: path required: true type: string @@ -1724,7 +1819,10 @@ paths: $ref: '#/definitions/googlerpcStatus' parameters: - name: name - description: "The name of the resource.\r\nFormat: resources/{id}\r\nid is the system generated unique identifier." + description: |- + The name of the resource. + Format: resources/{id} + id is the system generated unique identifier. in: path required: true type: string @@ -1905,7 +2003,9 @@ definitions: properties: name: type: string - title: "The name of the identityProvider.\r\nFormat: identityProviders/{id}" + title: |- + The name of the identityProvider. + Format: identityProviders/{id} type: $ref: '#/definitions/apiv1IdentityProviderType' title: @@ -1949,7 +2049,9 @@ definitions: properties: name: type: string - title: "The name of the user.\r\nFormat: users/{id}" + title: |- + The name of the user. + Format: users/{id} locale: type: string description: The preferred locale of the user. @@ -2006,12 +2108,17 @@ 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: name: type: string - title: "name is the name of the setting.\r\nFormat: settings/{setting}" + title: |- + name is the name of the setting. + Format: settings/{setting} generalSetting: $ref: '#/definitions/apiv1WorkspaceGeneralSetting' storageSetting: @@ -2026,7 +2133,9 @@ definitions: description: storage_type is the storage type. filepathTemplate: type: string - title: "The template of file path.\r\ne.g. assets/{timestamp}_{filename}" + title: |- + The template of file path. + e.g. assets/{timestamp}_{filename} uploadSizeLimitMb: type: string format: int64 @@ -2295,7 +2404,9 @@ definitions: additionalProperties: type: integer format: int32 - description: "stats is the stats of memo creating/updating activities.\r\nkey is the year-month-day string. e.g. \"2020-01-01\"." + description: |- + stats is the stats of memo creating/updating activities. + key is the year-month-day string. e.g. "2020-01-01". v1HeadingNode: type: object properties: @@ -2329,7 +2440,9 @@ definitions: properties: name: type: string - title: "The name of the inbox.\r\nFormat: inboxes/{id}" + title: |- + The name of the inbox. + Format: inboxes/{id} sender: type: string title: 'Format: users/{id}' @@ -2449,7 +2562,10 @@ definitions: additionalProperties: type: integer format: int32 - description: "tag_amounts is the amount of tags.\r\nkey is the tag name. e.g. \"tag1\".\r\nvalue is the amount of the tag." + description: |- + tag_amounts is the amount of tags. + key is the tag name. e.g. "tag1". + value is the amount of the tag. v1ListMemosResponse: type: object properties: @@ -2460,7 +2576,9 @@ definitions: $ref: '#/definitions/v1Memo' nextPageToken: type: string - description: "A token, which can be sent as `page_token` to retrieve the next page.\r\nIf this field is omitted, there are no subsequent pages." + description: |- + A token, which can be sent as `page_token` to retrieve the next page. + If this field is omitted, there are no subsequent pages. v1ListResourcesResponse: type: object properties: @@ -2508,7 +2626,10 @@ definitions: properties: name: type: string - description: "The name of the memo.\r\nFormat: memos/{id}\r\nid is the system generated id." + description: |- + The name of the memo. + Format: memos/{id} + id is the system generated id. uid: type: string description: The user defined id of the memo. @@ -2516,7 +2637,9 @@ definitions: $ref: '#/definitions/v1RowStatus' creator: type: string - title: "The name of the creator.\r\nFormat: users/{id}" + title: |- + The name of the creator. + Format: users/{id} createTime: type: string format: date-time @@ -2569,7 +2692,9 @@ definitions: readOnly: true parent: type: string - title: "The name of the parent memo.\r\nFormat: memos/{id}" + title: |- + The name of the parent memo. + Format: memos/{id} readOnly: true v1MemoProperty: type: object @@ -2591,10 +2716,14 @@ definitions: properties: memo: type: string - title: "The name of memo.\r\nFormat: \"memos/{uid}\"" + title: |- + The name of memo. + Format: "memos/{uid}" relatedMemo: type: string - title: "The name of related memo.\r\nFormat: \"memos/{uid}\"" + title: |- + The name of related memo. + Format: "memos/{uid}" type: $ref: '#/definitions/v1MemoRelationType' v1MemoRelationType: @@ -2743,7 +2872,9 @@ definitions: format: int32 creator: type: string - title: "The name of the creator.\r\nFormat: users/{id}" + title: |- + The name of the creator. + Format: users/{id} contentId: type: string reactionType: @@ -2777,7 +2908,10 @@ definitions: properties: name: type: string - description: "The name of the resource.\r\nFormat: resources/{id}\r\nid is the system generated unique identifier." + description: |- + The name of the resource. + Format: resources/{id} + id is the system generated unique identifier. uid: type: string description: The user defined id of the resource. @@ -2799,7 +2933,9 @@ definitions: format: int64 memo: type: string - title: "The related memo.\r\nFormat: memos/{id}" + title: |- + The related memo. + Format: memos/{id} v1RestoreMarkdownRequest: type: object properties: @@ -2923,7 +3059,9 @@ definitions: properties: name: type: string - title: "The name of the user.\r\nFormat: users/{id}" + title: |- + The name of the user. + Format: users/{id} id: type: integer format: int32 @@ -2997,7 +3135,9 @@ definitions: properties: owner: type: string - title: "The name of instance owner.\r\nFormat: \"users/{id}\"" + title: |- + The name of instance owner. + Format: "users/{id}" version: type: string title: version is the current version of instance 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 15367e1d07d15..4a883c70e1852 100644 --- a/server/router/api/v1/memo_service.go +++ b/server/router/api/v1/memo_service.go @@ -226,7 +226,13 @@ 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") + } + + if !workspaceMemoRelatedSetting.EnableMembersEdit && 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, } } From 3fe1f93328f3e21c75fb1ebdd0cdf91cc3bfcd4b Mon Sep 17 00:00:00 2001 From: Iziram Date: Tue, 9 Jul 2024 14:03:23 +0200 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=90=9E=20fix(Server+Web):=20fix=20rea?= =?UTF-8?q?donly?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixes readonly not applying on public memos. --- server/router/api/v1/memo_service.go | 3 ++- web/src/components/MemoContent/index.tsx | 4 ++-- web/src/components/MemoView.tsx | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/server/router/api/v1/memo_service.go b/server/router/api/v1/memo_service.go index 4a883c70e1852..5184b3127e5ab 100644 --- a/server/router/api/v1/memo_service.go +++ b/server/router/api/v1/memo_service.go @@ -232,7 +232,8 @@ func (s *APIV1Service) UpdateMemo(ctx context.Context, request *v1pb.UpdateMemoR return nil, status.Errorf(codes.Internal, "failed to get workspace memo related setting") } - if !workspaceMemoRelatedSetting.EnableMembersEdit && memo.CreatorID != user.ID { + membersCanEdit := memo.Visibility == store.Protected && workspaceMemoRelatedSetting.EnableMembersEdit + if !membersCanEdit && memo.CreatorID != user.ID { return nil, status.Errorf(codes.PermissionDenied, "permission denied") } diff --git a/web/src/components/MemoContent/index.tsx b/web/src/components/MemoContent/index.tsx index 0c0ddcc7dd56d..2d226cdfbd56d 100644 --- a/web/src/components/MemoContent/index.tsx +++ b/web/src/components/MemoContent/index.tsx @@ -38,8 +38,8 @@ const MemoContent: React.FC = (props: Props) => { const memoContentContainerRef = useRef(null); const [showCompactMode, setShowCompactMode] = useState(false); const memo = memoName ? memoStore.getMemoByName(memoName) : null; - const readonly = !currentUser || (!workspaceMemoRelatedSetting.enableMembersEdit && currentUser.name !== memo?.name); - const allowEdit = !props.readonly && memo && !readonly; + 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 e6448e9cc8700..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 = !user || (!workspaceMemoRelatedSetting.enableMembersEdit && 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.