diff --git a/src/element/ControlBar/component/ControlBar.svelte b/src/element/ControlBar/component/ControlBar.svelte index 953c6f7..834bb9b 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); @@ -207,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: { @@ -229,6 +221,14 @@ sx_page_content_local = g_bundle.document.prettyPrint(); sx_page_content_remote = g_bundle.document.toString(); } + + if(k_page) { + 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) { + b_read_only = !await k_document.fetchUserHasUpdatePermissions();; + } + } }); function toggle_collapse() { @@ -676,7 +676,7 @@

New updates are available every morning

- +
{/if} diff --git a/src/element/QueryTable/component/QueryTable.svelte b/src/element/QueryTable/component/QueryTable.svelte index 349b481..549bbc9 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/ui/component/DatasetsTable.svelte b/src/ui/component/DatasetsTable.svelte index 8b22709..42b9f34 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, @@ -69,7 +70,6 @@ import { }; export let g_context: Context; - export let b_read_only = false; let k_object_store = g_context.store; let g_version_current: ModelVersionDescriptor; @@ -241,6 +241,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 +287,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) { @@ -364,6 +369,20 @@ import { ]; } + 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 */ @@ -540,10 +559,14 @@ import { {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} diff --git a/src/vendor/confluence/module/confluence.ts b/src/vendor/confluence/module/confluence.ts index a42690a..52fdf4c 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 page restrictions + const g_response_page = 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_page.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 {