From d55b6e10b71ba9fe84e976dfa50e115cd114e34c Mon Sep 17 00:00:00 2001 From: AaronOneBlink Date: Mon, 8 Sep 2025 15:54:27 +1000 Subject: [PATCH 1/3] AP-5031 # changed draft-service to check if a user is authorised --- src/auth-service.ts | 2 +- src/draft-service.ts | 81 ++++++++++++++++++++------------ src/services/draft-data-store.ts | 5 +- 3 files changed, 54 insertions(+), 34 deletions(-) diff --git a/src/auth-service.ts b/src/auth-service.ts index f0b61355..10b57863 100644 --- a/src/auth-service.ts +++ b/src/auth-service.ts @@ -130,7 +130,7 @@ export async function isAuthorised( abortSignal?: AbortSignal, ): Promise { return getCurrentFormsAppUser(formsAppId, abortSignal) - .then(() => true) + .then((user) => !!user) .catch((error) => { if (error.status >= 400 && error.status < 500) { return false diff --git a/src/draft-service.ts b/src/draft-service.ts index 84c266e6..fa30301f 100644 --- a/src/draft-service.ts +++ b/src/draft-service.ts @@ -3,8 +3,11 @@ import _orderBy from 'lodash.orderby' import utilsService from './services/utils' import OneBlinkAppsError from './services/errors/oneBlinkAppsError' import { isOffline } from './offline-service' -import { getUsername, isLoggedIn } from './services/cognito' -import { getFormsKeyId } from './auth-service' +import { getUsername } from './services/cognito' +import { + getFormsKeyId, + isAuthorised as isFormsAppUserAuthorised, +} from './auth-service' import { getFormSubmissionDrafts, uploadDraftData } from './services/api/drafts' import { getPendingQueueSubmissions, @@ -214,7 +217,6 @@ function registerDraftsListener( async function executeDraftsListeners( localFormSubmissionDrafts: LocalFormSubmissionDraft[], ) { - console.log('Drafts have been updated', localFormSubmissionDrafts) for (const draftsListener of draftsListeners) { draftsListener(localFormSubmissionDrafts) } @@ -291,14 +293,18 @@ async function upsertDraft({ } try { + const isAuthorised = await isFormsAppUserAuthorised( + draftSubmission.formsAppId, + ) const formSubmissionDraftVersion = await saveDraftSubmission({ draftSubmission, autoSaveKey, onProgress, + isAuthorised, }) - if (isLoggedIn()) { - const localDraftsStorage = await getLocalDrafts() + if (isAuthorised) { + const localDraftsStorage = await getLocalDraftsFromStorage() if (formSubmissionDraftVersion) { console.log('Draft was saved on server', formSubmissionDraftVersion) @@ -349,7 +355,7 @@ async function upsertDraft({ await setAndBroadcastDrafts(localDraftsStorage) } else { let updated = false - const publicDraftsStorage = (await getPublicDrafts()).map( + const publicDraftsStorage = (await getPublicDraftsFromStorage()).map( (publicDraftSubmission) => { if ( publicDraftSubmission.formSubmissionDraftId === @@ -380,7 +386,7 @@ async function upsertDraft({ } } -async function getLocalDrafts(): Promise { +async function getLocalDraftsFromStorage(): Promise { const username = getUsername() if (username) { try { @@ -404,7 +410,7 @@ async function getLocalDrafts(): Promise { } } -async function getPublicDrafts(): Promise { +async function getPublicDraftsFromStorage(): Promise { try { const publicDrafts = await utilsService.localForage.getItem< DraftSubmission[] @@ -432,17 +438,26 @@ async function getPublicDrafts(): Promise { * @returns */ async function getDrafts(): Promise { - if (isLoggedIn()) { - const localDraftsStorage = await getLocalDrafts() - return await generateLocalFormSubmissionDraftsFromStorage( - localDraftsStorage, - ) - } else { - const publicDraftsStorage = await getPublicDrafts() - return await generatePublicLocalFormSubmissionDraftsFromStorage( - publicDraftsStorage, - ) - } + const localDraftsStorage = await getLocalDraftsFromStorage() + return await generateLocalFormSubmissionDraftsFromStorage(localDraftsStorage) +} + +/** + * Get an array of Drafts that have been submitted publicly on this device. + * + * #### Example + * + * ```js + * const drafts = await draftService.getPublicDrafts() + * ``` + * + * @returns + */ +async function getPublicDrafts(): Promise { + const publicDraftsStorage = await getPublicDraftsFromStorage() + return await generatePublicLocalFormSubmissionDraftsFromStorage( + publicDraftsStorage, + ) } async function tryGetFormSubmissionDrafts( @@ -486,8 +501,9 @@ async function getDraftAndData( formsAppId, abortSignal, ) - if (isLoggedIn()) { - const localDraftsStorage = await getLocalDrafts() + const isAuthorised = await isFormsAppUserAuthorised(formsAppId) + if (isAuthorised) { + const localDraftsStorage = await getLocalDraftsFromStorage() if (formSubmissionDrafts) { localDraftsStorage.syncedFormSubmissionDrafts = formSubmissionDrafts await setAndBroadcastDrafts(localDraftsStorage) @@ -531,8 +547,9 @@ async function deleteDraft( ): Promise { try { await removeLocalDraftSubmission(formSubmissionDraftId) - if (isLoggedIn()) { - const localDraftsStorage = await getLocalDrafts() + const isAuthorised = await isFormsAppUserAuthorised(formsAppId) + if (isAuthorised) { + const localDraftsStorage = await getLocalDraftsFromStorage() const formSubmissionDraft = localDraftsStorage.syncedFormSubmissionDrafts.find( ({ id }) => id === formSubmissionDraftId, @@ -577,7 +594,7 @@ async function deleteDraft( await setAndBroadcastDrafts(localDraftsStorage) } else { - let publicDraftsStorage = await getPublicDrafts() + let publicDraftsStorage = await getPublicDraftsFromStorage() const draftSubmission = publicDraftsStorage.find( (draftSubmission) => draftSubmission.formSubmissionDraftId === formSubmissionDraftId, @@ -678,10 +695,10 @@ async function syncDrafts({ } _isSyncingDrafts = true - console.log('Start attempting to sync drafts.') + const isAuthorised = await isFormsAppUserAuthorised(formsAppId) - if (!isLoggedIn()) { - const publicDrafts = await getPublicDrafts() + if (!isAuthorised) { + const publicDrafts = await getPublicDraftsFromStorage() const filteredPublicDrafts = [] // iterate through public draft records, and check if a draft submission exists for each record. // If no draft submission exists for a record, the draft was likely submitted, so we must remove it @@ -700,7 +717,7 @@ async function syncDrafts({ } try { - let localDraftsStorage = await getLocalDrafts() + let localDraftsStorage = await getLocalDraftsFromStorage() if (localDraftsStorage.deletedFormSubmissionDrafts.length) { console.log( 'Removing local draft data for deleted drafts', @@ -719,12 +736,12 @@ async function syncDrafts({ } // Get local drafts again to ensure nothing has happened while processing - localDraftsStorage = await getLocalDrafts() + localDraftsStorage = await getLocalDraftsFromStorage() localDraftsStorage.deletedFormSubmissionDrafts = newDeletedFormSubmissionDrafts } - const publicDraftsStorage = await getPublicDrafts() + const publicDraftsStorage = await getPublicDraftsFromStorage() // if public drafts exist, add them to the current logged in users' unsynced drafts // and remove them from local storage if (publicDraftsStorage.length) { @@ -747,13 +764,14 @@ async function syncDrafts({ draftSubmission, autoSaveKey: undefined, abortSignal, + isAuthorised, }) if (!formSubmissionDraftVersion) { newUnsyncedDraftSubmissions.push(draftSubmission) } } // Get local drafts again to ensure nothing has happened while processing - localDraftsStorage = await getLocalDrafts() + localDraftsStorage = await getLocalDraftsFromStorage() localDraftsStorage.unsyncedDraftSubmissions = newUnsyncedDraftSubmissions } @@ -807,6 +825,7 @@ export { upsertDraft, getDraftAndData, getDrafts, + getPublicDrafts, deleteDraft, syncDrafts, getLatestFormSubmissionDraftVersion, diff --git a/src/services/draft-data-store.ts b/src/services/draft-data-store.ts index 21dfd1c0..daac81bc 100644 --- a/src/services/draft-data-store.ts +++ b/src/services/draft-data-store.ts @@ -9,7 +9,6 @@ import { SubmissionTypes } from '@oneblink/types' import Sentry from '../Sentry' import { DraftSubmission, ProgressListener } from '../types/submissions' import { deleteAutoSaveData } from '../auto-save-service' -import { isLoggedIn } from './cognito' function getLocalDraftSubmissionKey(formSubmissionDraftId: string) { return `DRAFT_SUBMISSION_${formSubmissionDraftId}` @@ -47,11 +46,13 @@ export async function saveDraftSubmission({ autoSaveKey, onProgress, abortSignal, + isAuthorised, }: { draftSubmission: DraftSubmission autoSaveKey: string | undefined onProgress?: ProgressListener abortSignal?: AbortSignal + isAuthorised?: boolean }): Promise { await setLocalDraftSubmission(draftSubmission) @@ -60,7 +61,7 @@ export async function saveDraftSubmission({ } try { - if (isLoggedIn()) { + if (isAuthorised) { return await uploadDraftData(draftSubmission, onProgress, abortSignal) } } catch (error) { From 358cf730172db7f5c42d48bfa0b56bf6bfa1d8f6 Mon Sep 17 00:00:00 2001 From: AaronOneBlink Date: Mon, 8 Sep 2025 16:25:17 +1000 Subject: [PATCH 2/3] fixed function naming --- src/auth-service.ts | 38 --------------------------- src/draft-service.ts | 45 ++++++++++++++++++++++---------- src/services/draft-data-store.ts | 6 ++--- 3 files changed, 34 insertions(+), 55 deletions(-) diff --git a/src/auth-service.ts b/src/auth-service.ts index 10b57863..e00bbb3b 100644 --- a/src/auth-service.ts +++ b/src/auth-service.ts @@ -107,44 +107,6 @@ export function init({ oAuthClientId }: { oAuthClientId: string }) { registerAuthListener(listener) } -/** - * Determine if the current user is a OneBlink App User for a OneBlink Forms - * App. Returns `false` if the current user is not logged in. - * - * #### Example - * - * ```js - * const formsAppId = 1 - * const isAuthorised = await authService.isAuthorised(formsAppId) - * if (!isAuthorised) { - * // handle unauthorised user - * } - * ``` - * - * @param formsAppId - * @param abortSignal - * @returns - */ -export async function isAuthorised( - formsAppId: number, - abortSignal?: AbortSignal, -): Promise { - return getCurrentFormsAppUser(formsAppId, abortSignal) - .then((user) => !!user) - .catch((error) => { - if (error.status >= 400 && error.status < 500) { - return false - } else { - Sentry.captureException(error) - console.log( - 'Could not determine if the current user has access to this forms app', - error, - ) - return false - } - }) -} - /** * Get the current user's App User details for a OneBlink Forms App. Returns * `undefined` if the current user is not logged in. diff --git a/src/draft-service.ts b/src/draft-service.ts index fa30301f..460c5c39 100644 --- a/src/draft-service.ts +++ b/src/draft-service.ts @@ -4,10 +4,7 @@ import utilsService from './services/utils' import OneBlinkAppsError from './services/errors/oneBlinkAppsError' import { isOffline } from './offline-service' import { getUsername } from './services/cognito' -import { - getFormsKeyId, - isAuthorised as isFormsAppUserAuthorised, -} from './auth-service' +import { getFormsKeyId, getCurrentFormsAppUser } from './auth-service' import { getFormSubmissionDrafts, uploadDraftData } from './services/api/drafts' import { getPendingQueueSubmissions, @@ -44,6 +41,26 @@ interface LocalDraftsStorage { syncedFormSubmissionDrafts: SubmissionTypes.FormSubmissionDraft[] } +async function checkIfUsingPrivateDrafts( + formsAppId: number, + abortSignal?: AbortSignal, +): Promise { + return getCurrentFormsAppUser(formsAppId, abortSignal) + .then((user) => !!user) + .catch((error) => { + if (error.status >= 400 && error.status < 500) { + return false + } else { + Sentry.captureException(error) + console.log( + 'Could not determine if the current user has access to this forms app', + error, + ) + return false + } + }) +} + function generateLocalFormSubmissionDraftsFromDraftSubmissions( draftSubmissions: DraftSubmission[], pendingSubmissionsDraftIds: Set, @@ -293,17 +310,17 @@ async function upsertDraft({ } try { - const isAuthorised = await isFormsAppUserAuthorised( + const isUsingPrivateDrafts = await checkIfUsingPrivateDrafts( draftSubmission.formsAppId, ) const formSubmissionDraftVersion = await saveDraftSubmission({ draftSubmission, autoSaveKey, onProgress, - isAuthorised, + skipUpload: !isUsingPrivateDrafts, }) - if (isAuthorised) { + if (isUsingPrivateDrafts) { const localDraftsStorage = await getLocalDraftsFromStorage() if (formSubmissionDraftVersion) { @@ -501,8 +518,8 @@ async function getDraftAndData( formsAppId, abortSignal, ) - const isAuthorised = await isFormsAppUserAuthorised(formsAppId) - if (isAuthorised) { + const isUsingPrivateDrafts = await checkIfUsingPrivateDrafts(formsAppId) + if (isUsingPrivateDrafts) { const localDraftsStorage = await getLocalDraftsFromStorage() if (formSubmissionDrafts) { localDraftsStorage.syncedFormSubmissionDrafts = formSubmissionDrafts @@ -547,8 +564,8 @@ async function deleteDraft( ): Promise { try { await removeLocalDraftSubmission(formSubmissionDraftId) - const isAuthorised = await isFormsAppUserAuthorised(formsAppId) - if (isAuthorised) { + const isUsingPrivateDrafts = await checkIfUsingPrivateDrafts(formsAppId) + if (isUsingPrivateDrafts) { const localDraftsStorage = await getLocalDraftsFromStorage() const formSubmissionDraft = localDraftsStorage.syncedFormSubmissionDrafts.find( @@ -695,9 +712,9 @@ async function syncDrafts({ } _isSyncingDrafts = true - const isAuthorised = await isFormsAppUserAuthorised(formsAppId) + const isUsingPrivateDrafts = await checkIfUsingPrivateDrafts(formsAppId) - if (!isAuthorised) { + if (!isUsingPrivateDrafts) { const publicDrafts = await getPublicDraftsFromStorage() const filteredPublicDrafts = [] // iterate through public draft records, and check if a draft submission exists for each record. @@ -764,7 +781,7 @@ async function syncDrafts({ draftSubmission, autoSaveKey: undefined, abortSignal, - isAuthorised, + skipUpload: !isUsingPrivateDrafts, }) if (!formSubmissionDraftVersion) { newUnsyncedDraftSubmissions.push(draftSubmission) diff --git a/src/services/draft-data-store.ts b/src/services/draft-data-store.ts index daac81bc..6ade9e5f 100644 --- a/src/services/draft-data-store.ts +++ b/src/services/draft-data-store.ts @@ -46,13 +46,13 @@ export async function saveDraftSubmission({ autoSaveKey, onProgress, abortSignal, - isAuthorised, + skipUpload, }: { draftSubmission: DraftSubmission autoSaveKey: string | undefined onProgress?: ProgressListener abortSignal?: AbortSignal - isAuthorised?: boolean + skipUpload?: boolean }): Promise { await setLocalDraftSubmission(draftSubmission) @@ -61,7 +61,7 @@ export async function saveDraftSubmission({ } try { - if (isAuthorised) { + if (!skipUpload) { return await uploadDraftData(draftSubmission, onProgress, abortSignal) } } catch (error) { From 8ba2df45992b86ab64dd50d38db9678991cc00ec Mon Sep 17 00:00:00 2001 From: AaronOneBlink Date: Mon, 8 Sep 2025 16:47:37 +1000 Subject: [PATCH 3/3] re-add isAuthorised fn --- src/auth-service.ts | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/auth-service.ts b/src/auth-service.ts index e00bbb3b..f0b61355 100644 --- a/src/auth-service.ts +++ b/src/auth-service.ts @@ -107,6 +107,44 @@ export function init({ oAuthClientId }: { oAuthClientId: string }) { registerAuthListener(listener) } +/** + * Determine if the current user is a OneBlink App User for a OneBlink Forms + * App. Returns `false` if the current user is not logged in. + * + * #### Example + * + * ```js + * const formsAppId = 1 + * const isAuthorised = await authService.isAuthorised(formsAppId) + * if (!isAuthorised) { + * // handle unauthorised user + * } + * ``` + * + * @param formsAppId + * @param abortSignal + * @returns + */ +export async function isAuthorised( + formsAppId: number, + abortSignal?: AbortSignal, +): Promise { + return getCurrentFormsAppUser(formsAppId, abortSignal) + .then(() => true) + .catch((error) => { + if (error.status >= 400 && error.status < 500) { + return false + } else { + Sentry.captureException(error) + console.log( + 'Could not determine if the current user has access to this forms app', + error, + ) + return false + } + }) +} + /** * Get the current user's App User details for a OneBlink Forms App. Returns * `undefined` if the current user is not logged in.