From da7cf3a362f380fd09967e0f7ff6537dbd0c86b2 Mon Sep 17 00:00:00 2001 From: Justine West Date: Tue, 17 Jan 2023 11:25:10 -0800 Subject: [PATCH 1/3] hide table edit/update to latest when read only --- .../ControlBar/component/ControlBar.svelte | 15 +++-- .../QueryTable/component/QueryTable.svelte | 30 +++++++--- src/vendor/confluence/main/entrypoint.ts | 3 + src/vendor/confluence/module/confluence.ts | 56 +++++++++++++++++++ 4 files changed, 90 insertions(+), 14 deletions(-) diff --git a/src/element/ControlBar/component/ControlBar.svelte b/src/element/ControlBar/component/ControlBar.svelte index 953c6f7..43b85a5 100644 --- a/src/element/ControlBar/component/ControlBar.svelte +++ b/src/element/ControlBar/component/ControlBar.svelte @@ -167,11 +167,6 @@ // go async to allow svelte components to bind to local variables await Promise.resolve(); - // user does not have write permisisons to this page - if('READ_WRITE' !== G_META.access_mode) { - b_read_only = true; - } - // initial control bar alignment queueMicrotask(realign_control_bar); @@ -229,6 +224,16 @@ sx_page_content_local = g_bundle.document.prettyPrint(); sx_page_content_remote = g_bundle.document.toString(); } + + + if(k_page) { + let b_has_page_update = await k_page.fetchUserHasUpdatePermissions(); + b_read_only = !b_has_page_update; + if(k_document) { + let b_has_doc_update = await k_document.fetchUserHasUpdatePermissions(); + b_read_only = !b_has_page_update || b_has_doc_update; + } + } }); function toggle_collapse() { diff --git a/src/element/QueryTable/component/QueryTable.svelte b/src/element/QueryTable/component/QueryTable.svelte index 48584fd..bf63a57 100644 --- a/src/element/QueryTable/component/QueryTable.svelte +++ b/src/element/QueryTable/component/QueryTable.svelte @@ -107,6 +107,9 @@ // table edited $: b_changed = b_published? si_query_hash_previous !== si_query_hash_published : '' !== si_query_hash_previous; + // read-only mode + let b_read_only = true; + // once the component mounts onMount(async() => { // get query table's connection @@ -141,6 +144,13 @@ } // keep track of the number of rows in the published table n_published_rows = get_published_table_rows().length; + + // determine if the user has read-only access + const k_page = k_model.getContext().page; + + if(k_page) { + b_read_only = !await k_page.fetchUserHasUpdatePermissions(); + } }); const A_DUMMY_TABLE_ROWS = [{}, {}, {}]; @@ -775,15 +785,17 @@ Connected Data Table {g_source ? `with ${g_source.label}` : ''} - - - {#if b_display_parameters} - - - {/if} - + {#if !b_read_only} + + + {#if b_display_parameters} + + + {/if} + + {/if}
diff --git a/src/vendor/confluence/main/entrypoint.ts b/src/vendor/confluence/main/entrypoint.ts index 6324afc..73ea22b 100644 --- a/src/vendor/confluence/main/entrypoint.ts +++ b/src/vendor/confluence/main/entrypoint.ts @@ -373,6 +373,9 @@ function replace_edit_button() { if (p_original_edit_link) return; const dm_edit = qs(dm_main, 'a#editPageLink')! as HTMLAnchorElement; + if (!dm_edit) { // no edit button + return; + } p_original_edit_link = dm_edit.href; dm_edit.href = SR_HASH_VE_PAGE_EDIT_MODE; // remove all event listeners diff --git a/src/vendor/confluence/module/confluence.ts b/src/vendor/confluence/module/confluence.ts index a42690a..79ebea8 100644 --- a/src/vendor/confluence/module/confluence.ts +++ b/src/vendor/confluence/module/confluence.ts @@ -867,6 +867,62 @@ export class ConfluencePage extends ConfluenceEntity { async isDocumentMember(): Promise { return null !== await this.fetchDocument(); } + + async fetchUserHasUpdatePermissions(): Promise { + + // fetch document cover page restrictions + const g_response_cover = await confluence_get_json(`/content/${this.pageId}/restriction/byOperation/update`, { + search: { + expand: ['restrictions.user', 'restrictions.group'].join(','), + }, + }); + + + // destructure response data + const g_data = g_response_cover.data!; + const { + group: { + results: a_groups_cover, + }, + user: { + results: a_users_cover, + }, + } = g_data.restrictions; + + // no restriction(s) exists + if(!a_groups_cover.length && !a_users_cover.length) { + return true; + } + + // user key + const si_user_current = G_META.remote_user_key; + + // each user + for(const g_user of a_users_cover) { + // found current user + if(g_user.userKey === si_user_current) return true; + } + + // fetch user groups + const g_response_user = await confluence_get_json('/user/memberof', { + search: { + key: G_META.remote_user_key, + }, + }); + + // convert user groups into set + const as_groups_user = new Set((g_response_user.data?.results || []).map(g_group => g_group.name)); + + // each group + for(const g_group of a_groups_cover) { + // user belongs to authorized group + if(as_groups_user.has(g_group.name)) { + return true; + } + } + + return false; + } } export class ConfluenceDocument extends ConfluenceEntity { From d4bc0d02635e484b1cd49dc8d924daf174843df4 Mon Sep 17 00:00:00 2001 From: Justine West Date: Tue, 17 Jan 2023 16:00:01 -0800 Subject: [PATCH 2/3] cleanup --- .../ControlBar/component/ControlBar.svelte | 11 ++----- src/ui/component/DatasetsTable.svelte | 31 ++++++++++++++----- src/vendor/confluence/module/confluence.ts | 6 ++-- 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/src/element/ControlBar/component/ControlBar.svelte b/src/element/ControlBar/component/ControlBar.svelte index 43b85a5..b936d02 100644 --- a/src/element/ControlBar/component/ControlBar.svelte +++ b/src/element/ControlBar/component/ControlBar.svelte @@ -202,9 +202,6 @@ sx_document_metadata_local = JSON.stringify(g_bundle?.data, null, ' '); sx_document_metadata_remote = JSON.stringify(g_bundle?.data); - - // user does not have edit permissions to document - b_read_only ||= !await k_document.fetchUserHasUpdatePermissions(); // eslint-disable-line @typescript-eslint/no-unsafe-call } LOAD_PAGE_METADATA: { @@ -225,13 +222,11 @@ sx_page_content_remote = g_bundle.document.toString(); } - if(k_page) { - let b_has_page_update = await k_page.fetchUserHasUpdatePermissions(); - b_read_only = !b_has_page_update; + b_read_only = !await k_page.fetchUserHasUpdatePermissions();; + // page is in a document, determine if the user has edit access to the document if(k_document) { - let b_has_doc_update = await k_document.fetchUserHasUpdatePermissions(); - b_read_only = !b_has_page_update || b_has_doc_update; + b_read_only = !await k_document.fetchUserHasUpdatePermissions();; } } }); diff --git a/src/ui/component/DatasetsTable.svelte b/src/ui/component/DatasetsTable.svelte index 8b22709..a24d13d 100644 --- a/src/ui/component/DatasetsTable.svelte +++ b/src/ui/component/DatasetsTable.svelte @@ -25,9 +25,10 @@ import { VeOdm, } from '#/model/Serializable'; -import { - ObjectStore -} from '#/model/ObjectStore'; + + import { + ObjectStore + } from '#/model/ObjectStore'; import { faCheckCircle, @@ -123,6 +124,15 @@ import { } A_CONNECTIONS = A_CONNECTIONS; + + const k_page = g_context.page; + const k_document = g_context.document; + if(k_page) { + b_read_only = !await k_page.fetchUserHasUpdatePermissions(); + if(k_document) { + b_read_only = !await k_document.fetchUserHasUpdatePermissions();; + } + } })(); function set_connection_properties(k_connection: Connection, h_set: Partial) { @@ -241,6 +251,9 @@ import { // download page const k_page = ConfluencePage.fromBasicPageInfo(g_page); + // don't update page if the user doesn't have access to it + if(!await k_page.fetchUserHasUpdatePermissions()) continue; + // fetch xhtml contents let { document: k_doc, @@ -284,11 +297,13 @@ import { cf.setConnection(k_connection_new); let cfstring = await cf.fetchDisplayText(); let display = cdataDoc.select('//span[@class="ve-transclusion-display"]')[0].childNodes.item(0) as Text; - display.replaceData(0, display.data.length, cfstring); - cdataNode.replaceData(0, cdataNode.data.length, cdataDoc.toString()); - set_connection_properties(k_connection, { - cfs_touched_count: ++c_cfs_touched, - }); + if(display) { + display.replaceData(0, display.data.length, cfstring); + cdataNode.replaceData(0, cdataNode.data.length, cdataDoc.toString()); + set_connection_properties(k_connection, { + cfs_touched_count: ++c_cfs_touched, + }); + } } let sx_new_page = k_doc.toString(); if (sx_page === sx_new_page) { diff --git a/src/vendor/confluence/module/confluence.ts b/src/vendor/confluence/module/confluence.ts index 79ebea8..52fdf4c 100644 --- a/src/vendor/confluence/module/confluence.ts +++ b/src/vendor/confluence/module/confluence.ts @@ -870,8 +870,8 @@ export class ConfluencePage extends ConfluenceEntity { async fetchUserHasUpdatePermissions(): Promise { - // fetch document cover page restrictions - const g_response_cover = await confluence_get_json(`/content/${this.pageId}/restriction/byOperation/update`, { + // fetch page restrictions + const g_response_page = await confluence_get_json(`/content/${this.pageId}/restriction/byOperation/update`, { search: { expand: ['restrictions.user', 'restrictions.group'].join(','), }, @@ -879,7 +879,7 @@ export class ConfluencePage extends ConfluenceEntity { // destructure response data - const g_data = g_response_cover.data!; + const g_data = g_response_page.data!; const { group: { results: a_groups_cover, From 91086e9df86acad6324ac4b4677b20543f9ee6b1 Mon Sep 17 00:00:00 2001 From: Justine West Date: Wed, 18 Jan 2023 17:12:24 -0800 Subject: [PATCH 3/3] disable update data version for those w/o edit --- .../ControlBar/component/ControlBar.svelte | 2 +- src/ui/component/DatasetsTable.svelte | 34 ++++++++++++------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/element/ControlBar/component/ControlBar.svelte b/src/element/ControlBar/component/ControlBar.svelte index b936d02..834bb9b 100644 --- a/src/element/ControlBar/component/ControlBar.svelte +++ b/src/element/ControlBar/component/ControlBar.svelte @@ -676,7 +676,7 @@

New updates are available every morning

- +
{/if} diff --git a/src/ui/component/DatasetsTable.svelte b/src/ui/component/DatasetsTable.svelte index a24d13d..42b9f34 100644 --- a/src/ui/component/DatasetsTable.svelte +++ b/src/ui/component/DatasetsTable.svelte @@ -70,7 +70,6 @@ }; export let g_context: Context; - export let b_read_only = false; let k_object_store = g_context.store; let g_version_current: ModelVersionDescriptor; @@ -124,15 +123,6 @@ } A_CONNECTIONS = A_CONNECTIONS; - - const k_page = g_context.page; - const k_document = g_context.document; - if(k_page) { - b_read_only = !await k_page.fetchUserHasUpdatePermissions(); - if(k_document) { - b_read_only = !await k_document.fetchUserHasUpdatePermissions();; - } - } })(); function set_connection_properties(k_connection: Connection, h_set: Partial) { @@ -379,6 +369,20 @@ ]; } + async function can_update_to_latest(k_connection: Connection): Promise { + const info = await locate_tables(k_connection) + if(!info) return false; + for(const g_page of info.pages) { // TODO this should just requery all pages to prevent potential outdated data/conflicts + // download page + let k_page = ConfluencePage.fromBasicPageInfo(g_page); + let b_user_can_update = await k_page.fetchUserHasUpdatePermissions(); + if(!b_user_can_update){ + return false; + } + } + return true; + } + /* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call */ @@ -555,10 +559,14 @@ {k_connection.label} {#await fetch_version_info(k_connection)} -   Loading... - {:then [g_current_version, g_latest_version, s_hash, s_current_version, s_latest_version]} -   {s_current_version}     +   Loading...   + {:then [g_current_version, g_latest_version, s_hash, s_current_version, s_latest_version]} + {#await can_update_to_latest(k_connection)} +   Loading...   + {:then b_can_update} +   {s_current_version}     + {/await} {/await}